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 javax.naming.NamingException; 029 030 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext; 031 import org.apache.directory.server.i18n.I18n; 032 import org.apache.directory.shared.ldap.constants.MetaSchemaConstants; 033 import org.apache.directory.shared.ldap.constants.SchemaConstants; 034 import org.apache.directory.shared.ldap.entry.EntryAttribute; 035 import org.apache.directory.shared.ldap.entry.ServerEntry; 036 import org.apache.directory.shared.ldap.exception.LdapException; 037 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException; 038 import org.apache.directory.shared.ldap.exception.LdapOtherException; 039 import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException; 040 import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException; 041 import org.apache.directory.shared.ldap.message.ResultCodeEnum; 042 import org.apache.directory.shared.ldap.name.DN; 043 import org.apache.directory.shared.ldap.name.RDN; 044 import org.apache.directory.shared.ldap.schema.AttributeType; 045 import org.apache.directory.shared.ldap.schema.SchemaManager; 046 import org.apache.directory.shared.ldap.schema.SchemaObject; 047 import org.apache.directory.shared.ldap.schema.SchemaObjectWrapper; 048 import org.apache.directory.shared.ldap.schema.loader.ldif.SchemaEntityFactory; 049 import org.apache.directory.shared.ldap.schema.registries.Schema; 050 import org.slf4j.Logger; 051 import org.slf4j.LoggerFactory; 052 053 054 /** 055 * An abstract registry synchronizer with some reused functionality. 056 * 057 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 058 * @version $Rev$ 059 */ 060 public abstract class AbstractRegistrySynchronizer implements RegistrySynchronizer 061 { 062 /** A logger for this class */ 063 private static final Logger LOG = LoggerFactory.getLogger( AbstractRegistrySynchronizer.class ); 064 065 /** The global SchemaManager */ 066 protected final SchemaManager schemaManager; 067 068 /** The m-oid AttributeType */ 069 protected final AttributeType m_oidAT; 070 071 /** The Schema objetc factory */ 072 protected final SchemaEntityFactory factory; 073 074 /** A map associating a SchemaObject type with its path on the partition*/ 075 private final static Map<String, String> OBJECT_TYPE_TO_PATH = new HashMap<String, String>(); 076 077 static 078 { 079 // Removed the starting 'ou=' from the paths 080 OBJECT_TYPE_TO_PATH.put( SchemaConstants.ATTRIBUTE_TYPE, SchemaConstants.ATTRIBUTES_TYPE_PATH.substring( 3 ) ); 081 OBJECT_TYPE_TO_PATH.put( SchemaConstants.COMPARATOR, SchemaConstants.COMPARATORS_PATH.substring( 3 ) ); 082 OBJECT_TYPE_TO_PATH.put( SchemaConstants.DIT_CONTENT_RULE, SchemaConstants.DIT_CONTENT_RULES_PATH.substring( 3 ) ); 083 OBJECT_TYPE_TO_PATH.put( SchemaConstants.DIT_STRUCTURE_RULE, SchemaConstants.DIT_STRUCTURE_RULES_PATH.substring( 3 ) ); 084 OBJECT_TYPE_TO_PATH.put( SchemaConstants.MATCHING_RULE, SchemaConstants.MATCHING_RULES_PATH.substring( 3 ) ); 085 OBJECT_TYPE_TO_PATH.put( SchemaConstants.MATCHING_RULE_USE, 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 ) throws Exception 095 { 096 this.schemaManager = schemaManager; 097 m_oidAT = schemaManager.lookupAttributeTypeRegistry( 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 Exception If The DN is not a SchemaObject DN 108 */ 109 protected boolean isSchemaLoaded( DN dn ) throws Exception 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 NamingException If we got an error 152 */ 153 protected String getSchemaName( DN dn ) throws NamingException 154 { 155 if ( dn.size() < 2 ) 156 { 157 throw new NamingException( I18n.err( I18n.ERR_276 ) ); 158 } 159 160 RDN rdn = dn.getRdn( 1 ); 161 return ( String ) rdn.getNormValue(); 162 } 163 164 165 protected void checkOidIsUnique( ServerEntry entry ) throws Exception 166 { 167 String oid = getOid( entry ); 168 169 if ( schemaManager.getGlobalOidRegistry().contains( oid ) ) 170 { 171 throw new LdapOtherException( I18n.err( I18n.ERR_335, oid ) ); 172 } 173 } 174 175 176 /** 177 * Check that a SchemaObject exists in the global OidRegsitry, and if so, 178 * return it. 179 */ 180 protected SchemaObject checkOidExists( ServerEntry entry ) throws Exception 181 { 182 String oid = getOid( entry ); 183 184 if ( schemaManager.getGlobalOidRegistry().contains( oid ) ) 185 { 186 return schemaManager.getGlobalOidRegistry().getSchemaObject( oid ); 187 } 188 else 189 { 190 throw new LdapSchemaViolationException( ResultCodeEnum.OTHER, 191 I18n.err( I18n.ERR_336, oid ) ); 192 } 193 } 194 195 196 /** 197 * Checks that the parent DN is a valid DN 198 */ 199 protected void checkParent( DN newParent, SchemaManager schemaManager, String objectType ) throws LdapException 200 { 201 if ( newParent.size() != 3 ) 202 { 203 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_337 ) ); 204 } 205 206 RDN rdn = newParent.getRdn(); 207 208 if ( ! schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals( SchemaConstants.OU_AT_OID ) ) 209 { 210 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, 211 I18n.err( I18n.ERR_338, objectType ) ); 212 } 213 214 if ( ! ( ( String ) rdn.getNormValue() ).equalsIgnoreCase( OBJECT_TYPE_TO_PATH.get( objectType ) ) ) 215 { 216 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, 217 I18n.err( I18n.ERR_339, objectType, OBJECT_TYPE_TO_PATH.get( objectType ) ) ); 218 } 219 } 220 221 protected void checkOidIsUnique( SchemaObject schemaObject ) throws Exception 222 { 223 String oid = schemaObject.getOid(); 224 225 if ( schemaManager.getGlobalOidRegistry().contains( oid ) ) 226 { 227 throw new LdapSchemaViolationException( ResultCodeEnum.OTHER, 228 I18n.err( I18n.ERR_335, oid ) ); 229 } 230 } 231 232 233 protected void checkOidIsUnique( String oid ) throws Exception 234 { 235 if ( schemaManager.getGlobalOidRegistry().contains( oid ) ) 236 { 237 throw new LdapSchemaViolationException( ResultCodeEnum.OTHER, 238 I18n.err( I18n.ERR_335, oid ) ); 239 } 240 } 241 242 243 /** 244 * Add a new SchemaObject to the schema content, assuming that 245 * it has an associated schema and that this schema is loaded 246 */ 247 protected void addToSchema( SchemaObject schemaObject, String schemaName ) throws Exception 248 { 249 if ( isSchemaLoaded( schemaName ) ) 250 { 251 // Get the set of all the SchemaObjects associated with this schema 252 Set<SchemaObjectWrapper> schemaObjects = schemaManager.getRegistries().getObjectBySchemaName().get( schemaName ); 253 254 if ( schemaObjects == null ) 255 { 256 // TODO : this should never happen... 257 schemaObjects = schemaManager.getRegistries().addSchema( schemaName ); 258 } 259 260 SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject ); 261 262 if ( schemaObjects.contains( schemaObjectWrapper ) ) 263 { 264 String msg = I18n.err( I18n.ERR_341, schemaObject.getName(), schemaName ); 265 LOG.warn( msg ); 266 267 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 268 } 269 270 schemaObjects.add( schemaObjectWrapper ); 271 LOG.debug( "The SchemaObject {} has been added to the schema {}", schemaObject, schemaName ); 272 } 273 else 274 { 275 String msg = I18n.err( I18n.ERR_342, schemaObject.getName(), schemaName ); 276 LOG.warn( msg ); 277 278 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 279 } 280 } 281 282 283 284 285 /** 286 * Delete a SchemaObject from the schema registry, assuming that 287 * it has an associated schema and that this schema is loaded 288 */ 289 protected void deleteFromSchema( SchemaObject schemaObject, String schemaName ) throws Exception 290 { 291 if ( isSchemaLoaded( schemaName ) ) 292 { 293 Set<SchemaObjectWrapper> schemaObjects = schemaManager.getRegistries().getObjectBySchemaName().get( schemaName ); 294 295 SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject ); 296 297 if ( !schemaObjects.contains( schemaObjectWrapper ) ) 298 { 299 String msg = I18n.err( I18n.ERR_343, schemaObject.getName(), schemaName ); 300 LOG.warn( msg ); 301 302 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 303 } 304 305 schemaObjects.remove( schemaObjectWrapper ); 306 LOG.debug( "The SchemaObject {} has been removed from the schema {}", schemaObject, schemaName ); 307 } 308 else 309 { 310 String msg = I18n.err( I18n.ERR_342, schemaObject.getName(), schemaName ); 311 LOG.warn( msg ); 312 313 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 314 } 315 } 316 317 318 /** 319 * {@inheritDoc} 320 */ 321 public abstract boolean modify( ModifyOperationContext opContext, ServerEntry targetEntry, boolean cascade ) 322 throws Exception; 323 324 325 /*public final boolean modify( DN name, ModificationOperation modOp, ServerEntry mods, ServerEntry entry, ServerEntry targetEntry, 326 boolean cascade ) throws Exception 327 { 328 return modify( name, entry, targetEntry, cascade ); 329 } 330 331 332 public final boolean modify( DN name, List<Modification> mods, ServerEntry entry, 333 ServerEntry targetEntry, boolean cascade ) throws Exception 334 { 335 return modify( name, entry, targetEntry, cascade ); 336 } 337 */ 338 339 340 protected Set<String> getOids( Set<ServerEntry> results ) throws Exception 341 { 342 Set<String> oids = new HashSet<String>( results.size() ); 343 344 for ( ServerEntry result : results ) 345 { 346 DN dn = result.getDn(); 347 dn.normalize( schemaManager.getNormalizerMapping() ); 348 oids.add( ( String ) dn.getRdn().getNormValue() ); 349 } 350 351 return oids; 352 } 353 354 355 protected String getOid( ServerEntry entry ) throws Exception 356 { 357 EntryAttribute oid = entry.get( m_oidAT ); 358 359 if ( oid == null ) 360 { 361 return null; 362 } 363 364 return oid.getString(); 365 } 366 367 368 /** 369 * Unregister a SchemaObject's OID from the associated oidRegistry 370 * 371 * @param obj The SchemaObject to unregister 372 * @throws Exception If the unregistering failed 373 */ 374 protected void unregisterOids( SchemaObject obj ) throws Exception 375 { 376 schemaManager.getGlobalOidRegistry().unregister( obj.getOid() ); 377 } 378 379 380 /** 381 * Register a SchemaObject's OID in the associated oidRegistry 382 * 383 * @param obj The SchemaObject to register 384 * @throws Exception If the registering failed 385 */ 386 protected void registerOids( SchemaObject obj ) throws Exception 387 { 388 schemaManager.getGlobalOidRegistry().register( obj ); 389 } 390 391 392 /** 393 * Get a String containing the SchemaObjects referencing the 394 * given ShcemaObject 395 * 396 * @param schemaObject The SchemaObject we want the referencing SchemaObjects for 397 * @return A String containing all the SchemaObjects referencing the give SchemaObject 398 */ 399 protected String getReferenced( SchemaObject schemaObject ) 400 { 401 StringBuilder sb = new StringBuilder(); 402 403 Set<SchemaObjectWrapper> useds = schemaManager.getRegistries().getUsedBy( schemaObject ); 404 405 for ( SchemaObjectWrapper used:useds ) 406 { 407 sb.append( used ); 408 sb.append( '\n' ); 409 } 410 411 return sb.toString(); 412 } 413 }