/*
* 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.openldap.config.editor.wrappers;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import org.apache.directory.api.util.Strings;
import org.apache.directory.studio.openldap.common.ui.model.DbIndexTypeEnum;
/**
* A wrapper for the Databse indexes. It's used by the BDB, MDB, or HDB/BDB. Here is the
* index value's syntax :
* <pre>
* <olcDbIndex> ::= ATTR <attr-list> <index-types-e> | 'default' <index-types>
* <attr-list> ::= ',' ATTR <attr-list> | e
* <index-types> ::= <type> <types-e>
* <types-e> ::= ',' <type> <types-e> | e
* <type> ::= 'pres' | 'eq' | 'sub' | 'approx' | 'sub' | 'subinitial' | 'subany' |
* 'subfinal' | 'substr' | 'notags' | 'nolang' | 'nosubtypes'
* <index-types-e> ::= <index-types> | e
* </pre>
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class DbIndexWrapper implements Cloneable, Comparable<DbIndexWrapper>
{
/** A flag set when the 'default' special attribute is used */
private boolean isDefault;
/** The set of configured attributes */
private Set<String> attributes = new TreeSet<String>( new Comparator<String>()
{
@Override
public int compare( String string1, String string2 )
{
if ( string1 == null )
{
return -1;
}
else if ( string2 == null )
{
return 1;
}
return string1.compareTo( string2 );
}
}
);
/** The set of configured attributes */
private Set<DbIndexTypeEnum> indexTypes = new TreeSet<DbIndexTypeEnum>();
/**
* Build a DbIndexWrapper from a String containing the description of the index.
*
* @param indexStr The String that describes the index
*/
public DbIndexWrapper( String indexStr )
{
// We first have to parse the attributes. It's a list of Strings, or OIDs, separated
// by ',' and that ends at the first ' ' or the end of the line.
int pos = 0;
int startPos = 0;
boolean endAttributes = false;
// Valid chars are 'a'-'z', 'A'-'Z', '0'-'9', '.', '-' and '_'
for ( pos = 0; pos < indexStr.length(); pos++ )
{
char c = indexStr.charAt( pos );
endAttributes = c == ' ';
if ( ( c == ',' ) || endAttributes )
{
// This is the end of the attribute
String attrStr = indexStr.substring( startPos, pos );
if ( "default".equalsIgnoreCase( attrStr ) )
{
isDefault = true;
startPos = pos + 1;
break;
}
// Check that it's a valid Attribute
//if ( SchemaUtils.isAttributeNameValid( attrStr ) )
{
attributes.add( Strings.toLowerCase( attrStr ) );
startPos = pos + 1;
}
}
if ( endAttributes )
{
break;
}
}
// If the 'default' special attribute is present, we can discard all the other attributes
if ( isDefault )
{
attributes.clear();
}
if ( endAttributes )
{
pos++;
// Ok, we are done with the attributes, let's process the indexTypes now,
// starting where we left
for ( ; pos < indexStr.length(); pos++ )
{
char c = indexStr.charAt( pos );
if ( c == ',' )
{
String indexTypeName = indexStr.substring( startPos, pos );
// Check if we have this indexType
DbIndexTypeEnum indexType = DbIndexTypeEnum.getIndexType( indexTypeName );
if ( indexType != DbIndexTypeEnum.NONE )
{
indexTypes.add( indexType );
}
startPos = pos + 1;
}
}
if ( pos != startPos )
{
// Search for the index type
String indexTypeName = indexStr.substring( startPos, pos );
// Check if we have this indexType
DbIndexTypeEnum indexType = DbIndexTypeEnum.getIndexType( indexTypeName );
if ( indexType != DbIndexTypeEnum.NONE )
{
indexTypes.add( indexType );
}
}
}
}
/**
* @return the isDefault
*/
public boolean isDefault()
{
return isDefault;
}
/**
* @param isDefault the isDefault to set
*/
public void setDefault( boolean isDefault )
{
this.isDefault = isDefault;
}
/**
* @return The set of attributes
*/
public Set<String> getAttributes()
{
return attributes;
}
/**
* @return the indexTypes
*/
public Set<DbIndexTypeEnum> getIndexTypes()
{
return indexTypes;
}
/**
* @return The set of index types
*/
public Set<DbIndexTypeEnum> getTypes()
{
return indexTypes;
}
/**
* @see Object#clone()
*/
public DbIndexWrapper clone()
{
try
{
DbIndexWrapper clone = (DbIndexWrapper)super.clone();
// Clone the attributes
clone.attributes = new TreeSet<String>();
clone.attributes.addAll( attributes );
// Clone the indexTypes
clone.indexTypes = new TreeSet<DbIndexTypeEnum>();
clone.indexTypes.addAll( indexTypes );
return clone;
}
catch ( CloneNotSupportedException cnse )
{
return null;
}
}
/**
* @see Object#hashCode()
*/
public int hashCode()
{
int h = 37;
// Only iterate on Attributes
for ( String attribute : attributes )
{
h += h*17 + attribute.hashCode();
}
return h;
}
/**
* @see Object#equals()
*/
public boolean equals( Object that )
{
if ( that == this )
{
return true;
}
if ( ! ( that instanceof DbIndexWrapper ) )
{
return false;
}
return compareTo( (DbIndexWrapper)that ) == 0;
}
/**
* @see Comparable#compareTo()
*/
public int compareTo( DbIndexWrapper that )
{
// Compare by attributes only.
if ( that == null )
{
return 1;
}
// we will iterate on the two sets in parallel.
int limit = Math.min( attributes.size(), that.attributes.size() );
Iterator<String> thisIterator = attributes.iterator();
Iterator<String> thatIterator = that.attributes.iterator();
for ( int i = 0; i < limit; i++ )
{
int result = thisIterator.next().compareTo( thatIterator.next() );
if ( result != 0)
{
return result;
}
}
return attributes.size() - that.attributes.size();
}
/**
* @see Object#toString()
*/
public String toString()
{
StringBuilder sb = new StringBuilder();
// first, the Attribute, if it's not default
if ( isDefault )
{
if ( indexTypes.size() == 0 )
{
// No types either ? return a blank String
return "";
}
sb.append( "default" );
}
else
{
boolean isFirst = true;
for ( String attribute : attributes )
{
if ( isFirst )
{
isFirst = false;
}
else
{
sb.append( ',' );
}
sb.append( attribute );
}
}
// A space before the indexTypes
sb.append( ' ' );
if ( indexTypes.size() == 0 )
{
// No type ? Use default
sb.append( "default" );
}
else
{
boolean isFirst = true;
for ( DbIndexTypeEnum indexType : indexTypes )
{
if ( isFirst )
{
isFirst = false;
}
else
{
sb.append( ',' );
}
sb.append( indexType.getName() );
}
}
return sb.toString();
}
}