⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vmproxyarg.java

📁 velocity官方工具包 包括各种JAR包 示例 文档等
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package org.apache.velocity.runtime.directive;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */

import java.io.BufferedReader;
import java.io.StringReader;
import java.io.StringWriter;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.context.InternalContextAdapterImpl;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.runtime.parser.ParserTreeConstants;
import org.apache.velocity.runtime.parser.node.ASTReference;
import org.apache.velocity.runtime.parser.node.SimpleNode;

/**
 *  The function of this class is to proxy for the calling parameter to the VM.
 *
 *  This class is designed to be used in conjunction with the VMContext class
 *  which knows how to get and set values via it, rather than a simple get()
 *  or put() from a hashtable-like object.
 *
 *  There is probably a lot of undocumented subtlty here, so step lightly.
 *
 *  We rely on the observation that an instance of this object has a constant
 *  state throughout its lifetime as it's bound to the use-instance of a VM.
 *  In other words, it's created by the VelocimacroProxy class, to represent
 *  one of the arguments to a VM in a specific template.  Since the template
 *  is fixed (it's a file...), we don't have to worry that the args to the VM
 *  will change.  Yes, the VM will be called in other templates, or in other
 *  places on the same template, bit those are different use-instances.
 *
 *  These arguments can be, in the lingo of
 *  the parser, one of :
 *   <ul>
 *   <li> Reference() : anything that starts with '$'
 *   <li> StringLiteral() : something like "$foo" or "hello geir"
 *   <li> IntegerLiteral() : 1, 2 etc
 *   <li> FloatingPointLiteral() : 1.2, 2e5 etc
 *   <li> IntegerRange() : [ 1..2] or [$foo .. $bar]
 *   <li> ObjectArray() : [ "a", "b", "c"]
 *   <li> True() : true
 *   <li> False() : false
 *    <li>Word() : not likely - this is simply allowed by the parser so we can have
 *             syntactical sugar like #foreach($a in $b)  where 'in' is the Word
 *    </ul>
 *  Now, Reference(), StringLit, IntegerLiteral, IntRange, ObjArr are all dynamic things, so
 *  their value is gotten with the use of a context.  The others are constants.  The trick
 *  we rely on is that the context rather than this class really represents the
 *  state of the argument. We are simply proxying for the thing, returning the proper value
 *  when asked, and storing the proper value in the appropriate context when asked.
 *
 *  So, the hope here, so an instance of this can be shared across threads, is to
 *  keep any dynamic stuff out of it, relying on trick of having the appropriate
 *  context handed to us, and when a constant argument, letting VMContext punch that
 *  into a local context.
 *
 *  @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
 *  @version $Id: VMProxyArg.java 473363 2006-11-10 15:19:09Z wglass $
 */
public class VMProxyArg
{
    /** in the event our type is switched - we don't care really what it is */
    private static final int GENERALSTATIC = -1;

    /**  type of arg I will have */
    private int type = 0;

    /**  the AST if the type is such that it's dynamic (ex. JJTREFERENCE ) */
    private SimpleNode nodeTree = null;

    /**  reference for the object if we proxy for a static arg like an IntegerLiteral*/
    private Object staticObject = null;

    /** number of children in our tree if a reference */
    private int numTreeChildren = 0;

    /** our identity in the current context */
    private String contextReference = null;

    /** the reference we are proxying for  */
    private String callerReference = null;

    /** the 'de-dollared' reference if we are a ref but don't have a method attached */
    private String singleLevelRef = null;

    /** by default, we are dynamic.  safest */
    private boolean constant = false;

    private RuntimeServices rsvc = null;
    private Log log = null;

