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

File LinkingUberspector.java

 

Coverage histogram

../../../../img/srcFileCovDistChart7.png
64% of files have more coverage

Code metrics

22
57
8
1
233
139
25
0.44
7.12
8
3.12

Classes

Class Line # Actions
LinkingUberspector 67 57 0% 25 31
0.643678264.4%
 

Contributing tests

This file is covered by 6 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 java.util.ArrayList;
23    import java.util.Iterator;
24    import java.util.List;
25   
26    import org.apache.commons.lang3.StringUtils;
27    import org.apache.velocity.runtime.RuntimeServices;
28    import org.apache.velocity.util.ClassUtils;
29    import org.apache.velocity.util.RuntimeServicesAware;
30    import org.apache.velocity.util.introspection.Info;
31    import org.apache.velocity.util.introspection.Uberspect;
32    import org.apache.velocity.util.introspection.UberspectImpl;
33    import org.apache.velocity.util.introspection.UberspectLoggable;
34    import org.apache.velocity.util.introspection.VelMethod;
35    import org.apache.velocity.util.introspection.VelPropertyGet;
36    import org.apache.velocity.util.introspection.VelPropertySet;
37   
38    /**
39    * <p>
40    * Since the current version of the Velocity engine (1.5) does not allow more than one uberspector, this class is a
41    * workaround. It manually constructs an <strong>array of uberspectors</strong>, loading the classes in the order
42    * defined in the <code>"runtime.introspector.uberspect.arrayClasses"</code> property, and after that forwards calls to
43    * each of the uberspectors, in order, until one of them returns something different than <code>null</code>. Note that
44    * the calls will be made from the leftmost class to the rightmost one. This allows building and combining different
45    * small uberspectors that perform a specialised search for methods, instead of bloating a single class with different
46    * introspection tricks.
47    * </p>
48    * <p>
49    * This is not actually part of the array, but is more of a handle that allows the calls intended for only one
50    * uberspector to reach the array. It duplicates some of the code from the velocity runtime initialization code, hoping
51    * that a future version of the engine will support this natively.
52    * </p>
53    * <p>
54    * The array is defined using the configuration parameter <code>runtime.introspector.uberspect.arrayClasses</code>. This
55    * property should contain a list of canonical class names. Any wrong entry in the list will be ignored. If this
56    * property is not defined or contains only wrong classnames, then by default a <code>SecureUberspector</code> is used
57    * as the only entry in the array.
58    * </p>
59    *
60    * @since 1.5RC1
61    * @see ChainingUberspector
62    * @version $Id: a3aaea25b5e99e858970ed11023e74f805d99191 $
63    * @deprecated since 8.0M1; chaining uberspectors is much more powerful, this class was never more than a proof of
64    * concept
65    */
66    @Deprecated
 
