1 /*
   2  * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.corba.se.spi.orb ;
  26 
  27 import java.util.StringTokenizer ;
  28 import java.util.Arrays ;
  29 
  30 import java.lang.reflect.Array ;
  31 
  32 import java.net.URL ;
  33 import java.net.MalformedURLException ;
  34 
  35 import com.sun.corba.se.spi.logging.CORBALogDomains ;
  36 
  37 import com.sun.corba.se.impl.logging.ORBUtilSystemException ;
  38 import com.sun.corba.se.impl.orbutil.ObjectUtility ;
  39 
  40 import sun.corba.SharedSecrets;
  41 
  42 /** This is a static factory class for commonly used operations
  43 * for property parsing.  The following operations are supported:
  44 * <ul>
  45 * <li>maskErrorAction( Operation op ) executes op and returns the result.  If op throws an
  46 * exception, the result is null.
  47 * <li>indexAction( int arg ) returns the [arg] element of value, which must be an Object[]</li>
  48 * <li>identityAction() return the value</li>
  49 * <li>booleanAction() return a Boolean representing true or false values of the String value</li>
  50 * <li>integerAction() returns an Integer for the String value, which must be a decimal integer</li>
  51 * <li>stringAction() returns the String value</li>
  52 * <li>classAction() returns a class for the String value, as loaded by the ORB classloader</li>
  53 * <li>setFlagAction() always return Boolean.TRUE</li>
  54 * <li>URLAction() returns a java.net.URL for the String value, which must be a valid URL</li>
  55 * <li>integerRangeAction( int min, int max ) returns an Integer for the String value, which must be a
  56 * decimal integer in the range min to max inclusive</li>
  57 * <li>listAction( String sep, Operation ) tokenizes the String value with sep as separator, then
  58 * applies the Operation to each token, and returns an array of the result</li>
  59 * <li>sequenceAction( String, Operation[] ) tokenizes the String value with sep as separator, then
  60 * applies each Operation in the Operation array to successive tokens, and returns an array of the results</li>
  61 * <li>compose( Operation op1, Operation op2 ) is the operation that applies op2 to the result of applying
  62 * op1 to the value</li>
  63 * <li>mapAction( Operation ) applies the Operation to each element of an array of objects, and returns
  64 * an array of the results</li>
  65 * <li>mapSequenceAction( Operation[] ) applies the corresponding element of the Operation array to an
  66 * element of the Object[] value, and returns an array of the results</li>
  67 * <li>convertIntegerToShort coerces an Integer into a Short.</li>
  68 * </ul>
  69 * Other operations can be directly defined, and combined using these basic operations.
  70 */
  71 public abstract class OperationFactory {
  72     private OperationFactory() {}
  73 
  74     private static String getString( Object obj )
  75     {
  76         if (obj instanceof String)
  77             return (String)obj ;
  78         else
  79             throw new Error( "String expected" ) ;
  80     }
  81 
  82     private static Object[] getObjectArray( Object obj )
  83     {
  84         if (obj instanceof Object[])
  85             return (Object[])obj ;
  86         else
  87             throw new Error( "Object[] expected" ) ;
  88     }
  89 
  90     private static StringPair getStringPair( Object obj )
  91     {
  92         if (obj instanceof StringPair)
  93             return (StringPair)obj ;
  94         else
  95             throw new Error( "StringPair expected" ) ;
  96     }
  97 
  98     private static abstract class OperationBase implements Operation{
  99         public boolean equals( Object obj )
 100         {
 101             if (this==obj)
 102                 return true ;
 103 
 104             if (!(obj instanceof OperationBase))
 105                 return false ;
 106 
 107             OperationBase other = (OperationBase)obj ;
 108 
 109             return toString().equals( other.toString() ) ;
 110         }
 111 
 112         public int hashCode()
 113         {
 114             return toString().hashCode() ;
 115         }
 116     }
 117 
 118     private static class MaskErrorAction extends OperationBase
 119     {
 120         private Operation op ;
 121 
 122         public MaskErrorAction( Operation op )
 123         {
 124             this.op = op ;
 125         }
 126 
 127         public Object operate( Object arg )
 128         {
 129             try {
 130                 return op.operate( arg ) ;
 131             } catch (java.lang.Exception exc) {
 132                 return null ;
 133             }
 134         }
 135 
 136         public String toString()
 137         {
 138             return "maskErrorAction(" + op + ")" ;
 139         }
 140     }
 141 
 142     public static Operation maskErrorAction( Operation op )
 143     {
 144         return new MaskErrorAction( op ) ;
 145     }
 146 
 147     private static class IndexAction extends OperationBase
 148     {
 149         private int index ;
 150 
 151         public IndexAction( int index )
 152         {
 153             this.index = index ;
 154         }
 155 
 156         public Object operate( Object value )
 157         {
 158             return getObjectArray( value )[ index ] ;
 159         }
 160 
 161         public String toString()
 162         {
 163             return "indexAction(" + index + ")" ;
 164         }
 165     }
 166 
 167     public static Operation indexAction( int index )
 168     {
 169         return new IndexAction( index ) ;
 170     }
 171 
 172     private static class SuffixAction extends OperationBase
 173     {
 174         public Object operate( Object value )
 175         {
 176             return getStringPair( value ).getFirst() ;
 177         }
 178 
 179         public String toString() { return "suffixAction" ; }
 180     }
 181 
 182     private static Operation suffixActionImpl = new SuffixAction() ;
 183 
 184     private static class ValueAction extends OperationBase
 185     {
 186         public Object operate( Object value )
 187         {
 188             return getStringPair( value ).getSecond() ;
 189         }
 190 
 191         public String toString() { return "valueAction" ; }
 192     }
 193 
 194     private static Operation valueActionImpl = new ValueAction() ;
 195 
 196     private static class IdentityAction extends OperationBase
 197     {
 198         public Object operate( Object value )
 199         {
 200             return value ;
 201         }
 202 
 203         public String toString() { return "identityAction" ; }
 204     }
 205 
 206     private static Operation identityActionImpl = new IdentityAction() ;
 207 
 208     private static class BooleanAction extends OperationBase
 209     {
 210         public Object operate( Object value )
 211         {
 212             return new Boolean( getString( value ) ) ;
 213         }
 214 
 215         public String toString() { return "booleanAction" ; }
 216     }
 217 
 218     private static Operation booleanActionImpl = new BooleanAction() ;
 219 
 220     private static class IntegerAction extends OperationBase
 221     {
 222         public Object operate( Object value )
 223         {
 224             return new Integer( getString( value ) ) ;
 225         }
 226 
 227         public String toString() { return "integerAction" ; }
 228     }
 229 
 230     private static Operation integerActionImpl = new IntegerAction() ;
 231 
 232     private static class StringAction extends OperationBase
 233     {
 234         public Object operate( Object value )
 235         {
 236             return value ;
 237         }
 238 
 239         public String toString() { return "stringAction" ; }
 240     }
 241 
 242     private static Operation stringActionImpl = new StringAction() ;
 243 
 244     private static class ClassAction extends OperationBase
 245     {
 246         public Object operate( Object value )
 247         {
 248             String className = getString( value ) ;
 249 
 250             try {
 251                 Class<?> result =
 252                     SharedSecrets.getJavaCorbaAccess().loadClass( className ) ;
 253                 return result ;
 254             } catch (Exception exc) {
 255                 ORBUtilSystemException wrapper = ORBUtilSystemException.get(
 256                     CORBALogDomains.ORB_LIFECYCLE ) ;
 257                 throw wrapper.couldNotLoadClass( exc, className ) ;
 258             }
 259         }
 260 
 261         public String toString() { return "classAction" ; }
 262     }
 263 
 264     private static Operation classActionImpl = new ClassAction() ;
 265 
 266     private static class SetFlagAction extends OperationBase
 267     {
 268         public Object operate( Object value )
 269         {
 270             return Boolean.TRUE ;
 271         }
 272 
 273         public String toString() { return "setFlagAction" ; }
 274     }
 275 
 276     private static Operation setFlagActionImpl = new SetFlagAction() ;
 277 
 278     private static class URLAction extends OperationBase
 279     {
 280         public Object operate( Object value )
 281         {
 282             String val = (String)value ;
 283             try {
 284                 return new URL( val ) ;
 285             } catch (MalformedURLException exc) {
 286                 ORBUtilSystemException wrapper = ORBUtilSystemException.get(
 287                     CORBALogDomains.ORB_LIFECYCLE ) ;
 288                 throw wrapper.badUrl( exc, val ) ;
 289             }
 290         }
 291 
 292         public String toString() { return "URLAction" ; }
 293     }
 294 
 295     private static Operation URLActionImpl = new URLAction() ;
 296 
 297     public static Operation identityAction()
 298     {
 299         return identityActionImpl ;
 300     }
 301 
 302     public static Operation suffixAction()
 303     {
 304         return suffixActionImpl ;
 305     }
 306 
 307     public static Operation valueAction()
 308     {
 309         return valueActionImpl ;
 310     }
 311 
 312     public static Operation booleanAction()
 313     {
 314         return booleanActionImpl ;
 315     }
 316 
 317     public static Operation integerAction()
 318     {
 319         return integerActionImpl ;
 320     }
 321 
 322     public static Operation stringAction()
 323     {
 324         return stringActionImpl ;
 325     }
 326 
 327     public static Operation classAction()
 328     {
 329         return classActionImpl ;
 330     }
 331 
 332     public static Operation setFlagAction()
 333     {
 334         return setFlagActionImpl ;
 335     }
 336 
 337     public static Operation URLAction()
 338     {
 339         return URLActionImpl ;
 340     }
 341 
 342     private static class IntegerRangeAction extends OperationBase
 343     {
 344         private int min ;
 345         private int max ;
 346 
 347         IntegerRangeAction( int min, int max )
 348         {
 349             this.min = min ;
 350             this.max = max ;
 351         }
 352 
 353         public Object operate( Object value )
 354         {
 355             int result = Integer.parseInt( getString( value ) ) ;
 356             if ((result >= min) && (result <= max))
 357                 return new Integer( result ) ;
 358             else
 359                 throw new IllegalArgumentException(
 360                     "Property value " + result + " is not in the range " +
 361                     min + " to " + max ) ;
 362         }
 363 
 364         public String toString() {
 365             return "integerRangeAction(" + min + "," + max + ")" ;
 366         }
 367     }
 368 
 369     public static Operation integerRangeAction( int min, int max )
 370     {
 371         return new IntegerRangeAction( min, max ) ;
 372     }
 373 
 374     private static class ListAction extends OperationBase {
 375         private String sep ;
 376         private Operation act ;
 377 
 378         ListAction( String sep, Operation act )
 379         {
 380             this.sep = sep ;
 381             this.act = act ;
 382         }
 383 
 384         // Note that this method carefully constructs an array of the type
 385         // of the first result, rather than just using Object[], which is
 386         // not convertible into the correct type.  Also note that no tokens
 387         // results in a null result.
 388         public Object operate( Object value )
 389         {
 390             StringTokenizer st = new StringTokenizer( getString( value ),
 391                 sep ) ;
 392             int length = st.countTokens() ;
 393             Object result = null ;
 394             int ctr = 0 ;
 395             while (st.hasMoreTokens()) {
 396                 String next = st.nextToken() ;
 397                 Object val = act.operate( next ) ;
 398                 if (result == null)
 399                     result = Array.newInstance( val.getClass(), length ) ;
 400                 Array.set( result, ctr++, val ) ;
 401             }
 402 
 403             return result ;
 404         }
 405 
 406         public String toString() {
 407             return "listAction(separator=\"" + sep +
 408                 "\",action=" + act + ")" ;
 409         }
 410     }
 411 
 412     public static Operation listAction( String sep, Operation act )
 413     {
 414         return new ListAction( sep, act ) ;
 415     }
 416 
 417     private static class SequenceAction extends OperationBase
 418     {
 419         private String sep ;
 420         private Operation[] actions ;
 421 
 422         SequenceAction( String sep, Operation[] actions )
 423         {
 424             this.sep = sep ;
 425             this.actions = actions ;
 426         }
 427 
 428         public Object operate( Object value )
 429         {
 430             StringTokenizer st = new StringTokenizer( getString( value ),
 431                 sep ) ;
 432 
 433             int numTokens = st.countTokens() ;
 434             if (numTokens != actions.length)
 435                 throw new Error(
 436                     "Number of tokens and number of actions do not match" ) ;
 437 
 438             int ctr = 0 ;
 439             Object[] result = new Object[ numTokens ] ;
 440             while (st.hasMoreTokens()) {
 441                 Operation act = actions[ctr] ;
 442                 String next = st.nextToken() ;
 443                 result[ctr++] = act.operate( next ) ;
 444             }
 445 
 446             return result ;
 447         }
 448 
 449         public String toString() {
 450             return "sequenceAction(separator=\"" + sep +
 451                 "\",actions=" +
 452                 Arrays.toString(actions) + ")" ;
 453         }
 454     }
 455 
 456     public static Operation sequenceAction( String sep,
 457         Operation[] actions )
 458     {
 459         return new SequenceAction( sep, actions ) ;
 460     }
 461 
 462     private static class ComposeAction extends OperationBase
 463     {
 464         private Operation op1 ;
 465         private Operation op2 ;
 466 
 467         ComposeAction( Operation op1, Operation op2 )
 468         {
 469             this.op1 = op1 ;
 470             this.op2 = op2 ;
 471         }
 472 
 473         public Object operate( Object value )
 474         {
 475             return op2.operate( op1.operate( value ) ) ;
 476         }
 477 
 478         public String toString() {
 479             return "composition(" + op1 + "," + op2 + ")" ;
 480         }
 481     }
 482 
 483     public static Operation compose( Operation op1, Operation op2 )
 484     {
 485         return new ComposeAction( op1, op2 ) ;
 486     }
 487 
 488     private static class MapAction extends OperationBase
 489     {
 490         Operation op ;
 491 
 492         MapAction( Operation op )
 493         {
 494             this.op = op ;
 495         }
 496 
 497         public Object operate( Object value )
 498         {
 499             Object[] values = (Object[])value ;
 500             Object[] result = new Object[ values.length ] ;
 501             for (int ctr=0; ctr<values.length; ctr++ )
 502                 result[ctr] = op.operate( values[ctr] ) ;
 503             return result ;
 504         }
 505 
 506         public String toString() {
 507             return "mapAction(" + op + ")" ;
 508         }
 509     }
 510 
 511     public static Operation mapAction( Operation op )
 512     {
 513         return new MapAction( op ) ;
 514     }
 515 
 516     private static class MapSequenceAction extends OperationBase
 517     {
 518         private Operation[] op ;
 519 
 520         public MapSequenceAction( Operation[] op )
 521         {
 522             this.op = op ;
 523         }
 524 
 525         // XXX Does this correctly handle array types?  It seems
 526         // that hetereogeneous arrays work this way, while
 527         // homogeneous arrays need to use Array.newInstance tricks.
 528         public Object operate( Object value )
 529         {
 530             Object[] values = (Object[])value ;
 531             Object[] result = new Object[ values.length ] ;
 532             for (int ctr=0; ctr<values.length; ctr++ )
 533                 result[ctr] = op[ctr].operate( values[ctr] ) ;
 534             return result ;
 535         }
 536 
 537         public String toString() {
 538             return "mapSequenceAction(" +
 539                 Arrays.toString(op) + ")" ;
 540         }
 541     }
 542 
 543     public static Operation mapSequenceAction( Operation[] op )
 544     {
 545         return new MapSequenceAction( op ) ;
 546     }
 547 
 548     private static class ConvertIntegerToShort extends OperationBase
 549     {
 550         public Object operate( Object value )
 551         {
 552             Integer val = (Integer)value ;
 553             return new Short( val.shortValue() ) ;
 554         }
 555 
 556         public String toString() {
 557             return "ConvertIntegerToShort" ;
 558         }
 559     }
 560 
 561     private static Operation convertIntegerToShortImpl = new ConvertIntegerToShort() ;
 562 
 563     public static Operation convertIntegerToShort()
 564     {
 565         return convertIntegerToShortImpl ;
 566     }
 567 }