/*
* 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.io;
import java.util.ArrayList;
import java.util.List;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.apache.directory.api.ldap.model.constants.LdapConstants;
import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.api.ldap.model.schema.LdapSyntax;
import org.apache.directory.api.ldap.model.schema.MatchingRule;
import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
import org.apache.directory.api.ldap.model.schema.MutableObjectClass;
import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
import org.apache.directory.api.ldap.model.schema.UsageEnum;
import org.apache.directory.studio.common.core.jobs.StudioProgressMonitor;
import org.apache.directory.studio.connection.core.Connection;
import org.apache.directory.studio.connection.core.io.ConnectionWrapper;
import org.apache.directory.studio.schemaeditor.model.Project;
import org.apache.directory.studio.schemaeditor.model.Schema;
/**
* A Schema Connector for ApacheDS.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ApacheDsSchemaConnector extends AbstractSchemaConnector implements SchemaConnector
{
/**
* This enum represents the different types of nodes that can be found while
* reading the schema from the DIT.
*/
private enum SchemaNodeTypes
{
ATTRIBUTE_TYPE, OBJECT_CLASS, MATCHING_RULE, SYNTAX, UNKNOWN
}
/**
* {@inheritDoc}
*/
public void importSchema( Project project, StudioProgressMonitor monitor )
throws SchemaConnectorException
{
monitor.beginTask( Messages.getString( "ApacheDsSchemaConnector.FetchingSchema" ), 1 ); //$NON-NLS-1$
List<Schema> schemas = new ArrayList<Schema>();
project.setInitialSchema( schemas );
ConnectionWrapper wrapper = project.getConnection().getConnectionWrapper();
// Looking for all the defined schemas
SearchControls constraintSearch = new SearchControls();
constraintSearch.setSearchScope( SearchControls.ONELEVEL_SCOPE );
NamingEnumeration<SearchResult> answer = wrapper
.search( SchemaConstants.OU_SCHEMA, "(objectclass=metaSchema)", constraintSearch, DEREF_ALIAS_METHOD, //$NON-NLS-1$ //$NON-NLS-2$
HANDLE_REFERALS_METHOD, null, monitor, null );
if ( answer != null )
{
try
{
while ( answer.hasMore() )
{
SearchResult searchResult = answer.next();
// Getting the 'cn' Attribute
Attribute cnAttribute = searchResult.getAttributes().get( SchemaConstants.CN_AT );
// Looping on the values
NamingEnumeration<?> ne = cnAttribute.getAll();
if ( ne != null )
{
while ( ne.hasMore() )
{
String cnValue = (String)ne.next();
Schema schema = getSchema( wrapper, cnValue, monitor );
schema.setProject( project );
schemas.add( schema );
}
}
}
}
catch ( Exception e )
{
throw new SchemaConnectorException( e );
}
}
monitor.worked( 1 );
}
/**
* {@inheritDoc}
*/
public boolean isSuitableConnector( Connection connection, StudioProgressMonitor monitor )
{
ConnectionWrapper wrapper = connection.getConnectionWrapper();
SearchControls constraintSearch = new SearchControls();
constraintSearch.setSearchScope( SearchControls.OBJECT_SCOPE );
constraintSearch.setReturningAttributes( new String[]
{ SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES } );
NamingEnumeration<SearchResult> answer = wrapper.search( "", LdapConstants.OBJECT_CLASS_STAR, constraintSearch, //$NON-NLS-1$ //$NON-NLS-2$
DEREF_ALIAS_METHOD, HANDLE_REFERALS_METHOD, null, monitor, null );
if ( answer != null )
{
try
{
if ( answer.hasMore() )
{
SearchResult searchResult = answer.next();
Attribute vendorNameAttribute = searchResult.getAttributes().get( SchemaConstants.VENDOR_NAME_AT );
if ( vendorNameAttribute == null )
{
return false;
}
if ( vendorNameAttribute.size() != 1 )
{
return false;
}
String vendorName = null;
try
{
vendorName = ( String ) vendorNameAttribute.get();
}
catch ( NamingException e )
{
return false;
}
return ( ( vendorName != null ) && vendorName.equalsIgnoreCase( "Apache Software Foundation" ) ); //$NON-NLS-1$
}
}
catch ( NamingException e )
{
monitor.reportError( e );
}
}
return false;
}
private static Schema getSchema( ConnectionWrapper wrapper, String name, StudioProgressMonitor monitor )
throws NamingException
{
monitor.subTask( name );
// Creating the schema
Schema schema = new Schema( name );
// Looking for the nodes of the schema
SearchControls constraintSearch = new SearchControls();
constraintSearch.setSearchScope( SearchControls.SUBTREE_SCOPE );
NamingEnumeration<SearchResult> answer = wrapper.search( "cn=" + name + ", ou=schema", LdapConstants.OBJECT_CLASS_STAR, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
constraintSearch, DEREF_ALIAS_METHOD, HANDLE_REFERALS_METHOD, null, monitor, null );
if ( answer != null )
{
try
{
while ( answer.hasMore() )
{
SearchResult searchResult = answer.next();
switch ( getNodeType( searchResult ) )
{
case ATTRIBUTE_TYPE:
AttributeType at = createAttributeType( searchResult );
at.setSchemaName( name );
schema.addAttributeType( at );
break;
case OBJECT_CLASS:
MutableObjectClass oc = createObjectClass( searchResult );
oc.setSchemaName( name );
schema.addObjectClass( oc );
break;
case MATCHING_RULE:
MatchingRule mr = createMatchingRule( searchResult );
mr.setSchemaName( name );
schema.addMatchingRule( mr );
break;
case SYNTAX:
LdapSyntax syntax = createSyntax( searchResult );
syntax.setSchemaName( name );
schema.addSyntax( syntax );
break;
default:
break;
}
}
}
catch ( NamingException e )
{
monitor.reportError( e );
}
}
return schema;
}
/**
* Gets the Type of node of the given SearchResult.
*
* @param sr the SearchResult to be identified
* @return the Type of node
* @throws NamingException if an error occurrs when reading the SearchResult
*/
private static SchemaNodeTypes getNodeType( SearchResult sr ) throws NamingException
{
// Getting the 'ObjectClass' Attribute
Attribute objectClassAttribute = sr.getAttributes().get( SchemaConstants.OBJECT_CLASS_AT );
// Looping on the values
NamingEnumeration<?> ne = objectClassAttribute.getAll();
while ( ne.hasMore() )
{
String value = ( String ) ne.next();
if ( SchemaConstants.META_ATTRIBUTE_TYPE_OC.equalsIgnoreCase( value ) )
{
return SchemaNodeTypes.ATTRIBUTE_TYPE;
}
else if ( SchemaConstants.META_OBJECT_CLASS_OC.equalsIgnoreCase( value ) )
{
return SchemaNodeTypes.OBJECT_CLASS;
}
else if ( SchemaConstants.META_MATCHING_RULE_OC.equalsIgnoreCase( value ) )
{
return SchemaNodeTypes.MATCHING_RULE;
}
else if ( SchemaConstants.META_SYNTAX_OC.equalsIgnoreCase( value ) )
{
return SchemaNodeTypes.SYNTAX;
}
}
return SchemaNodeTypes.UNKNOWN;
}
/**
* Create the AttributeTypeImpl associated with the given SearchResult.
*
* @param sr the SearchResult
* @return the AttributeTypeImpl associated with the SearchResult, or null if no
* AttributeTypeImpl could be created
* @throws NamingException
*/
private static AttributeType createAttributeType( SearchResult sr ) throws NamingException
{
MutableAttributeType at = new MutableAttributeType( getStringValue( sr, MetaSchemaConstants.M_OID_AT ) );
at.setNames( getStringValues( sr, MetaSchemaConstants.M_NAME_AT ) );
at.setDescription( getStringValue( sr, MetaSchemaConstants.M_DESCRIPTION_AT ) );
at.setObsolete( getBooleanValue( sr, MetaSchemaConstants.M_OBSOLETE_AT ) );
at.setSuperiorOid( getStringValue( sr, MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT ) );
at.setUsage( getUsage( sr ) );
at.setSyntaxOid( getStringValue( sr, MetaSchemaConstants.M_SYNTAX_AT ) );
at.setSyntaxLength( getSyntaxLength( sr ) );
at.setCollective( getBooleanValue( sr, MetaSchemaConstants.M_COLLECTIVE_AT ) );
at.setSingleValued( getBooleanValue( sr, MetaSchemaConstants.M_SINGLE_VALUE_AT ) );
at.setUserModifiable( getBooleanValue( sr, MetaSchemaConstants.M_NO_USER_MODIFICATION_AT ) );
at.setEqualityOid( getStringValue( sr, MetaSchemaConstants.M_EQUALITY_AT ) );
at.setOrderingOid( getStringValue( sr, MetaSchemaConstants.M_ORDERING_AT ) );
at.setSubstringOid( getStringValue( sr, MetaSchemaConstants.M_SUBSTR_AT ) );
return at;
}
/**
* Create the ObjectClassImpl associated with the given SearchResult.
*
* @param sr the SearchResult
* @return the ObjectClassImpl associated with the SearchResult, or null if no
* ObjectClassImpl could be created
* @throws NamingException
*/
private static MutableObjectClass createObjectClass( SearchResult sr ) throws NamingException
{
MutableObjectClass oc = new MutableObjectClass( getStringValue( sr, MetaSchemaConstants.M_OID_AT ) );
oc.setNames( getStringValues( sr, MetaSchemaConstants.M_NAME_AT ) );
oc.setDescription( getStringValue( sr, MetaSchemaConstants.M_DESCRIPTION_AT ) );
oc.setObsolete( getBooleanValue( sr, MetaSchemaConstants.M_OBSOLETE_AT ) );
oc.setSuperiorOids( getStringValues( sr, MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT ) );
oc.setType( getType( sr ) );
oc.setMayAttributeTypeOids( getStringValues( sr, MetaSchemaConstants.M_MAY_AT ) );
oc.setMustAttributeTypeOids( getStringValues( sr, MetaSchemaConstants.M_MUST_AT ) );
return oc;
}
/**
* Create the MatchingRule associated with the given SearchResult.
*
* @param sr the SearchResult
* @return the MatchingRule associated with the SearchResult, or null if no
* ObjectClass could be created
* @throws NamingException
*/
private static MatchingRule createMatchingRule( SearchResult sr ) throws NamingException
{
MutableMatchingRule mr = new MutableMatchingRule( getStringValue( sr, MetaSchemaConstants.M_OID_AT ) );
mr.setNames( getStringValues( sr, MetaSchemaConstants.M_NAME_AT ) );
mr.setDescription( getStringValue( sr, MetaSchemaConstants.M_DESCRIPTION_AT ) );
mr.setObsolete( getBooleanValue( sr, MetaSchemaConstants.M_OBSOLETE_AT ) );
mr.setSyntaxOid( getStringValue( sr, MetaSchemaConstants.M_SYNTAX_AT ) );
return mr;
}
/**
* Create the MatchingRule associated with the given SearchResult.
*
* @param sr the SearchResult
* @return the MatchingRule associated with the SearchResult, or null if no
* ObjectClass could be created
* @throws NamingException
*/
private static LdapSyntax createSyntax( SearchResult sr ) throws NamingException
{
LdapSyntax syntax = new LdapSyntax( getStringValue( sr, MetaSchemaConstants.M_OID_AT ) );
syntax.setNames( getStringValues( sr, MetaSchemaConstants.M_NAME_AT ) );
syntax.setDescription( getStringValue( sr, MetaSchemaConstants.M_DESCRIPTION_AT ) );
syntax.setObsolete( getBooleanValue( sr, MetaSchemaConstants.M_OBSOLETE_AT ) );
syntax.setHumanReadable( isHumanReadable( sr ) );
return syntax;
}
/**
* Gets the usage of the attribute type contained a SearchResult.
*
* @param sr the SearchResult
* @return the usage of the attribute type
* @throws NamingException if an error occurs when searching in the SearchResult
*/
private static UsageEnum getUsage( SearchResult sr ) throws NamingException
{
Attribute at = sr.getAttributes().get( MetaSchemaConstants.M_USAGE_AT );
if ( at == null )
{
return UsageEnum.USER_APPLICATIONS;
}
else
{
try
{
return UsageEnum.getUsage( ( String ) at.get() );
}
catch ( IllegalArgumentException e )
{
return UsageEnum.USER_APPLICATIONS;
}
catch ( NullPointerException e )
{
return UsageEnum.USER_APPLICATIONS;
}
}
}
/**
* Gets the syntax length of the attribute type contained a SearchResult.
*
* @param sr the SearchResult
* @return the syntax length of the attribute type, or -1 if no syntax length was found
* @throws NamingException if an error occurs when searching in the SearchResult
*/
private static int getSyntaxLength( SearchResult sr ) throws NamingException
{
Attribute at = sr.getAttributes().get( MetaSchemaConstants.M_LENGTH_AT );
if ( at == null )
{
return -1;
}
else
{
try
{
return Integer.parseInt( ( String ) at.get() );
}
catch ( NumberFormatException e )
{
return -1;
}
}
}
/**
* Gets the String value of a Schema element of an attribute type contained in a SearchResult.
*
* @param sr the SearchResult
* @param schemaElement The Schema Element we are looking for
* @return The String value if found
* @throws NamingException if an error occurs when searching in the SearchResult
*/
private static String getStringValue( SearchResult sr, String schemaElement ) throws NamingException
{
Attribute at = sr.getAttributes().get( schemaElement );
if ( at == null )
{
return null;
}
else
{
return ( String ) at.get();
}
}
/**
* Gets the Boolean value for a Schema element of an attribute type contained in a SearchResult.
*
* @param sr the SearchResult
* @param schemaElement The Schema Element we are looking for
* @return The boolean value if found
* @throws NamingException if an error occurs when searching in the SearchResult
*/
private static boolean getBooleanValue( SearchResult sr, String schemaElement ) throws NamingException
{
Attribute at = sr.getAttributes().get( schemaElement );
if ( at == null )
{
return false;
}
else
{
return Boolean.parseBoolean( ( String ) at.get() );
}
}
/**
* Gets the list of values for a schema element of an object class contained in a SearchResult.
*
* @param sr the SearchResult
* @param schemaElement The Schema Element we are looking for
* @return the optional attribute types of the attribute type, or an empty array if no optional attribute type was found
* @throws NamingException
* if an error occurrs when searching in the SearchResult
*/
private static List<String> getStringValues( SearchResult sr, String schemaElement ) throws NamingException
{
List<String> names = new ArrayList<String>();
Attribute at = sr.getAttributes().get( schemaElement );
if ( at != null )
{
NamingEnumeration<?> ne = at.getAll();
while ( ne.hasMore() )
{
names.add( ( String ) ne.next() );
}
}
return names;
}
/**
* Gets the type of the object class contained a SearchResult.
*
* @param sr the SearchResult
* @return the type of the object class
* @throws NamingException if an error occurrs when searching in the SearchResult
*/
private static ObjectClassTypeEnum getType( SearchResult sr ) throws NamingException
{
Attribute at = sr.getAttributes().get( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT );
if ( at == null )
{
return ObjectClassTypeEnum.STRUCTURAL;
}
else
{
try
{
return ObjectClassTypeEnum.getClassType( ( String ) at.get() );
}
catch ( IllegalArgumentException e )
{
return ObjectClassTypeEnum.STRUCTURAL;
}
catch ( NullPointerException e )
{
return ObjectClassTypeEnum.STRUCTURAL;
}
}
}
/**
* Gets whether or not the schema object contained a SearchResult is obsolete.
*
* @param sr the SearchResult
* @return true if the schema object is obsolete, false if not
* @throws NamingException if an error occurs when searching in the SearchResult
*/
private static boolean isHumanReadable( SearchResult sr ) throws NamingException
{
Attribute at = sr.getAttributes().get( MetaSchemaConstants.X_NOT_HUMAN_READABLE_AT );
if ( at == null )
{
return false;
}
else
{
return !Boolean.parseBoolean( ( String ) at.get() );
}
}
/**
* {@inheritDoc}
*/
public void exportSchema( Project project, StudioProgressMonitor monitor )
throws SchemaConnectorException
{
// TODO Auto-generated method stub
}
}