();
static
{
// Removed the starting 'ou=' from the paths
- OBJECT_TYPE_TO_PATH.put( SchemaConstants.ATTRIBUTE_TYPE, SchemaConstants.ATTRIBUTES_TYPE_PATH.substring( 3 ) );
+ OBJECT_TYPE_TO_PATH.put( SchemaConstants.ATTRIBUTE_TYPE, SchemaConstants.ATTRIBUTES_TYPE_PATH.substring( 3 ) );
OBJECT_TYPE_TO_PATH.put( SchemaConstants.COMPARATOR, SchemaConstants.COMPARATORS_PATH.substring( 3 ) );
OBJECT_TYPE_TO_PATH.put( SchemaConstants.DIT_CONTENT_RULE, SchemaConstants.DIT_CONTENT_RULES_PATH.substring( 3 ) );
OBJECT_TYPE_TO_PATH.put( SchemaConstants.DIT_STRUCTURE_RULE, SchemaConstants.DIT_STRUCTURE_RULES_PATH.substring( 3 ) );
@@ -88,20 +88,20 @@ public abstract class AbstractRegistrySy
OBJECT_TYPE_TO_PATH.put( SchemaConstants.SYNTAX, SchemaConstants.SYNTAXES_PATH.substring( 3 ) );
OBJECT_TYPE_TO_PATH.put( SchemaConstants.SYNTAX_CHECKER, SchemaConstants.SYNTAX_CHECKERS_PATH.substring( 3 ) );
}
-
-
+
+
protected AbstractRegistrySynchronizer( SchemaManager schemaManager ) throws Exception
{
this.schemaManager = schemaManager;
m_oidAT = schemaManager.getAttributeType( MetaSchemaConstants.M_OID_AT );
factory = new SchemaEntityFactory();
}
-
-
+
+
/**
* Tells if the schema the DN references is loaded or not
*
- * @param dn The SchemaObject's DN
+ * @param dn The SchemaObject's DN
* @return true if the schema is loaded
* @throws Exception If The DN is not a SchemaObject DN
*/
@@ -109,8 +109,8 @@ public abstract class AbstractRegistrySy
{
return schemaManager.isSchemaLoaded( getSchemaName( dn ) );
}
-
-
+
+
/**
* Tells if the schemaName is loaded or not
*
@@ -121,10 +121,10 @@ public abstract class AbstractRegistrySy
{
return schemaManager.isSchemaLoaded( schemaName );
}
-
-
+
+
/**
- * Tells if a schema is loaded and enabled
+ * Tells if a schema is loaded and enabled
*
* @param schemaName The schema we want to check
* @return true if the schema is loaded and enabled, false otherwise
@@ -132,13 +132,13 @@ public abstract class AbstractRegistrySy
protected boolean isSchemaEnabled( String schemaName )
{
Schema schema = schemaManager.getLoadedSchema( schemaName );
-
+
return ( ( schema != null ) && schema.isEnabled() );
}
-
-
+
+
/**
- * Exctract the schema name from the DN. It is supposed to be the
+ * Exctract the schema name from the DN. It is supposed to be the
* second RDN in the dn :
*
* ou=schema, cn=MySchema, ...
@@ -155,7 +155,7 @@ public abstract class AbstractRegistrySy
{
throw new LdapInvalidDnException( I18n.err( I18n.ERR_276 ) );
}
-
+
RDN rdn = dn.getRdn( 1 );
return rdn.getNormValue().getString();
}
@@ -171,7 +171,7 @@ public abstract class AbstractRegistrySy
}
}
-
+
/**
* Check that a SchemaObject exists in the global OidRegsitry, and if so,
* return it.
@@ -191,7 +191,7 @@ public abstract class AbstractRegistrySy
}
}
-
+
/**
* Checks that the parent DN is a valid DN
*/
@@ -201,18 +201,18 @@ public abstract class AbstractRegistrySy
{
throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, I18n.err( I18n.ERR_337 ) );
}
-
+
RDN rdn = newParent.getRdn();
-
+
if ( ! schemaManager.getAttributeTypeRegistry().getOidByName( rdn.getNormType() ).equals( SchemaConstants.OU_AT_OID ) )
{
- throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
+ throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
I18n.err( I18n.ERR_338, objectType ) );
}
-
+
if ( !rdn.getNormValue().getString().equalsIgnoreCase( OBJECT_TYPE_TO_PATH.get( objectType ) ) )
{
- throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
+ throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
I18n.err( I18n.ERR_339, objectType, OBJECT_TYPE_TO_PATH.get( objectType ) ) );
}
}
@@ -238,7 +238,7 @@ public abstract class AbstractRegistrySy
}
}
-
+
/**
* Add a new SchemaObject to the schema content, assuming that
* it has an associated schema and that this schema is loaded
@@ -249,23 +249,23 @@ public abstract class AbstractRegistrySy
{
// Get the set of all the SchemaObjects associated with this schema
Set schemaObjects = schemaManager.getRegistries().getObjectBySchemaName().get( schemaName );
-
+
if ( schemaObjects == null )
{
// TODO : this should never happen...
schemaObjects = schemaManager.getRegistries().addSchema( schemaName );
}
-
+
SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
-
+
if ( schemaObjects.contains( schemaObjectWrapper ) )
{
String msg = I18n.err( I18n.ERR_341, schemaObject.getName(), schemaName );
LOG.warn( msg );
-
+
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
}
-
+
schemaObjects.add( schemaObjectWrapper );
LOG.debug( "The SchemaObject {} has been added to the schema {}", schemaObject, schemaName );
}
@@ -273,14 +273,14 @@ public abstract class AbstractRegistrySy
{
String msg = I18n.err( I18n.ERR_342, schemaObject.getName(), schemaName );
LOG.warn( msg );
-
+
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
}
}
-
-
-
+
+
+
/**
* Delete a SchemaObject from the schema registry, assuming that
* it has an associated schema and that this schema is loaded
@@ -292,15 +292,15 @@ public abstract class AbstractRegistrySy
Set schemaObjects = schemaManager.getRegistries().getObjectBySchemaName().get( schemaName );
SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
-
+
if ( !schemaObjects.contains( schemaObjectWrapper ) )
{
String msg = I18n.err( I18n.ERR_343, schemaObject.getName(), schemaName );
LOG.warn( msg );
-
+
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
}
-
+
schemaObjects.remove( schemaObjectWrapper );
LOG.debug( "The SchemaObject {} has been removed from the schema {}", schemaObject, schemaName );
}
@@ -308,50 +308,50 @@ public abstract class AbstractRegistrySy
{
String msg = I18n.err( I18n.ERR_342, schemaObject.getName(), schemaName );
LOG.warn( msg );
-
+
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
}
}
-
+
/**
* {@inheritDoc}
*/
- public abstract boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean cascade )
+ public abstract boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean cascade )
throws LdapException;
-
-
+
+
protected Set getOids( Set results ) throws Exception
{
Set oids = new HashSet( results.size() );
-
+
for ( Entry result : results )
{
DN dn = result.getDn();
- dn.normalize( schemaManager.getNormalizerMapping() );
+ dn.normalize( schemaManager );
oids.add( dn.getRdn().getNormValue().getString() );
}
-
+
return oids;
}
-
-
+
+
protected String getOid( Entry entry ) throws LdapException
{
EntryAttribute oid = entry.get( m_oidAT );
-
+
if ( oid == null )
{
return null;
}
-
+
return oid.getString();
}
-
-
+
+
/**
* Unregister a SchemaObject's OID from the associated oidRegistry
- *
+ *
* @param obj The SchemaObject to unregister
* @throws Exception If the unregistering failed
*/
@@ -359,11 +359,11 @@ public abstract class AbstractRegistrySy
{
schemaManager.getGlobalOidRegistry().unregister( obj.getOid() );
}
-
-
+
+
/**
* Register a SchemaObject's OID in the associated oidRegistry
- *
+ *
* @param obj The SchemaObject to register
* @throws Exception If the registering failed
*/
@@ -371,10 +371,10 @@ public abstract class AbstractRegistrySy
{
schemaManager.getGlobalOidRegistry().register( obj );
}
-
-
+
+
/**
- * Get a String containing the SchemaObjects referencing the
+ * Get a String containing the SchemaObjects referencing the
* given ShcemaObject
*
* @param schemaObject The SchemaObject we want the referencing SchemaObjects for
@@ -383,15 +383,15 @@ public abstract class AbstractRegistrySy
protected String getReferenced( SchemaObject schemaObject )
{
StringBuilder sb = new StringBuilder();
-
+
Set useds = schemaManager.getRegistries().getUsedBy( schemaObject );
-
+
for ( SchemaObjectWrapper used:useds )
{
sb.append( used );
sb.append( '\n' );
}
-
+
return sb.toString();
}
}
Modified: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/schema/registries/synchronizers/SchemaSynchronizer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/schema/registries/synchronizers/SchemaSynchronizer.java?rev=982332&r1=982331&r2=982332&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/schema/registries/synchronizers/SchemaSynchronizer.java (original)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/schema/registries/synchronizers/SchemaSynchronizer.java Wed Aug 4 17:13:46 2010
@@ -55,7 +55,7 @@ import org.slf4j.LoggerFactory;
/**
* This class handle modifications made on a global schema. Modifications made
* on SchemaObjects are handled by the specific shcemaObject synchronizers.
- *
+ *
* @TODO poorly implemented - revisit the SchemaChangeHandler for this puppy
* and do it right.
*
@@ -68,21 +68,21 @@ public class SchemaSynchronizer implemen
private final SchemaEntityFactory factory;
//private final PartitionSchemaLoader loader;
-
+
private final SchemaManager schemaManager;
-
+
/** The global registries */
private final Registries registries;
-
+
/** The m-disable AttributeType */
private final AttributeType disabledAT;
-
+
/** The CN attributeType */
private final AttributeType cnAT;
-
+
/** The m-dependencies AttributeType */
private final AttributeType dependenciesAT;
-
+
/** A static DN referencing ou=schema */
private final DN ouSchemaDN;
@@ -102,45 +102,45 @@ public class SchemaSynchronizer implemen
cnAT = registries.getAttributeTypeRegistry().lookup( SchemaConstants.CN_AT );
dependenciesAT = registries.getAttributeTypeRegistry()
.lookup( MetaSchemaConstants.M_DEPENDENCIES_AT );
-
+
ouSchemaDN = new DN( SchemaConstants.OU_SCHEMA, schemaManager );
}
/**
- * The only modification done on a schema element is on the m-disabled
+ * The only modification done on a schema element is on the m-disabled
* attributeType
- *
+ *
* Depending in the existence of this attribute in the previous entry, we will
* have to update the entry or not.
*/
public boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean cascade ) throws LdapException
{
Entry entry = modifyContext.getEntry();
- List mods = modifyContext.getModItems();
+ List mods = modifyContext.getModItems();
boolean hasModification = SCHEMA_UNCHANGED;
-
- // Check if the entry has a m-disabled attribute
+
+ // Check if the entry has a m-disabled attribute
EntryAttribute disabledInEntry = entry.get( disabledAT );
Modification disabledModification = ServerEntryUtils.getModificationItem( mods, disabledAT );
-
+
// The attribute might be present, but that does not mean we will change it.
// If it's absent, and if we have it in the previous entry, that mean we want
// to enable the schema
if ( disabledModification != null )
{
- // We are trying to modify the m-disabled attribute.
+ // We are trying to modify the m-disabled attribute.
ModificationOperation modification = disabledModification.getOperation();
EntryAttribute attribute = disabledModification.getAttribute();
-
+
hasModification = modifyDisable( modifyContext, modification, attribute, disabledInEntry );
}
else if ( disabledInEntry != null )
{
hasModification = modifyDisable( modifyContext, ModificationOperation.REMOVE_ATTRIBUTE, null, disabledInEntry );
}
-
-
+
+
return hasModification;
}
@@ -153,7 +153,7 @@ public class SchemaSynchronizer implemen
/**
* Handles the addition of a metaSchema object to the schema partition.
- *
+ *
* @param name the dn of the new metaSchema object
* @param entry the attributes of the new metaSchema object
*/
@@ -173,7 +173,7 @@ public class SchemaSynchronizer implemen
// check if the new schema is enabled or disabled
boolean isEnabled = false;
EntryAttribute disabled = entry.get( disabledAT );
-
+
if ( disabled == null )
{
// If the attribute is absent, then the schema is enabled by default
@@ -183,27 +183,27 @@ public class SchemaSynchronizer implemen
{
isEnabled = true;
}
-
+
// check to see that all dependencies are resolved and loaded if this
// schema is enabled, otherwise check that the dependency schemas exist
checkForDependencies( isEnabled, entry );
-
+
/*
* There's a slight problem that may result when adding a metaSchema
* object if the addition of the physical entry fails. If the schema
* is enabled when added in the condition tested below, that schema
* is added to the global registries. We need to add this so subsequent
* schema entity additions are loaded into the registries as they are
- * added to the schema partition. However if the metaSchema object
+ * added to the schema partition. However if the metaSchema object
* addition fails then we're left with this schema object looking like
* it is enabled in the registries object's schema hash. The effects
* of this are unpredictable.
- *
- * This whole problem is due to the inability of these handlers to
+ *
+ * This whole problem is due to the inability of these handlers to
* react to a failed operation. To fix this we would need some way
* for these handlers to respond to failed operations and revert their
* effects on the registries.
- *
+ *
* TODO: might want to add a set of failedOnXXX methods to the adapter
* where on failure the schema service calls the schema manager and it
* calls the appropriate methods on the respective handler. This way
@@ -221,11 +221,11 @@ public class SchemaSynchronizer implemen
/**
* Called to react to the deletion of a metaSchema object. This method
- * simply removes the schema from the loaded schema map of the global
- * registries.
- *
+ * simply removes the schema from the loaded schema map of the global
+ * registries.
+ *
* @param name the dn of the metaSchema object being deleted
- * @param entry the attributes of the metaSchema object
+ * @param entry the attributes of the metaSchema object
*/
public void delete( Entry entry, boolean cascade ) throws LdapException
{
@@ -235,16 +235,16 @@ public class SchemaSynchronizer implemen
// Before allowing a schema object to be deleted we must check
// to make sure it's not depended upon by another schema
Set dependents = schemaManager.listDependentSchemaNames( schemaName );
-
+
if ( ( dependents != null ) && ! dependents.isEmpty() )
{
- String msg = I18n.err( I18n.ERR_381, dependents );
+ String msg = I18n.err( I18n.ERR_381, dependents );
LOG.warn( msg );
throw new LdapUnwillingToPerformException(
ResultCodeEnum.UNWILLING_TO_PERFORM,
msg );
}
-
+
// no need to check if schema is enabled or disabled here
// if not in the loaded set there will be no negative effect
schemaManager.unload( schemaName );
@@ -253,10 +253,10 @@ public class SchemaSynchronizer implemen
/**
- * Responds to the rdn (commonName) of the metaSchema object being
- * changed. Changes all the schema entities associated with the
+ * Responds to the rdn (commonName) of the metaSchema object being
+ * changed. Changes all the schema entities associated with the
* renamed schema so they now map to a new schema name.
- *
+ *
* @param name the dn of the metaSchema object renamed
* @param entry the entry of the metaSchema object before the rename
* @param newRdn the new commonName of the metaSchema object
@@ -274,28 +274,28 @@ public class SchemaSynchronizer implemen
/*
* This operation has to do the following:
- *
- * [1] check and make sure there are no dependent schemas on the
+ *
+ * [1] check and make sure there are no dependent schemas on the
* one being renamed - if so an exception should result
- *
- * [2] make non-schema object registries modify the mapping
+ *
+ * [2] make non-schema object registries modify the mapping
* for their entities: non-schema object registries contain
* objects that are not SchemaObjects and hence do not carry
* their schema within the object as a property
- *
+ *
* [3] make schema object registries do the same but the way
* they do them will be different since these objects will
- * need to be replaced or will require a setter for the
+ * need to be replaced or will require a setter for the
* schema name
*/
-
+
// step [1]
/*
String schemaName = getSchemaName( entry.getDn() );
Set dependents = schemaManager.listDependentSchemaNames( schemaName );
if ( ! dependents.isEmpty() )
{
- throw new LdapUnwillingToPerformException(
+ throw new LdapUnwillingToPerformException(
"Cannot allow a rename on " + schemaName + " schema while it has depentents.",
ResultCodeEnum.UNWILLING_TO_PERFORM );
}
@@ -303,7 +303,7 @@ public class SchemaSynchronizer implemen
// check if the new schema is enabled or disabled
boolean isEnabled = false;
EntryAttribute disabled = entry.get( disabledAT );
-
+
if ( disabled == null )
{
isEnabled = true;
@@ -319,13 +319,13 @@ public class SchemaSynchronizer implemen
}
// do steps 2 and 3 if the schema has been enabled and is loaded
-
- // step [2]
+
+ // step [2]
String newSchemaName = ( String ) newRdn.getUpValue();
registries.getComparatorRegistry().renameSchema( schemaName, newSchemaName );
registries.getNormalizerRegistry().renameSchema( schemaName, newSchemaName );
registries.getSyntaxCheckerRegistry().renameSchema( schemaName, newSchemaName );
-
+
// step [3]
renameSchema( registries.getAttributeTypeRegistry(), schemaName, newSchemaName );
renameSchema( registries.getDitContentRuleRegistry(), schemaName, newSchemaName );
@@ -337,13 +337,13 @@ public class SchemaSynchronizer implemen
renameSchema( registries.getLdapSyntaxRegistry(), schemaName, newSchemaName );
*/
}
-
+
/**
* Moves are not allowed for metaSchema objects so this always throws an
* UNWILLING_TO_PERFORM LdapException.
*/
- public void moveAndRename( DN oriChildName, DN newParentName, String newRn, boolean deleteOldRn,
+ public void moveAndRename( DN oriChildName, DN newParentName, String newRn, boolean deleteOldRn,
Entry entry, boolean cascade ) throws LdapUnwillingToPerformException
{
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
@@ -355,25 +355,25 @@ public class SchemaSynchronizer implemen
* Moves are not allowed for metaSchema objects so this always throws an
* UNWILLING_TO_PERFORM LdapException.
*/
- public void move( DN oriChildName, DN newParentName,
+ public void move( DN oriChildName, DN newParentName,
Entry entry, boolean cascade ) throws LdapUnwillingToPerformException
{
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
I18n.err( I18n.ERR_383 ) );
}
-
+
// -----------------------------------------------------------------------
// private utility methods
// -----------------------------------------------------------------------
-
+
/**
* Modify the Disable flag (the flag can be set to true or false).
- *
+ *
* We can ADD, REMOVE or MODIFY this flag. The following matrix expose what will be the consequences
* of this operation, depending on the current state
- *
+ *
*
* +-------------------+--------------------+--------------------+
* op/state | TRUE | FALSE | ABSENT |
@@ -390,15 +390,15 @@ public class SchemaSynchronizer implemen
* +-------+-------+-------------------+--------------------+--------------------+
*
*/
- private boolean modifyDisable( ModifyOperationContext modifyContext, ModificationOperation modOp,
+ private boolean modifyDisable( ModifyOperationContext modifyContext, ModificationOperation modOp,
EntryAttribute disabledInMods, EntryAttribute disabledInEntry ) throws LdapException
{
DN name = modifyContext.getDn();
-
+
switch ( modOp )
{
/*
- * If the user is adding a new m-disabled attribute to an enabled schema,
+ * If the user is adding a new m-disabled attribute to an enabled schema,
* we check that the value is "TRUE" and disable that schema if so.
*/
case ADD_ATTRIBUTE :
@@ -406,11 +406,11 @@ public class SchemaSynchronizer implemen
{
return disableSchema( getSchemaName( name ) );
}
-
+
break;
/*
- * If the user is removing the m-disabled attribute we check if the schema is currently
+ * If the user is removing the m-disabled attribute we check if the schema is currently
* disabled. If so we enable the schema.
*/
case REMOVE_ATTRIBUTE :
@@ -418,29 +418,29 @@ public class SchemaSynchronizer implemen
{
return enableSchema( getSchemaName( name ) );
}
-
+
break;
/*
- * If the user is replacing the m-disabled attribute we check if the schema is
+ * If the user is replacing the m-disabled attribute we check if the schema is
* currently disabled and enable it if the new state has it as enabled. If the
* schema is not disabled we disable it if the mods set m-disabled to true.
*/
case REPLACE_ATTRIBUTE :
-
+
boolean isCurrentlyDisabled = false;
-
+
if ( disabledInEntry != null )
{
isCurrentlyDisabled = "TRUE".equalsIgnoreCase( disabledInEntry.getString() );
}
-
+
boolean isNewStateDisabled = false;
-
+
if ( disabledInMods != null )
{
Value> val = disabledInMods.get();
-
+
if ( val == null )
{
isNewStateDisabled = false;
@@ -460,13 +460,13 @@ public class SchemaSynchronizer implemen
{
return disableSchema( getSchemaName( name ) );
}
-
+
break;
-
+
default:
throw new IllegalArgumentException( I18n.err( I18n.ERR_384, modOp ) );
}
-
+
return SCHEMA_UNCHANGED;
}
@@ -476,7 +476,7 @@ public class SchemaSynchronizer implemen
return schema.getRdn().getNormValue().getString();
}
-
+
private boolean disableSchema( String schemaName ) throws LdapException
{
Schema schema = registries.getLoadedSchema( schemaName );
@@ -488,50 +488,50 @@ public class SchemaSynchronizer implemen
LOG.error( msg );
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
}
-
+
return schemaManager.disable( schemaName );
/*
// First check that the schema is not already disabled
Map schemas = registries.getLoadedSchemas();
-
+
Schema schema = schemas.get( schemaName );
-
+
if ( ( schema == null ) || schema.isDisabled() )
{
// The schema is disabled, do nothing
return SCHEMA_UNCHANGED;
}
-
+
Set dependents = schemaManager.listEnabledDependentSchemaNames( schemaName );
-
+
if ( ! dependents.isEmpty() )
{
throw new LdapUnwillingToPerformException(
"Cannot disable schema with enabled dependents: " + dependents,
ResultCodeEnum.UNWILLING_TO_PERFORM );
}
-
+
schema.disable();
-
+
// Use brute force right now : iterate through all the schemaObjects
// searching for those associated with the disabled schema
disableAT( session, schemaName );
-
- Set content = registries.getLoadedSchema( schemaName ).getContent();
+
+ Set content = registries.getLoadedSchema( schemaName ).getContent();
for ( SchemaObjectWrapper schemaWrapper : content )
{
SchemaObject schemaObject = schemaWrapper.get();
-
+
System.out.println( "Disabling " + schemaObject.getName() );
}
-
+
return SCHEMA_MODIFIED;
*/
}
-
-
+
+
/**
* Enabling a schema consist on switching all of its schema element to enable.
* We have to do it on a temporary registries.
@@ -545,7 +545,7 @@ public class SchemaSynchronizer implemen
// We have to load the schema before enabling it.
schemaManager.loadDisabled( schemaName );
}
-
+
return schemaManager.enable( schemaName );
}
@@ -553,7 +553,7 @@ public class SchemaSynchronizer implemen
/**
* Checks to make sure the dependencies either exist for disabled metaSchemas,
* or exist and are loaded (enabled) for enabled metaSchemas.
- *
+ *
* @param isEnabled whether or not the new metaSchema is enabled
* @param entry the Attributes for the new metaSchema object
* @throws NamingException if the dependencies do not resolve or are not
@@ -567,20 +567,20 @@ public class SchemaSynchronizer implemen
{
return;
}
-
+
if ( isEnabled )
{
// check to make sure all the dependencies are also enabled
Map loaded = registries.getLoadedSchemas();
-
+
for ( Value> value:dependencies )
{
String dependency = value.getString();
-
+
if ( ! loaded.containsKey( dependency ) )
{
- throw new LdapUnwillingToPerformException(
- ResultCodeEnum.UNWILLING_TO_PERFORM, "Unwilling to perform operation on enabled schema with disabled or missing dependencies: "
+ throw new LdapUnwillingToPerformException(
+ ResultCodeEnum.UNWILLING_TO_PERFORM, "Unwilling to perform operation on enabled schema with disabled or missing dependencies: "
+ dependency );
}
}
@@ -590,10 +590,10 @@ public class SchemaSynchronizer implemen
for ( Value> value:dependencies )
{
String dependency = value.getString();
-
+
if ( schemaManager.getLoadedSchema( StringTools.toLowerCase( dependency ) ) == null )
{
- throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
+ throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
I18n.err( I18n.ERR_385, dependency ) );
}
}
Modified: directory/apacheds/trunk/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerContext.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerContext.java?rev=982332&r1=982331&r2=982332&view=diff
==============================================================================
--- directory/apacheds/trunk/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerContext.java (original)
+++ directory/apacheds/trunk/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerContext.java Wed Aug 4 17:13:46 2010
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
- *
+ * under the License.
+ *
*/
package org.apache.directory.server.core.jndi;
@@ -112,10 +112,10 @@ public abstract class ServerContext impl
/** The directory service which owns this context **/
private final DirectoryService service;
-
+
/** The SchemManager instance */
protected SchemaManager schemaManager;
-
+
/** A reference to the ObjectClass AT */
protected AttributeType OBJECT_CLASS_AT;
@@ -126,7 +126,7 @@ public abstract class ServerContext impl
private final DN dn;
/** The set of registered NamingListeners */
- private final Map listeners =
+ private final Map listeners =
new HashMap();
/** The request controls to set on operations before performing them */
@@ -137,7 +137,7 @@ public abstract class ServerContext impl
/** Connection level controls associated with the session */
protected Control[] connectControls = EMPTY_CONTROLS;
-
+
private final CoreSession session;
@@ -152,10 +152,10 @@ public abstract class ServerContext impl
* of the newly created context. It also checks to make sure the
* referenced name actually exists within the system. This constructor
* is used for all InitialContext requests.
- *
+ *
* @param service the parent service that manages this context
* @param env the environment properties used by this context.
- * @throws NamingException if the environment parameters are not set
+ * @throws NamingException if the environment parameters are not set
* correctly.
*/
protected ServerContext( DirectoryService service, Hashtable env ) throws Exception
@@ -163,32 +163,32 @@ public abstract class ServerContext impl
this.service = service;
this.env = env;
-
+
LdapJndiProperties props = LdapJndiProperties.getLdapJndiProperties( this.env );
dn = props.getProviderDn();
/*
- * Need do bind operation here, and bindContext returned contains the
+ * Need do bind operation here, and bindContext returned contains the
* newly created session.
*/
- BindOperationContext bindContext = doBindOperation( props.getBindDn(), props.getCredentials(),
+ BindOperationContext bindContext = doBindOperation( props.getBindDn(), props.getCredentials(),
props.getSaslMechanism(), props.getSaslAuthId() );
session = bindContext.getSession();
OperationManager operationManager = service.getOperationManager();
-
+
if ( ! operationManager.hasEntry( new EntryOperationContext( session, dn ) ) )
{
throw new NameNotFoundException( I18n.err( I18n.ERR_490, dn ) );
}
-
+
schemaManager = service.getSchemaManager();
// setup attribute type value
OBJECT_CLASS_AT = schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT );
}
-
-
+
+
/**
* Must be called by all subclasses to initialize the nexus proxy and the
* environment settings to be used by this Context implementation. This
@@ -209,12 +209,12 @@ public abstract class ServerContext impl
this.env.put( DirectoryService.JNDI_KEY, service );
session = new DefaultCoreSession( principal, service );
OperationManager operationManager = service.getOperationManager();
-
+
if ( ! operationManager.hasEntry( new EntryOperationContext( session, dn ) ) )
{
throw new NameNotFoundException( I18n.err( I18n.ERR_490, dn ) );
}
-
+
schemaManager = service.getSchemaManager();
// setup attribute type value
@@ -231,12 +231,12 @@ public abstract class ServerContext impl
this.env.put( DirectoryService.JNDI_KEY, service );
this.session = session;
OperationManager operationManager = service.getOperationManager();
-
- if ( ! operationManager.hasEntry( new EntryOperationContext( session, ( DN ) dn ) ) )
+
+ if ( ! operationManager.hasEntry( new EntryOperationContext( session, dn ) ) )
{
throw new NameNotFoundException( I18n.err( I18n.ERR_490, dn ) );
}
-
+
schemaManager = service.getSchemaManager();
// setup attribute type value
@@ -260,7 +260,7 @@ public abstract class ServerContext impl
}
else
{
- // TODO : handle the 'follow' referral option
+ // TODO : handle the 'follow' referral option
opCtx.throwReferral();
}
}
@@ -268,9 +268,9 @@ public abstract class ServerContext impl
// Protected Methods for Operations
// ------------------------------------------------------------------------
// Use these methods instead of manually calling the nexusProxy so we can
- // add request controls to operation contexts before the call and extract
- // response controls from the contexts after the call. NOTE that the
- // JndiUtils.fromJndiControls( requestControls ) must be cleared after each operation. This makes a
+ // add request controls to operation contexts before the call and extract
+ // response controls from the contexts after the call. NOTE that the
+ // JndiUtils.fromJndiControls( requestControls ) must be cleared after each operation. This makes a
// context not thread safe.
// ------------------------------------------------------------------------
@@ -285,15 +285,15 @@ public abstract class ServerContext impl
AddOperationContext opCtx = new AddOperationContext( session, entry );
opCtx.addRequestControls( JndiUtils.fromJndiControls( requestControls ) );
-
+
// Inject the referral handling into the operation context
injectReferralControl( opCtx );
-
+
// execute add operation
OperationManager operationManager = service.getOperationManager();
operationManager.add( opCtx );
-
- // clear the request controls and set the response controls
+
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( opCtx.getResponseControls() );
}
@@ -317,7 +317,7 @@ public abstract class ServerContext impl
OperationManager operationManager = service.getOperationManager();
operationManager.delete( opCtx );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( opCtx.getResponseControls() );
}
@@ -336,18 +336,18 @@ public abstract class ServerContext impl
{
OperationManager operationManager = service.getOperationManager();
EntryFilteringCursor results = null;
-
+
Object typesOnlyObj = getEnvironment().get( "java.naming.ldap.typesOnly" );
boolean typesOnly = false;
-
+
if( typesOnlyObj != null )
{
typesOnly = Boolean.parseBoolean( typesOnlyObj.toString() );
}
-
+
SearchOperationContext searchContext = null;
- // We have to check if it's a compare operation or a search.
+ // We have to check if it's a compare operation or a search.
// A compare operation has a OBJECT scope search, the filter must
// be of the form (object=value) (no wildcards), and no attributes
// should be asked to be returned.
@@ -357,7 +357,7 @@ public abstract class ServerContext impl
&& ( filter instanceof EqualityNode ) )
{
CompareOperationContext compareContext = new CompareOperationContext( session, dn, ((EqualityNode)filter).getAttribute(), ((EqualityNode)filter).getValue() );
-
+
// Inject the referral handling into the operation context
injectReferralControl( compareContext );
@@ -369,12 +369,12 @@ public abstract class ServerContext impl
searchControls );
searchContext.setAliasDerefMode( aliasDerefMode );
searchContext.addRequestControls( JndiUtils.fromJndiControls( requestControls ) );
-
+
searchContext.setTypesOnly( typesOnly );
-
+
if ( result )
{
- Entry emptyEntry = new DefaultEntry( service.getSchemaManager(), DN.EMPTY_DN );
+ Entry emptyEntry = new DefaultEntry( service.getSchemaManager(), DN.EMPTY_DN );
return new BaseEntryFilteringCursor( new SingletonCursor( emptyEntry ), searchContext );
}
else
@@ -385,13 +385,13 @@ public abstract class ServerContext impl
else
{
// It's a Search
-
+
// setup the op context and populate with request controls
searchContext = new SearchOperationContext( session, dn, filter, searchControls );
searchContext.setAliasDerefMode( aliasDerefMode );
searchContext.addRequestControls( JndiUtils.fromJndiControls( requestControls ) );
searchContext.setTypesOnly( typesOnly );
-
+
// Inject the referral handling into the operation context
injectReferralControl( searchContext );
@@ -399,7 +399,7 @@ public abstract class ServerContext impl
results = operationManager.search( searchContext );
}
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( searchContext.getResponseControls() );
@@ -420,7 +420,7 @@ public abstract class ServerContext impl
OperationManager operationManager = service.getOperationManager();
EntryFilteringCursor results = operationManager.list( listContext );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( listContext.getResponseControls() );
@@ -433,7 +433,7 @@ public abstract class ServerContext impl
GetRootDSEOperationContext getRootDseContext = new GetRootDSEOperationContext( session, target );
getRootDseContext.addRequestControls( JndiUtils.fromJndiControls( requestControls ) );
- // do not reset request controls since this is not an external
+ // do not reset request controls since this is not an external
// operation and not do bother setting the response controls either
OperationManager operationManager = service.getOperationManager();
return operationManager.getRootDSE( getRootDseContext );
@@ -452,7 +452,7 @@ public abstract class ServerContext impl
OperationManager operationManager = service.getOperationManager();
Entry serverEntry = operationManager.lookup( lookupContext );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( lookupContext.getResponseControls() );
return serverEntry;
@@ -471,7 +471,7 @@ public abstract class ServerContext impl
OperationManager operationManager = service.getOperationManager();
Entry serverEntry = operationManager.lookup( lookupContext );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( lookupContext.getResponseControls() );
@@ -490,7 +490,7 @@ public abstract class ServerContext impl
/**
* Used to encapsulate [de]marshalling of controls before and after bind operations.
*/
- protected BindOperationContext doBindOperation( DN bindDn, byte[] credentials, String saslMechanism,
+ protected BindOperationContext doBindOperation( DN bindDn, byte[] credentials, String saslMechanism,
String saslAuthId ) throws Exception
{
// setup the op context and populate with request controls
@@ -505,7 +505,7 @@ public abstract class ServerContext impl
OperationManager operationManager = service.getOperationManager();
operationManager.bind( bindContext );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( bindContext.getResponseControls() );
return bindContext;
@@ -525,12 +525,12 @@ public abstract class ServerContext impl
// Inject the referral handling into the operation context
injectReferralControl( moveAndRenameContext );
-
+
// execute moveAndRename operation
OperationManager operationManager = service.getOperationManager();
operationManager.moveAndRename( moveAndRenameContext );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( moveAndRenameContext.getResponseControls() );
}
@@ -547,12 +547,12 @@ public abstract class ServerContext impl
// Inject the referral handling into the operation context
injectReferralControl( modifyContext );
-
+
// execute modify operation
OperationManager operationManager = service.getOperationManager();
operationManager.modify( modifyContext );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( modifyContext.getResponseControls() );
}
@@ -569,12 +569,12 @@ public abstract class ServerContext impl
// Inject the referral handling into the operation context
injectReferralControl( moveContext );
-
+
// execute move operation
OperationManager operationManager = service.getOperationManager();
operationManager.move( moveContext );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( moveContext.getResponseControls() );
}
@@ -591,29 +591,29 @@ public abstract class ServerContext impl
// Inject the referral handling into the operation context
injectReferralControl( renameContext );
-
+
// execute rename operation
OperationManager operationManager = service.getOperationManager();
operationManager.rename( renameContext );
- // clear the request controls and set the response controls
+ // clear the request controls and set the response controls
requestControls = EMPTY_CONTROLS;
responseControls = JndiUtils.toJndiControls( renameContext.getResponseControls() );
}
-
+
public CoreSession getSession()
{
return session;
}
-
-
+
+
public DirectoryService getDirectoryService()
{
return service;
}
-
-
+
+
// ------------------------------------------------------------------------
// New Impl Specific Public Methods
// ------------------------------------------------------------------------
@@ -642,10 +642,10 @@ public abstract class ServerContext impl
// Protected Accessor Methods
// ------------------------------------------------------------------------
-
+
/**
* Gets the distinguished name of the entry associated with this Context.
- *
+ *
* @return the distinguished name of this Context's entry.
*/
protected DN getDn()
@@ -674,7 +674,7 @@ public abstract class ServerContext impl
JndiUtils.wrap( e );
}
}
-
+
listeners.clear();
}
@@ -698,7 +698,7 @@ public abstract class ServerContext impl
/**
- * @see javax.naming.Context#addToEnvironment(java.lang.String,
+ * @see javax.naming.Context#addToEnvironment(java.lang.String,
* java.lang.Object)
*/
public Object addToEnvironment( String propName, Object propVal ) throws NamingException
@@ -732,7 +732,7 @@ public abstract class ServerContext impl
{
DN target = buildTarget( DN.fromName( name ) );
Entry serverEntry = null;
-
+
try
{
serverEntry = service.newEntry( target );
@@ -741,7 +741,7 @@ public abstract class ServerContext impl
{
throw new NamingException( le.getMessage() );
}
-
+
try
{
serverEntry.add( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, JavaLdapSupport.JCONTAINER_ATTR );
@@ -773,10 +773,10 @@ public abstract class ServerContext impl
}
/*
- * Add the new context to the server which as a side effect adds
+ * Add the new context to the server which as a side effect adds
* operational attributes to the serverEntry refering instance which
* can them be used to initialize a new ServerLdapContext. Remember
- * we need to copy over the controls as well to propagate the complete
+ * we need to copy over the controls as well to propagate the complete
* environment besides what's in the hashtable for env.
*/
try
@@ -787,9 +787,9 @@ public abstract class ServerContext impl
{
JndiUtils.wrap( e );
}
-
+
ServerLdapContext ctx = null;
-
+
try
{
ctx = new ServerLdapContext( service, session.getEffectivePrincipal(), DN.toName( target ) );
@@ -798,7 +798,7 @@ public abstract class ServerContext impl
{
JndiUtils.wrap( e );
}
-
+
return ctx;
}
@@ -875,7 +875,7 @@ public abstract class ServerContext impl
// let's be sure that the Attributes is case insensitive
Entry outServerEntry = null;
-
+
try
{
outServerEntry = ServerEntryUtils.toServerEntry( AttributeUtils.toCaseInsensitive( res
@@ -925,7 +925,7 @@ public abstract class ServerContext impl
{
// Serialize and add outAttrs
Entry serverEntry = null;
-
+
try
{
serverEntry = service.newEntry( target );
@@ -955,14 +955,14 @@ public abstract class ServerContext impl
// Serialize object into entry attributes and add it.
try
- {
+ {
JavaLdapSupport.serialize( serverEntry, obj, service.getSchemaManager() );
}
catch ( LdapException le )
{
throw new NamingException( I18n.err( I18n.ERR_495, obj ) );
}
-
+
try
{
doAddOperation( target, serverEntry );
@@ -976,9 +976,9 @@ public abstract class ServerContext impl
{
// Grab attributes and merge with outAttrs
Entry serverEntry = null;
-
+
try
- {
+ {
serverEntry = ServerEntryUtils.toServerEntry( ( ( DirContext ) obj ).getAttributes( "" ),
target, service.getSchemaManager() );
}
@@ -992,7 +992,7 @@ public abstract class ServerContext impl
for ( EntryAttribute serverAttribute : outServerEntry )
{
try
- {
+ {
serverEntry.put( serverAttribute );
}
catch ( LdapException le )
@@ -1043,7 +1043,7 @@ public abstract class ServerContext impl
// calculate parents
DN oldParent = oldDn;
-
+
try
{
oldParent = oldParent.remove( oldDn.size() - 1 );
@@ -1052,9 +1052,9 @@ public abstract class ServerContext impl
{
throw new NamingException( I18n.err( I18n.ERR_313, lide.getMessage() ) );
}
-
+
DN newParent = newDn;
-
+
try
{
newParent = newParent.remove( newDn.size() - 1 );
@@ -1071,7 +1071,7 @@ public abstract class ServerContext impl
/*
* Attempt to use the java.naming.ldap.deleteRDN environment property
- * to get an override for the deleteOldRdn option to modifyRdn.
+ * to get an override for the deleteOldRdn option to modifyRdn.
*/
if ( null != env.get( DELETE_OLD_RDN_PROP ) )
{
@@ -1085,7 +1085,7 @@ public abstract class ServerContext impl
* RDN name change or a move operation. If the two names are the same
* except for the RDN then it is a simple modifyRdn operation. If the
* names differ in size or have a different baseDN then the operation is
- * a move operation. Furthermore if the RDN in the move operation
+ * a move operation. Furthermore if the RDN in the move operation
* changes it is both an RDN change and a move operation.
*/
if ( oldParent.equals( newParent ) )
@@ -1143,7 +1143,7 @@ public abstract class ServerContext impl
{
DN target = buildTarget( DN.fromName( name ) );
OperationManager operationManager = service.getOperationManager();
-
+
try
{
if ( operationManager.hasEntry( new EntryOperationContext( session, target ) ) )
@@ -1229,7 +1229,7 @@ public abstract class ServerContext impl
try
{
- obj = DirectoryManager.getObjectInstance( null, name, this, env,
+ obj = DirectoryManager.getObjectInstance( null, name, this, env,
ServerEntryUtils.toBasicAttributes( serverEntry ) );
}
catch ( Exception e )
@@ -1254,7 +1254,7 @@ public abstract class ServerContext impl
// Initialize and return a context since the entry is not a java object
ServerLdapContext ctx = null;
-
+
try
{
ctx = new ServerLdapContext( service, session.getEffectivePrincipal(), DN.toName( target ) );
@@ -1263,7 +1263,7 @@ public abstract class ServerContext impl
{
JndiUtils.wrap( e );
}
-
+
return ctx;
}
@@ -1287,11 +1287,11 @@ public abstract class ServerContext impl
/**
- * Non-federated implementation presuming the name argument is not a
- * composite name spanning multiple namespaces but a compound name in
+ * Non-federated implementation presuming the name argument is not a
+ * composite name spanning multiple namespaces but a compound name in
* the same LDAP namespace. Hence the parser returned is always the
- * same as calling this method with the empty String.
- *
+ * same as calling this method with the empty String.
+ *
* @see javax.naming.Context#getNameParser(java.lang.String)
*/
public NameParser getNameParser( String name ) throws NamingException
@@ -1314,11 +1314,11 @@ public abstract class ServerContext impl
/**
- * Non-federated implementation presuming the name argument is not a
- * composite name spanning multiple namespaces but a compound name in
+ * Non-federated implementation presuming the name argument is not a
+ * composite name spanning multiple namespaces but a compound name in
* the same LDAP namespace. Hence the parser returned is always the
* same as calling this method with the empty String Name.
- *
+ *
* @see javax.naming.Context#getNameParser(javax.naming.Name)
*/
public NameParser getNameParser( final Name name ) throws NamingException
@@ -1431,13 +1431,13 @@ public abstract class ServerContext impl
* Example: This context is ou=people and say name is the relative
* name of uid=jwalker and the prefix is dc=domain. Then we must
* compose the name relative to prefix which would be:
- *
+ *
* uid=jwalker,ou=people,dc=domain.
- *
+ *
* The following general algorithm generates the right name:
* 1). Find the Dn for name and walk it from the head to tail
* trying to match for the head of prefix.
- * 2). Remove name components from the Dn until a match for the
+ * 2). Remove name components from the Dn until a match for the
* head of the prefix is found.
* 3). Return the remainder of the fqn or Dn after chewing off some
*/
@@ -1455,7 +1455,7 @@ public abstract class ServerContext impl
return DN.toName( fqn );
}
else
- // 2). Remove name components from the Dn until a match
+ // 2). Remove name components from the Dn until a match
{
try
{
@@ -1489,7 +1489,7 @@ public abstract class ServerContext impl
criteria.setScope( SearchScope.getSearchScope( scope ) );
criteria.setAliasDerefMode( AliasDerefMode.getEnum( env ) );
criteria.setBase( buildTarget( DN.fromName( name ) ) );
-
+
service.getEventService().addListener( listener );
listeners.put( namingListener, listener );
}
@@ -1511,7 +1511,7 @@ public abstract class ServerContext impl
try
{
DirectoryListener listener = listeners.remove( namingListener );
-
+
if ( listener != null )
{
service.getEventService().removeListener( listener );
@@ -1546,9 +1546,9 @@ public abstract class ServerContext impl
// ------------------------------------------------------------------------
/**
- * Clones this context's DN and adds the components of the name relative to
- * this context to the left hand side of this context's cloned DN.
- *
+ * Clones this context's DN and adds the components of the name relative to
+ * this context to the left hand side of this context's cloned DN.
+ *
* @param relativeName a name relative to this context.
* @return the name of the target
* @throws InvalidNameException if relativeName is not a valid name in
@@ -1561,14 +1561,14 @@ public abstract class ServerContext impl
// Add to left hand side of cloned DN the relative name arg
try
{
- relativeName.normalize( schemaManager.getNormalizerMapping() );
+ relativeName.normalize( schemaManager );
target = target.addAllNormalized( target.size(), relativeName );
}
catch (LdapInvalidDnException lide )
{
throw new InvalidNameException( lide.getMessage() );
}
-
+
return target;
}
}