View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.server.core.api.schema.registries.synchronizers;
21  
22  
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
29  import org.apache.directory.api.ldap.model.constants.SchemaConstants;
30  import org.apache.directory.api.ldap.model.entry.Attribute;
31  import org.apache.directory.api.ldap.model.entry.Entry;
32  import org.apache.directory.api.ldap.model.exception.LdapException;
33  import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
34  import org.apache.directory.api.ldap.model.exception.LdapOtherException;
35  import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
36  import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
37  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
38  import org.apache.directory.api.ldap.model.name.Dn;
39  import org.apache.directory.api.ldap.model.name.Rdn;
40  import org.apache.directory.api.ldap.model.schema.AttributeType;
41  import org.apache.directory.api.ldap.model.schema.SchemaManager;
42  import org.apache.directory.api.ldap.model.schema.SchemaObject;
43  import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
44  import org.apache.directory.api.ldap.model.schema.registries.Schema;
45  import org.apache.directory.api.ldap.schema.loader.SchemaEntityFactory;
46  import org.apache.directory.api.util.Strings;
47  import org.apache.directory.server.i18n.I18n;
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  
52  /**
53   * An abstract registry synchronizer with some reused functionality.
54   *
55   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
56   */
57  public abstract class AbstractRegistrySynchronizer implements RegistrySynchronizer
58  {
59      /** A logger for this class */
60      private static final Logger LOG = LoggerFactory.getLogger( AbstractRegistrySynchronizer.class );
61  
62      /** The global SchemaManager */
63      protected final SchemaManager schemaManager;
64  
65      /** The m-oid AttributeType */
66      protected final AttributeType moidAT;
67  
68      /** The Schema objetc factory */
69      protected final SchemaEntityFactory factory;
70  
71      /** A map associating a SchemaObject type with its path on the partition*/
72      private static final Map<String, String> OBJECT_TYPE_TO_PATH = new HashMap<>();
73  
74      static
75      {
76          // Removed the starting 'ou=' from the paths
77          OBJECT_TYPE_TO_PATH.put( SchemaConstants.ATTRIBUTE_TYPE, SchemaConstants.ATTRIBUTE_TYPES_PATH.substring( 3 ) );
78          OBJECT_TYPE_TO_PATH.put( SchemaConstants.COMPARATOR, SchemaConstants.COMPARATORS_PATH.substring( 3 ) );
79          OBJECT_TYPE_TO_PATH
80              .put( SchemaConstants.DIT_CONTENT_RULE, SchemaConstants.DIT_CONTENT_RULES_PATH.substring( 3 ) );
81          OBJECT_TYPE_TO_PATH.put( SchemaConstants.DIT_STRUCTURE_RULE,
82              SchemaConstants.DIT_STRUCTURE_RULES_PATH.substring( 3 ) );
83          OBJECT_TYPE_TO_PATH.put( SchemaConstants.MATCHING_RULE, SchemaConstants.MATCHING_RULES_PATH.substring( 3 ) );
84          OBJECT_TYPE_TO_PATH.put( SchemaConstants.MATCHING_RULE_USE,
85              SchemaConstants.MATCHING_RULE_USE_PATH.substring( 3 ) );
86          OBJECT_TYPE_TO_PATH.put( SchemaConstants.NAME_FORM, SchemaConstants.NAME_FORMS_PATH.substring( 3 ) );
87          OBJECT_TYPE_TO_PATH.put( SchemaConstants.NORMALIZER, SchemaConstants.NORMALIZERS_PATH.substring( 3 ) );
88          OBJECT_TYPE_TO_PATH.put( SchemaConstants.OBJECT_CLASS, SchemaConstants.OBJECT_CLASSES_PATH.substring( 3 ) );
89          OBJECT_TYPE_TO_PATH.put( SchemaConstants.SYNTAX, SchemaConstants.SYNTAXES_PATH.substring( 3 ) );
90          OBJECT_TYPE_TO_PATH.put( SchemaConstants.SYNTAX_CHECKER, SchemaConstants.SYNTAX_CHECKERS_PATH.substring( 3 ) );
91      }
92  
93  
94      protected AbstractRegistrySynchronizer( SchemaManager schemaManager )
95      {
96          this.schemaManager = schemaManager;
97          moidAT = schemaManager.getAttributeType( MetaSchemaConstants.M_OID_AT );
98          factory = new SchemaEntityFactory();
99      }
100 
101 
102     /**
103      * Tells if the schema the Dn references is loaded or not
104      *
105      * @param dn The SchemaObject's Dn
106      * @return true if the schema is loaded
107      * @throws LdapException If The Dn is not a SchemaObject Dn
108      */
109     protected boolean isSchemaLoaded( Dn dn ) throws LdapException
110     {
111         return schemaManager.isSchemaLoaded( getSchemaName( dn ) );
112     }
113 
114 
115     /**
116      * Tells if the schemaName is loaded or not
117      *
118      * @param schemaName The schema we want to check
119      * @return true if the schema is loaded
120      */
121     protected boolean isSchemaLoaded( String schemaName )
122     {
123         return schemaManager.isSchemaLoaded( schemaName );
124     }
125 
126 
127     /**
128      * Tells if a schema is loaded and enabled
129      *
130      * @param schemaName The schema we want to check
131      * @return true if the schema is loaded and enabled, false otherwise
132      */
133     protected boolean isSchemaEnabled( String schemaName )
134     {
135         Schema schema = schemaManager.getLoadedSchema( schemaName );
136 
137         return ( schema != null ) && schema.isEnabled();
138     }
139 
140 
141     /**
142      * Exctract the schema name from the Dn. It is supposed to be the
143      * second Rdn in the dn :
144      * <pre>
145      * ou=schema, cn=MySchema, ...
146      * </pre>
147      * Here, the schemaName is MySchema
148      *
149      * @param dn The Dn we want to get the schema name from
150      * @return The schema name
151      * @throws LdapException If we got an error
152      */
153     protected String getSchemaName( Dn dn ) throws LdapException
154     {
155         int size = dn.size();
156 
157         if ( size < 2 )
158         {
159             throw new LdapInvalidDnException( I18n.err( I18n.ERR_276 ) );
160         }
161 
162         Rdn rdn = dn.getRdn( size - 2 );
163 
164         return Strings.trim( rdn.getAva().getValue().getNormalized() );
165     }
166 
167 
168     protected void checkOidIsUnique( Entry entry ) throws LdapException
169     {
170         String oid = getOid( entry );
171 
172         if ( schemaManager.getGlobalOidRegistry().contains( oid ) )
173         {
174             throw new LdapOtherException( I18n.err( I18n.ERR_335, oid ) );
175         }
176     }
177 
178 
179     /**
180      * Check that a SchemaObject exists in the global OidRegsitry, and if so,
181      * return it.
182      * 
183      * @param entry The Entry we want to verify the existence of
184      * @return The found SchemaObject
185      * @throws LdapException  If the check failed
186      */
187     protected SchemaObject checkOidExists( Entry entry ) throws LdapException
188     {
189         String oid = getOid( entry );
190 
191         if ( schemaManager.getGlobalOidRegistry().contains( oid ) )
192         {
193             return schemaManager.getGlobalOidRegistry().getSchemaObject( oid );
194         }
195         else
196         {
197             throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
198                 I18n.err( I18n.ERR_336, oid ) );
199         }
200     }
201 
202 
203     /**
204      * Checks that the parent Dn is a valid Dn
205      * 
206      * @param newParent The parent DN to check
207      * @param schemaManager The SchemaManager instance
208      * @param objectType The ObjectType to check
209      * @throws LdapException  If the deletion failed
210      */
211     protected void checkParent( Dn newParent, SchemaManager schemaManager, String objectType ) throws LdapException
212     {
213         if ( newParent.size() != 3 )
214         {
215             throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_337 ) );
216         }
217 
218         Rdn rdn = newParent.getRdn();
219 
220         if ( !schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() )
221             .equals( SchemaConstants.OU_AT_OID ) )
222         {
223             throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
224                 I18n.err( I18n.ERR_338, objectType ) );
225         }
226 
227         if ( !rdn.getValue().equalsIgnoreCase( OBJECT_TYPE_TO_PATH.get( objectType ) ) )
228         {
229             throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
230                 I18n.err( I18n.ERR_339, objectType, OBJECT_TYPE_TO_PATH.get( objectType ) ) );
231         }
232     }
233 
234 
235     protected void checkOidIsUnique( SchemaObject schemaObject ) throws LdapException
236     {
237         String oid = schemaObject.getOid();
238 
239         if ( schemaManager.getGlobalOidRegistry().contains( oid ) )
240         {
241             throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
242                 I18n.err( I18n.ERR_335, oid ) );
243         }
244     }
245 
246 
247     protected void checkOidIsUnique( String oid ) throws LdapException
248     {
249         if ( schemaManager.getGlobalOidRegistry().contains( oid ) )
250         {
251             throw new LdapSchemaViolationException( ResultCodeEnum.OTHER,
252                 I18n.err( I18n.ERR_335, oid ) );
253         }
254     }
255 
256 
257     /**
258      * Add a new SchemaObject to the schema content, assuming that
259      * it has an associated schema and that this schema is loaded
260      * 
261      * @param schemaObject The SchemaObject to add
262      * @param schemaName The Schema we want the SchemaObject to be added in
263      * @throws LdapException  If the addition failed
264      */
265     protected void addToSchema( SchemaObject schemaObject, String schemaName ) throws LdapException
266     {
267         if ( isSchemaLoaded( schemaName ) )
268         {
269             // Get the set of all the SchemaObjects associated with this schema
270             Set<SchemaObjectWrapper> schemaObjects = schemaManager.getRegistries().getObjectBySchemaName()
271                 .get( schemaName );
272 
273             if ( schemaObjects == null )
274             {
275                 // TODO : this should never happen...
276                 schemaObjects = schemaManager.getRegistries().addSchema( schemaName );
277             }
278 
279             SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
280 
281             if ( schemaObjects.contains( schemaObjectWrapper ) )
282             {
283                 String msg = I18n.err( I18n.ERR_341, schemaObject.getName(), schemaName );
284                 LOG.warn( msg );
285 
286                 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
287             }
288 
289             schemaObjects.add( schemaObjectWrapper );
290             LOG.debug( "The SchemaObject {} has been added to the schema {}", schemaObject, schemaName );
291         }
292         else
293         {
294             String msg = I18n.err( I18n.ERR_342, schemaObject.getName(), schemaName );
295             LOG.warn( msg );
296 
297             throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
298         }
299     }
300 
301 
302     /**
303      * Delete a SchemaObject from the schema registry, assuming that
304      * it has an associated schema and that this schema is loaded
305      * 
306      * @param schemaObject The SchemaObject to delete
307      * @param schemaName The Schema we want the SchemaObject to be deleted from
308      * @throws LdapException  If the deletion failed
309      */
310     protected void deleteFromSchema( SchemaObject schemaObject, String schemaName ) throws LdapException
311     {
312         if ( isSchemaLoaded( schemaName ) )
313         {
314             Set<SchemaObjectWrapper> schemaObjects = schemaManager.getRegistries().getObjectBySchemaName()
315                 .get( schemaName );
316 
317             SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
318 
319             if ( !schemaObjects.contains( schemaObjectWrapper ) )
320             {
321                 String msg = I18n.err( I18n.ERR_343, schemaObject.getName(), schemaName );
322                 LOG.warn( msg );
323 
324                 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
325             }
326 
327             schemaObjects.remove( schemaObjectWrapper );
328             LOG.debug( "The SchemaObject {} has been removed from the schema {}", schemaObject, schemaName );
329         }
330         else
331         {
332             String msg = I18n.err( I18n.ERR_342, schemaObject.getName(), schemaName );
333             LOG.warn( msg );
334 
335             throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
336         }
337     }
338 
339 
340     protected Set<String> getOids( Set<Entry> results )
341     {
342         Set<String> oids = new HashSet<>( results.size() );
343 
344         for ( Entry result : results )
345         {
346             Dn dn = result.getDn();
347             oids.add( dn.getRdn().getValue() );
348         }
349 
350         return oids;
351     }
352 
353 
354     protected String getOid( Entry entry ) throws LdapException
355     {
356         Attribute oid = entry.get( moidAT );
357 
358         if ( oid == null )
359         {
360             return null;
361         }
362 
363         return oid.getString();
364     }
365 
366 
367     /**
368      * Unregister a SchemaObject's OID from the associated oidRegistry
369      *
370      * @param obj The SchemaObject to unregister
371      * @throws LdapException If the unregistering failed
372      */
373     protected void unregisterOids( SchemaObject obj ) throws LdapException
374     {
375         schemaManager.getGlobalOidRegistry().unregister( obj.getOid() );
376     }
377 
378 
379     /**
380      * Register a SchemaObject's OID in the associated oidRegistry
381      *
382      * @param obj The SchemaObject to register
383      * @throws LdapException If the registering failed
384      */
385     protected void registerOids( SchemaObject obj ) throws LdapException
386     {
387         schemaManager.getGlobalOidRegistry().register( obj );
388     }
389 
390 
391     /**
392      * Get a String containing the SchemaObjects referencing the
393      * given ShcemaObject
394      *
395      * @param schemaObject The SchemaObject we want the referencing SchemaObjects for
396      * @return A String containing all the SchemaObjects referencing the give SchemaObject
397      */
398     protected String getReferenced( SchemaObject schemaObject )
399     {
400         StringBuilder sb = new StringBuilder();
401 
402         Set<SchemaObjectWrapper> useds = schemaManager.getRegistries().getUsedBy( schemaObject );
403 
404         for ( SchemaObjectWrapper used : useds )
405         {
406             sb.append( used );
407             sb.append( '\n' );
408         }
409 
410         return sb.toString();
411     }
412 }