001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * docs/licenses/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * docs/licenses/cddl.txt.  If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 *      Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 *      Copyright 2017-2021 Ping Identity Corporation
026 */
027package com.unboundid.directory.sdk.common.types;
028
029import com.unboundid.ldap.sdk.LDAPException;
030import com.unboundid.util.ThreadSafety;
031import com.unboundid.util.ThreadSafetyLevel;
032
033import java.util.List;
034
035/**
036 * A ValueConstructor is used to build String values using a value-pattern
037 * template that references attribute values within an Entry. An instance is
038 * created by calling {@link ServerContext#createValueConstructor}.
039 *
040 * <h2>Referencing Attribute Values</h2>
041 *
042 * Any text provided in the value-pattern is copied verbatim into the
043 * constructed value with the exception of attribute names embedded
044 * in '{}'s. For instance, a value template of "{uid}@example.com"
045 * and an entry with a uid value of "jsmith" would produce a value
046 * of "jsmith@example.com".
047 *
048 * <p>
049 * If a value template references multiple attributes, at most one may be
050 * multivalued. If one attribute is multivalued then the returned value
051 * will be multivalued with the same number of values.
052 * For example a template of '{givenName} {sn}' would produce
053 * values ['Jim Smith', 'James Smith'] if givenName had values of ['Jim',
054 * 'James'] and sn had a value of 'Smith'. If the source entry has no
055 * value or if there are multiple multivalued attributes, the attribute
056 * value construction will fail.
057 *
058 * <p>
059 * To include a '{' in the constructed value (when constructing JSON for
060 * instance) use '{{' in the value-pattern. Likewise, '}}' will result in '}'
061 * in the value pattern.
062 *
063 * <h2>Regular Expressions</h2>
064 *
065 * A regular expression with a substitution pattern can be used
066 * to further manipulate an individual attribute
067 * value.  The java.util.regex.Pattern and java.util.regex.Matcher
068 * classes are used to perform the substitution.
069 * The regular expression with replacement value uses this syntax
070 * '{attr-name:/regex/replacement/flags}'.
071 * <ul>
072 *  <li>
073 *   'attr-name' is an attribute name such as 'cn'.
074 *  </li>
075 *  <li>
076 *   'regex' is a regular expression using the syntax described in the
077 *   java.util.regex.Pattern javadoc.  The optional flag value can also
078 *   be used to change how this regular expression is interpreted.
079 *  </li>
080 *  <li>
081 *   'replacement' is a replacement value that is passed to the
082 *   java.util.regex.Matcher#replaceFirst or java.util.regex.Matcher#replaceAll
083 *   method to perform the replacement.  The 'g' (global) flag controls
084 *   whether replaceFirst or replaceAll is called.
085 *  </li>
086 *  <li>
087 *   'flags' is an optional set of single character flags that
088 *   control how the regular expression is interpreted and how the replacement
089 *   is performed. The flags are:
090 *   <ul>
091 *    <li>
092 *     'g' : Matcher#replaceAll is called instead of Matcher#replaceFirst to
093 *           replace all matching values instead of just the first one.
094 *    </li>
095 *    <li>
096 *     'i' : the regex pattern is compiled with Pattern.CASE_INSENSITIVE.
097 *    </li>
098 *    <li>
099 *     'x' : the regex pattern is compiled with Pattern.COMMENTS.
100 *    </li>
101 *    <li>
102 *     's' : the regex pattern is compiled with Pattern.DOTALL.
103 *    </li>
104 *    <li>
105 *     'm' : the regex pattern is compiled with Pattern.MULTILINE.
106 *    </li>
107 *    <li>
108 *     'u' : the regex pattern is compiled with Pattern.UNICODE_CASE.
109 *    </li>
110 *    <li>
111 *     'd' : the regex pattern is compiled with Pattern.UNIX_LINES.
112 *    </li>
113 *   </ul>
114 * </ul>
115 *
116 * The substitution value is constructed using Java code equivalent to:
117 * <pre>
118 *   Pattern pattern = Pattern.compile(regex, flagsMask);
119 *   Matcher matcher = pattern.matcher(attributeValueInput);
120 *   String substitutionValueOutput = matcher.replaceFirst(replacement);
121 * </pre>
122 *
123 * <h2>JSON Attribute Values</h2>
124 *
125 * To extract JSON fields within JSON attributes append '.' and then the
126 * JSON field to extract to the attribute name. For example, if
127 * 'ubidEmailJSON' is a JSON attribute and the 'value' field is to be
128 * extracted then 'ubidEmailJSON.value' could be specified for the attribute
129 * name resulting in '{ubidEmailJSON.value}' or
130 * '{ubidEmailJSON.value:/regex/replacement/flags}' if a regular expression
131 * is to be used.
132 *
133 * <h2>Escaping and Transforming Attribute Values</h2>
134 *
135 * To apply modifiers to the values extracted append ':' and then the name
136 * of the modifier to apply. For example, if attribute 'mail' is to be
137 * included in a constructed JSON value then modifier 'jsonEscape' could be
138 * specified resulting in '{{ "userMail":"{mail:jsonEscape}" }}' or
139 * '{{ "userMail":"{mail:/regex/replacement/flags:jsonEscape}" }}' if a
140 * regular expression is to be used. Note that '{{' expands to '{' and
141 * '}}' to '}'.
142 *
143 * <p>
144 * The modifiers are:
145 * <ul>
146 *   <li>
147 *     'dnEscape' : Escape text for use in a DN value.
148 *   </li>
149 *   <li>
150 *     'jsonEscape' : Escape text for use in a JSON value.
151 *   </li>
152 *   <li>
153 *     'ldapFilterEscape' : Escape text for use in an LDAP filter.
154 *   </li>
155 *   <li>
156 *     'lowerCase' : Convert text to lower case.
157 *   </li>
158 *   <li>
159 *     'trim' : Remove leading and trailing whitespace.
160 *   </li>
161 *   <li>
162 *     'upperCase' : Convert text to upper case.
163 *   </li>
164 * </ul>
165 *
166 * <h2>Example</h2>
167 * Here is an example to summarize these points.  Suppose, the 'uid'
168 * field of the target entry needs to be populated with the initials of
169 * the first and last name followed by the user's employee number which
170 * is stored in the 'eid' attribute.  For example, 'John Smith' with an
171 * employee id of 12345, would get a uid of 'js12345'.  The value-pattern
172 * would be
173 * '{givenname:/^(.)(.*)/$1/s:lowerCase}{sn:/^(.)(.*)/$1/s:lowerCase}{eid}'.
174 * The employee's initials are extracted from the 'givenname' and 'sn'
175 * attributes.  The '^(.)(.*)' regular expression used for these attributes
176 * matches the entire value and stores the initial character in the $1
177 * variable, which is used for the replacement.  (The 's' flag is used to
178 * guard against the unlikely event that the user's 'givenname' or 'sn'
179 * attribute includes a newline character.) The lowerCase modifier converts
180 * the initial to lowercase.
181 */
182@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
183public interface ValueConstructor
184{
185  /**
186   * Returns a list of values constructed using the value template that was
187   * used to create this ValueConstructor substituting attribute values from
188   * the provided entry where they appear in the value template.
189   *
190   * @param  entry  Attributes referenced in the value template are pulled from
191   *                this entry.
192   *
193   * @return  The list of attribute values based on the value template and the
194   *          specified entry.
195   *
196   * @throws  LDAPException  If the provided entry does not include values for
197   *                         all attributes that appear in the value template;
198   *                         if the value template includes regular expressions
199   *                         for extracting portions of an attribute value, and
200   *                         the attribute value does not match the regular
201   *                         expression; or if the value template references
202   *                         multiple attributes that have more than one value.
203   */
204  List<String> constructValues(com.unboundid.ldap.sdk.Entry entry)
205          throws LDAPException;
206
207
208  /**
209   * Returns a list of values constructed using the value template that was
210   * used to create this ValueConstructor substituting attribute values from
211   * the provided entry where they appear in the value template.
212   *
213   * @param  entry  Attributes referenced in the value template are pulled from
214   *                this entry.
215   *
216   * @return  The list of attribute values based on the value template and the
217   *          specified entry.
218   *
219   * @throws  LDAPException  If the provided entry does not include values for
220   *                         all attributes that appear in the value template;
221   *                         if the value template includes regular expressions
222   *                         for extracting portions of an attribute value, and
223   *                         the attribute value does not match the regular
224   *                         expression; or if the value template references
225   *                         multiple attributes that have more than one value.
226   */
227  List<String> constructValues(
228          com.unboundid.directory.sdk.common.types.Entry entry)
229          throws LDAPException;
230}