1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.component.wiki.internal

File DefaultWikiComponentInvocationHandler.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart1.png
85% of files have more coverage

Code metrics

8
24
3
1
156
78
9
0.38
8
3
3

Classes

Class Line # Actions
DefaultWikiComponentInvocationHandler 46 24 0% 9 32
0.085714298.6%
 

Contributing tests

This file is covered by 1 test. .

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.component.wiki.internal;
21   
22    import java.lang.reflect.InvocationHandler;
23    import java.lang.reflect.Method;
24    import java.lang.reflect.ParameterizedType;
25    import java.util.HashMap;
26    import java.util.List;
27    import java.util.Map;
28   
29    import org.slf4j.Logger;
30    import org.slf4j.LoggerFactory;
31    import org.xwiki.component.descriptor.ComponentDescriptor;
32    import org.xwiki.component.manager.ComponentLookupException;
33    import org.xwiki.component.manager.ComponentManager;
34    import org.xwiki.component.util.ReflectionUtils;
35    import org.xwiki.component.wiki.WikiComponent;
36    import org.xwiki.component.wiki.WikiComponentRuntimeException;
37    import org.xwiki.rendering.block.XDOM;
38   
39    /**
40    * Method invocation handler for wiki component proxy instances. Has a reference on a map of name/body wiki code of
41    * supported methods.
42    *
43    * @version $Id: 53ed15cc3861dad8569e69c20278f2857a6e2b1e $
44    * @since 4.2M3
45    */
 
46    public class DefaultWikiComponentInvocationHandler implements InvocationHandler
47    {
48    /**
49    * The key under which the component reference (a virtual "this") is kept in the method invocation context.
50    */
51    private static final String METHOD_CONTEXT_COMPONENT_KEY = "component";
52   
53    /**
54    * The logger to log.
55    */
56    private final Logger logger = LoggerFactory.getLogger(DefaultWikiComponentInvocationHandler.class);
57   
58    /**
59    * Our component manager.
60    */
61    private ComponentManager componentManager;
62   
63    /**
64    * The proxied wiki component.
65    */
66    private DefaultWikiComponent wikiComponent;
67   
68    /**
69    * Constructor of this invocation handler.
70    *
71    * @param wikiComponent the proxied wiki component
72    * @param componentManager the component manager
73    */
 
74  1 toggle public DefaultWikiComponentInvocationHandler(DefaultWikiComponent wikiComponent, ComponentManager componentManager)
75    {
76  1 this.wikiComponent = wikiComponent;
77  1 this.componentManager = componentManager;
78    }
79   
80    /**
81    * Retrieves the wiki component dependencies from the component manager and puts them in the method context under
82    * the configured key.
83    *
84    * @param methodContext The context where the dependencies must be injected
85    */
 
86  0 toggle private void injectComponentDependencies(Map<String, Object> methodContext)
87    {
88  0 for (Map.Entry<String, ComponentDescriptor> dependency : this.wikiComponent.getDependencies().entrySet()) {
89  0 ComponentDescriptor cd = dependency.getValue();
90  0 Class<?> roleTypeClass = ReflectionUtils.getTypeClass(cd.getRoleType());
91  0 Object componentDependency = null;
92  0 try {
93  0 if (roleTypeClass.isAssignableFrom(List.class)) {
94    // If the ParameterizedType is a List, the raw Type is the List Class and the first Type argument
95    // is the actual component (which can be a ParameterizedType itself).
96    // Example: java.util.List<org.xwiki.model.reference.EntityReferenceSerializer<java.lang.String>>
97    // raw Type: java.util.List
98    // Type arguments [0]: org.xwiki.model.reference.EntityReferenceSerializer<java.lang.String>
99  0 componentDependency =
100    componentManager.getInstanceList(
101    ((ParameterizedType) cd.getRoleType()).getActualTypeArguments()[0]);
102  0 } else if (roleTypeClass.isAssignableFrom(Map.class)) {
103    // If the ParameterizedType is a Map, the raw Type is the Map, the first argument can only be a
104    // String in our implementation and the second argument is the actual component.
105    // Example: java.util.Map<java.lang.String,
106    // org.xwiki.model.reference.EntityReferenceSerializer<java.lang.String>>
107    // raw Type: java.util.Map
108    // Type arguments [0]: java.lang.String
109    // [1]: org.xwiki.model.reference.EntityReferenceSerializer<java.lang.String>
110  0 componentDependency = componentManager.getInstanceMap(
111    ((ParameterizedType) cd.getRoleType()).getActualTypeArguments()[1]);
112    } else {
113    // Not a List or a Map, note that the role Type can be a ParameterizedType itself
114    // Example: org.xwiki.model.reference.EntityReferenceSerializer<java.lang.String>
115  0 componentDependency = componentManager.getInstance(cd.getRoleType(), cd.getRoleHint());
116    }
117    } catch (ComponentLookupException e) {
118  0 this.logger.warn(String.format(
119    "No component found for role [%s] with hint [%s], declared as dependency for wiki component [%s]",
120    cd.getRoleType().toString(), cd.getRoleHint(), this.wikiComponent.getDocumentReference()));
121    }
122  0 methodContext.put(dependency.getKey(), componentDependency);
123    }
124    }
125   
 
126  0 toggle @Override
127    public Object invoke(Object proxy, Method method, Object[] args) throws Exception
128    {
129    // We look for the method in the XObjects.
130  0 if (!this.wikiComponent.getHandledMethods().containsKey(method.getName())) {
131  0 if (method.getDeclaringClass() == Object.class || method.getDeclaringClass() == WikiComponent.class) {
132    // return ObjectMethodsProxy.invoke(proxy, method, args);
133  0 return method.invoke(wikiComponent, args);
134    } else {
135    // Note: We throw a runtime exception so that our exception doesn't get wrapped by a generic
136    // UndeclaredThrowableException which would not make much sense for the user.
137    // See http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/UndeclaredThrowableException.html
138  0 throw new WikiComponentRuntimeException(
139    String.format("You need to add an Object of type [%s] in document [%s] to implement method [%s.%s]",
140    WikiComponentConstants.METHOD_CLASS,
141    this.wikiComponent.getDocumentReference(),
142    method.getDeclaringClass().getName(),
143    method.getName()));
144    }
145    } else {
146  0 WikiComponentMethodExecutor methodExecutor =
147    componentManager.getInstance(WikiComponentMethodExecutor.class);
148  0 Map<String, Object> methodContext = new HashMap<String, Object>();
149  0 XDOM xdom = this.wikiComponent.getHandledMethods().get(method.getName());
150  0 methodContext.put(METHOD_CONTEXT_COMPONENT_KEY, proxy);
151  0 this.injectComponentDependencies(methodContext);
152  0 return methodExecutor.execute(method, args, wikiComponent.getDocumentReference(), xdom,
153    wikiComponent.getSyntax(), methodContext);
154    }
155    }
156    }