/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* 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.
*
*/
package org.apache.directory.studio.schemaeditor.model.hierarchy;
import java.util.List;
import org.apache.commons.collections.map.MultiValueMap;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.api.ldap.model.schema.ObjectClass;
import org.apache.directory.api.ldap.model.schema.SchemaObject;
import org.apache.directory.api.util.Strings;
import org.apache.directory.studio.schemaeditor.Activator;
import org.apache.directory.studio.schemaeditor.controller.SchemaHandler;
import org.apache.directory.studio.schemaeditor.model.Schema;
/**
* This class represents the HierarchyManager.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class HierarchyManager
{
/** The parents map is used to store for each element its parents */
private MultiValueMap parentsMap;
/** The parents map is used to store for each element its children */
private MultiValueMap childrenMap;
/** The SchemaHandler */
private SchemaHandler schemaHandler;
/** The RootObject of the Hierarchy */
private RootObject root;
/**
* Creates a new instance of HierarchyManager.
*/
public HierarchyManager()
{
// Initializing the maps
parentsMap = new MultiValueMap();
childrenMap = new MultiValueMap();
// Getting the SchemaHandler
schemaHandler = Activator.getDefault().getSchemaHandler();
// Loading the complete Schema
loadSchema();
}
/**
* Adds an attribute type.
*
* @param at
* the attribute type
*/
private void addAttributeType( AttributeType at )
{
// Checking Aliases and OID
checkAliasesAndOID( at );
String superiorName = at.getSuperiorOid();
if ( superiorName != null )
// The attribute type has a superior
{
AttributeType superior = schemaHandler.getAttributeType( superiorName );
if ( superior != null )
// The superior attribute type object exists
{
parentsMap.put( at, superior );
childrenMap.put( superior, at );
}
else
// The superior attribute type object does not exist
{
// Then, its parent is the name of its superior and
// it becomes the children of it and the RootObject
parentsMap.put( at, Strings.toLowerCase( superiorName ) );
childrenMap.put( Strings.toLowerCase( superiorName ), at );
childrenMap.put( root, at );
}
}
else
// The attribute type does not have a superior
{
// Then, its parent is the RootObject
parentsMap.put( at, root );
childrenMap.put( root, at );
}
}
/**
* Adds an object class.
*
* @param oc
* the object class
*/
private void addObjectClass( ObjectClass oc )
{
// Checking Aliases and OID
checkAliasesAndOID( oc );
List<String> superClasseNames = oc.getSuperiorOids();
if ( ( superClasseNames != null ) && ( superClasseNames.size() > 0 ) )
// The object class has one or more superiors
{
for ( String superClassName : superClasseNames )
{
ObjectClass superClass = schemaHandler.getObjectClass( superClassName );
if ( superClass == null )
{
parentsMap.put( oc, Strings.toLowerCase( superClassName ) );
childrenMap.put( Strings.toLowerCase( superClassName ), oc );
childrenMap.put( root, oc );
}
else
{
parentsMap.put( oc, superClass );
childrenMap.put( superClass, oc );
}
}
}
else
// The object class does not have any declared superior
// Then, it is a child of the "top (2.5.6.0)" object class
// (Unless it is the "top (2.5.6.0)" object class itself)
{
ObjectClass topOC = schemaHandler.getObjectClass( "2.5.6.0" ); //$NON-NLS-1$
if ( oc.equals( topOC ) )
// The given object class is the "top (2.5.6.0)" object class
{
parentsMap.put( oc, root );
childrenMap.put( root, oc );
}
else
{
if ( topOC != null )
// The "top (2.5.6.0)" object class exists
{
parentsMap.put( oc, topOC );
childrenMap.put( topOC, oc );
}
else
// The "top (2.5.6.0)" object class does not exist
{
parentsMap.put( oc, "2.5.6.0" ); //$NON-NLS-1$
childrenMap.put( "2.5.6.0", oc ); //$NON-NLS-1$
childrenMap.put( root, oc );
}
}
}
}
/**
* This method is called when an attribute type is added.
*
* @param at
* the added attribute type
*/
public void attributeTypeAdded( AttributeType at )
{
addAttributeType( at );
}
/**
* This method is called when an attribute type is modified.
*
* @param at
* the modified attribute type
*/
public void attributeTypeModified( AttributeType at )
{
// Removing the attribute type
List<Object> parents = getParents( at );
if ( parents != null )
{
for ( Object parent : parents )
{
childrenMap.remove( parent, at );
}
parentsMap.remove( at );
}
// Adding the attribute type again
addAttributeType( at );
}
/**
* This method is called when an attribute type is removed.
*
* @param at
* the removed attribute type
*/
public void attributeTypeRemoved( AttributeType at )
{
removeAttributeType( at );
}
/**
* Checks the Aliases and OID of an attribute type or an object class.
*
* @param object
* an attribute type or an object class.
*/
private void checkAliasesAndOID( SchemaObject object )
{
// Aliases
List<String> aliases = object.getNames();
if ( aliases != null )
{
for ( String alias : aliases )
{
// Looking for children objects for this alias value
@SuppressWarnings("unchecked")
List<Object> children = ( List<Object> ) childrenMap.get( Strings.toLowerCase( alias ) );
if ( children != null )
{
for ( Object value : children )
{
childrenMap.put( object, value );
parentsMap.remove( value, Strings.toLowerCase( alias ) );
parentsMap.put( value, object );
}
childrenMap.remove( Strings.toLowerCase( alias ) );
}
}
}
// OID
String oid = object.getOid();
if ( oid != null )
{
// Looking for children objects for this OID value
@SuppressWarnings("unchecked")
List<Object> children = ( List<Object> ) childrenMap.get( Strings.toLowerCase( oid ) );
if ( children != null )
{
for ( Object value : children )
{
childrenMap.put( object, value );
if ( oid.equals( "2.5.6.0" ) ) //$NON-NLS-1$
{
childrenMap.remove( root, value );
}
parentsMap.remove( value, Strings.toLowerCase( oid ) );
parentsMap.put( value, object );
}
childrenMap.remove( Strings.toLowerCase( oid ) );
}
}
}
/**
* Gets the children of the given object.
*
* @param o
* the object
* @return
* the children of the given object
*/
@SuppressWarnings("unchecked")
public List<Object> getChildren( Object o )
{
return ( List<Object> ) childrenMap.get( o );
}
/**
* Gets the parents of the given object.
*
* @param o
* the object
* @return
* the parents of the given object
*/
@SuppressWarnings("unchecked")
public List<Object> getParents( Object o )
{
return ( List<Object> ) parentsMap.get( o );
}
/**
* Gets the RootObject of the Hierarchy.
*
* @return
* the RootObject of the Hierarchy
*/
public RootObject getRootObject()
{
return root;
}
/**
* Loads the Schema.
*/
private void loadSchema()
{
if ( schemaHandler != null )
{
// Creating the root element
root = new RootObject();
// Looping on the schemas
for ( Schema schema : schemaHandler.getSchemas() )
{
// Looping on the attribute types
for ( AttributeType at : schema.getAttributeTypes() )
{
addAttributeType( at );
}
// Looping on the object classes
for ( ObjectClass oc : schema.getObjectClasses() )
{
addObjectClass( oc );
}
}
}
}
/**
* This method is called when an object class is added.
*
* @param oc
* the added object class
*/
public void objectClassAdded( ObjectClass oc )
{
addObjectClass( oc );
}
/**
* This method is called when an object class is modified.
*
* @param oc
* the modified object class
*/
public void objectClassModified( ObjectClass oc )
{
// Removing the object class type
List<Object> parents = getParents( oc );
if ( parents != null )
{
for ( Object parent : parents )
{
childrenMap.remove( parent, oc );
}
parentsMap.remove( oc );
}
// Adding the object class again
addObjectClass( oc );
}
/**
* This method is called when an object class is removed.
*
* @param oc
* the removed object class
*/
public void objectClassRemoved( ObjectClass oc )
{
removeObjectClass( oc );
}
/**
* Removes an attribute type.
*
* @param at
* the attribute type
*/
private void removeAttributeType( AttributeType at )
{
// Removing the attribute type as child of its superior
String superiorName = at.getSuperiorOid();
if ( ( superiorName != null ) && ( !"".equals( superiorName ) ) ) //$NON-NLS-1$
{
AttributeType superiorAT = schemaHandler.getAttributeType( superiorName );
if ( superiorAT == null )
{
childrenMap.remove( Strings.toLowerCase( superiorName ), at );
}
else
{
childrenMap.remove( superiorAT, at );
}
}
else
{
childrenMap.remove( root, at );
}
// Attaching each child (if there are children) to the RootObject
List<Object> children = getChildren( at );
if ( children != null )
{
for ( Object child : children )
{
AttributeType childAT = ( AttributeType ) child;
parentsMap.remove( child, at );
parentsMap.put( child, root );
childrenMap.put( root, child );
String childSuperiorName = childAT.getSuperiorOid();
if ( ( childSuperiorName != null ) && ( !"".equals( childSuperiorName ) ) ) //$NON-NLS-1$
{
parentsMap.put( child, Strings.toLowerCase( childSuperiorName ) );
childrenMap.put( Strings.toLowerCase( childSuperiorName ), child );
}
}
}
childrenMap.remove( at );
parentsMap.remove( at );
}
private void removeObjectClass( ObjectClass oc )
{
// Removing the object class as child of its superiors
List<String> superClassesNames = oc.getSuperiorOids();
if ( ( superClassesNames != null ) && ( superClassesNames.size() > 0 ) )
{
for ( String superClassName : superClassesNames )
{
if ( !"".equals( superClassName ) ) //$NON-NLS-1$
{
ObjectClass superClassOC = schemaHandler.getObjectClass( superClassName );
if ( superClassOC == null )
{
childrenMap.remove( Strings.toLowerCase( superClassName ), oc );
childrenMap.remove( root, oc );
}
else
{
childrenMap.remove( superClassOC, oc );
}
}
}
}
else
{
if ( oc.getOid().equals( "2.5.6.0" ) ) //$NON-NLS-1$
// The given object class is the "top (2.5.6.0)" object class
{
childrenMap.remove( root, oc );
}
else
{
ObjectClass topOC = schemaHandler.getObjectClass( "2.5.6.0" ); //$NON-NLS-1$
if ( topOC != null )
// The "top (2.5.6.0)" object class exists
{
childrenMap.remove( topOC, oc );
}
else
// The "top (2.5.6.0)" object class does not exist
{
childrenMap.remove( "2.5.6.0", oc ); //$NON-NLS-1$
}
}
}
// Attaching each child (if there are children) to the RootObject
List<Object> children = getChildren( oc );
if ( children != null )
{
for ( Object child : children )
{
ObjectClass childOC = ( ObjectClass ) child;
parentsMap.remove( child, oc );
parentsMap.put( child, root );
childrenMap.put( root, child );
List<String> childSuperClassesNames = childOC.getSuperiorOids();
if ( ( childSuperClassesNames != null ) && ( childSuperClassesNames.size() > 0 ) )
{
String correctSuperClassName = getCorrectSuperClassName( oc, childSuperClassesNames );
if ( correctSuperClassName != null )
{
parentsMap.put( child, Strings.toLowerCase( correctSuperClassName ) );
childrenMap.put( Strings.toLowerCase( correctSuperClassName ), child );
}
}
else
{
parentsMap.put( child, "2.5.6.0" ); //$NON-NLS-1$
childrenMap.put( "2.5.6.0", child ); //$NON-NLS-1$
}
}
}
childrenMap.remove( oc );
parentsMap.remove( oc );
}
private String getCorrectSuperClassName( ObjectClass oc, List<String> childSuperClassesNames )
{
if ( childSuperClassesNames != null )
{
List<String> aliases = oc.getNames();
if ( aliases != null )
{
for ( String childSuperClassName : childSuperClassesNames )
{
if ( aliases.contains( childSuperClassName ) )
{
return childSuperClassName;
}
}
}
}
// Default
return null;
}
}