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

File DefaultWikiComponentManager.java

 

Coverage histogram

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

Code metrics

14
63
8
1
246
150
21
0.33
7.88
8
2.62

Classes

Class Line # Actions
DefaultWikiComponentManager 58 63 0% 21 10
0.8823529588.2%
 

Contributing tests

This file is covered by 3 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.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: 7b89504ac52846d1b8b08e2eb24fc580e0bf7a65 $
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<EntityReference, List<WikiComponent>> registeredComponents = new ConcurrentHashMap<>();
84   
 
85  1904 toggle @Override
86    public void registerWikiComponent(WikiComponent component) throws WikiComponentException
87    {
88    // Save current context information
89  1904 DocumentReference currentUserReference = this.wikiComponentManagerContext.getCurrentUserReference();
90  1904 EntityReference currentEntityReference = this.wikiComponentManagerContext.getCurrentEntityReference();
91   
92  1904 try {
93    // Get the component role interface
94  1904 Type roleType = component.getRoleType();
95  1904 Class< ? > roleTypeClass = ReflectionUtils.getTypeClass(roleType);
96  1904 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  1904 this.wikiComponentManagerContext.setCurrentUserReference(component.getAuthorReference());
100  1904 this.wikiComponentManagerContext.setCurrentEntityReference(component.getEntityReference());
101   
102    // Since we are responsible to create the component instance, we also are responsible of its initialization
103  1904 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  1904 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  1904 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  1904 this.wikiComponentManagerContext.setCurrentUserReference(currentUserReference);
125  1904 this.wikiComponentManagerContext.setCurrentEntityReference(currentEntityReference);
126    }
127    }
128   
 
129  1904 toggle private void cacheWikiComponent(WikiComponent component)
130    {
131  1904 List<WikiComponent> wikiComponents = this.registeredComponents.get(component.getEntityReference());
132  1904 if (wikiComponents == null) {
133  1903 wikiComponents = new ArrayList<>();
134  1903 this.registeredComponents.put(component.getEntityReference(), wikiComponents);
135    }
136  1904 if (!wikiComponents.contains(component)) {
137  1903 wikiComponents.add(component);
138    }
139    }
140   
 
141  2 toggle @Override
142    public void unregisterWikiComponents(DocumentReference reference) throws WikiComponentException
143    {
144  2 this.unregisterWikiComponents((EntityReference) reference);
145    }
146   
 
147  10456 toggle @Override
148    public void unregisterWikiComponents(EntityReference reference) throws WikiComponentException
149    {
150  10456 List<WikiComponent> wikiComponents = this.registeredComponents.get(reference);
151  10456 if (wikiComponents != null) {
152  247 Iterator<WikiComponent> iterator = wikiComponents.iterator();
153  494 while (iterator.hasNext()) {
154  247 unregisterWikiComponent(iterator);
155    }
156    // Clean up wiki component cache for the passed reference, if it doesn't contain any wiki component
157  247 wikiComponents = this.registeredComponents.get(reference);
158  247 if (wikiComponents.isEmpty()) {
159  247 this.registeredComponents.remove(reference);
160    }
161    }
162    }
163   
 
164  247 toggle private void unregisterWikiComponent(Iterator<WikiComponent> iterator)
165    throws WikiComponentException
166    {
167  247 WikiComponent wikiComponent = iterator.next();
168   
169    // Save current context information
170  247 DocumentReference currentUserReference = this.wikiComponentManagerContext.getCurrentUserReference();
171  247 EntityReference currentEntityReference = this.wikiComponentManagerContext.getCurrentEntityReference();
172  247 try {
173    // Set the proper information so the component manager use the proper keys to find components to
174    // unregister
175  247 this.wikiComponentManagerContext.setCurrentUserReference(wikiComponent.getAuthorReference());
176  247 this.wikiComponentManagerContext.setCurrentEntityReference(wikiComponent.getEntityReference());
177    // Remove from the Component Manager
178  247 getComponentManager(wikiComponent.getScope()).unregisterComponent(wikiComponent.getRoleType(),
179    wikiComponent.getRoleHint());
180    // Remove from the wiki component cache
181  247 iterator.remove();
182    } catch (ComponentLookupException e) {
183  0 throw new WikiComponentException(String.format("Failed to find a component manager for scope [%s]",
184    wikiComponent.getScope()), e);
185    } finally {
186  247 this.wikiComponentManagerContext.setCurrentUserReference(currentUserReference);
187  247 this.wikiComponentManagerContext.setCurrentEntityReference(currentEntityReference);
188    }
189    }
190   
191    /**
192    * @param scope the scope required
193    * @return the Component Manager to use to register/unregister the wiki macro. The Component Manager to use depends
194    * on the macro scope. For example a macro that has the "current user" scope, it must be registered against
195    * the User Component Manager.
196    * @throws ComponentLookupException if the Component Manager for the specified scope cannot be found
197    */
 
198  2151 toggle private ComponentManager getComponentManager(WikiComponentScope scope) throws ComponentLookupException
199    {
200  2151 ComponentManager cm;
201   
202  2151 switch (scope) {
203  13 case USER:
204  13 cm = this.rootComponentManager.getInstance(ComponentManager.class, "user");
205  13 break;
206  920 case WIKI:
207  920 cm = this.rootComponentManager.getInstance(ComponentManager.class, "wiki");
208  920 break;
209  1218 default:
210  1218 cm = this.rootComponentManager;
211    }
212   
213  2151 return cm;
214    }
215   
216    /**
217    * Helper method to create a component descriptor from role and hint.
218    *
219    * @param roleType the component role type of the descriptor to create
220    * @param roleHint the hint of the implementation for the descriptor to create
221    * @return the constructed {@link ComponentDescriptor}
222    */
 
223  1904 toggle private ComponentDescriptor createComponentDescriptor(Type roleType, String roleHint)
224    {
225  1904 DefaultComponentDescriptor cd = new DefaultComponentDescriptor();
226  1904 cd.setRoleType(roleType);
227  1904 cd.setRoleHint(roleHint);
228  1904 return cd;
229    }
230   
231    /**
232    * Helper method that checks if at least one of an array of interfaces is the {@link Initializable} class.
233    *
234    * @param interfaces the array of interfaces to test
235    * @return true if at least one of the passed interfaces is the is the {@link Initializable} class.
236    */
 
237  1904 toggle private boolean isInitializable(Class< ? >[] interfaces)
238    {
239  1904 for (Class< ? > iface : interfaces) {
240  1906 if (Initializable.class.equals(iface)) {
241  0 return true;
242    }
243    }
244  1904 return false;
245    }
246    }