[xwiki-notifications] r10959 - xwiki-platform/core/trunk/xwiki-velocity/src/main/java/org/xwiki/velocity/introspection
sdumitriu (SVN)
notifications at xwiki.org
Tue Jul 1 02:12:29 CEST 2008
Author: sdumitriu
Date: 2008-07-01 02:12:29 +0200 (Tue, 01 Jul 2008)
New Revision: 10959
Added:
xwiki-platform/core/trunk/xwiki-velocity/src/main/java/org/xwiki/velocity/introspection/LinkingUberspector.java
Log:
XWIKI-2531: Custom Velocity Uberspector that allows linking several uberspectors
Done
Added: xwiki-platform/core/trunk/xwiki-velocity/src/main/java/org/xwiki/velocity/introspection/LinkingUberspector.java
===================================================================
--- xwiki-platform/core/trunk/xwiki-velocity/src/main/java/org/xwiki/velocity/introspection/LinkingUberspector.java (rev 0)
+++ xwiki-platform/core/trunk/xwiki-velocity/src/main/java/org/xwiki/velocity/introspection/LinkingUberspector.java 2008-07-01 00:12:29 UTC (rev 10959)
@@ -0,0 +1,260 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.lang.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.Info;
+import org.apache.velocity.util.introspection.SecureUberspector;
+import org.apache.velocity.util.introspection.Uberspect;
+import org.apache.velocity.util.introspection.UberspectImpl;
+import org.apache.velocity.util.introspection.UberspectLoggable;
+import org.apache.velocity.util.introspection.VelMethod;
+import org.apache.velocity.util.introspection.VelPropertyGet;
+import org.apache.velocity.util.introspection.VelPropertySet;
+
+/**
+ * <p>
+ * 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 an <strong>array of uberspectors</strong>, loading the classes in the order
+ * defined in the <code>"runtime.introspector.uberspect.arrayClasses"</code> property, and after that forwards calls to
+ * each of the uberspectors, in order, until one of them returns something different than <code>null</code>. Note that
+ * the calls will be made from the leftmost class to the rightmost one. This allows building and combining different
+ * small uberspectors that perform a specialised search for methods, instead of bloating a single class with different
+ * introspection tricks.
+ * </p>
+ * <p>
+ * This is not actually part of the array, but is more of a handle that allows the calls intended for only one
+ * uberspector to reach the array. It duplicates some of the code from the velocity runtime initialization code, hoping
+ * that a future version of the engine will support this natively.
+ * </p>
+ * <p>
+ * The array is defined using the configuration parameter <code>runtime.introspector.uberspect.arrayClasses</code>. 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 <code>SecureUberspector</code> is used
+ * as the only entry in the array.
+ * </p>
+ *
+ * @since 1.5RC1
+ * @see ChainingUberspector
+ * @version $Id$
+ */
+public class LinkingUberspector extends UberspectImpl implements Uberspect, RuntimeServicesAware, UberspectLoggable
+{
+ /** The key of the parameter that allows defining the array of uberspectors. */
+ public static final String UBERSPECT_ARRAY_CLASSNAMES = "runtime.introspector.uberspect.arrayClasses";
+
+ /** The runtime is needed for accessing the configuration. */
+ private RuntimeServices runtime;
+
+ /** The array of uberspectors to use. */
+ private List<Uberspect> uberspectors;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.velocity.util.RuntimeServicesAware#setRuntimeServices(org.apache.velocity.runtime.RuntimeServices)
+ */
+ public void setRuntimeServices(RuntimeServices rs)
+ {
+ this.runtime = rs;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation initializes the array of uberspectors.
+ * </p>
+ *
+ * @see org.apache.velocity.util.introspection.Uberspect#init()
+ */
+ @Override
+ public void init()
+ {
+ this.log.debug("Initializing the linking uberspector.");
+ // Create the array
+ String[] arrayClassnames = this.runtime.getConfiguration().getStringArray(UBERSPECT_ARRAY_CLASSNAMES);
+ this.uberspectors = new ArrayList<Uberspect>(arrayClassnames.length);
+ for (String classname : arrayClassnames) {
+ initializeUberspector(classname);
+ }
+ // If the chain is empty, use a SecureUberspector
+ if (this.uberspectors.isEmpty()) {
+ this.log.error("No uberspectors defined! "
+ + "This uberspector is just a placeholder that relies on at least one real uberspector "
+ + "to actually allow method calls. Using SecureUberspector instead as a fallback.");
+ initializeUberspector(SecureUberspector.class.getCanonicalName());
+ }
+ }
+
+ /**
+ * Instantiates and initializes an uberspector class and adds it to the array. Also set the log and runtime
+ * services, if the class implements the proper interfaces.
+ *
+ * @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);
+ }
+
+ // Initialize the uberspector
+ try {
+ u.init();
+ // Add it to the array
+ this.uberspectors.add(u);
+ } catch (Exception e) {
+ this.log.warn(e.getMessage());
+ // If the initialization failed, don't add this uberspector to the chain.
+ }
+ }
+ }
+
+ /**
+ * 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}, <code>null</code> is returned.
+ */
+ protected Uberspect instantiateUberspector(String classname)
+ {
+ Object o = null;
+ try {
+ o = ClassUtils.getNewInstance(classname);
+ } catch (ClassNotFoundException e) {
+ 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;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.velocity.util.introspection.Uberspect#getIterator(java.lang.Object,
+ * org.apache.velocity.util.introspection.Info)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Iterator getIterator(Object obj, Info i) throws Exception
+ {
+ Iterator it;
+ for (Uberspect u : this.uberspectors) {
+ it = u.getIterator(obj, i);
+ if (it != null) {
+ return it;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.velocity.util.introspection.Uberspect#getMethod(java.lang.Object, java.lang.String,
+ * java.lang.Object[], org.apache.velocity.util.introspection.Info)
+ */
+ @Override
+ public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) throws Exception
+ {
+ VelMethod method;
+ for (Uberspect u : this.uberspectors) {
+ method = u.getMethod(obj, methodName, args, i);
+ if (method != null) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.velocity.util.introspection.Uberspect#getPropertyGet(java.lang.Object, java.lang.String,
+ * org.apache.velocity.util.introspection.Info)
+ */
+ @Override
+ public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) throws Exception
+ {
+ VelPropertyGet getter;
+ for (Uberspect u : this.uberspectors) {
+ getter = u.getPropertyGet(obj, identifier, i);
+ if (getter != null) {
+ return getter;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.velocity.util.introspection.Uberspect#getPropertySet(java.lang.Object, java.lang.String,
+ * java.lang.Object, org.apache.velocity.util.introspection.Info)
+ */
+ @Override
+ public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) throws Exception
+ {
+ VelPropertySet setter;
+ for (Uberspect u : this.uberspectors) {
+ setter = u.getPropertySet(obj, identifier, arg, i);
+ if (setter != null) {
+ return setter;
+ }
+ }
+ return null;
+ }
+}
Property changes on: xwiki-platform/core/trunk/xwiki-velocity/src/main/java/org/xwiki/velocity/introspection/LinkingUberspector.java
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the notifications
mailing list