001/* 002 * Copyright 2016-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2016-2017 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 */ 021package com.unboundid.ldap.sdk.transformations; 022 023 024 025import java.util.ArrayList; 026import java.util.Collection; 027import java.util.Collections; 028import java.util.HashMap; 029import java.util.Map; 030 031import com.unboundid.ldap.sdk.Attribute; 032import com.unboundid.ldap.sdk.Entry; 033import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; 034import com.unboundid.ldap.sdk.schema.Schema; 035import com.unboundid.util.Debug; 036import com.unboundid.util.StaticUtils; 037import com.unboundid.util.ThreadSafety; 038import 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) 049public 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}