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 */ 020package org.apache.directory.server.core.api.schema.registries.synchronizers; 021 022 023import java.util.HashMap; 024import java.util.HashSet; 025import java.util.Map; 026import java.util.Set; 027 028import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants; 029import org.apache.directory.api.ldap.model.constants.SchemaConstants; 030import org.apache.directory.api.ldap.model.entry.Attribute; 031import org.apache.directory.api.ldap.model.entry.Entry; 032import org.apache.directory.api.ldap.model.exception.LdapException; 033import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; 034import org.apache.directory.api.ldap.model.exception.LdapOtherException; 035import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException; 036import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException; 037import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 038import org.apache.directory.api.ldap.model.name.Dn; 039import org.apache.directory.api.ldap.model.name.Rdn; 040import org.apache.directory.api.ldap.model.schema.AttributeType; 041import org.apache.directory.api.ldap.model.schema.SchemaManager; 042import org.apache.directory.api.ldap.model.schema.SchemaObject; 043import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper; 044import org.apache.directory.api.ldap.model.schema.registries.Schema; 045import org.apache.directory.api.ldap.schema.loader.SchemaEntityFactory; 046import org.apache.directory.api.util.Strings; 047import org.apache.directory.server.i18n.I18n; 048import org.slf4j.Logger; 049import org.slf4j.LoggerFactory; 050 051 052/** 053 * An abstract registry synchronizer with some reused functionality. 054 * 055 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 056 */ 057public abstract class AbstractRegistrySynchronizer implements RegistrySynchronizer 058{ 059 /** A logger for this class */ 060 private static final Logger LOG = LoggerFactory.getLogger( AbstractRegistrySynchronizer.class ); 061 062 /** The global SchemaManager */ 063 protected final SchemaManager schemaManager; 064 065 /** The m-oid AttributeType */ 066 protected final AttributeType moidAT; 067 068 /** The Schema objetc factory */ 069 protected final SchemaEntityFactory factory; 070 071 /** A map associating a SchemaObject type with its path on the partition*/ 072 private static final Map<String, String> OBJECT_TYPE_TO_PATH = new HashMap<>(); 073 074 static 075 { 076 // Removed the starting 'ou=' from the paths 077 OBJECT_TYPE_TO_PATH.put( SchemaConstants.ATTRIBUTE_TYPE, SchemaConstants.ATTRIBUTE_TYPES_PATH.substring( 3 ) ); 078 OBJECT_TYPE_TO_PATH.put( SchemaConstants.COMPARATOR, SchemaConstants.COMPARATORS_PATH.substring( 3 ) ); 079 OBJECT_TYPE_TO_PATH 080 .put( SchemaConstants.DIT_CONTENT_RULE, SchemaConstants.DIT_CONTENT_RULES_PATH.substring( 3 ) ); 081 OBJECT_TYPE_TO_PATH.put( SchemaConstants.DIT_STRUCTURE_RULE, 082 SchemaConstants.DIT_STRUCTURE_RULES_PATH.substring( 3 ) ); 083 OBJECT_TYPE_TO_PATH.put( SchemaConstants.MATCHING_RULE, SchemaConstants.MATCHING_RULES_PATH.substring( 3 ) ); 084 OBJECT_TYPE_TO_PATH.put( SchemaConstants.MATCHING_RULE_USE, 085 SchemaConstants.MATCHING_RULE_USE_PATH.substring( 3 ) ); 086 OBJECT_TYPE_TO_PATH.put( SchemaConstants.NAME_FORM, SchemaConstants.NAME_FORMS_PATH.substring( 3 ) ); 087 OBJECT_TYPE_TO_PATH.put( SchemaConstants.NORMALIZER, SchemaConstants.NORMALIZERS_PATH.substring( 3 ) ); 088 OBJECT_TYPE_TO_PATH.put( SchemaConstants.OBJECT_CLASS, SchemaConstants.OBJECT_CLASSES_PATH.substring( 3 ) ); 089 OBJECT_TYPE_TO_PATH.put( SchemaConstants.SYNTAX, SchemaConstants.SYNTAXES_PATH.substring( 3 ) ); 090 OBJECT_TYPE_TO_PATH.put( SchemaConstants.SYNTAX_CHECKER, SchemaConstants.SYNTAX_CHECKERS_PATH.substring( 3 ) ); 091 } 092 093 094 protected AbstractRegistrySynchronizer( SchemaManager schemaManager ) 095 { 096 this.schemaManager = schemaManager; 097 moidAT = schemaManager.getAttributeType( MetaSchemaConstants.M_OID_AT ); 098 factory = new SchemaEntityFactory(); 099 } 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}