001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.server.core.schema.registries.synchronizers;
021
022
023 import java.util.HashMap;
024 import java.util.HashSet;
025 import java.util.Map;
026 import java.util.Set;
027
028 import org.apache.directory.server.constants.ApacheSchemaConstants;
029 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
030 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
031 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
032 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
033 import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
034 import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
035 import org.apache.directory.server.i18n.I18n;
036 import org.apache.directory.shared.ldap.constants.MetaSchemaConstants;
037 import org.apache.directory.shared.ldap.constants.SchemaConstants;
038 import org.apache.directory.shared.ldap.entry.EntryAttribute;
039 import org.apache.directory.shared.ldap.entry.ServerEntry;
040 import org.apache.directory.shared.ldap.entry.Value;
041 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
042 import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
043 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
044 import org.apache.directory.shared.ldap.schema.AttributeType;
045 import org.apache.directory.shared.ldap.schema.ObjectClass;
046 import org.apache.directory.shared.ldap.schema.SchemaManager;
047 import org.apache.directory.shared.ldap.schema.registries.ObjectClassRegistry;
048 import org.apache.directory.shared.ldap.schema.registries.Registries;
049 import org.slf4j.Logger;
050 import org.slf4j.LoggerFactory;
051
052
053 /**
054 * Central point of control for schemas enforced by the server. The
055 * following duties are presently performed by this class:
056 *
057 * <ul>
058 * <li>Provide central point of access for all registries: global and SAA specific registries</li>
059 * <li>Manage enabling and disabling schemas</li>
060 * <li>Responding to specific schema object changes</li>
061 * </ul>
062 *
063 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
064 * @version $Rev$, $Date$
065 */
066 public class RegistrySynchronizerAdaptor
067 {
068 /** A logger for this class */
069 private static final Logger LOG = LoggerFactory.getLogger( RegistrySynchronizerAdaptor.class );
070
071 // indices of handlers and object ids into arrays
072 private static final int COMPARATOR_INDEX = 0;
073 private static final int NORMALIZER_INDEX = 1;
074 private static final int SYNTAX_CHECKER_INDEX = 2;
075 private static final int SYNTAX_INDEX = 3;
076 private static final int MATCHING_RULE_INDEX = 4;
077 private static final int ATTRIBUTE_TYPE_INDEX = 5;
078 private static final int OBJECT_CLASS_INDEX = 6;
079 private static final int MATCHING_RULE_USE_INDEX = 7;
080 private static final int DIT_STRUCTURE_RULE_INDEX = 8;
081 private static final int DIT_CONTENT_RULE_INDEX = 9;
082 private static final int NAME_FORM_INDEX = 10;
083
084 private static final Set<String> VALID_OU_VALUES = new HashSet<String>();
085 private static final String[] META_OBJECT_CLASSES = new String[] {
086 MetaSchemaConstants.META_COMPARATOR_OC,
087 MetaSchemaConstants.META_NORMALIZER_OC,
088 MetaSchemaConstants.META_SYNTAX_CHECKER_OC,
089 MetaSchemaConstants.META_SYNTAX_OC,
090 MetaSchemaConstants.META_MATCHING_RULE_OC,
091 MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC,
092 MetaSchemaConstants.META_OBJECT_CLASS_OC,
093 MetaSchemaConstants.META_MATCHING_RULE_USE_OC,
094 MetaSchemaConstants.META_DIT_STRUCTURE_RULE_OC,
095 MetaSchemaConstants.META_DIT_CONTENT_RULE_OC,
096 MetaSchemaConstants.META_NAME_FORM_OC
097 };
098
099 private final Registries registries;
100 private final AttributeType objectClassAT;
101 private final RegistrySynchronizer[] registrySynchronizers = new RegistrySynchronizer[11];
102 private final Map<String, RegistrySynchronizer> objectClass2synchronizerMap = new HashMap<String, RegistrySynchronizer>();
103 private final SchemaSynchronizer schemaSynchronizer;
104
105 static
106 {
107 VALID_OU_VALUES.add( SchemaConstants.NORMALIZERS_AT.toLowerCase() );
108 VALID_OU_VALUES.add( SchemaConstants.COMPARATORS_AT.toLowerCase() );
109 VALID_OU_VALUES.add( SchemaConstants.SYNTAX_CHECKERS_AT.toLowerCase() );
110 VALID_OU_VALUES.add( "syntaxes".toLowerCase() );
111 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULES_AT.toLowerCase() );
112 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULE_USE_AT.toLowerCase() );
113 VALID_OU_VALUES.add( SchemaConstants.ATTRIBUTE_TYPES_AT.toLowerCase() );
114 VALID_OU_VALUES.add( SchemaConstants.OBJECT_CLASSES_AT.toLowerCase() );
115 VALID_OU_VALUES.add( SchemaConstants.NAME_FORMS_AT.toLowerCase() );
116 VALID_OU_VALUES.add( SchemaConstants.DIT_CONTENT_RULES_AT.toLowerCase() );
117 VALID_OU_VALUES.add( SchemaConstants.DIT_STRUCTURE_RULES_AT.toLowerCase() );
118 }
119
120
121 public RegistrySynchronizerAdaptor( SchemaManager schemaManager ) throws Exception
122 {
123 this.registries = schemaManager.getRegistries();
124 this.schemaSynchronizer = new SchemaSynchronizer( schemaManager );
125 this.objectClassAT = this.registries.getAttributeTypeRegistry()
126 .lookup( SchemaConstants.OBJECT_CLASS_AT );
127
128 this.registrySynchronizers[COMPARATOR_INDEX] = new ComparatorSynchronizer( schemaManager );
129 this.registrySynchronizers[NORMALIZER_INDEX] = new NormalizerSynchronizer( schemaManager );
130 this.registrySynchronizers[SYNTAX_CHECKER_INDEX] = new SyntaxCheckerSynchronizer( schemaManager );
131 this.registrySynchronizers[SYNTAX_INDEX] = new SyntaxSynchronizer( schemaManager );
132 this.registrySynchronizers[MATCHING_RULE_INDEX] = new MatchingRuleSynchronizer( schemaManager );
133 this.registrySynchronizers[ATTRIBUTE_TYPE_INDEX] = new AttributeTypeSynchronizer( schemaManager );
134 this.registrySynchronizers[OBJECT_CLASS_INDEX] = new ObjectClassSynchronizer( schemaManager );
135 this.registrySynchronizers[MATCHING_RULE_USE_INDEX] = new MatchingRuleUseSynchronizer( schemaManager );
136 this.registrySynchronizers[DIT_STRUCTURE_RULE_INDEX] = new DitStructureRuleSynchronizer( schemaManager );
137 this.registrySynchronizers[DIT_CONTENT_RULE_INDEX] = new DitContentRuleSynchronizer( schemaManager );
138 this.registrySynchronizers[NAME_FORM_INDEX] = new NameFormSynchronizer( schemaManager );
139
140 ObjectClassRegistry ocReg = registries.getObjectClassRegistry();
141 for ( int ii = 0; ii < META_OBJECT_CLASSES.length; ii++ )
142 {
143 ObjectClass oc = ocReg.lookup( META_OBJECT_CLASSES[ii] );
144 objectClass2synchronizerMap.put( oc.getOid(), registrySynchronizers[ii] );
145 }
146 }
147
148
149 /**
150 * Add a new SchemaObject or a new Schema in the Schema partition.
151 *
152 * @param opContext The Add context, containing the entry to be added
153 * @throws Exception If the addition failed
154 */
155 public void add( AddOperationContext opContext ) throws Exception
156 {
157 EntryAttribute oc = opContext.getEntry().get( objectClassAT );
158
159 // First check if we are adding a schemaObject
160 for ( Value<?> value:oc )
161 {
162
163 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() );
164
165 if ( objectClass2synchronizerMap.containsKey( oid ) )
166 {
167 // This is one of the eleven SchemaObject :
168 // AT, C, DCR, DSR, MR, MRU, NF, N, OC, S, SC
169 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
170 ServerEntry entry = opContext.getEntry();
171 synchronizer.add( entry );
172 return;
173 }
174 }
175
176 // This is a Schema
177 // e.g. ou=my custom schema,ou=schema
178 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
179 {
180 ServerEntry entry = opContext.getEntry();
181 schemaSynchronizer.add( entry );
182 return;
183 }
184
185 // Check if it is a valid container for AT, C, DCR, DSR, MR, MRU, NF, N, OC, S, SC
186 // e.g. ou=attributeTypes,ou=my custom schema,ou=schema
187 if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) )
188 {
189 if ( opContext.getDn().size() != 3 )
190 {
191 String msg = I18n.err( I18n.ERR_81 );
192 LOG.error( msg );
193 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, msg );
194 }
195
196 String ouValue = ( String ) opContext.getDn().getRdn().getNormValue();
197 ouValue = ouValue.trim().toLowerCase();
198
199 if ( ! VALID_OU_VALUES.contains( ouValue ) )
200 {
201 String msg = I18n.err( I18n.ERR_82, VALID_OU_VALUES );
202 LOG.error( msg );
203 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, msg );
204 }
205
206 // this is a valid container.
207 return;
208 }
209
210
211 String msg = I18n.err( I18n.ERR_83, opContext.getDn() );
212 LOG.error( msg );
213 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
214 }
215
216
217 /**
218 * {@inheritDoc}
219 */
220 public void delete( DeleteOperationContext opContext, boolean doCascadeDelete )
221 throws Exception
222 {
223 ServerEntry entry = opContext.getEntry();
224
225 EntryAttribute oc = entry.get( objectClassAT );
226
227 for ( Value<?> value:oc )
228 {
229 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() );
230
231 if ( objectClass2synchronizerMap.containsKey( oid ) )
232 {
233 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
234 synchronizer.delete( entry, doCascadeDelete );
235 return;
236 }
237 }
238
239 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
240 {
241 schemaSynchronizer.delete( entry, doCascadeDelete );
242 return;
243 }
244
245 if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) )
246 {
247 if ( opContext.getDn().size() != 3 )
248 {
249 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_378 ) );
250 }
251
252 String ouValue = ( String ) opContext.getDn().getRdn().getNormValue();
253 ouValue = ouValue.trim().toLowerCase();
254
255 if ( ! VALID_OU_VALUES.contains( ouValue ) )
256 {
257 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
258 I18n.err( I18n.ERR_379, VALID_OU_VALUES ) );
259 }
260
261 return;
262 }
263
264 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
265 }
266
267
268 /**
269 * Modify the schema
270 *
271 * @param opContext The context
272 * @param targetEntry The modified entry
273 * @param doCascadeModify Not used
274 * @throws Exception If the modification failed
275 */
276 public boolean modify( ModifyOperationContext opContext, ServerEntry targetEntry, boolean doCascadeModify ) throws Exception
277 {
278 ServerEntry entry = opContext.getEntry();
279 EntryAttribute oc = entry.get( objectClassAT );
280
281 for ( Value<?> value:oc )
282 {
283 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() );
284
285 if ( objectClass2synchronizerMap.containsKey( oid ) )
286 {
287 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
288 boolean hasModification = synchronizer.modify( opContext, targetEntry, doCascadeModify );
289 return hasModification;
290 }
291 }
292
293 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
294 {
295 boolean hasModification = schemaSynchronizer.modify( opContext, targetEntry, doCascadeModify );
296 return hasModification;
297 }
298
299 if ( oc.contains( ApacheSchemaConstants.SCHEMA_MODIFICATION_ATTRIBUTES_OC ) )
300 {
301 return false;
302 }
303
304 LOG.error( String.format( I18n.err( I18n.ERR_84 ),
305 opContext.getDn(), entry, opContext.getModItems() ) );
306 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
307 }
308
309
310 /**
311 * Rename a Schema Object.
312 *
313 * @param opContext The contect contaoning the rename informations
314 * @param doCascadeModify unused
315 * @throws Exception If the rename failed
316 */
317 public void rename( RenameOperationContext opContext, boolean doCascadeModify )
318 throws Exception
319 {
320 ServerEntry originalEntry = opContext.getEntry().getOriginalEntry();
321 EntryAttribute oc = originalEntry.get( objectClassAT );
322
323 for ( Value<?> value:oc )
324 {
325 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() );
326
327 if ( objectClass2synchronizerMap.containsKey( oid ) )
328 {
329 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
330 synchronizer.rename( originalEntry, opContext.getNewRdn(), doCascadeModify );
331 return;
332 }
333 }
334
335 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
336 {
337 schemaSynchronizer.rename( originalEntry, opContext.getNewRdn(), doCascadeModify );
338 return;
339 }
340
341 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
342 }
343
344
345 /* (non-Javadoc)
346 * @see org.apache.directory.server.core.schema.SchemaChangeManager#replace(org.apache.directory.server.core.interceptor.context.MoveOperationContext, org.apache.directory.server.core.entry.ServerEntry, boolean)
347 */
348 public void move( MoveOperationContext opContext, ServerEntry entry, boolean cascade ) throws Exception
349 {
350 EntryAttribute oc = entry.get( objectClassAT );
351
352 for ( Value<?> value:oc )
353 {
354 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() );
355
356 if ( objectClass2synchronizerMap.containsKey( oid ) )
357 {
358 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
359 synchronizer.move( opContext.getDn(), opContext.getParent(), entry, cascade );
360 return;
361 }
362 }
363
364 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
365 {
366 schemaSynchronizer.move( opContext.getDn(), opContext.getParent(), entry, cascade );
367 return;
368 }
369
370 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
371 }
372
373
374 /* (non-Javadoc)
375 * @see org.apache.directory.server.core.schema.SchemaChangeManager#move(org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext, org.apache.directory.server.core.entry.ServerEntry, boolean)
376 */
377 public void moveAndRename( MoveAndRenameOperationContext opContext, ServerEntry entry, boolean cascade ) throws Exception
378 {
379 EntryAttribute oc = entry.get( objectClassAT );
380
381 for ( Value<?> value:oc )
382 {
383 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() );
384
385 if ( objectClass2synchronizerMap.containsKey( oid ) )
386 {
387 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
388 synchronizer.moveAndRename( opContext.getDn(), opContext.getParent(), opContext.getNewRdn(),
389 opContext.getDelOldDn(), entry, cascade );
390 return;
391 }
392 }
393
394 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
395 {
396 schemaSynchronizer.moveAndRename( opContext.getDn(), opContext.getParent(), opContext.getNewRdn(),
397 opContext.getDelOldDn(), entry, cascade );
398 return;
399 }
400
401 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
402 }
403 }