View Javadoc

1   package com.atlassian.plugin;
2   
3   import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
4   import com.atlassian.plugin.hostcontainer.HostContainer;
5   import com.atlassian.plugin.util.ClassLoaderUtils;
6   import com.atlassian.util.concurrent.CopyOnWriteMap;
7   import org.slf4j.Logger;
8   import org.slf4j.LoggerFactory;
9   
10  import java.util.ArrayList;
11  import java.util.Collections;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Map.Entry;
15  
16  import static java.util.Collections.unmodifiableMap;
17  
18  /**
19   * Default implementation of a descriptor factory that allows filtering of
20   * descriptor keys
21   */
22  public class DefaultModuleDescriptorFactory implements ModuleDescriptorFactory
23  {
24      private static Logger log = LoggerFactory.getLogger(DefaultModuleDescriptorFactory.class);
25  
26      private final Map<String, Class<? extends ModuleDescriptor>> moduleDescriptorClasses = CopyOnWriteMap.<String, Class<? extends ModuleDescriptor>> builder().stableViews()
27          .newHashMap();
28      private final List<String> permittedModuleKeys = new ArrayList<String>();
29      private final HostContainer hostContainer;
30  
31      /**
32       * @deprecated Since 2.2.0, use
33       *             {@link #DefaultModuleDescriptorFactory(HostContainer)}
34       *             instead
35       */
36      @Deprecated
37      public DefaultModuleDescriptorFactory()
38      {
39          this(new DefaultHostContainer());
40      }
41  
42      /**
43       * Instantiates a descriptor factory that uses the host container to create
44       * descriptors
45       * 
46       * @param hostContainer The host container implementation for descriptor
47       *            creation
48       * @since 2.2.0
49       */
50      public DefaultModuleDescriptorFactory(final HostContainer hostContainer)
51      {
52          this.hostContainer = hostContainer;
53      }
54  
55      public Class<? extends ModuleDescriptor> getModuleDescriptorClass(final String type)
56      {
57          return moduleDescriptorClasses.get(type);
58      }
59  
60      public ModuleDescriptor<?> getModuleDescriptor(final String type) throws PluginParseException, IllegalAccessException, InstantiationException, ClassNotFoundException
61      {
62          if (shouldSkipModuleOfType(type))
63          {
64              return null;
65          }
66  
67          final Class<? extends ModuleDescriptor> moduleDescriptorClazz = getModuleDescriptorClass(type);
68  
69          if (moduleDescriptorClazz == null)
70          {
71              throw new PluginParseException("Cannot find ModuleDescriptor class for plugin of type '" + type + "'.");
72          }
73  
74          return hostContainer.create(moduleDescriptorClazz);
75      }
76  
77      protected boolean shouldSkipModuleOfType(final String type)
78      {
79          synchronized (permittedModuleKeys)
80          {
81              return !permittedModuleKeys.isEmpty() && !permittedModuleKeys.contains(type);
82          }
83      }
84  
85      @SuppressWarnings("unused")
86      public void setModuleDescriptors(final Map<String, String> moduleDescriptorClassNames)
87      {
88          for (final Entry<String, String> entry : moduleDescriptorClassNames.entrySet())
89          {
90              final Class<ModuleDescriptor<?>> descriptorClass = getClassFromEntry(entry);
91              if (descriptorClass != null)
92              {
93                  addModuleDescriptor(entry.getKey(), descriptorClass);
94              }
95          }
96      }
97  
98      private <D extends ModuleDescriptor<?>> Class<D> getClassFromEntry(final Map.Entry<String, String> entry)
99      {
100         if (shouldSkipModuleOfType(entry.getKey()))
101         {
102             return null;
103         }
104 
105         try
106         {
107             final Class<D> descriptorClass = ClassLoaderUtils.loadClass(entry.getValue(), getClass());
108 
109             if (!ModuleDescriptor.class.isAssignableFrom(descriptorClass))
110             {
111                 log.error("Configured plugin module descriptor class " + entry.getValue() + " does not inherit from ModuleDescriptor");
112                 return null;
113             }
114             return descriptorClass;
115         }
116         catch (final ClassNotFoundException e)
117         {
118             log.error("Unable to add configured plugin module descriptor " + entry.getKey() + ". Class not found: " + entry.getValue());
119             return null;
120         }
121     }
122 
123     public boolean hasModuleDescriptor(final String type)
124     {
125         return moduleDescriptorClasses.containsKey(type);
126     }
127 
128     public void addModuleDescriptor(final String type, final Class<? extends ModuleDescriptor> moduleDescriptorClass)
129     {
130         moduleDescriptorClasses.put(type, moduleDescriptorClass);
131     }
132 
133     public void removeModuleDescriptorForType(final String type)
134     {
135         moduleDescriptorClasses.remove(type);
136     }
137 
138     protected final Map<String, Class<? extends ModuleDescriptor>> getDescriptorClassesMap()
139     {
140         return unmodifiableMap(moduleDescriptorClasses);
141     }
142 
143     /**
144      * Sets the list of module keys that will be loaded. If this list is empty,
145      * then the factory will permit all recognised module types to load. This
146      * allows you to run the plugin system in a 'restricted mode'
147      * 
148      * @param permittedModuleKeys List of (String) keys
149      */
150     public void setPermittedModuleKeys(List<String> permittedModuleKeys)
151     {
152         if (permittedModuleKeys == null)
153         {
154             permittedModuleKeys = Collections.emptyList();
155         }
156 
157         synchronized (this.permittedModuleKeys)
158         {
159             // synced
160             this.permittedModuleKeys.clear();
161             this.permittedModuleKeys.addAll(permittedModuleKeys);
162         }
163     }
164 }