001package com.identityworksllc.iiq.common.iterators; 002 003import sailpoint.api.SailPointContext; 004import sailpoint.tools.GeneralException; 005import sailpoint.tools.RFC4180LineParser; 006import sailpoint.tools.Util; 007 008import java.util.ArrayList; 009import java.util.Collections; 010import java.util.List; 011 012/** 013 * The generic implementation of a colon-separated column token, e.g., 'col1:blah:stuff'. 014 * The first component of a column token is always the column name, as it would be recognized 015 * by JDBC's ResultSet class. If present, the second component is always a type token. 016 * 017 * At this time, type tokens are understood by {@link ResultSetIterator#deriveTypedValue(SailPointContext, Object, String)}. 018 * See that method's documentation for the accepted type token values. 019 * 020 * If a third (or more) component is present, they will be considered arguments to the type 021 * interpreter and vary by type. For example, a timestamp type may accept a date format. 022 * 023 * Token components are split using Sailpoint's {@link RFC4180LineParser}, meaning that quotes 024 * are respected like a typical CSV. 025 */ 026public final class ColumnToken { 027 /** 028 * The base column name 029 */ 030 private String baseColumnName; 031 032 /** 033 * Any type parameters passed after the 2nd argument 034 */ 035 private final List<String> typeParameters; 036 037 /** 038 * The type token 039 */ 040 private String typeToken; 041 042 /** 043 * Creates a new column token object from the input 044 * 045 * @param input The input string of the form described in deriveTypedValue 046 */ 047 public ColumnToken(String input) { 048 if (Util.isNullOrEmpty(input)) { 049 throw new IllegalArgumentException("Column token string cannot be null or empty"); 050 } 051 052 this.typeParameters = new ArrayList<>(); 053 054 try { 055 RFC4180LineParser parser = new RFC4180LineParser(ColumnConfig.COLUMN_TYPE_SEPARATOR); 056 List<String> pieces = parser.parseLine(input); 057 058 if (pieces.size() == 1) { 059 this.baseColumnName = pieces.get(0); 060 this.typeToken = null; 061 } else if (pieces.size() >= 2) { 062 this.baseColumnName = pieces.get(0); 063 this.typeToken = pieces.get(1); 064 if (pieces.size() >= 3) { 065 for (int p = 2; p < pieces.size(); p++) { 066 String piece = pieces.get(p); 067 if (piece == null) { 068 piece = ""; 069 } 070 this.typeParameters.add(piece); 071 } 072 } 073 } 074 } catch (GeneralException e) { 075 throw new IllegalArgumentException("Unparseable input: " + input, e); 076 } 077 } 078 079 /** 080 * Returns the base column name (the start of the token) 081 * 082 * @return The base column name 083 */ 084 public String getBaseColumnName() { 085 return baseColumnName; 086 } 087 088 /** 089 * Returns the given type parameter, or null if the index given is out of bounds 090 * 091 * @param index The type parameter index 092 * @return The value requested, or null if not defined 093 */ 094 public String getTypeParameter(int index) { 095 if (index < this.typeParameters.size() && index >= 0) { 096 return this.typeParameters.get(index); 097 } else { 098 return null; 099 } 100 } 101 102 /** 103 * Gets the list of type parameters, which is always non-null, but may be empty 104 * 105 * @return The list of type parameters 106 */ 107 public List<String> getTypeParameters() { 108 return Collections.unmodifiableList(typeParameters); 109 } 110 111 /** 112 * Gets the type token part of the string, e.g., 'xml' or 'timestamp' 113 * 114 * @return The type token part of the input string 115 */ 116 public String getTypeToken() { 117 return typeToken; 118 } 119}