blob: 5e308f5d07bfbc9043aa283986416238d8f1e749 [file] [log] [blame]
package jpos.config.simple;
///////////////////////////////////////////////////////////////////////////////
//
// This software is provided "AS IS". The JavaPOS working group (including
// each of the Corporate members, contributors and individuals) MAKES NO
// REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NON-INFRINGEMENT. The JavaPOS working group shall not be liable for
// any damages suffered as a result of using, modifying or distributing this
// software or its derivatives. Permission to use, copy, modify, and distribute
// the software and its documentation for any purpose is hereby granted.
//
// The JavaPOS Config/Loader (aka JCL) is now under the CPL license, which
// is an OSS Apache-like license. The complete license is located at:
// http://oss.software.ibm.com/developerworks/opensource/license-cpl.html
//
///////////////////////////////////////////////////////////////////////////////
import jpos.config.JposEntry;
import java.util.*;
import java.io.Serializable;
import jpos.config.*;
import jpos.util.JposEntryUtility;
/**
* This is a simple implementation of the JposEntry interface using a Hashtable
* to collect the properties
* @since 0.1 (Philly 99 meeting)
* @author E. Michael Maximilien (maxim@us.ibm.com)
*/
public class SimpleEntry implements JposEntry, Serializable, Comparable
{
//--------------------------------------------------------------------------
// Ctor(s)
//
/**
* Default ctor (sets the JposRegPopulator to null)
* @since 1.3 (Washington DC 2001 meeting)
*/
public SimpleEntry() { regPopulator = null; }
/**
* One argument ctor taking the JposRegPopulator for this entry
* @param populator the JposRegPopulator for this entry
* @since 1.3 (Washington DC 2001 meeting)
*/
public SimpleEntry( JposRegPopulator populator ) { regPopulator = populator; }
/**
* One argument ctor taking the JposRegPopulator for this entry
* @param logicalName the logical name for this entry
* @param populator the JposRegPopulator for this entry
* @since 1.3 (Washington DC 2001 meeting)
*/
public SimpleEntry( String logicalName, JposRegPopulator populator )
{
this( populator );
addProperty( LOGICAL_NAME_PROP_NAME, logicalName );
}
/**
* One argument ctor taking the LogicalName this entry
* @param logicalName the logical name string for this entry
* @since 2.0.0
*/
SimpleEntry( String logicalName ) { addProperty( LOGICAL_NAME_PROP_NAME, logicalName ); }
//--------------------------------------------------------------------------
// Public instance methods
//
/**
* @return count of number of properties
* @since 0.1 (Philly 99 meeting)
*/
public int getPropertyCount() { return properties.size(); }
/**
* @return an enumerator for the properties names
* @since 0.1 (Philly 99 meeting)
*/
public Enumeration getPropertyNames() { return properties.keys(); }
/**
* @return true if there is a property by the name specified
* @param propName the property name String
* @since 0.1 (Philly 99 meeting)
*/
public boolean hasPropertyWithName( String propName ) { return properties.containsKey( propName ); }
/**
* @return true if there is a property by the value specified
* NOTE: Object.equals method will be used to compare
* @param propValue the property's value Object
* @since 0.1 (Philly 99 meeting)
*/
public boolean hasPropertyWithValue( Object propValue ) { return properties.contains( propValue ); }
/**
* @return the property's value Object
* @param propName the property's propName String
* @since 0.1 (Philly 99 meeting)
*/
public Object getPropertyValue( String propName ) { return properties.get( propName ); }
/**
* @return the property's type
* @param propName the property's name String
* @since 2.0.0
*/
public Class getPropertyType( String propName ) { return getPropertyValue( propName ).getClass(); }
/**
* Modifies the property value of the property passed
* @return the oldPropValue or null if this property does not exist
* @param propName the property name
* @param propValue the new property value
* @since 1.3 (Tokyo 2001 meeting)
* @throws java.lang.IllegalArgumentException if the propName or propValue is null
*/
public Object modifyPropertyValue( String propName, Object propValue ) throws IllegalArgumentException
{
checkNull( propName );
checkNull( propValue );
if( hasPropertyWithName( propName ) == false )
return null;
Object oldValue = removeProperty( propName );
addProperty( propName, propValue );
return oldValue;
}
/**
* Adds a property to the JposEntry object.
* NOTE: any property with the same name gets overlaid
* @param propName the name of this property (should be unique per property)
* @param propValue the properties value Object
* @since 0.1 (Philly 99 meeting)
* @throws java.lang.IllegalArgumentException if the propName or propValue is null
*/
public Object addProperty( String propName, Object propValue ) throws IllegalArgumentException
{
checkNull( propName );
checkNull( propValue );
return properties.put( propName, propValue );
}
/**
* Looks for a property with name specified and removes it. If none exist then
* does nothing and return null
* @return the value for the name passed
* @param propName the name String of the property to remove
* @since 0.1 (Philly 99 meeting)
*/
public Object removeProperty( String propName ) { return properties.remove( propName ); }
/**
* @return true if the two JposEntries have the same properties
* @since 0.1 (Philly 99 meeting)
*/
public boolean equals( JposEntry otherEntry )
{
if( otherEntry == null ) return false;
if( getPropertyCount() != otherEntry.getPropertyCount() ) return false;
Enumeration otherPropNames = otherEntry.getPropertyNames();
while( otherPropNames.hasMoreElements() )
{
String name = (String)otherPropNames.nextElement();
Object value = otherEntry.getPropertyValue( name );
if( !hasPropertyWithName( name ) ) return false;
if( !getPropertyValue( name ).equals( value ) ) return false;
}
return true;
}
/**
* @return a copy of this JposEntry object
* @since 1.3 (Tokyo 2001 meeting)
*/
public JposEntry copy()
{
JposEntry entryCopy = new SimpleEntry();
Enumeration entryNames = getPropertyNames();
while( entryNames.hasMoreElements() )
{
String propName = (String)entryNames.nextElement();
entryCopy.addProperty( propName,getPropertyValue( propName ) );
}
return entryCopy;
}
/**
* @return the JposRegPopulator that loads/saves this entry. If null the default
* populator is used
* @since 1.3 (Washington DC 2001 meeting)
*/
public JposRegPopulator getRegPopulator() { return regPopulator; }
/**
* @return the logical name for this JposEntry. This is a shortcut for easily getting
* the logical name vs getting a property and passing the logical name constant
* @see jpos.config.JposEntry#getPropertyValue
* @see jpos.config.JposEntry#LOGICAL_NAME_PROP_NAME
* @since 1.3 (Washington DC 2001 meeting)
*/
public String getLogicalName() { return (String)getPropertyValue( JposEntry.LOGICAL_NAME_PROP_NAME ); }
/**
* @return the JposEntry.Prop with name specified or null if no such property exist
* @param propName the property name
* @since 2.0.0
*/
public JposEntry.Prop getProp( String propName )
{
Object propValue = getPropertyValue( propName );
if( propValue == null ) return null;
return new Prop( propName, propValue );
}
/**
* @return an Iterator over the properties in this JposEntry as JposEntry.Prop objects
* @since 1.3 (Washington DC 2001)
*/
public Iterator getProps()
{
List list = new ArrayList();
Enumeration names = getPropertyNames();
while( names.hasMoreElements() )
{
String name = (String)names.nextElement();
list.add( new Prop( name, getPropertyValue( name ) ) );
}
return list.iterator();
}
/**
* Adds a new property
* @param prop the JposEntry.Prop to add
* @since 1.3 (Washington DC 2001 meeting)
* @throws java.lang.IllegalArgumentException if the argument is null
*/
public void add( JposEntry.Prop prop ) throws IllegalArgumentException
{
checkNull( prop );
addProperty( prop.getName(), prop.getValue() );
}
/**
* Removes the property
* @param prop the JposEntry.Prop to remove
* @since 1.3 (Washington DC 2001 meeting)
*/
public void remove( JposEntry.Prop prop ) { removeProperty( prop.getName() ); }
/**
* Modifies the property with name of property passed with the new value if
* that property currently exist in the entry otherwise does nothing
* @param prop the JposEntry.Prop to modify
* @since 2.0.0
* @throws java.lang.IllegalArgumentException if the prop is null
*/
public void modify( JposEntry.Prop prop ) throws IllegalArgumentException
{
checkNull( prop );
if( hasPropertyWithName( prop.getName() ) == false ) return;
modifyPropertyValue( prop.getName(), prop.getValue() );
}
/**
* @return true if this entry has the property passed
* @param prop the JposEntry.Prop to check for
* @since 1.3 (Washington DC 2001 meeting)
*/
public boolean hasProp( JposEntry.Prop prop ) { return hasPropertyWithName( prop.getName() ); }
/**
* @return a JposEntry.Prop object created with the <name, value, type> tripplet
* passed as arguments
* @param propName the property name
* @param propValue the property value
* @param propType the property type (valid for this value)
* @throws jpos.config.JposConfigException if any of the argument is null or the
* property value and type mismatch or this is not a valid property type
* @see jpos.config.JposEntryConst#PROP_TYPES
* @since 2.0.0
*/
public JposEntry.Prop createProp( String propName, Object propValue, Class propType ) throws JposConfigException
{
if( propName == null || propValue == null || propType == null )
throw new JposConfigException( "Cannot create JposEntry.Prop with null argument" );
if( JposEntryUtility.validatePropValue( propValue, propType ) == false )
throw new JposConfigException( "Cannot create JposEntry.Prop with invalid value or type" );
return new Prop( propName, propValue );
}
//--------------------------------------------------------------------------
// Public overidden methods
//
/**
* @return true if the two JposEntries have the same properties
* @since 1.3 (SF 2K meeting)
*/
public boolean equals( Object object )
{
if( object instanceof JposEntry )
return equals( (JposEntry)object );
return false;
}
/**
* @return 0 if two entries are the same -1 if this is less or 1 of more than other
* the comparison for > and < uses the logicalName of the entry to decide
* @param otherEntry the other JposEntry
*/
public int compareTo( Object other )
{
if( other == null || ( (other instanceof JposEntry ) == false ) )
throw new RuntimeException( "Cannot compare: " + other + " with JposEntry: " + this );
JposEntry otherEntry = (JposEntry)other;
if( equals( otherEntry ) ) return 0;
return getLogicalName().compareTo( otherEntry.getLogicalName() );
}
/**
* @return a String representation of this entry
* @since 1.3 (SF 2K meeting)
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append( "<JposEntry logicalName=\"" + getPropertyValue( JposEntry.LOGICAL_NAME_PROP_NAME ) + "\">\n" );
sb.append( "\t<creation factoryClass=\"" + getPropertyValue( JposEntry.SI_FACTORY_CLASS_PROP_NAME ) + "\" serviceClass=\"" + getPropertyValue( JposEntry.SERVICE_CLASS_PROP_NAME ) + "\"/>\n" );
sb.append( "\t<vendor name=\"" + getPropertyValue( JposEntry.VENDOR_NAME_PROP_NAME ) + "\" url=" + getPropertyValue( JposEntry.VENDOR_URL_PROP_NAME ) + "\"/>\n" );
sb.append( "\t<jpos category=\"" + getPropertyValue( JposEntry.DEVICE_CATEGORY_PROP_NAME ) + "\" version=\"" + getPropertyValue( JposEntry.JPOS_VERSION_PROP_NAME ) + "\"/>\n" );
sb.append( "\t<product description=\"" + getPropertyValue( JposEntry.PRODUCT_DESCRIPTION_PROP_NAME ) + "\" name=\"" + getPropertyValue( JposEntry.PRODUCT_NAME_PROP_NAME ) + "\" url=\"" + getPropertyValue( JposEntry.PRODUCT_URL_PROP_NAME ) + "\"/>\n" );
sb.append( "\n" );
Enumeration otherPropNames = JposEntryUtility.getNonRequiredPropNames( this );
while( otherPropNames.hasMoreElements() )
{
String name = (String)otherPropNames.nextElement();
String value = getPropertyValue( name ).toString();
String typeClassName = JposEntryUtility.shortClassName( value.getClass() );
sb.append( "\t<prop name=\"" + name + "\" value=\"" + value +
"\" type=\"" + typeClassName +"\"/>\n" );
}
sb.append( "</JposEntry>\n" );
return sb.toString();
}
//--------------------------------------------------------------------------
// Package methods
//
/**
* Sets the JposRegPopulator that loads/saves this entry. If null the default
* populator is used
* @since 1.3 (Washington DC 2001 meeting)
*/
void setRegPopulator( JposRegPopulator populator ) { regPopulator = populator; }
//---------------------------------------------------------------------
// Class methods
//
/**
* Checks that the Object argument is not null and if it is throw a IllegalArgumentException
* @param object the Object argument
* @throws java.lang.IllegalArgumentException if the object is null
*/
protected static void checkNull( Object object ) throws IllegalArgumentException
{
if( object == null )
throw new IllegalArgumentException( "Invalid null argument passed for a JposEntry property value or name" );
}
//--------------------------------------------------------------------------
// Instance variables
//
private Hashtable properties = new Hashtable();
private transient JposRegPopulator regPopulator = null;
//-------------------------------------------------------------------------
// Inner classes
//
/**
* Inner class to represent a property of a JposEntry
* @author E. Michael Maximilien
* @since 1.3 (Washington DC 2001)
*/
public static class Prop implements JposEntry.Prop, Comparable
{
//---------------------------------------------------------------------
// Ctor(s)
//
/**
* Creates a JposEntry.Prop object
* @param name the name of this property
* @param value the value of this property
* @throws java.lang.IllegalArgumentException if any of the arguments are null
*/
public Prop( String name, Object value ) throws IllegalArgumentException
{
checkNull( name );
checkNull( value );
this.name = name;
this.value = value;
this.typeClass = value.getClass();
}
//---------------------------------------------------------------------
// Public methods
//
/** @return the name of this property */
public String getName() { return name; }
/** @return the value of this property (the value is returned as an Object) */
public Object getValue() { return value; }
/** @return the value of this property as a String */
public String getValueAsString() { return String.valueOf( value ); }
/**
* Returns the Class object that is the type of this property value
* possible values returned are the java.lang wrapper classes for the
* primitive types e.g. Integer, Byte, Boolean, ...
* @return the type of this property as a java.lang.Class object
*/
public Class getType() { return typeClass; }
/**
* Sets the name of this property
* @param s the String object
* @throws java.lang.IllegalArgumentException if the argument is null
*/
public void setName( String s ) throws IllegalArgumentException
{
checkNull( s );
name = s;
}
/**
* Sets the value of this property (String). Also sets its Type.
* <p><b>This is the default type of any property</b></p>
* @param objValue the object's value
* @throws java.lang.IllegalArgumentException if the value is null or
* that this is not a valid typed property value
*/
public void setValue( Object objValue ) throws IllegalArgumentException
{
checkNull( objValue );
if( JposEntryUtility.validatePropValue( objValue, objValue.getClass() ) == false )
throw new IllegalArgumentException( "Cannot set property named = " + getName() +
" with value = " + objValue +
" invalid value or type" );
setValue( objValue, objValue.getClass() );
}
/**
* @return true if the property is of the type specified by the Class
* object passed
* @param type the Class object
*/
public boolean isOfType( Class type )
{
if( type == null || typeClass == null ) return false;
return typeClass.equals( type );
}
/** @return a new copy of this JposEntry.Prop object */
public JposEntry.Prop copy() { return new SimpleEntry.Prop( getName(), getValue() ); }
//---------------------------------------------------------------------
// Public overridden
//
/**
* @return true if this and otherProp have same name and value
* @param otherProp the other JposEntry.Prop
*/
public boolean equals( Object otherProp )
{
if( otherProp == null ) return false;
if( !( otherProp instanceof JposEntry.Prop ) ) return false;
JposEntry.Prop prop = (JposEntry.Prop)otherProp;
return ( getName().equals( prop.getName() ) ) &&
( getValue().equals( prop.getValue() ) );
}
/**
* @return 0 if two entries are the same -1 if this is less or 1 of more than other
* the comparison for > and < uses the logicalName of the entry to decide
* @param otherEntry the other JposEntry
*/
public int compareTo( Object other )
{
if( other == null || ( (other instanceof JposEntry.Prop ) == false ) )
throw new RuntimeException( "Cannot compare: " + other + " with JposEntry.Prop: " + this );
JposEntry.Prop otherEntryProp = (JposEntry.Prop)other;
if( equals( otherEntryProp ) ) return 0;
return getName().compareTo( otherEntryProp.getName() );
}
/** @return a unique key for this object */
public int hashCode() { return getName().hashCode(); }
//---------------------------------------------------------------------
// Private methods
//
/**
* Sets the value of this property as an Object that must match the
* the type specified. Also sets its Type.
* @param object the Object value (must be one of wrapper for primitive types
* or java.lang.String)
* @param type the java.lang.Class object matching the object type
* @throws java.lang.IllegalArgumentException if the object value type does not
* match the Class type
*/
private void setValue( Object object, Class type ) throws IllegalArgumentException
{
checkNull( object );
checkNull( type );
if( !object.getClass().equals( type ) )
throw new IllegalArgumentException( "Value and value type not in agreement for property named = " + name );
value = object;
typeClass = type;
}
//---------------------------------------------------------------------
// Instance variables
//
private String name = "";
private Object value = null;
private Class typeClass = null;
}
//--------------------------------------------------------------------------
// Public constants
//
/**
* serialVersionUID constant to maintain serialization compatibility between releases
* @since 1.3 (SF 2K meeting)
*/
public static final long serialVersionUID = 6937048853319310114L;
}