View Javadoc

    1   /*
    2    * Copyright 2002,2004 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16
    17  package org.apache.commons.jexl.util.introspection;
    18
    19  import org.apache.commons.jexl.util.ArrayIterator;
    20  import org.apache.commons.jexl.util.EnumerationIterator;
    21  import org.apache.commons.jexl.util.AbstractExecutor;
    22  import org.apache.commons.jexl.util.GetExecutor;
    23  import org.apache.commons.jexl.util.BooleanPropertyExecutor;
    24  import org.apache.commons.jexl.util.PropertyExecutor;
    25  import org.apache.commons.logging.Log;
    26
    27  import java.lang.reflect.Method;
    28  import java.lang.reflect.InvocationTargetException;
    29  import java.util.Iterator;
    30  import java.util.Collection;
    31  import java.util.Map;
    32  import java.util.Enumeration;
    33  import java.util.ArrayList;
    34
    35  /***
    36   *  Implementation of Uberspect to provide the default introspective
    37   *  functionality of Velocity
    38   *
    39   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
    40   * @version $Id: UberspectImpl.java,v 1.6 2004/08/19 17:15:59 dion Exp $
    41   */
    42  public class UberspectImpl implements Uberspect, UberspectLoggable
    43  {
    44      /***
    45       *  Our runtime logger.
    46       */
    47      private Log rlog;
    48
    49      /***
    50       *  the default Velocity introspector
    51       */
    52      private static Introspector introspector;
    53
    54      /***
    55       *  init - does nothing - we need to have setRuntimeLogger
    56       *  called before getting our introspector, as the default
    57       *  vel introspector depends upon it.
    58       */
    59      public void init()
    60          throws Exception
    61      {
    62      }
    63
    64      /***
    65       *  Sets the runtime logger - this must be called before anything
    66       *  else besides init() as to get the logger.  Makes the pull
    67       *  model appealing...
    68       */
    69      public void setRuntimeLogger(Log runtimeLogger)
    70      {
    71          rlog = runtimeLogger;
    72          introspector = new Introspector(rlog);
    73      }
    74
    75      /***
    76       *  To support iteratives - #foreach()
    77       */
    78      public Iterator getIterator(Object obj, Info i)
    79              throws Exception
    80      {
    81          if (obj.getClass().isArray())
    82          {
    83              return new ArrayIterator(obj);
    84          }
    85          else if (obj instanceof Collection)
    86          {
    87              return ((Collection) obj).iterator();
    88          }
    89          else if (obj instanceof Map)
    90          {
    91              return ((Map) obj).values().iterator();
    92          }
    93          else if (obj instanceof Iterator)
    94          {
    95              rlog.warn ("Warning! The iterative "
    96                            + " is an Iterator in the #foreach() loop at ["
    97                            + i.getLine() + "," + i.getColumn() + "]"
    98                            + " in template " + i.getTemplateName()
    99                            + ". Because it's not resetable,"
    100                           + " if used in more than once, this may lead to"
    101                           + " unexpected results.");
    102
    103             return ((Iterator) obj);
    104         }
    105         else if (obj instanceof Enumeration)
    106         {
    107             rlog.warn ("Warning! The iterative "
    108                           + " is an Enumeration in the #foreach() loop at ["
    109                           + i.getLine() + "," + i.getColumn() + "]"
    110                           + " in template " + i.getTemplateName()
    111                           + ". Because it's not resetable,"
    112                           + " if used in more than once, this may lead to"
    113                           + " unexpected results.");
    114
    115             return new EnumerationIterator((Enumeration) obj);
    116         }
    117
    118         /*  we have no clue what this is  */
    119         rlog.warn ("Could not determine type of iterator in "
    120                       +  "#foreach loop "
    121                       + " at [" + i.getLine() + "," + i.getColumn() + "]"
    122                       + " in template " + i.getTemplateName() );
    123
    124         return null;
    125     }
    126
    127     /***
    128      *  Method
    129      */
    130     public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i)
    131             throws Exception
    132     {
    133         if (obj == null)
    134             return null;
    135
    136         Method m = introspector.getMethod(obj.getClass(), methodName, args);
    137
    138         return (m != null) ? new VelMethodImpl(m) : null;
    139     }
    140
    141     /***
    142      * Property  getter
    143      */
    144     public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i)
    145             throws Exception
    146     {
    147         AbstractExecutor executor;
    148
    149         Class claz = obj.getClass();
    150
    151         /*
    152          *  first try for a getFoo() type of property
    153          *  (also getfoo() )
    154          */
    155
    156         executor = new PropertyExecutor(rlog,introspector, claz, identifier);
    157
    158         /*
    159          *  look for boolean isFoo()
    160          */
    161
    162         if( executor.isAlive() == false)
    163         {
    164             executor = new BooleanPropertyExecutor(rlog, introspector, claz, identifier);
    165         }
    166
    167         /*
    168          *  if that didn't work, look for get("foo")
    169          */
    170
    171         if (executor.isAlive() == false)
    172         {
    173             executor = new GetExecutor(rlog, introspector, claz, identifier);
    174         }
    175
    176         return (executor != null) ? new VelGetterImpl(executor) : null;
    177     }
    178
    179     /***
    180      * Property setter
    181      */
    182     public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i)
    183             throws Exception
    184     {
    185         Class claz = obj.getClass();
    186
    187         VelMethod vm = null;
    188         try
    189         {
    190             /*
    191              *  first, we introspect for the set<identifier> setter method
    192              */
    193
    194             Object[] params = {arg};
    195
    196             try
    197             {
    198                 vm = getMethod(obj, "set" + identifier, params, i);
    199
    200                 if (vm == null)
    201                 {
    202                    throw new NoSuchMethodException();
    203                 }
    204             }
    205             catch(NoSuchMethodException nsme2)
    206             {
    207                 StringBuffer sb = new StringBuffer("set");
    208                 sb.append(identifier);
    209
    210                 if (Character.isLowerCase( sb.charAt(3)))
    211                 {
    212                     sb.setCharAt(3, Character.toUpperCase(sb.charAt(3)));
    213                 }
    214                 else
    215                 {
    216                     sb.setCharAt(3, Character.toLowerCase(sb.charAt(3)));
    217                 }
    218
    219                 vm = getMethod(obj, sb.toString(), params, i);
    220
    221                 if (vm == null)
    222                 {
    223                    throw new NoSuchMethodException();
    224                 }
    225             }
    226         }
    227         catch (NoSuchMethodException nsme)
    228         {
    229             /*
    230              *  right now, we only support the Map interface
    231              */
    232
    233             if (Map.class.isAssignableFrom(claz))
    234             {
    235                 Object[] params = {new Object(), new Object()};
    236
    237                 vm = getMethod(obj, "put", params, i);
    238
    239                 if (vm!=null)
    240                     return new VelSetterImpl(vm, identifier);
    241             }
    242        }
    243
    244        return (vm!=null) ?  new VelSetterImpl(vm) : null;
    245     }
    246
    247     /***
    248      *  Implementation of VelMethod
    249      */
    250     public class VelMethodImpl implements VelMethod
    251     {
    252         Method method = null;
    253
    254         public VelMethodImpl(Method m)
    255         {
    256             method = m;
    257         }
    258
    259         private VelMethodImpl()
    260         {
    261         }
    262
    263         public Object invoke(Object o, Object[] params)
    264             throws Exception
    265         {
    266             try
    267             {
    268                 return method.invoke(o, params);
    269             }
    270             catch( InvocationTargetException e )
    271             {
    272                 final Throwable t = e.getTargetException();
    273
    274                 if( t instanceof Exception )
    275                 {
    276                     throw (Exception)t;
    277                 }
    278                 else if (t instanceof Error)
    279                 {
    280                     throw (Error)t;
    281                 }
    282                 else
    283                 {
    284                     throw e;
    285                 }
    286             }
    287         }
    288
    289         public boolean isCacheable()
    290         {
    291             return true;
    292         }
    293
    294         public String getMethodName()
    295         {
    296             return method.getName();
    297         }
    298
    299         public Class getReturnType()
    300         {
    301             return method.getReturnType();
    302         }
    303     }
    304
    305     public class VelGetterImpl implements VelPropertyGet
    306     {
    307         AbstractExecutor ae = null;
    308
    309         public VelGetterImpl(AbstractExecutor exec)
    310         {
    311             ae = exec;
    312         }
    313
    314         private VelGetterImpl()
    315         {
    316         }
    317
    318         public Object invoke(Object o)
    319             throws Exception
    320         {
    321             return ae.execute(o);
    322         }
    323
    324         public boolean isCacheable()
    325         {
    326             return true;
    327         }
    328
    329         public String getMethodName()
    330         {
    331             return ae.getMethod().getName();
    332         }
    333
    334     }
    335
    336     public class VelSetterImpl implements VelPropertySet
    337     {
    338         VelMethod vm = null;
    339         String putKey = null;
    340
    341         public VelSetterImpl(VelMethod velmethod)
    342         {
    343             this.vm = velmethod;
    344         }
    345
    346         public VelSetterImpl(VelMethod velmethod, String key)
    347         {
    348             this.vm = velmethod;
    349             putKey = key;
    350         }
    351
    352         private VelSetterImpl()
    353         {
    354         }
    355
    356         public Object invoke(Object o, Object value)
    357             throws Exception
    358         {
    359             ArrayList al = new ArrayList();
    360
    361             if (putKey != null)
    362             {
    363                 al.add(putKey);
    364                 al.add(value);
    365             }
    366             else
    367             {
    368                 al.add(value);
    369             }
    370
    371             return vm.invoke(o,al.toArray());
    372         }
    373
    374         public boolean isCacheable()
    375         {
    376             return true;
    377         }
    378
    379         public String getMethodName()
    380         {
    381             return vm.getMethodName();
    382         }
    383
    384     }
    385 }