View Javadoc

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