67    public class LinkingUberspector extends UberspectImpl implements Uberspect, RuntimeServicesAware, UberspectLoggable
68    {
69    /** The key of the parameter that allows defining the array of uberspectors. */
70    public static final String UBERSPECT_ARRAY_CLASSNAMES = "runtime.introspector.uberspect.arrayClasses";
71   
72    /** The runtime is needed for accessing the configuration. */
73    private RuntimeServices runtime;
74   
75    /** The array of uberspectors to use. */
76    private List<Uberspect> uberspectors;
77   
 
78  6 toggle @Override
79    public void setRuntimeServices(RuntimeServices rs)
80    {
81  6 this.runtime = rs;
82    }
83   
84    /**
85    * {@inheritDoc}
86    * <p>
87    * This implementation initializes the array of uberspectors.
88    * </p>
89    *
90    * @see org.apache.velocity.util.introspection.Uberspect#init()
91    */
 
92  6 toggle @Override
93    public void init()
94    {
95  6 this.log.debug("Initializing the linking uberspector.");
96    // Create the array
97  6 String[] arrayClassnames = this.runtime.getConfiguration().getStringArray(UBERSPECT_ARRAY_CLASSNAMES);
98  6 this.uberspectors = new ArrayList<Uberspect>(arrayClassnames.length);
99  6 for (String classname : arrayClassnames) {
100  13 initializeUberspector(classname);
101    }
102    // If the chain is empty, use a SecureUberspector
103  6 if (this.uberspectors.isEmpty()) {
104  1 this.log.error("No uberspectors defined! "
105    + "This uberspector is just a placeholder that relies on at least one real uberspector "
106    + "to actually allow method calls. Using SecureUberspector instead as a fallback.");
107  1 initializeUberspector(SecureUberspector.class.getCanonicalName());
108    }
109    }
110   
111    /**
112    * Instantiates and initializes an uberspector class and adds it to the array. Also set the log and runtime
113    * services, if the class implements the proper interfaces.
114    *
115    * @param classname The name of the uberspector class to add to the chain.
116    */
 
117  14 toggle protected void initializeUberspector(String classname)
118    {
119    // Avoids direct recursive calls
120  14 if (!StringUtils.isEmpty(classname) && !classname.equals(this.getClass().getCanonicalName())) {
121  13 Uberspect u = instantiateUberspector(classname);
122  13 if (u == null) {
123  3 return;
124    }
125   
126    // Set the log and runtime services, if applicable
127  10 if (u instanceof UberspectLoggable) {
128  10 ((UberspectLoggable) u).setLog(this.log);
129    }
130  10 if (u instanceof RuntimeServicesAware) {
131  2 ((RuntimeServicesAware) u).setRuntimeServices(this.runtime);
132    }
133   
134    // Initialize the uberspector
135  10 try {
136  10 u.init();
137    // Add it to the array
138  10 this.uberspectors.add(u);
139    } catch (Exception e) {
140  0 this.log.warn(e.getMessage());
141    // If the initialization failed, don't add this uberspector to the chain.
142    }
143    }
144    }
145   
146    /**
147    * Tries to create an uberspector instance using reflection.
148    *
149    * @param classname The name of the uberspector class to instantiate.
150    * @return An instance of the specified Uberspector. If the class cannot be instantiated using the default
151    * constructor, or does not implement {@link Uberspect}, <code>null</code> is returned.
152    */
 
153  13 toggle protected Uberspect instantiateUberspector(String classname)
154    {
155  13 Object o = null;
156  13 try {
157  13 o = ClassUtils.getNewInstance(classname);
158    } catch (ClassNotFoundException e) {
159  0 this.log.warn(String.format("The specified uberspector [%s]"
160    + " does not exist or is not accessible to the current classloader.", classname));
161    } catch (IllegalAccessException e) {
162  1 this.log.warn(String.format("The specified uberspector [%s] does not have a public default constructor.",
163    classname));
164    } catch (InstantiationException e) {
165  1 this.log.warn(String.format("The specified uberspector [%s] cannot be instantiated.", classname));
166    } catch (ExceptionInInitializerError e) {
167  0 this.log.warn(String.format("Exception while instantiating the Uberspector [%s]: %s", classname, e
168    .getMessage()));
169    }
170   
171  13 if (!(o instanceof Uberspect)) {
172  3 if (o != null) {
173  1 this.log.warn("The specified class for Uberspect [" + classname + "] does not implement "
174    + Uberspect.class.getName());
175    }
176  3 return null;
177    }
178  10 return (Uberspect) o;
179    }
180   
 
181  0 toggle @SuppressWarnings("unchecked")
182    @Override
183    public Iterator getIterator(Object obj, Info i) throws Exception
184    {
185  0 Iterator it;
186  0 for (Uberspect u : this.uberspectors) {
187  0 it = u.getIterator(obj, i);
188  0 if (it != null) {
189  0 return it;
190    }
191    }
192  0 return null;
193    }
194   
 
195  9 toggle @Override
196    public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) throws Exception
197    {
198  9 VelMethod method;
199  9 for (Uberspect u : this.uberspectors) {
200  12 method = u.getMethod(obj, methodName, args, i);
201  12 if (method != null) {
202  6 return method;
203    }
204    }
205  3 return null;
206    }
207   
 
208  0 toggle @Override
209    public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) throws Exception
210    {
211  0 VelPropertyGet getter;
212  0 for (Uberspect u : this.uberspectors) {
213  0 getter = u.getPropertyGet(obj, identifier, i);
214  0 if (getter != null) {
215  0 return getter;
216    }
217    }
218  0 return null;
219    }
220   
 
221  0 toggle @Override
222    public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) throws Exception
223    {
224  0 VelPropertySet setter;
225  0 for (Uberspect u : this.uberspectors) {
226  0 setter = u.getPropertySet(obj, identifier, arg, i);
227  0 if (setter != null) {
228  0 return setter;
229    }
230    }
231  0 return null;
232    }
233    }