blob: d84523b0fd95d6f439fdac69920328ab3c484a15 [file] [log] [blame]
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.corba.se.spi.orb ;
import java.util.StringTokenizer ;
import java.util.Arrays ;
import java.lang.reflect.Array ;
import java.net.URL ;
import java.net.MalformedURLException ;
import com.sun.corba.se.spi.logging.CORBALogDomains ;
import com.sun.corba.se.impl.logging.ORBUtilSystemException ;
import com.sun.corba.se.impl.orbutil.ObjectUtility ;
import sun.corba.SharedSecrets;
/** This is a static factory class for commonly used operations
* for property parsing. The following operations are supported:
* <ul>
* <li>maskErrorAction( Operation op ) executes op and returns the result. If op throws an
* exception, the result is null.
* <li>indexAction( int arg ) returns the [arg] element of value, which must be an Object[]</li>
* <li>identityAction() return the value</li>
* <li>booleanAction() return a Boolean representing true or false values of the String value</li>
* <li>integerAction() returns an Integer for the String value, which must be a decimal integer</li>
* <li>stringAction() returns the String value</li>
* <li>classAction() returns a class for the String value, as loaded by the ORB classloader</li>
* <li>setFlagAction() always return Boolean.TRUE</li>
* <li>URLAction() returns a java.net.URL for the String value, which must be a valid URL</li>
* <li>integerRangeAction( int min, int max ) returns an Integer for the String value, which must be a
* decimal integer in the range min to max inclusive</li>
* <li>listAction( String sep, Operation ) tokenizes the String value with sep as separator, then
* applies the Operation to each token, and returns an array of the result</li>
* <li>sequenceAction( String, Operation[] ) tokenizes the String value with sep as separator, then
* applies each Operation in the Operation array to successive tokens, and returns an array of the results</li>
* <li>compose( Operation op1, Operation op2 ) is the operation that applies op2 to the result of applying
* op1 to the value</li>
* <li>mapAction( Operation ) applies the Operation to each element of an array of objects, and returns
* an array of the results</li>
* <li>mapSequenceAction( Operation[] ) applies the corresponding element of the Operation array to an
* element of the Object[] value, and returns an array of the results</li>
* <li>convertIntegerToShort coerces an Integer into a Short.</li>
* </ul>
* Other operations can be directly defined, and combined using these basic operations.
*/
public abstract class OperationFactory {
private OperationFactory() {}
private static String getString( Object obj )
{
if (obj instanceof String)
return (String)obj ;
else
throw new Error( "String expected" ) ;
}
private static Object[] getObjectArray( Object obj )
{
if (obj instanceof Object[])
return (Object[])obj ;
else
throw new Error( "Object[] expected" ) ;
}
private static StringPair getStringPair( Object obj )
{
if (obj instanceof StringPair)
return (StringPair)obj ;
else
throw new Error( "StringPair expected" ) ;
}
private static abstract class OperationBase implements Operation{
public boolean equals( Object obj )
{
if (this==obj)
return true ;
if (!(obj instanceof OperationBase))
return false ;
OperationBase other = (OperationBase)obj ;
return toString().equals( other.toString() ) ;
}
public int hashCode()
{
return toString().hashCode() ;
}
}
private static class MaskErrorAction extends OperationBase
{
private Operation op ;
public MaskErrorAction( Operation op )
{
this.op = op ;
}
public Object operate( Object arg )
{
try {
return op.operate( arg ) ;
} catch (java.lang.Exception exc) {
return null ;
}
}
public String toString()
{
return "maskErrorAction(" + op + ")" ;
}
}
public static Operation maskErrorAction( Operation op )
{
return new MaskErrorAction( op ) ;
}
private static class IndexAction extends OperationBase
{
private int index ;
public IndexAction( int index )
{
this.index = index ;
}
public Object operate( Object value )
{
return getObjectArray( value )[ index ] ;
}
public String toString()
{
return "indexAction(" + index + ")" ;
}
}
public static Operation indexAction( int index )
{
return new IndexAction( index ) ;
}
private static class SuffixAction extends OperationBase
{
public Object operate( Object value )
{
return getStringPair( value ).getFirst() ;
}
public String toString() { return "suffixAction" ; }
}
private static Operation suffixActionImpl = new SuffixAction() ;
private static class ValueAction extends OperationBase
{
public Object operate( Object value )
{
return getStringPair( value ).getSecond() ;
}
public String toString() { return "valueAction" ; }
}
private static Operation valueActionImpl = new ValueAction() ;
private static class IdentityAction extends OperationBase
{
public Object operate( Object value )
{
return value ;
}
public String toString() { return "identityAction" ; }
}
private static Operation identityActionImpl = new IdentityAction() ;
private static class BooleanAction extends OperationBase
{
public Object operate( Object value )
{
return new Boolean( getString( value ) ) ;
}
public String toString() { return "booleanAction" ; }
}
private static Operation booleanActionImpl = new BooleanAction() ;
private static class IntegerAction extends OperationBase
{
public Object operate( Object value )
{
return new Integer( getString( value ) ) ;
}
public String toString() { return "integerAction" ; }
}
private static Operation integerActionImpl = new IntegerAction() ;
private static class StringAction extends OperationBase
{
public Object operate( Object value )
{
return value ;
}
public String toString() { return "stringAction" ; }
}
private static Operation stringActionImpl = new StringAction() ;
private static class ClassAction extends OperationBase
{
public Object operate( Object value )
{
String className = getString( value ) ;
try {
Class<?> result =
SharedSecrets.getJavaCorbaAccess().loadClass( className ) ;
return result ;
} catch (Exception exc) {
ORBUtilSystemException wrapper = ORBUtilSystemException.get(
CORBALogDomains.ORB_LIFECYCLE ) ;
throw wrapper.couldNotLoadClass( exc, className ) ;
}
}
public String toString() { return "classAction" ; }
}
private static Operation classActionImpl = new ClassAction() ;
private static class SetFlagAction extends OperationBase
{
public Object operate( Object value )
{
return Boolean.TRUE ;
}
public String toString() { return "setFlagAction" ; }
}
private static Operation setFlagActionImpl = new SetFlagAction() ;
private static class URLAction extends OperationBase
{
public Object operate( Object value )
{
String val = (String)value ;
try {
return new URL( val ) ;
} catch (MalformedURLException exc) {
ORBUtilSystemException wrapper = ORBUtilSystemException.get(
CORBALogDomains.ORB_LIFECYCLE ) ;
throw wrapper.badUrl( exc, val ) ;
}
}
public String toString() { return "URLAction" ; }
}
private static Operation URLActionImpl = new URLAction() ;
public static Operation identityAction()
{
return identityActionImpl ;
}
public static Operation suffixAction()
{
return suffixActionImpl ;
}
public static Operation valueAction()
{
return valueActionImpl ;
}
public static Operation booleanAction()
{
return booleanActionImpl ;
}
public static Operation integerAction()
{
return integerActionImpl ;
}
public static Operation stringAction()
{
return stringActionImpl ;
}
public static Operation classAction()
{
return classActionImpl ;
}
public static Operation setFlagAction()
{
return setFlagActionImpl ;
}
public static Operation URLAction()
{
return URLActionImpl ;
}
private static class IntegerRangeAction extends OperationBase
{
private int min ;
private int max ;
IntegerRangeAction( int min, int max )
{
this.min = min ;
this.max = max ;
}
public Object operate( Object value )
{
int result = Integer.parseInt( getString( value ) ) ;
if ((result >= min) && (result <= max))
return new Integer( result ) ;
else
throw new IllegalArgumentException(
"Property value " + result + " is not in the range " +
min + " to " + max ) ;
}
public String toString() {
return "integerRangeAction(" + min + "," + max + ")" ;
}
}
public static Operation integerRangeAction( int min, int max )
{
return new IntegerRangeAction( min, max ) ;
}
private static class ListAction extends OperationBase {
private String sep ;
private Operation act ;
ListAction( String sep, Operation act )
{
this.sep = sep ;
this.act = act ;
}
// Note that this method carefully constructs an array of the type
// of the first result, rather than just using Object[], which is
// not convertible into the correct type. Also note that no tokens
// results in a null result.
public Object operate( Object value )
{
StringTokenizer st = new StringTokenizer( getString( value ),
sep ) ;
int length = st.countTokens() ;
Object result = null ;
int ctr = 0 ;
while (st.hasMoreTokens()) {
String next = st.nextToken() ;
Object val = act.operate( next ) ;
if (result == null)
result = Array.newInstance( val.getClass(), length ) ;
Array.set( result, ctr++, val ) ;
}
return result ;
}
public String toString() {
return "listAction(separator=\"" + sep +
"\",action=" + act + ")" ;
}
}
public static Operation listAction( String sep, Operation act )
{
return new ListAction( sep, act ) ;
}
private static class SequenceAction extends OperationBase
{
private String sep ;
private Operation[] actions ;
SequenceAction( String sep, Operation[] actions )
{
this.sep = sep ;
this.actions = actions ;
}
public Object operate( Object value )
{
StringTokenizer st = new StringTokenizer( getString( value ),
sep ) ;
int numTokens = st.countTokens() ;
if (numTokens != actions.length)
throw new Error(
"Number of tokens and number of actions do not match" ) ;
int ctr = 0 ;
Object[] result = new Object[ numTokens ] ;
while (st.hasMoreTokens()) {
Operation act = actions[ctr] ;
String next = st.nextToken() ;
result[ctr++] = act.operate( next ) ;
}
return result ;
}
public String toString() {
return "sequenceAction(separator=\"" + sep +
"\",actions=" +
Arrays.toString(actions) + ")" ;
}
}
public static Operation sequenceAction( String sep,
Operation[] actions )
{
return new SequenceAction( sep, actions ) ;
}
private static class ComposeAction extends OperationBase
{
private Operation op1 ;
private Operation op2 ;
ComposeAction( Operation op1, Operation op2 )
{
this.op1 = op1 ;
this.op2 = op2 ;
}
public Object operate( Object value )
{
return op2.operate( op1.operate( value ) ) ;
}
public String toString() {
return "composition(" + op1 + "," + op2 + ")" ;
}
}
public static Operation compose( Operation op1, Operation op2 )
{
return new ComposeAction( op1, op2 ) ;
}
private static class MapAction extends OperationBase
{
Operation op ;
MapAction( Operation op )
{
this.op = op ;
}
public Object operate( Object value )
{
Object[] values = (Object[])value ;
Object[] result = new Object[ values.length ] ;
for (int ctr=0; ctr<values.length; ctr++ )
result[ctr] = op.operate( values[ctr] ) ;
return result ;
}
public String toString() {
return "mapAction(" + op + ")" ;
}
}
public static Operation mapAction( Operation op )
{
return new MapAction( op ) ;
}
private static class MapSequenceAction extends OperationBase
{
private Operation[] op ;
public MapSequenceAction( Operation[] op )
{
this.op = op ;
}
// XXX Does this correctly handle array types? It seems
// that hetereogeneous arrays work this way, while
// homogeneous arrays need to use Array.newInstance tricks.
public Object operate( Object value )
{
Object[] values = (Object[])value ;
Object[] result = new Object[ values.length ] ;
for (int ctr=0; ctr<values.length; ctr++ )
result[ctr] = op[ctr].operate( values[ctr] ) ;
return result ;
}
public String toString() {
return "mapSequenceAction(" +
Arrays.toString(op) + ")" ;
}
}
public static Operation mapSequenceAction( Operation[] op )
{
return new MapSequenceAction( op ) ;
}
private static class ConvertIntegerToShort extends OperationBase
{
public Object operate( Object value )
{
Integer val = (Integer)value ;
return new Short( val.shortValue() ) ;
}
public String toString() {
return "ConvertIntegerToShort" ;
}
}
private static Operation convertIntegerToShortImpl = new ConvertIntegerToShort() ;
public static Operation convertIntegerToShort()
{
return convertIntegerToShortImpl ;
}
}