1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.velocity.introspection

File ChainingUberspector.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

18
36
4
1
177
86
19
0.53
9
4
4.75

Classes

Class Line # Actions
ChainingUberspector 62 36 0% 19 4
0.931034593.1%
 

Contributing tests

This file is covered by 17 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.velocity.introspection;
21   
22    import org.apache.commons.lang3.StringUtils;
23    import org.apache.velocity.runtime.RuntimeServices;
24    import org.apache.velocity.util.ClassUtils;
25    import org.apache.velocity.util.RuntimeServicesAware;
26    import org.apache.velocity.util.introspection.Uberspect;
27    import org.apache.velocity.util.introspection.UberspectLoggable;
28   
29    /**
30    * <p>
31    * Since the current version of the Velocity engine (1.5) does not allow more than one uberspector, this class is a
32    * workaround. It manually constructs a <strong>chain of uberspectors</strong>, loading the classes in the order
33    * defined in the <code>"runtime.introspector.uberspect.chainClasses"</code> property, and after that simply
34    * forwarding all calls to the top of the chain. Note that the calls will be made from the rightmost class to the
35    * leftmost one. Along the chain, each uberspectors can forward the call to the rest of the chain, build its own result,
36    * and/or process in any way the resulting value. This allows uberspectors to enhance the list of returned methods,
37    * block out methods returned by other uberspectors, or take various actions on the returned method (for example add or
38    * remove parameters before searching the method, log executed method names, or catch exceptions when executing those
39    * methods).
40    * </p>
41    * <p>
42    * This is not actually part of the chain, but is more of a handle that allows the calls intended for only one
43    * uberspector to reach the chain. It duplicates some of the code from the velocity runtime initialization code, hoping
44    * that a future version of the engine will support chaining natively.
45    * </p>
46    * <p>
47    * The chain is defined using the configuration parameter <code>runtime.introspector.uberspect.chainClasses</code>.
48    * This property should contain a list of canonical class names. Any wrong entry in the list will be ignored. If this
49    * property is not defined or contains only wrong classnames, then by default a <code>SecureUberspector</code> is used
50    * as the only entry in the chain. The first (leftmost) uberspector does not have to be chainable (as it will not need
51    * to forward calls). If a uberspector in the middle of the chain is not chainable, then it will break the chain at that
52    * point (all previos uberspectors will be discarded from the chain).
53    * </p>
54    *
55    * @since 1.5M1
56    * @see ChainableUberspector
57    * @version $Id: 275615d5ea172188b04c63beb3967695bdd10224 $
58    * @deprecated since 8.0M1; Velocity supports the same functionality natively since 1.6; just move the configuration
59    * from {@code runtime.introspector.uberspect.chainClasses} to {@code runtime.introspector.uberspect}
60    */
61    @Deprecated
 
62    public class ChainingUberspector extends AbstractChainableUberspector implements Uberspect, RuntimeServicesAware,
63    UberspectLoggable
64    {
65    /** The key of the parameter that allows defining the list of chained uberspectors. */
66    public static final String UBERSPECT_CHAIN_CLASSNAMES = "runtime.introspector.uberspect.chainClasses";
67   
68    /** The runtime is needed for accessing the configuration. */
69    private RuntimeServices runtime;
70   
 
71  17 toggle @Override
72    public void setRuntimeServices(RuntimeServices rs)
73    {
74  17 this.runtime = rs;
75    }
76   
77    /**
78    * {@inheritDoc}
79    * <p>
80    * This implementation initializes the uberspector chain.
81    * </p>
82    *
83    * @see org.apache.velocity.util.introspection.Uberspect#init()
84    */
 
85  17 toggle @Override
86    public void init()
87    {
88  17 this.log.debug("Initializing the chaining uberspector.");
89    // Create the chain
90    // TODO Since we're in Plexus already, should we use components?
91  17 String[] chainClassnames = this.runtime.getConfiguration().getStringArray(UBERSPECT_CHAIN_CLASSNAMES);
92  17 for (String classname : chainClassnames) {
93  34 initializeUberspector(classname);
94    }
95    // If the chain is empty, use a SecureUberspector
96  17 if (this.inner == null) {
97  1 this.log.error("No chained uberspectors defined! "
98    + "This uberspector is just a placeholder that relies on a real uberspector "
99    + "to actually allow method calls. Using SecureUberspect instead as a fallback.");
100  1 initializeUberspector(SecureUberspector.class.getCanonicalName());
101    }
102    // Initialize all the uberspectors in the chain
103  17 try {
104  17 this.inner.init();
105    } catch (Exception e) {
106  0 this.log.warn(e.getMessage());
107    }
108    }
109   
110    /**
111    * Instantiates an uberspector class and adds it to the chain. Also set the log and runtime services, if the class
112    * implements the proper interfaces. The {@link Uberspect#init()} method is not called.
113    *
114    * @param classname The name of the uberspector class to add to the chain.
115    */
 
116  35 toggle protected void initializeUberspector(String classname)
117    {
118    // Avoids direct recursive calls
119  35 if (!StringUtils.isEmpty(classname) && !classname.equals(this.getClass().getCanonicalName())) {
120  34 Uberspect u = instantiateUberspector(classname);
121  34 if (u == null) {
122  3 return;
123    }
124   
125    // Set the log and runtime services, if applicable
126  31 if (u instanceof UberspectLoggable) {
127  31 ((UberspectLoggable) u).setLog(this.log);
128    }
129  31 if (u instanceof RuntimeServicesAware) {
130  11 ((RuntimeServicesAware) u).setRuntimeServices(this.runtime);
131    }
132   
133    // Link it in the chain
134  31 if (u instanceof ChainableUberspector) {
135  5 ((ChainableUberspector) u).wrap(this.inner);
136  26 } else if (u instanceof org.apache.velocity.util.introspection.ChainableUberspector) {
137  10 ((org.apache.velocity.util.introspection.ChainableUberspector) u).wrap(this.inner);
138    }
139  31 this.inner = u;
140    }
141    }
142   
143    /**
144    * Tries to create an uberspector instance using reflection.
145    *
146    * @param classname The name of the uberspector class to instantiate.
147    * @return An instance of the specified Uberspector. If the class cannot be instantiated using the default
148    * constructor, or does not implement {@link Uberspect}, <code>null</code> is returned.
149    */
 
150  34 toggle protected Uberspect instantiateUberspector(String classname)
151    {
152  34 Object o = null;
153  34 try {
154  34 o = ClassUtils.getNewInstance(classname);
155    } catch (ClassNotFoundException cnfe) {
156  0 this.log.warn(String.format("The specified uberspector [%s]"
157    + " does not exist or is not accessible to the current classloader.", classname));
158    } catch (IllegalAccessException e) {
159  1 this.log.warn(String.format("The specified uberspector [%s] does not have a public default constructor.",
160    classname));
161    } catch (InstantiationException e) {
162  1 this.log.warn(String.format("The specified uberspector [%s] cannot be instantiated.", classname));
163    } catch (ExceptionInInitializerError e) {
164  0 this.log.warn(String.format("Exception while instantiating the Uberspector [%s]: %s", classname, e
165    .getMessage()));
166    }
167   
168  34 if (!(o instanceof Uberspect)) {
169  3 if (o != null) {
170  1 this.log.warn("The specified class for Uberspect [" + classname + "] does not implement "
171    + Uberspect.class.getName());
172    }
173  3 return null;
174    }
175  31 return (Uberspect) o;
176    }
177    }