All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xwiki.velocity.introspection.ChainingUberspector Maven / Gradle / Ivy

There is a newer version: 16.10.2
Show newest version
/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.velocity.introspection;

import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.util.ClassUtils;
import org.apache.velocity.util.RuntimeServicesAware;
import org.apache.velocity.util.introspection.Uberspect;
import org.apache.velocity.util.introspection.UberspectLoggable;

/**
 * 

* Since the current version of the Velocity engine (1.5) does not allow more than one uberspector, this class is a * workaround. It manually constructs a chain of uberspectors, loading the classes in the order * defined in the "runtime.introspector.uberspect.chainClasses" property, and after that simply * forwarding all calls to the top of the chain. Note that the calls will be made from the rightmost class to the * leftmost one. Along the chain, each uberspectors can forward the call to the rest of the chain, build its own result, * and/or process in any way the resulting value. This allows uberspectors to enhance the list of returned methods, * block out methods returned by other uberspectors, or take various actions on the returned method (for example add or * remove parameters before searching the method, log executed method names, or catch exceptions when executing those * methods). *

*

* This is not actually part of the chain, but is more of a handle that allows the calls intended for only one * uberspector to reach the chain. It duplicates some of the code from the velocity runtime initialization code, hoping * that a future version of the engine will support chaining natively. *

*

* The chain is defined using the configuration parameter runtime.introspector.uberspect.chainClasses. * This property should contain a list of canonical class names. Any wrong entry in the list will be ignored. If this * property is not defined or contains only wrong classnames, then by default a SecureUberspector is used * as the only entry in the chain. The first (leftmost) uberspector does not have to be chainable (as it will not need * to forward calls). If a uberspector in the middle of the chain is not chainable, then it will break the chain at that * point (all previos uberspectors will be discarded from the chain). *

* * @since 1.5M1 * @see ChainableUberspector * @version $Id: 275615d5ea172188b04c63beb3967695bdd10224 $ * @deprecated since 8.0M1; Velocity supports the same functionality natively since 1.6; just move the configuration * from {@code runtime.introspector.uberspect.chainClasses} to {@code runtime.introspector.uberspect} */ @Deprecated public class ChainingUberspector extends AbstractChainableUberspector implements Uberspect, RuntimeServicesAware, UberspectLoggable { /** The key of the parameter that allows defining the list of chained uberspectors. */ public static final String UBERSPECT_CHAIN_CLASSNAMES = "runtime.introspector.uberspect.chainClasses"; /** The runtime is needed for accessing the configuration. */ private RuntimeServices runtime; @Override public void setRuntimeServices(RuntimeServices rs) { this.runtime = rs; } /** * {@inheritDoc} *

* This implementation initializes the uberspector chain. *

* * @see org.apache.velocity.util.introspection.Uberspect#init() */ @Override public void init() { this.log.debug("Initializing the chaining uberspector."); // Create the chain // TODO Since we're in Plexus already, should we use components? String[] chainClassnames = this.runtime.getConfiguration().getStringArray(UBERSPECT_CHAIN_CLASSNAMES); for (String classname : chainClassnames) { initializeUberspector(classname); } // If the chain is empty, use a SecureUberspector if (this.inner == null) { this.log.error("No chained uberspectors defined! " + "This uberspector is just a placeholder that relies on a real uberspector " + "to actually allow method calls. Using SecureUberspect instead as a fallback."); initializeUberspector(SecureUberspector.class.getCanonicalName()); } // Initialize all the uberspectors in the chain try { this.inner.init(); } catch (Exception e) { this.log.warn(e.getMessage()); } } /** * Instantiates an uberspector class and adds it to the chain. Also set the log and runtime services, if the class * implements the proper interfaces. The {@link Uberspect#init()} method is not called. * * @param classname The name of the uberspector class to add to the chain. */ protected void initializeUberspector(String classname) { // Avoids direct recursive calls if (!StringUtils.isEmpty(classname) && !classname.equals(this.getClass().getCanonicalName())) { Uberspect u = instantiateUberspector(classname); if (u == null) { return; } // Set the log and runtime services, if applicable if (u instanceof UberspectLoggable) { ((UberspectLoggable) u).setLog(this.log); } if (u instanceof RuntimeServicesAware) { ((RuntimeServicesAware) u).setRuntimeServices(this.runtime); } // Link it in the chain if (u instanceof ChainableUberspector) { ((ChainableUberspector) u).wrap(this.inner); } else if (u instanceof org.apache.velocity.util.introspection.ChainableUberspector) { ((org.apache.velocity.util.introspection.ChainableUberspector) u).wrap(this.inner); } this.inner = u; } } /** * Tries to create an uberspector instance using reflection. * * @param classname The name of the uberspector class to instantiate. * @return An instance of the specified Uberspector. If the class cannot be instantiated using the default * constructor, or does not implement {@link Uberspect}, null is returned. */ protected Uberspect instantiateUberspector(String classname) { Object o = null; try { o = ClassUtils.getNewInstance(classname); } catch (ClassNotFoundException cnfe) { this.log.warn(String.format("The specified uberspector [%s]" + " does not exist or is not accessible to the current classloader.", classname)); } catch (IllegalAccessException e) { this.log.warn(String.format("The specified uberspector [%s] does not have a public default constructor.", classname)); } catch (InstantiationException e) { this.log.warn(String.format("The specified uberspector [%s] cannot be instantiated.", classname)); } catch (ExceptionInInitializerError e) { this.log.warn(String.format("Exception while instantiating the Uberspector [%s]: %s", classname, e .getMessage())); } if (!(o instanceof Uberspect)) { if (o != null) { this.log.warn("The specified class for Uberspect [" + classname + "] does not implement " + Uberspect.class.getName()); } return null; } return (Uberspect) o; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy