1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.component.wiki.internal

File DefaultWikiComponentManager.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

14
62
7
1
240
145
20
0.32
8.86
7
2.86

Classes

Class Line # Actions
DefaultWikiComponentManager 58 62 0% 20 13
0.843373584.3%
 

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.Type;
23    import java.util.ArrayList;
24    import java.util.Iterator;
25    import java.util.List;
26    import java.util.Map;
27    import java.util.concurrent.ConcurrentHashMap;
28   
29    import javax.inject.Inject;
30    import javax.inject.Singleton;
31   
32    import org.slf4j.Logger;
33    import org.xwiki.component.annotation.Component;
34    import org.xwiki.component.descriptor.ComponentDescriptor;
35    import org.xwiki.component.descriptor.DefaultComponentDescriptor;
36    import org.xwiki.component.manager.ComponentLookupException;
37    import org.xwiki.component.manager.ComponentManager;
38    import org.xwiki.component.manager.ComponentRepositoryException;
39    import org.xwiki.component.phase.Initializable;
40    import org.xwiki.component.phase.InitializationException;
41    import org.xwiki.component.util.ReflectionUtils;
42    import org.xwiki.component.wiki.WikiComponent;
43    import org.xwiki.component.wiki.WikiComponentException;
44    import org.xwiki.component.wiki.WikiComponentManager;
45    import org.xwiki.component.wiki.WikiComponentScope;
46    import org.xwiki.model.reference.DocumentReference;
47    import org.xwiki.model.reference.EntityReference;
48   
49    /**
50    * Default implementation of {@link WikiComponentManager}. Creates proxy objects which method invocation handler keeps a
51    * reference on a set of declared method and associated wiki content to "execute".
52    *
53    * @version $Id: 3cd46bf8f21fd0680045b55bef57e1ab15de863a $
54    * @since 4.2M3
55    */
56    @Component
57    @Singleton
 
58    public class DefaultWikiComponentManager implements WikiComponentManager
59    {
60    /**
61    * The logger to log.
62    */
63    @Inject
64    private Logger logger;
65   
66    /**
67    * Component managers in which wiki component can be registered.
68    */
69    @Inject
70    private ComponentManager rootComponentManager;
71   
72    /**
73    * Allows to get and set context user and reference.
74    */
75    @Inject
76    private WikiComponentManagerContext wikiComponentManagerContext;
77   
78    /**
79    * Map of registered components. We need to keep a cache because wiki components can be components of various
80    * Role Types and we cannot ask the Component Manager for wiki component only (which we need to do when we need to
81    * unregister them). A wiki page can hold one or several wiki components.
82    */
83    private Map<DocumentReference, List<WikiComponent>> registeredComponents = new ConcurrentHashMap<>();
84   
 
85  312 toggle @Override
86    public void registerWikiComponent(WikiComponent component) throws WikiComponentException
87    {
88    // Save current context information
89  312 DocumentReference currentUserReference = this.wikiComponentManagerContext.getCurrentUserReference();
90  312 EntityReference currentEntityReference = this.wikiComponentManagerContext.getCurrentEntityReference();
91   
92  312 try {
93    // Get the component role interface
94  312 Type roleType = component.getRoleType();
95  312 Class< ? > roleTypeClass = ReflectionUtils.getTypeClass(roleType);
96  312 ComponentDescriptor componentDescriptor = createComponentDescriptor(roleType, component.getRoleHint());
97   
98    // Set the proper information so the component manager use the proper keys to find components to register
99  312 this.wikiComponentManagerContext.setCurrentUserReference(component.getAuthorReference());
100  312 this.wikiComponentManagerContext.setCurrentEntityReference(component.getDocumentReference());
101   
102    // Since we are responsible to create the component instance, we also are responsible of its initialization
103  312 if (this.isInitializable(component.getClass().getInterfaces())) {
104  0 try {
105  0 ((Initializable) component).initialize();
106    } catch (InitializationException e) {
107  0 this.logger.error("Failed to initialize wiki component", e);
108    }
109    }
110   
111    // Register the wiki component against the Component Manager
112  312 getComponentManager(component.getScope()).registerComponent(componentDescriptor,
113    roleTypeClass.cast(component));
114   
115    // And add it the wiki component cache so that we can remove it later on. We need to do this since we need
116    // to be able to unregister a wiki component associated with a wiki page
117  312 cacheWikiComponent(component);
118    } catch (ComponentLookupException e) {
119  0 throw new WikiComponentException(String.format("Failed to find a component manager for scope [%s] wiki "
120    + "component registration failed", component.getScope()), e);
121    } catch (ComponentRepositoryException e) {
122  0 throw new WikiComponentException("Failed to register wiki component against component repository", e);
123    } finally {
124  312 this.wikiComponentManagerContext.setCurrentUserReference(currentUserReference);
125  312 this.wikiComponentManagerContext.setCurrentEntityReference(currentEntityReference);
126    }
127    }
128   
 
129  312 toggle private void cacheWikiComponent(WikiComponent component)
130    {
131  312 List<WikiComponent> wikiComponents = this.registeredComponents.get(component.getDocumentReference());
132  312 if (wikiComponents == null) {
133  310 wikiComponents = new ArrayList<>();
134  310 this.registeredComponents.put(component.getDocumentReference(), wikiComponents);
135    }
136  312 if (!wikiComponents.contains(component)) {
137  311 wikiComponents.add(component);
138    }
139    }
140   
 
141  3968 toggle @Override
142    public void unregisterWikiComponents(DocumentReference reference) throws WikiComponentException
143    {
144  3968 List<WikiComponent> wikiComponents = this.registeredComponents.get(reference);
145  3968 if (wikiComponents != null) {
146  7 Iterator<WikiComponent> iterator = wikiComponents.iterator();
147  14 while (iterator.hasNext()) {
148  7 unregisterWikiComponent(iterator);
149    }
150    // Clean up wiki component cache for the passed reference, if it doesn't contain any wiki component
151  7 wikiComponents = this.registeredComponents.get(reference);
152  7 if (wikiComponents.isEmpty()) {
153  7 this.registeredComponents.remove(reference);
154    }
155    }
156    }
157   
 
158  7 toggle private void unregisterWikiComponent(Iterator<WikiComponent> iterator)
159    throws WikiComponentException
160    {
161  7 WikiComponent wikiComponent = iterator.next();
162   
163    // Save current context information
164  7 DocumentReference currentUserReference = this.wikiComponentManagerContext.getCurrentUserReference();
165  7 EntityReference currentEntityReference = this.wikiComponentManagerContext.getCurrentEntityReference();
166  7 try {
167    // Set the proper information so the component manager use the proper keys to find components to
168    // unregister
169  7 this.wikiComponentManagerContext.setCurrentUserReference(wikiComponent.getAuthorReference());
170  7 this.wikiComponentManagerContext.setCurrentEntityReference(wikiComponent.getDocumentReference());
171    // Remove from the Component Manager
172  7 getComponentManager(wikiComponent.getScope()).unregisterComponent(wikiComponent.getRoleType(),
173    wikiComponent.getRoleHint());
174    // Remove from the wiki component cache
175  7 iterator.remove();
176    } catch (ComponentLookupException e) {
177  0 throw new WikiComponentException(String.format("Failed to find a component manager for scope [%s]",
178    wikiComponent.getScope()), e);
179    } finally {
180  7 this.wikiComponentManagerContext.setCurrentUserReference(currentUserReference);
181  7 this.wikiComponentManagerContext.setCurrentEntityReference(currentEntityReference);
182    }
183    }
184   
185    /**
186    * @param scope the scope required
187    * @return the Component Manager to use to register/unregister the wiki macro. The Component Manager to use depends
188    * on the macro scope. For example a macro that has the "current user" scope, it must be registered against
189    * the User Component Manager.
190    * @throws ComponentLookupException if the Component Manager for the specified scope cannot be found
191    */
 
192  319 toggle private ComponentManager getComponentManager(WikiComponentScope scope) throws ComponentLookupException
193    {
194  319 ComponentManager cm;
195   
196  319 switch (scope) {
197  0 case USER:
198  0 cm = this.rootComponentManager.getInstance(ComponentManager.class, "user");
199  0 break;
200  135 case WIKI:
201  135 cm = this.rootComponentManager.getInstance(ComponentManager.class, "wiki");
202  135 break;
203  184 default:
204  184 cm = this.rootComponentManager;
205    }
206   
207  319 return cm;
208    }
209   
210    /**
211    * Helper method to create a component descriptor from role and hint.
212    *
213    * @param roleType the component role type of the descriptor to create
214    * @param roleHint the hint of the implementation for the descriptor to create
215    * @return the constructed {@link ComponentDescriptor}
216    */
 
217  312 toggle private ComponentDescriptor createComponentDescriptor(Type roleType, String roleHint)
218    {
219  312 DefaultComponentDescriptor cd = new DefaultComponentDescriptor();
220  312 cd.setRoleType(roleType);
221  312 cd.setRoleHint(roleHint);
222  312 return cd;
223    }
224   
225    /**
226    * Helper method that checks if at least one of an array of interfaces is the {@link Initializable} class.
227    *
228    * @param interfaces the array of interfaces to test
229    * @return true if at least one of the passed interfaces is the is the {@link Initializable} class.
230    */
 
231  312 toggle private boolean isInitializable(Class< ? >[] interfaces)
232    {
233  312 for (Class< ? > iface : interfaces) {
234  624 if (Initializable.class.equals(iface)) {
235  0 return true;
236    }
237    }
238  312 return false;
239    }
240    }