    /**
     *  ctor for current impl
     *
     *  takes the reference literal we are proxying for, the literal
     *  the VM we are for is called with...
     * @param rs
     *
     *  @param contextRef reference arg in the definition of the VM, used in the VM
     *  @param callerRef  reference used by the caller as an arg to the VM
     *  @param t  type of arg : JJTREFERENCE, JJTTRUE, etc
     */
    public VMProxyArg( RuntimeServices rs, String contextRef, String callerRef, int t )
    {
        rsvc = rs;
        log = rsvc.getLog();

        contextReference = contextRef;
        callerReference = callerRef;
        type = t;

        /*
         *  make our AST if necessary
         */
        setup();

        /*
         *  if we are multi-node tree, then save the size to
         *  avoid fn call overhead
         */
        if( nodeTree != null)
        {
            numTreeChildren = nodeTree.jjtGetNumChildren();
        }

        /*
         *  if we are a reference, and 'scalar' (i.e. $foo )
         *  then get the de-dollared ref so we can
         *  hit our context directly, avoiding the AST
         */
        if ( type == ParserTreeConstants.JJTREFERENCE )
        {
            if ( numTreeChildren == 0)
            {
                /*
                 * do this properly and use the Reference node
                 */
                 singleLevelRef = ((ASTReference) nodeTree).getRootString();
            }
        }
    }

    /**
     *  tells if arg we are poxying for is
     *  dynamic or constant.
     *
     *  @return true of constant, false otherwise
     */
    public boolean isConstant()
    {
        return constant;
    }

    /**
     *  Invoked by VMContext when Context.put() is called for a proxied reference.
     *
     *  @param context context to modify via direct placement, or AST.setValue()
     *  @param o  new value of reference
     *  @return Object currently null
     */
    public Object setObject(  InternalContextAdapter context,  Object o )
    {
        /*
         *  if we are a reference, we could be updating a property
         */

        if( type == ParserTreeConstants.JJTREFERENCE )
        {
            if( numTreeChildren > 0)
            {
                /*
                 *  we are a property, and being updated such as
                 *  #foo( $bar.BangStart)
                 */

                try
                {
                    ( (ASTReference) nodeTree).setValue( context, o );
                }
                catch( MethodInvocationException mie )
                {
                    log.error("VMProxyArg.getObject() : method invocation error setting value", mie);
                }
           }
            else
            {
                /*
                 *  we are a 'single level' reference like $foo, so we can set
                 *  out context directly
                 */

                context.put( singleLevelRef, o);

                // alternate impl : usercontext.put( singleLevelRef, o);
             }
        }
        else
        {
            /*
             *  if we aren't a reference, then we simply switch type,
             *  get a new value, and it doesn't go into the context
             *
             *  in current impl, this shouldn't happen.
             */

            type = GENERALSTATIC;
            staticObject = o;

            log.error("VMProxyArg.setObject() : Programmer error : I am a constant!  No setting! : "
                      + contextReference + " / " + callerReference);
        }

        return null;
    }


    /**
     *  returns the value of the reference.  Generally, this is only
     *  called for dynamic proxies, as the static ones should have
     *  been stored in the VMContext's localcontext store
     *
     *  @param context Context to use for getting current value
     *  @return Object value
     * @exception MethodInvocationException passes on potential exception from reference method call
     */
    public Object getObject( InternalContextAdapter context )  throws MethodInvocationException
    {
        try
        {

            /*
             *  we need to output based on our type
             */

            Object retObject = null;

            if ( type == ParserTreeConstants.JJTREFERENCE )
            {
                /*
                 *  two     cases :  scalar reference ($foo) or multi-level ($foo.bar....)
                 */

                if ( numTreeChildren == 0)
                {
                    /*
                     *  if I am a single-level reference, can I not get get it out of my context?
                     */

                    retObject = context.get( singleLevelRef );
                }
                else
                {
                    /*
                     *  I need to let the AST produce it for me.
                     */

                    retObject = nodeTree.execute( null, context);
                }
            }
            else if (type == ParserTreeConstants.JJTMAP)
            {
                retObject = nodeTree.value(context);
            }
            else if( type == ParserTreeConstants.JJTOBJECTARRAY )
            {
                retObject = nodeTree.value( context );
            }
            else if ( type == ParserTreeConstants.JJTINTEGERRANGE)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -