/*
* 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.model.overlay;
import java.text.ParseException;
import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.api.util.Position;
import org.apache.directory.api.util.Strings;
/**
* This class represents 'OlcValSortOverlay' value.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class OlcValSortValue
{
/** The 'weighted' constant string */
private static final String WEIGHTED_STRING = "weighted";
/** The attribute */
private String attribute;
/** The base DN */
private Dn baseDn;
/** The sort method */
private OlcValSortMethodEnum sortMethod;
private boolean isWeighted = false;
/**
* Gets the attribute.
*
* @return the attribute
*/
public String getAttribute()
{
return attribute;
}
/**
* Gets the base DN.
*
* @return the base DN
*/
public Dn getBaseDn()
{
return baseDn;
}
/**
* Gets the sort method.
*
* @return the sort method
*/
public OlcValSortMethodEnum getSortMethod()
{
return sortMethod;
}
/**
* Return whether or the selected sort method is weighted.
*
* @return <code>true</code> if the sort method is weighted,
* <code>false</code> if not
*/
public boolean isWeighted()
{
return isWeighted;
}
/**
* Sets the attribute.
*
* @param attribute the attribute
*/
public void setAttribute( String attribute )
{
this.attribute = attribute;
}
/**
* Sets the base DN.
*
* @param baseDn the base DN
*/
public void setBaseDn( Dn baseDn )
{
this.baseDn = baseDn;
}
/**
* Sets the sort method.
*
* @param sortMethod the sort method
*/
public void setSortMethod( OlcValSortMethodEnum sortMethod )
{
this.sortMethod = sortMethod;
}
/**
* Sets whether or the selected sort method is weighted..
*
* @param isWeighted the value
*/
public void setWeighted( boolean isWeighted )
{
this.isWeighted = isWeighted;
}
/**
* {@inheritDoc}
*/
public String toString()
{
StringBuilder sb = new StringBuilder();
// Attribute
sb.append( attribute );
sb.append( ' ' );
// Base DN
boolean baseDnNeedsEscaping = false;
if ( baseDn != null )
{
baseDnNeedsEscaping = needsEscaping( baseDn.toString() );
}
if ( baseDnNeedsEscaping )
{
sb.append( '"' );
}
sb.append( baseDn );
if ( baseDnNeedsEscaping )
{
sb.append( '"' );
}
sb.append( ' ' );
// Weighted
if ( isWeighted )
{
sb.append( WEIGHTED_STRING );
// Sort method
if ( sortMethod != null )
{
// Sort method
sb.append( ' ' );
sb.append( sortMethod );
}
}
else
{
// Sort method
sb.append( sortMethod );
}
return sb.toString();
}
/**
* Indicates if the given string needs escaping.
*
* @param s the string
* @return <code>true</code> if the given string needs escaping
* <code>false</code> if not.
*/
private boolean needsEscaping( String s )
{
if ( s != null )
{
return s.contains( " " );
}
return false;
}
/**
* Parses a OlcValSortValue value.
*
* @param s the string to be parsed
* @return the associated OlcValSortValue object
* @throws ParseException if there are any recognition errors (bad syntax)
*/
public static synchronized OlcValSortValue parse( String s ) throws ParseException
{
if ( s == null )
{
return null;
}
// Trimming the value
s = Strings.trim( s );
// Getting the chars of the string
char[] chars = s.toCharArray();
// Creating the position
Position pos = new Position();
pos.start = 0;
pos.end = 0;
pos.length = chars.length;
return parseInternal( chars, pos );
}
/**
* Parses the given string.
*
* @param chars the characters
* @param pos the position
* @return the associated OlcValSortValue object
* @throws ParseException
*/
private static OlcValSortValue parseInternal( char[] chars, Position pos ) throws ParseException
{
OlcValSortValue olcValSortValue = new OlcValSortValue();
// Empty (trimmed) string?
if ( chars.length == 0 )
{
return null;
}
do
{
// Attribute
String attribute = getQuotedOrNotQuotedOptionValue( chars, pos );
if ( ( attribute != null ) && ( !attribute.isEmpty() ) )
{
olcValSortValue.setAttribute( attribute );
}
else
{
throw new ParseException( "Could not find the 'Attribute' value", pos.start );
}
// Base DN
String baseDn = getQuotedOrNotQuotedOptionValue( chars, pos );
if ( ( baseDn != null ) && ( !baseDn.isEmpty() ) )
{
try
{
olcValSortValue.setBaseDn( new Dn( baseDn ) );
}
catch ( LdapInvalidDnException e )
{
throw new ParseException( "Could not convert '" + baseDn + "' to a valid DN.", pos.start );
}
}
else
{
throw new ParseException( "Could not find the 'Base DN value", pos.start );
}
// Getting the next item
// It can either "weighted" or a sort method
String weightedOrSortMethod = getQuotedOrNotQuotedOptionValue( chars, pos );
if ( ( weightedOrSortMethod != null ) && ( !weightedOrSortMethod.isEmpty() ) )
{
// Weighted
if ( isWeighted( weightedOrSortMethod ) )
{
olcValSortValue.setWeighted( true );
}
// Sort Method
else if ( isSortMethod( weightedOrSortMethod ) )
{
olcValSortValue.setSortMethod( OlcValSortMethodEnum.fromString( weightedOrSortMethod ) );
}
else
{
throw new ParseException( "Could not identify keyword '" + weightedOrSortMethod
+ "' as a valid sort method.", pos.start );
}
}
// Getting the next item
// It should not exist if the previous item was "weighted" and
// must a sort method it the previous item was "weighted"
String sortMethod = getQuotedOrNotQuotedOptionValue( chars, pos );
if ( ( sortMethod != null ) && ( !sortMethod.isEmpty() ) )
{
if ( olcValSortValue.isWeighted() )
{
if ( isSortMethod( sortMethod ) )
{
olcValSortValue.setSortMethod( OlcValSortMethodEnum.fromString( sortMethod ) );
}
else
{
throw new ParseException( "Could not identify keyword '" + sortMethod
+ "' as a valid sort method.", pos.start );
}
}
else
{
throw new ParseException( "Keyword '" + sortMethod + "' is not allowed after sort method.",
pos.start );
}
}
}
while ( ( pos.start != pos.length ) && ( ( Strings.charAt( chars, pos.start ) ) != '\0' ) );
return olcValSortValue;
}
/**
* Indicates if the given string is "weighted".
*
* @param s the string to test
* @return <code>true</code> if the given string is "weighted",
* <code>false</code> if not.
*/
private static boolean isWeighted( String s )
{
return WEIGHTED_STRING.equalsIgnoreCase( s );
}
/**
* Indicates if the given string is one of the sort methods.
*
* @param s the string to test
* @return <code>true</code> if the given string is one of the sort methods,
* <code>false</code> if not.
*/
private static boolean isSortMethod( String s )
{
return ( OlcValSortMethodEnum.fromString( s ) != null );
}
private static String getQuotedOrNotQuotedOptionValue( char[] chars, Position pos ) throws ParseException
{
if ( pos.start != pos.length )
{
char quoteChar = '\0';
boolean isInQuotes = false;
char c = Strings.charAt( chars, pos.start );
char[] v = new char[chars.length - pos.start];
int current = 0;
do
{
if ( ( current == 0 ) && !isInQuotes )
{
// Whitespace
if ( Character.isWhitespace( c ) )
{
// We ignore all whitespaces until we find the start of the value
pos.start++;
continue;
}
// Double quotes (") or single quotes (')
else if ( ( c == '"' ) || ( c == '\'' ) )
{
isInQuotes = true;
quoteChar = c;
pos.start++;
continue;
}
// Any other char is part of a value
else
{
v[current++] = c;
pos.start++;
}
}
else
{
if ( isInQuotes )
{
// Double quotes (") or single quotes (')
if ( quoteChar == c )
{
isInQuotes = false;
pos.start++;
continue;
}
// Checking for escaped quotes
else if ( c == '\\' )
{
// Double quotes (")
if ( ( quoteChar == '"' ) && ( Strings.areEquals( chars, pos.start, "\\\"" ) >= 0 ) )
{
v[current++] = '"';
pos.start += 2;
continue;
}
// Single quotes (')
else if ( ( quoteChar == '\'' ) && ( Strings.areEquals( chars, pos.start, "\\'" ) >= 0 ) )
{
v[current++] = '\'';
pos.start += 2;
continue;
}
}
// Any other char is part of a value
else
{
v[current++] = c;
pos.start++;
}
}
else
{
// Whitespace
if ( Character.isWhitespace( c ) )
{
// Once we have found the start of the value, the first whitespace is the exit
break;
}
// Any other char is part of a value
else
{
v[current++] = c;
pos.start++;
}
}
}
}
while ( ( c = Strings.charAt( chars, pos.start ) ) != '\0' );
// Checking the resulting value
if ( current == 0 )
{
throw new ParseException( "Couldn't find a value.", pos.start );
}
char[] value = new char[current];
System.arraycopy( v, 0, value, 0, current );
// Getting the value as a String
return new String( value );
}
return null;
}
}