You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2004/11/08 00:15:58 UTC
svn commit: rev 56875 - in incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common: ldif util
Author: akarasulu
Date: Sun Nov 7 15:15:56 2004
New Revision: 56875
Added:
incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/PropertiesUtils.java
Modified:
incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParser.java
incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParserImpl.java
Log:
Changes ...
o added new utility file for managing properties
o partially cleaned up LDIF parser wrt formating and exceptions thrown
Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParser.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParser.java (original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParser.java Sun Nov 7 15:15:56 2004
@@ -16,14 +16,9 @@
package org.apache.ldap.common.ldif ;
-import java.text.ParseException ;
-
import javax.naming.NamingException ;
import javax.naming.directory.Attributes ;
-import org.apache.ldap.common.util.MultiMap;
-
-
/**
* Parses an ldif into a multimap or an JNDI Attributes instance of attribute
@@ -35,55 +30,32 @@
* be accessed and removed from the MultiMap or Attributes instance if need be
* according to the specific context in which this parser is used.
*
- * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
- * @author $Author: akarasulu $
- * @version $Revision: 1.7 $
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
*/
public interface LdifParser
{
/**
* Parses an String representing an entry in LDAP Data Interchange Format
- * (LDIF) storing its name and attributes in the supplied MultiMap instance.
- *
- * @param a_mmap the MultiMap instance to populate with LDIF attributes
- * including the DN of the entry represented by the LDIF.
- * @param an_ldif the entry in LDAP Data Interchange Format
- * @deprecated
- * @throws ParseException if the LDIF is malformed
- * @throws NamingException if a naming exception results while the LDIF is
- * being parsed
- * TODO investigate if we need to throw a NamingException here
- */
- void parse( MultiMap a_mmap, String an_ldif )
- throws ParseException, NamingException ;
-
- /**
- * Parses an String representing an entry in LDAP Data Interchange Format
* (LDIF) storing its attributes in the supplied Attributes instance.
*
- * @param an_attributes the Attributes instance to populate with LDIF
+ * @param attributes the Attributes instance to populate with LDIF
* attributes including the DN of the entry represented by the LDIF.
- * @param an_ldif the entry in LDAP Data Interchange Format
- * @throws ParseException if the LDIF is malformed
+ * @param ldif the entry in LDAP Data Interchange Format
* @throws NamingException if a naming exception results while the LDIF is
* being parsed
- * TODO investigate if we need to throw a NamingException here
*/
- void parse( Attributes an_attributes, String an_ldif )
- throws ParseException, NamingException ;
+ void parse( Attributes attributes, String ldif ) throws NamingException ;
/**
* Parses an LDIF into a special LdifEntry structure that tracks control
* attributes within an LDIF.
*
- * @param an_ldif the LDIF to parse
+ * @param ldif the LDIF to parse
* @return the LdifEntry parsed
- * @throws ParseException if the LDIF is malformed
* @throws NamingException if a naming exception results while the LDIF is
* being parsed
- * TODO investigate if we need to throw a NamingException here
*/
- LdifEntry parse( String an_ldif )
- throws ParseException, NamingException ;
+ LdifEntry parse( String ldif ) throws NamingException ;
}
Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParserImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParserImpl.java (original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/ldif/LdifParserImpl.java Sun Nov 7 15:15:56 2004
@@ -13,21 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.ldap.common.ldif ;
-
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.ldap.common.ldif;
-import java.text.ParseException ;
-import java.io.IOException ;
-import java.io.StringReader ;
-import java.io.BufferedReader ;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.BufferedReader;
-import javax.naming.NamingException ;
-import javax.naming.directory.Attributes ;
-import javax.naming.directory.DirContext ;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
-import org.apache.ldap.common.util.Base64 ;
-import org.apache.ldap.common.util.MultiMap;
+import org.apache.ldap.common.util.Base64;
+import org.apache.ldap.common.message.ResultCodeEnum;
+import org.apache.eve.exception.EveNamingException;
/**
@@ -38,108 +52,22 @@
* Attributes instance. Until they are the populated container cannot be deemed
* representative of an entry.
*
- * @task Get the RFC for LDIF syntax in this javadoc.
+ * @todo Get the RFC for LDIF syntax in this javadoc.
* @see <a href="http://www.faqs.org/rfcs/rfc2849.html"> RFC 2849 </a>
- * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
- * @author $Author: jmachols $
- * @version $Revision: 1.12 $
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
*/
-public class LdifParserImpl
- implements LdifParser
+public class LdifParserImpl implements LdifParser
{
/**
- * Parses an LDIF String populating a multimap with both single valued and
- * multivalued attributes.
- *
- * @param a_attrHash the hash of attributes to values.
- * @param an_ldif the LDIF as a String.
- * @deprecated
- * @throws ParseException if an_ldif violates LDIF syntax.
- */
- public void parse( MultiMap a_attrHash, String an_ldif )
- throws ParseException
- {
- boolean l_isBase64Encoded = false ;
- int l_lineCount = 0 ;
- int l_index ;
- String l_line ;
- String l_attrName ;
- String l_attrValue ;
- StringReader l_strIn = new StringReader( an_ldif ) ;
- BufferedReader l_in = new BufferedReader( l_strIn ) ;
-
- try
- {
- while ( ( l_line = l_in.readLine() ) != null )
- {
- // Try to advance to ':' if one exists.
- if ( ( l_index = l_line.indexOf( ':' ) ) == -1 )
- {
- throw new ParseException( "Line " + l_lineCount + " ["
- + l_line + "] does not correspond to an LDIF entry "
- + "attribute value pair.\n{" + an_ldif + "}",
- l_lineCount ) ;
- }
-
- // Capture data while at first colon.
- l_attrName = l_line.substring( 0, l_index ).trim() ;
-
- // Consume next char and check if it's a colon for binary attr.
- if ( l_line.charAt( ++l_index ) == ':' )
- {
- l_isBase64Encoded = true ;
- }
-
- // Advance index past whitespace to the first char of the value.
- try
- {
- while ( l_line.charAt( ++l_index ) == ' ' )
- {
- ; // Nothing
- }
-
- // Capture attribute value from first char till end of line.
- l_attrValue = l_line.substring( l_index ) ;
- }
- catch ( StringIndexOutOfBoundsException e )
- {
- l_attrValue = "" ;
- }
-
- /*
- * We need to construct an attribute yet we may not know if it
- * is single valued or multi valued. Our best bet is to just
- * cover all possibilities using a basic attribute instance that
- * the basic attrubutes instance creates automatically.
- */
- if ( l_isBase64Encoded && ( l_attrValue != null ) )
- {
- a_attrHash.put( l_attrName, base64decode( l_attrValue ) ) ;
- l_isBase64Encoded = false ;
- }
- else
- {
- a_attrHash.put( l_attrName, l_attrValue ) ;
- }
- }
- }
- catch ( IOException e )
- {
- // Does not really occur: we follow form by transforming w/ rethrow
- throw new ParseException( e.getMessage(), l_lineCount ) ;
- }
- }
-
-
- /**
* Decodes an encoded string in base64 into a byte array.
*
- * @param a_attrValue the value of a encoded binary attribute.
+ * @param attrValue the value of a encoded binary attribute.
* @return the decoded binary data as a byte array.
*/
- public byte [] base64decode( String a_attrValue )
+ public byte [] base64decode( String attrValue )
{
- return ( Base64.decode( a_attrValue.toCharArray() ) ) ;
+ return ( Base64.decode( attrValue.toCharArray() ) );
}
@@ -147,60 +75,58 @@
* Parses an String representing an entry in LDAP Data Interchange Format
* (LDIF) storing its attributes in the supplied Attributes instance.
*
- * @param an_attributes the attributes from the LDIF
+ * @param attributes the attributes from the LDIF
* including the DN of the entry represented by the LDIF.
- * @param an_ldif the entry in LDAP Data Interchange Format
- * @throws ParseException if an_ldif violates LDIF syntax.
- * @throws NamingException TODO doc me
+ * @param ldif the entry in LDAP Data Interchange Format
+ * @throws NamingException if there any failures while parsing the LDIF and
+ * populating the attirubutes
*/
- public void parse( Attributes an_attributes, String an_ldif )
- throws ParseException, NamingException
+ public void parse( Attributes attributes, String ldif ) throws NamingException
{
- boolean l_isBase64Encoded = false ;
- int l_lineCount = 0 ;
- int l_index ;
- String l_line ;
- String l_attrName ;
- String l_attrValue ;
- StringReader l_strIn = new StringReader( an_ldif ) ;
- BufferedReader l_in = new BufferedReader( l_strIn ) ;
+ boolean isBase64Encoded = false;
+ int lineCount = 0;
+ int index;
+ String line;
+ String attrName;
+ String attrValue;
+ StringReader strIn = new StringReader( ldif );
+ BufferedReader in = new BufferedReader( strIn );
try
{
- while ( ( l_line = l_in.readLine() ) != null )
+ while ( ( line = in.readLine() ) != null )
{
// Try to advance to ':' if one exists.
- if ( ( l_index = l_line.indexOf( ':' ) ) == -1 )
+ if ( ( index = line.indexOf( ':' ) ) == -1 )
{
- throw new ParseException( "Line " + l_lineCount + " ["
- + l_line + "] does not correspond to an LDIF entry "
- + "attribute value pair.\n{" + an_ldif + "}",
- l_lineCount ) ;
+ throw new EveNamingException( "Line " + lineCount + " ["
+ + line + "] does not correspond to an LDIF entry "
+ + "attribute value pair.\n{" + ldif + "}",
+ ResultCodeEnum.OTHER );
}
// Capture data while at first colon.
- l_attrName = l_line.substring( 0, l_index ).trim() ;
+ attrName = line.substring( 0, index ).trim();
// Consume next char and check if it's a colon for binary attr.
- if ( l_line.charAt( ++l_index ) == ':' )
+ if ( line.charAt( ++index ) == ':' )
{
- l_isBase64Encoded = true ;
+ isBase64Encoded = true;
}
// Advance index past whitespace to the first char of the value.
try
{
- while ( l_line.charAt( ++l_index ) == ' ' )
- {
- ; // Does nothing!
+ while ( line.charAt( ++index ) == ' ' )
+ {; // Does nothing!
}
// Capture attribute value from first char till end of line.
- l_attrValue = l_line.substring( l_index ) ;
+ attrValue = line.substring( index );
}
catch ( StringIndexOutOfBoundsException e )
{
- l_attrValue = "" ;
+ attrValue = "";
}
/*
@@ -209,22 +135,21 @@
* cover all possibilities using a basic attribute instance that
* the basic attrubutes instance creates automatically.
*/
- if ( l_isBase64Encoded && ( l_attrValue != null ) )
+ if ( isBase64Encoded && ( attrValue != null ) )
{
- an_attributes.put( l_attrName,
- base64decode( l_attrValue ) ) ;
- l_isBase64Encoded = false ;
+ attributes.put( attrName, base64decode( attrValue ) );
+ isBase64Encoded = false;
}
else
{
- an_attributes.put( l_attrName, l_attrValue ) ;
+ attributes.put( attrName, attrValue );
}
}
}
catch ( IOException e )
{
// Does not really occur: we follow form by transforming w/ rethrow
- throw new ParseException( e.getMessage(), l_lineCount ) ;
+ throw new EveNamingException( ResultCodeEnum.OTHER );
}
}
@@ -235,23 +160,23 @@
*
* @param an_ldif the entry in LDAP Data Interchange Format
* @return the LdifEntry parsed from the LDIF string
- * @throws ParseException if an_ldif violates LDIF syntax
- * @throws NamingException TODO document me
+ * @throws NamingException if there any failures while parsing the LDIF and
+ * populating the attirubutes
*/
public LdifEntry parse( String an_ldif )
- throws ParseException, NamingException
+ throws NamingException
{
- boolean l_isBase64Encoded = false ;
- int l_lineCount = 0 ;
- int l_index ;
- String l_line ;
- String l_attrName = new String () ;
- String l_attrValue = new String () ;
- String l_prevAttrValue = null ;
- StringReader l_strIn = new StringReader( an_ldif ) ;
- BufferedReader l_in = new BufferedReader( l_strIn ) ;
- LdifEntry l_entry = new LdifEntry() ;
- int l_currentModOp = -1 ;
+ boolean l_isBase64Encoded = false;
+ int l_lineCount = 0;
+ int l_index;
+ String l_line;
+ String l_attrName = new String ();
+ String l_attrValue = new String ();
+ String l_prevAttrValue = null;
+ StringReader l_strIn = new StringReader( an_ldif );
+ BufferedReader l_in = new BufferedReader( l_strIn );
+ LdifEntry l_entry = new LdifEntry();
+ int l_currentModOp = -1;
try
{
@@ -265,20 +190,21 @@
{
if ( l_currentModOp == -1 )
{
- throw new ParseException( "A modification"
+ throw new EveNamingException( "A modification"
+ " type must be supplied for a change "
- + "type of modify", l_lineCount ) ;
+ + "type of modify",
+ ResultCodeEnum.OTHER );
}
l_entry.addModificationItem( l_currentModOp,
- l_attrName, l_attrValue ) ;
+ l_attrName, l_attrValue );
}
else
{
if ( l_isBase64Encoded && ( l_attrValue != null ) )
{
l_entry.addAttribute( l_attrName,
- base64decode( l_attrValue ) ) ;
- l_isBase64Encoded = false ;
+ base64decode( l_attrValue ) );
+ l_isBase64Encoded = false;
}
else
{
@@ -286,27 +212,26 @@
}
}
}
- l_currentModOp = -1 ;
- l_prevAttrValue = null ;
- continue ;
+ l_currentModOp = -1;
+ l_prevAttrValue = null;
+ continue;
}
// Try to advance to ':' if one exists.
if ( ( l_index = l_line.indexOf( ':' ) ) == -1 )
{
- throw new ParseException( "Line " + l_lineCount + " ["
+ throw new EveNamingException( "Line " + l_lineCount + " ["
+ l_line + "] does not correspond to an LDIF entry "
+ "attribute value pair.\n{" + an_ldif + "}",
- l_lineCount ) ;
-
+ ResultCodeEnum.OTHER );
}
// Capture data while at first colon.
- l_attrName = l_line.substring( 0, l_index ).trim() ;
+ l_attrName = l_line.substring( 0, l_index ).trim();
// Consume next char and check if it's a colon for binary attr.
if ( l_line.charAt( ++l_index ) == ':' )
{
- l_isBase64Encoded = true ;
+ l_isBase64Encoded = true;
}
// Advance index past whitespace to the first char of the value.
@@ -314,15 +239,15 @@
{
while ( l_line.charAt( ++l_index ) == ' ' )
{
- ; // Does nothing!
+ ; // Does nothing!
}
// Capture attribute value from first char till end of line.
- l_attrValue = l_line.substring( l_index ) ;
+ l_attrValue = l_line.substring( l_index );
}
catch ( StringIndexOutOfBoundsException e )
{
- l_attrValue = "" ;
+ l_attrValue = "";
}
/*
@@ -331,55 +256,58 @@
*/
if ( l_attrName.equalsIgnoreCase( "dn" ) )
{
- l_entry.setDn( l_attrValue ) ;
+ l_entry.setDn( l_attrValue );
}
else if ( l_attrName.equalsIgnoreCase( "version" ) )
{
- l_entry.setVersion( Integer.parseInt( l_attrValue ) ) ;
+ l_entry.setVersion( Integer.parseInt( l_attrValue ) );
}
else if ( l_attrName.equalsIgnoreCase( "control" ) )
{
- ; // Not implemented
+ ; // Not implemented
}
else if ( l_attrName.equalsIgnoreCase( "changetype" ) )
{
- l_entry.setModType( l_attrValue ) ;
+ l_entry.setModType( l_attrValue );
}
else if ( l_attrName.equalsIgnoreCase( "add" ) )
{
if ( !l_entry.getModType().equalsIgnoreCase( "modify" ) )
{
- throw new ParseException( "Cannot use modification "
+ throw new EveNamingException( "Cannot use modification "
+ l_attrName + " identifier on "
+ l_entry.getModType()
- + " change type", l_lineCount ) ;
+ + " change type",
+ ResultCodeEnum.OTHER );
}
- l_currentModOp = DirContext.ADD_ATTRIBUTE ;
+ l_currentModOp = DirContext.ADD_ATTRIBUTE ;
}
else if ( l_attrName.equalsIgnoreCase( "replace" ) )
{
if ( !l_entry.getModType().equalsIgnoreCase( "modify" ) )
{
- throw new ParseException( "Cannot use modification "
+ throw new EveNamingException( "Cannot use modification "
+ l_attrName + " identifier on "
+ l_entry.getModType()
- + " change type", l_lineCount ) ;
+ + " change type",
+ ResultCodeEnum.OTHER );
}
- l_currentModOp = DirContext.REPLACE_ATTRIBUTE ;
+ l_currentModOp = DirContext.REPLACE_ATTRIBUTE;
}
else if ( l_attrName.equalsIgnoreCase( "delete" ) )
{
if ( !l_entry.getModType().equalsIgnoreCase( "modify" ) )
{
- throw new ParseException( "Cannot use modification "
+ throw new EveNamingException( "Cannot use modification "
+ l_attrName + " identifier on "
+ l_entry.getModType()
- + " change type", l_lineCount ) ;
+ + " change type",
+ ResultCodeEnum.OTHER );
}
- l_currentModOp = DirContext.REMOVE_ATTRIBUTE ;
+ l_currentModOp = DirContext.REMOVE_ATTRIBUTE;
if ( l_attrValue != null )
{
- l_prevAttrValue = l_attrValue ;
+ l_prevAttrValue = l_attrValue;
}
}
else
@@ -388,34 +316,34 @@
{
if ( l_currentModOp == -1 )
{
- throw new ParseException( "A modification type must"
+ throw new EveNamingException( "A modification type must"
+ " be supplied for a change type of modify",
- l_lineCount ) ;
+ ResultCodeEnum.OTHER );
}
l_entry.addModificationItem( l_currentModOp, l_attrName,
- l_attrValue ) ;
+ l_attrValue );
}
else
{
if ( l_isBase64Encoded && ( l_attrValue != null ) )
{
l_entry.addAttribute( l_attrName,
- base64decode( l_attrValue ) ) ;
- l_isBase64Encoded = false ;
+ base64decode( l_attrValue ) );
+ l_isBase64Encoded = false;
}
else
{
- l_entry.addAttribute( l_attrName, l_attrValue ) ;
+ l_entry.addAttribute( l_attrName, l_attrValue );
}
}
}
}
- return l_entry ;
+ return l_entry;
}
catch ( IOException e )
{
// Does not really occur: we follow form by transforming w/ rethrow
- throw new ParseException( e.getMessage(), l_lineCount ) ;
+ throw new EveNamingException( e.getMessage(), ResultCodeEnum.OTHER );
}
}
}
Added: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/PropertiesUtils.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/util/PropertiesUtils.java Sun Nov 7 15:15:56 2004
@@ -0,0 +1,608 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed 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.ldap.common.util;
+
+
+import java.util.*;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.FileInputStream;
+
+import javax.naming.directory.Attributes;
+import javax.naming.NamingException;
+
+import org.apache.ldap.common.NotImplementedException;
+import org.apache.ldap.common.ldif.LdifParserImpl;
+import org.apache.ldap.common.message.LockableAttributesImpl;
+
+
+/**
+ * A utility class used for accessing, finding, merging and macro expanding
+ * properties, on disk, via URLS or as resources.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class PropertiesUtils
+{
+ /** default properties file extension */
+ private static final String DOTPROPERTIES = ".properties";
+
+
+ // ------------------------------------------------------------------------
+ // Utilities for discovering Properties
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Loads a properties object in a properties file if it exists relative to
+ * the filename ${user.home}. If the file ${user.home}/[filename] does not
+ * exist then one last attempt to find the file is made if filename does not
+ * have a .properties extension. If so and ${user.home}/[filename].properties
+ * exists then it is loaded.
+ *
+ * @param filename the properties file name with or without an extension
+ * @return the user properties object
+ */
+ public static Properties findUserProperties( String filename )
+ {
+ return findProperties( new File( System.getProperty( "user.home" ) ), filename ) ;
+ }
+
+
+ /**
+ * Create a new properties object and load the properties file if it exists
+ * relative to [dir]/[filename] or [dir]/[filename].properties.
+ *
+ * @param dir the base directory
+ * @param filename the full fine name or the base name w/o the extension
+ * @return the loaded properties object
+ */
+ public static Properties findProperties( File dir, String filename )
+ {
+ final File asis = new File( dir, filename );
+
+ if ( asis.exists() )
+ {
+ return getProperties( asis );
+ }
+
+ if ( filename.endsWith( DOTPROPERTIES ) )
+ {
+ String noExt = filename.substring( 0, filename.length() - 11 );
+ if ( new File( dir, noExt).exists() )
+ {
+ return getProperties( new File( dir, noExt) );
+ }
+
+ return new Properties();
+ }
+
+ File withExt = new File( dir, filename + DOTPROPERTIES );
+ if ( withExt.exists() )
+ {
+ return getProperties( withExt );
+ }
+
+ return new Properties();
+ }
+
+
+ /**
+ * Load a properties from a resource relative to a supplied class. First
+ * an attempt is made to locate a property file colocated with the class
+ * with the name [class].properties. If this cannot be found or errors
+ * result an empty Properties file is returned.
+ *
+ * @param ref a class to use for relative path references
+ * @return the static properties
+ */
+ public static Properties getStaticProperties( Class ref )
+ {
+ final Properties properties = new Properties();
+ final String address = ref.toString().replace( '.','/' );
+ final String path = address + ".properties";
+ InputStream input = ref.getResourceAsStream( path );
+
+ if( null != input )
+ {
+ try
+ {
+ properties.load( input );
+ }
+ catch ( IOException e )
+ {
+ return properties;
+ }
+ }
+
+ return properties;
+ }
+
+
+ /**
+ * Load properties from a resource relative to a supplied class and path.
+ *
+ * @param ref a class to use for relative path references
+ * @param path the relative path to the resoruce
+ * @return the static properties
+ */
+ public static Properties getStaticProperties( Class ref, String path )
+ {
+ Properties properties = new Properties();
+ InputStream input = ref.getResourceAsStream( path );
+
+ if( input == null )
+ {
+ return properties;
+ }
+
+ try
+ {
+ properties.load( input );
+ }
+ catch ( IOException e )
+ {
+ return properties;
+ }
+
+ return properties;
+ }
+
+
+ /**
+ * Creates a properties object and loads the properties in the file otherwise
+ * and empty property object will be returned.
+ *
+ * @param file the properties file
+ * @return the properties object
+ */
+ public static Properties getProperties( File file )
+ {
+ Properties properties = new Properties();
+
+ if( null == file )
+ {
+ return properties;
+ }
+
+ if( file.exists() )
+ {
+ try
+ {
+ properties.load( new FileInputStream( file ) );
+ }
+ catch ( IOException e )
+ {
+ return properties;
+ }
+ }
+
+ return properties;
+ }
+
+
+ /**
+ * Loads a properties file as a CL resource if it exists and returns an
+ * empty Properties object otherwise.
+ *
+ * @param classloader the loader to use for the resources
+ * @param path the path to the resource
+ * @return the loaded or new Properties
+ */
+ public static Properties getProperties( ClassLoader classloader, String path )
+ {
+ Properties properties = new Properties();
+ InputStream input = classloader.getResourceAsStream( path );
+
+ if( input != null )
+ {
+ try
+ {
+ properties.load( input );
+ }
+ catch ( IOException e )
+ {
+ return properties;
+ }
+ }
+
+ return properties;
+ }
+
+
+ /**
+ * Loads a properties file as a class resource if it exists and returns an
+ * empty Properties object otherwise.
+ *
+ * @param clazz the class to use for resolving the resources
+ * @param path the relative path to the resource
+ * @return the loaded or new Properties
+ */
+ public static Properties getProperties( Class clazz, String path )
+ {
+ Properties properties = new Properties();
+ InputStream input = clazz.getResourceAsStream( path );
+
+ if( input != null )
+ {
+ try
+ {
+ properties.load( input );
+ }
+ catch ( IOException e )
+ {
+ return properties;
+ }
+ }
+
+ return properties;
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Utilities for operating on or setting Properties values
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Expands out a set of property key macros in the following format
+ * ${foo.bar} where foo.bar is a property key, by dereferencing the value
+ * of the key using the original source Properties and other optional
+ * Properties.
+ *
+ * If the original expanded Properties contain the value for the macro key,
+ * foo.bar, then dereferencing stops by using the value in the expanded
+ * Properties: the other optional Properties are NOT used at all.
+ *
+ * If the original expanded Properties do NOT contain the value for the
+ * macro key, then the optional Properties are used in order. The first of
+ * the optionals to contain the value for the macro key (foo.bar) shorts the
+ * search. Hence the first optional Properties in the array to contain a
+ * value for the macro key (foo.bar) is used to set the expanded value.
+ *
+ * If a macro cannot be expanded because it's key was not defined within the
+ * expanded Properties or one of the optional Properties then it is left as
+ * is.
+ *
+ * @param expanded the Properties to perform the macro expansion upon
+ * @param optionals null or an optional set of Properties to use for
+ * dereferencing macro keys (foo.bar)
+ */
+ public static void macroExpand( Properties expanded, Properties [] optionals )
+ {
+ // Handle null optionals
+ if ( null == optionals )
+ {
+ optionals = new Properties [ 0 ];
+ }
+
+ Enumeration list = expanded.propertyNames();
+ while ( list.hasMoreElements() )
+ {
+ String key = ( String ) list.nextElement();
+ String macro = expanded.getProperty( key );
+
+ int n = macro.indexOf( "${" );
+ if( n < 0 )
+ {
+ continue;
+ }
+
+ int m = macro.indexOf( "}", n+2 );
+ if( m < 0 )
+ {
+ continue;
+ }
+
+ final String symbol = macro.substring( n+2, m );
+
+ if ( expanded.containsKey( symbol ) )
+ {
+ final String value = expanded.getProperty( symbol );
+ final String head = macro.substring( 0, n );
+ final String tail = macro.substring( m+1 );
+ final String resolved = head + value + tail;
+ expanded.put( key, resolved );
+ continue;
+ }
+
+ /*
+ * Check if the macro key exists within the array of optional
+ * Properties. Set expanded value to first Properties with the
+ * key and break out of the loop.
+ */
+ for ( int ii = 0; ii < optionals.length; ii++ )
+ {
+ if ( optionals[ii].containsKey( symbol ) )
+ {
+ final String value = optionals[ii].getProperty( symbol );
+ final String head = macro.substring( 0, n );
+ final String tail = macro.substring( m+1 );
+ final String resolved = head + value + tail;
+ expanded.put( key, resolved );
+ break;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Discovers a value within a set of Properties either halting on the first
+ * time the property is discovered or continuing on to take the last value
+ * found for the property key.
+ *
+ * @param key a property key
+ * @param sources a set of source Properties
+ * @param haltOnDiscovery true if we stop on finding a value, false
+ * otherwise
+ * @return the value found or null
+ */
+ public static String discover( String key, Properties[] sources, boolean haltOnDiscovery )
+ {
+ String retval = null;
+
+ for( int ii = 0; ii < sources.length; ii++ )
+ {
+ if ( sources[ii].containsKey( key ) )
+ {
+ retval = sources[ii].getProperty( key );
+
+ if ( haltOnDiscovery )
+ {
+ break;
+ }
+ }
+ }
+
+ return retval;
+ }
+
+
+ /**
+ * Merges a set of properties from source Properties into a target
+ * properties instance containing keys. This method does not allow null
+ * overrides.
+ *
+ * @param keys the keys to discover values for
+ * @param sources the sources to search
+ * @param haltOnDiscovery true to halt on first find or false to continue
+ * to last find
+ */
+ public static void discover( Properties keys, Properties[] sources, boolean haltOnDiscovery )
+ {
+ if ( null == sources || null == keys ) { return; }
+
+ /*
+ * H A N D L E S I N G L E V A L U E D K E Y S
+ */
+ Iterator list = keys.keySet().iterator();
+ while ( list.hasNext() )
+ {
+ String key = ( String ) list.next();
+ String value = discover( key, sources, haltOnDiscovery );
+
+ if ( value != null )
+ {
+ keys.setProperty( key, value );
+ }
+ }
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Various Property Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Gets a String property as a boolean returning a defualt if the key is
+ * not present. In any case, true, on, 1 and yes strings return true and
+ * everything else returns
+ *
+ * @param props the properties to get the value from
+ * @param key the property key
+ * @param defaultValue the default value to return if key is not present
+ * @return true defaultValue if property does not exist, else return true
+ * if the String value is one of 'true', 'on', '1', 'yes', otherwise false
+ * is returned
+ */
+ public static boolean get( Properties props, String key, boolean defaultValue )
+ {
+ if ( props == null || ! props.containsKey( key ) || props.getProperty( key ) == null )
+ {
+ return defaultValue;
+ }
+
+ String val = props.getProperty( key ).trim().toLowerCase();
+ return val.equals( "true" ) || val.equals( "on" ) || val.equals( "1" ) || val.equals( "yes" );
+ }
+
+
+ public static int get( Properties props, String key, int defaultValue )
+ {
+ if ( props == null || ! props.containsKey( key ) || props.getProperty( key ) == null )
+ {
+ return defaultValue;
+ }
+
+ throw new NotImplementedException();
+ }
+
+
+ public static long get( Properties props, String key, long defaultValue )
+ {
+ if ( props == null || ! props.containsKey( key ) || props.getProperty( key ) == null )
+ {
+ return defaultValue;
+ }
+
+ throw new NotImplementedException();
+ }
+
+
+ public static byte get( Properties props, String key, byte defaultValue )
+ {
+ if ( props == null || ! props.containsKey( key ) || props.getProperty( key ) == null )
+ {
+ return defaultValue;
+ }
+
+ throw new NotImplementedException();
+ }
+
+
+ public static char get( Properties props, String key, char defaultValue )
+ {
+ if ( props == null || ! props.containsKey( key ) || props.getProperty( key ) == null )
+ {
+ return defaultValue;
+ }
+
+ throw new NotImplementedException();
+ }
+
+
+ /**
+ * Fills a set with the space delimited values of a property. If values is
+ * null a new Set is created and returned.
+ *
+ * @param props the properties to get the property values from
+ * @param key the key of the multivalued property
+ * @param values the values to populate
+ * @return the values set so it can be filled then used
+ */
+ public static Set fill( Properties props, String key, Set values )
+ {
+ if ( values == null ) { values = new HashSet(); }
+ return ( Set ) fillCollection( props, key, values, " " );
+ }
+
+
+ /**
+ * Fills a set with the delimited values of a property. If values is
+ * null a new Set is created and returned.
+ *
+ * @param props the properties to get the property values from
+ * @param key the key of the multivalued property
+ * @param values the values to populate
+ * @param delimiter the delimiter string to split the property with
+ * @return the values set so it can be filled then used
+ */
+ public static Set fill( Properties props, String key, Set values, String delimiter )
+ {
+ if ( values == null ) { values = new HashSet(); }
+ return ( Set ) fillCollection( props, key, values, delimiter );
+ }
+
+
+ /**
+ * Fills a list with the space delimited values of a property. The list
+ * maintains the order of values in the multivalued property. If values is
+ * null a new List is created and returned.
+ *
+ * @param props the properties to get the property values from
+ * @param key the key of the multivalued property
+ * @param values the values to populate
+ * @return the values list so it can be filled then used
+ */
+ public static List fill( Properties props, String key, List values )
+ {
+ if ( values == null ) { values = new ArrayList(); }
+ return ( List ) fillCollection( props, key, values, " " );
+ }
+
+
+ /**
+ * Fills a list with the space delimited values of a property. The list
+ * maintains the order of values in the multivalued property. If values is
+ * null a new List is created and returned.
+ *
+ * @param props the properties to get the property values from
+ * @param key the key of the multivalued property
+ * @param values the values to populate
+ * @param delimiter the delimiter string to split the property with
+ * @return the values list so it can be filled then used
+ */
+ public static List fill( Properties props, String key, List values, String delimiter )
+ {
+ if ( values == null ) { values = new ArrayList(); }
+ return ( List ) fillCollection( props, key, values, delimiter );
+ }
+
+
+ /**
+ * Fills a collection with the delimited values of a property.
+ *
+ * @param props the properties to get the property values from
+ * @param key the key of the multivalued property
+ * @param values the values to populate
+ * @param delimiter the delimiter string to split the property with
+ * @return the values collection so it can be filled then used
+ */
+ public static Collection fillCollection( Properties props, String key, Collection values, String delimiter )
+ {
+ if ( props == null || ! props.containsKey( key ) || props.getProperty( key ) == null )
+ {
+ return values;
+ }
+
+ String[] items = props.getProperty( key ).trim().split( delimiter );
+ for ( int ii = 0; ii < items.length; ii++ )
+ {
+ values.add( items[ii] );
+ }
+
+ return values;
+ }
+
+
+ /**
+ * Creates, fills and returns an Attributes instance using the LDIF encoded
+ * within the property value. The LDIF should use '*' (asterisk) characters
+ * as line delimiters within the property value. These are replaced with
+ * newlines and fed to the LDIF parser. Also note that the LdifParser
+ * deposites the DN as a property within the attributes object.
+ *
+ * @param props the properties to get the ldif property from
+ * @param key the key for the LDIF property
+ * @return the attributes for the encoded LDIF entry
+ */
+ public static Attributes fillAttributes( Properties props, String key, Attributes values ) throws NamingException
+ {
+ if ( props == null || ! props.containsKey( key ) || props.getProperty( key ) == null )
+ {
+ if ( values == null )
+ {
+ return new LockableAttributesImpl();
+ }
+
+ return values;
+ }
+
+ if ( values == null )
+ {
+ values = new LockableAttributesImpl();
+ }
+
+ String ldif = props.getProperty( key ).trim().replace( '*', '\n' );
+ ( new LdifParserImpl() ).parse( values, ldif );
+ return values;
+ }
+}