001    package org.apache.commons.ognl;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     * http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import org.apache.commons.ognl.enhance.ExpressionCompiler;
023    import org.apache.commons.ognl.enhance.OgnlExpressionCompiler;
024    import org.apache.commons.ognl.enhance.UnsupportedCompilationException;
025    
026    import java.lang.reflect.Method;
027    
028    /**
029     * $Id: ASTStaticMethod.java 1194869 2011-10-29 11:10:16Z mcucchiara $
030     *
031     * @author Luke Blanshard (blanshlu@netscape.net)
032     * @author Drew Davidson (drew@ognl.org)
033     */
034    public class ASTStaticMethod
035        extends SimpleNode
036        implements NodeType
037    {
038    
039        private String className;
040    
041        private String methodName;
042    
043        private Class getterClass;
044    
045        public ASTStaticMethod( int id )
046        {
047            super( id );
048        }
049    
050        public ASTStaticMethod( OgnlParser p, int id )
051        {
052            super( p, id );
053        }
054    
055        /**
056         * Called from parser action.
057         */
058        void init( String className, String methodName )
059        {
060            this.className = className;
061            this.methodName = methodName;
062        }
063    
064        protected Object getValueBody( OgnlContext context, Object source )
065            throws OgnlException
066        {
067            ObjectArrayPool objectArrayPool = OgnlRuntime.getObjectArrayPool();
068            Object[] args = objectArrayPool.create( jjtGetNumChildren() );
069            Object root = context.getRoot();
070    
071            try
072            {
073                for ( int i = 0, icount = args.length; i < icount; ++i )
074                {
075                    args[i] = children[i].getValue( context, root );
076                }
077    
078                return OgnlRuntime.callStaticMethod( context, className, methodName, args );
079            }
080            finally
081            {
082                objectArrayPool.recycle( args );
083            }
084        }
085    
086        public Class getGetterClass()
087        {
088            return getterClass;
089        }
090    
091        public Class getSetterClass()
092        {
093            return getterClass;
094        }
095    
096        public String toGetSourceString( OgnlContext context, Object target )
097        {
098            String result = className + "#" + methodName + "(";
099    
100            try
101            {
102                Class clazz = OgnlRuntime.classForName( context, className );
103                Method m = OgnlRuntime.getMethod( context, clazz, methodName, children, true );
104    
105                if ( clazz == null || m == null )
106                {
107                    throw new UnsupportedCompilationException(
108                        "Unable to find class/method combo " + className + " / " + methodName );
109                }
110    
111                if ( !context.getMemberAccess().isAccessible( context, clazz, m, methodName ) )
112                {
113                    throw new UnsupportedCompilationException(
114                        "Method is not accessible, check your jvm runtime security settings. " + "For static class method "
115                            + className + " / " + methodName );
116                }
117    
118                OgnlExpressionCompiler compiler = OgnlRuntime.getCompiler( context );
119                if ( ( children != null ) && ( children.length > 0 ) )
120                {
121                    Class[] parms = m.getParameterTypes();
122    
123                    for ( int i = 0; i < children.length; i++ )
124                    {
125                        if ( i > 0 )
126                        {
127                            result = result + ", ";
128                        }
129    
130                        Class prevType = context.getCurrentType();
131    
132                        Node child = children[i];
133                        Object root = context.getRoot();
134    
135                        String parmString = ASTMethodUtil.getParmString( context, root, child, prevType );
136    
137                        Class valueClass = ASTMethodUtil.getValueClass( context, root, child );
138    
139                        if ( valueClass != parms[i] )
140                        {
141                            if ( parms[i].isArray() )
142                            {
143                                parmString = compiler.createLocalReference( context, "(" + ExpressionCompiler.getCastString(
144                                    parms[i] ) + ")org.apache.commons.ognl.OgnlOps.toArray(" + parmString + ", "
145                                    + parms[i].getComponentType().getName() + ".class, true)", parms[i] );
146    
147                            }
148                            else if ( parms[i].isPrimitive() )
149                            {
150                                Class wrapClass = OgnlRuntime.getPrimitiveWrapperClass( parms[i] );
151    
152                                parmString = compiler.createLocalReference( context, "((" + wrapClass.getName()
153                                    + ")org.apache.commons.ognl.OgnlOps.convertValue(" + parmString + ","
154                                    + wrapClass.getName() + ".class, true))." + OgnlRuntime.getNumericValueGetter(
155                                    wrapClass ), parms[i] );
156    
157                            }
158                            else if ( parms[i] != Object.class )
159                            {
160                                parmString = compiler.createLocalReference( context, "(" + parms[i].getName()
161                                    + ")org.apache.commons.ognl.OgnlOps.convertValue(" + parmString + ","
162                                    + parms[i].getName() + ".class)", parms[i] );
163                            }
164                            else if ( ( NodeType.class.isInstance( child ) && ( (NodeType) child ).getGetterClass() != null
165                                && Number.class.isAssignableFrom( ( (NodeType) child ).getGetterClass() ) )
166                                || valueClass.isPrimitive() )
167                            {
168                                parmString = " ($w) " + parmString;
169                            }
170                            else if ( valueClass.isPrimitive() )
171                            {
172                                parmString = "($w) " + parmString;
173                            }
174                        }
175    
176                        result += parmString;
177                    }
178                }
179    
180                result += ")";
181    
182                try
183                {
184                    Object contextObj = getValueBody( context, target );
185                    context.setCurrentObject( contextObj );
186                }
187                catch ( Throwable t )
188                {
189                    // ignore
190                }
191    
192                if ( m != null )
193                {
194                    getterClass = m.getReturnType();
195    
196                    context.setCurrentType( m.getReturnType() );
197                    context.setCurrentAccessor( compiler.getSuperOrInterfaceClass( m, m.getDeclaringClass() ) );
198                }
199    
200            }
201            catch ( Throwable t )
202            {
203                throw OgnlOps.castToRuntime( t );
204            }
205    
206            return result;
207        }
208    
209        public String toSetSourceString( OgnlContext context, Object target )
210        {
211            return toGetSourceString( context, target );
212        }
213    
214        public <R, P> R accept( NodeVisitor<? extends R, ? super P> visitor, P data )
215            throws OgnlException
216        {
217            return visitor.visit( this, data );
218        }
219    
220        /**
221         * Get the class name for this method.
222         *
223         * @return the class name.
224         * @since 4.0
225         */
226        public String getClassName()
227        {
228            return className;
229        }
230    
231        /**
232         * Get the method name for this method.
233         *
234         * @return the method name.
235         * @since 4.0
236         */
237        public String getMethodName()
238        {
239            return methodName;
240        }
241    }