001 /*
002 * Copyright 2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2016 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.transformations;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collection;
027 import java.util.Collections;
028 import java.util.HashMap;
029 import java.util.Map;
030
031 import com.unboundid.ldap.sdk.Attribute;
032 import com.unboundid.ldap.sdk.Entry;
033 import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition;
034 import com.unboundid.ldap.sdk.schema.Schema;
035 import com.unboundid.util.Debug;
036 import com.unboundid.util.StaticUtils;
037 import com.unboundid.util.ThreadSafety;
038 import com.unboundid.util.ThreadSafetyLevel;
039
040
041
042 /**
043 * This class provides an implementation of an entry transformation that can be
044 * used to replace existing attributes in entries with a default set of values.
045 * The default attributes will not be added to entries that do not have existing
046 * values for the target attributes.
047 */
048 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
049 public final class ReplaceAttributeTransformation
050 implements EntryTransformation
051 {
052 // The schema to use when processing.
053 private final Schema schema;
054
055 // The set of attributes to replace in entries.
056 private final Map<String,Attribute> attributes;
057
058
059
060 /**
061 * Creates a new replace attribute transformation that will replace existing
062 * values of the specified attribute with the provided set of default values.
063 *
064 * @param schema The schema to use to identify alternate names that
065 * may be used to reference the attributes to replace.
066 * It may be {@code null} to use a default standard
067 * schema.
068 * @param attributeName The name of the attribute for which to replace
069 * existing values. It must not be {@code null}.
070 * @param newValues The new values to use in place of the existing
071 * values for the specified attribute.
072 */
073 public ReplaceAttributeTransformation(final Schema schema,
074 final String attributeName,
075 final String... newValues)
076 {
077 this(schema, new Attribute(attributeName, schema, newValues));
078 }
079
080
081
082 /**
083 * Creates a new replace attribute transformation that will replace existing
084 * values of the specified attribute with the provided set of default values.
085 *
086 * @param schema The schema to use to identify alternate names that
087 * may be used to reference the attributes to replace.
088 * It may be {@code null} to use a default standard
089 * schema.
090 * @param attributeName The name of the attribute for which to replace
091 * existing values. It must not be {@code null}.
092 * @param newValues The new values to use in place of the existing
093 * values for the specified attribute.
094 */
095 public ReplaceAttributeTransformation(final Schema schema,
096 final String attributeName,
097 final Collection<String> newValues)
098 {
099 this(schema, new Attribute(attributeName, schema, newValues));
100 }
101
102
103
104 /**
105 * Creates a new replace attribute transformation that will replace existing
106 * copies of the specified attributes with the provided versions.
107 *
108 * @param schema The schema to use to identify alternate names that may
109 * be used to reference the attributes to replace. It may
110 * be {@code null} to use a default standard schema.
111 * @param attributes The attributes to be used in place of existing
112 * attributes of the same type. It must not be
113 * {@code null} or empty.
114 */
115 public ReplaceAttributeTransformation(final Schema schema,
116 final Attribute... attributes)
117 {
118 this(schema, StaticUtils.toList(attributes));
119 }
120
121
122
123 /**
124 * Creates a new replace attribute transformation that will replace existing
125 * copies of the specified attributes with the provided versions.
126 *
127 * @param schema The schema to use to identify alternate names that may
128 * be used to reference the attributes to replace. It may
129 * be {@code null} to use a default standard schema.
130 * @param attributes The attributes to be used in place of existing
131 * attributes of the same type. It must not be
132 * {@code null} or empty.
133 */
134 public ReplaceAttributeTransformation(final Schema schema,
135 final Collection<Attribute> attributes)
136 {
137 // If a schema was provided, then use it. Otherwise, use the default
138 // standard schema.
139 Schema s = schema;
140 if (s == null)
141 {
142 try
143 {
144 s = Schema.getDefaultStandardSchema();
145 }
146 catch (final Exception e)
147 {
148 // This should never happen.
149 Debug.debugException(e);
150 }
151 }
152 this.schema = s;
153
154
155 // Identify all of the names that may be used to reference the attributes
156 // to replace.
157 final HashMap<String,Attribute> attrMap = new HashMap<String,Attribute>(10);
158 for (final Attribute a : attributes)
159 {
160 final String baseName = StaticUtils.toLowerCase(a.getBaseName());
161 attrMap.put(baseName, a);
162
163 if (s != null)
164 {
165 final AttributeTypeDefinition at = s.getAttributeType(baseName);
166 if (at != null)
167 {
168 attrMap.put(StaticUtils.toLowerCase(at.getOID()),
169 new Attribute(at.getOID(), s, a.getValues()));
170 for (final String name : at.getNames())
171 {
172 final String lowerName = StaticUtils.toLowerCase(name);
173 if (! attrMap.containsKey(lowerName))
174 {
175 attrMap.put(lowerName, new Attribute(name, s, a.getValues()));
176 }
177 }
178 }
179 }
180 }
181 this.attributes = Collections.unmodifiableMap(attrMap);
182 }
183
184
185
186 /**
187 * {@inheritDoc}
188 */
189 public Entry transformEntry(final Entry e)
190 {
191 if (e == null)
192 {
193 return null;
194 }
195
196
197 // First, see if the entry has any of the target attributes. If not, we can
198 // just return the provided entry.
199 boolean hasAttributeToReplace = false;
200 final Collection<Attribute> originalAttributes = e.getAttributes();
201 for (final Attribute a : originalAttributes)
202 {
203 if (attributes.containsKey(StaticUtils.toLowerCase(a.getBaseName())))
204 {
205 hasAttributeToReplace = true;
206 break;
207 }
208 }
209
210 if (! hasAttributeToReplace)
211 {
212 return e;
213 }
214
215
216 // Create a copy of the entry with all appropriate attributes replaced with
217 // the appropriate default versions.
218 final ArrayList<Attribute> newAttributes =
219 new ArrayList<Attribute>(originalAttributes.size());
220 for (final Attribute a : originalAttributes)
221 {
222 final Attribute replacement =
223 attributes.get(StaticUtils.toLowerCase(a.getBaseName()));
224 if (replacement == null)
225 {
226 newAttributes.add(a);
227 }
228 else
229 {
230 if (a.hasOptions())
231 {
232 newAttributes.add(new Attribute(a.getName(), schema,
233 replacement.getRawValues()));
234 }
235 else
236 {
237 newAttributes.add(replacement);
238 }
239 }
240 }
241
242 return new Entry(e.getDN(), schema, newAttributes);
243 }
244
245
246
247 /**
248 * {@inheritDoc}
249 */
250 public Entry translate(final Entry original, final long firstLineNumber)
251 {
252 return transformEntry(original);
253 }
254
255
256
257 /**
258 * {@inheritDoc}
259 */
260 public Entry translateEntryToWrite(final Entry original)
261 {
262 return transformEntry(original);
263 }
264 }