View Javadoc

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