1 package com.atlassian.plugin.module;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4 import com.atlassian.plugin.PluginParseException;
5 import com.atlassian.plugin.Plugin;
6 import org.apache.commons.lang.Validate;
7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9
10 import java.util.Map;
11 import java.util.HashMap;
12 import java.util.Set;
13 import java.util.Collection;
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public class PrefixDelegatingModuleFactory implements ModuleFactory
33 {
34 Logger log = LoggerFactory.getLogger(PrefixDelegatingModuleFactory.class);
35 private final Map<String, ModuleFactory> delegateModuleFactories;
36
37 public PrefixDelegatingModuleFactory(Set<PrefixModuleFactory> delegates)
38 {
39 Map<String, ModuleFactory> factories = new HashMap<String, ModuleFactory>();
40 for (PrefixModuleFactory factory : delegates)
41 {
42 factories.put(factory.getPrefix(), factory);
43 }
44 this.delegateModuleFactories = factories;
45 }
46
47 public void addPrefixModuleFactory(PrefixModuleFactory prefixModuleFactory)
48 {
49 delegateModuleFactories.put(prefixModuleFactory.getPrefix(), prefixModuleFactory);
50 }
51
52
53
54
55
56
57
58
59 protected ModuleFactory getModuleFactoryForPrefix(final ModuleReference moduleReference, ModuleDescriptor<?> moduleDescriptor)
60 {
61 ModuleFactory moduleFactory = delegateModuleFactories.get(moduleReference.prefix);
62 if (moduleFactory == null)
63 {
64 Plugin plugin = moduleDescriptor.getPlugin();
65 if (plugin instanceof ContainerManagedPlugin)
66 {
67 Collection<PrefixModuleFactory> containerFactories = ((ContainerManagedPlugin) plugin).getContainerAccessor().getBeansOfType(PrefixModuleFactory.class);
68 for (PrefixModuleFactory prefixModuleFactory : containerFactories)
69 {
70 if (moduleReference.prefix.equals(prefixModuleFactory.getPrefix()))
71 {
72 moduleFactory = prefixModuleFactory;
73 break;
74 }
75 }
76 }
77 }
78
79 return moduleFactory;
80 }
81
82
83 public <T> T createModule(String className, final ModuleDescriptor<T> moduleDescriptor) throws PluginParseException
84 {
85 Validate.notNull(className, "The className cannot be null");
86 Validate.notNull(moduleDescriptor, "The moduleDescriptor cannot be null");
87
88 final ModuleReference moduleReference = getBeanReference(className);
89
90 Object result = null;
91
92 final ModuleFactory moduleFactory = getModuleFactoryForPrefix(moduleReference, moduleDescriptor);
93 if (moduleFactory == null)
94 {
95 throw new PluginParseException("Failed to create a module. Prefix '" + moduleReference.prefix + "' not supported");
96 }
97 try
98 {
99 result = moduleFactory.createModule(moduleReference.beanIdentifier, moduleDescriptor);
100 }
101 catch (NoClassDefFoundError error)
102 {
103 log.error("Detected an error (NoClassDefFoundError) instantiating the module for plugin '" + moduleDescriptor.getPlugin().getKey() + "'" + " for module '" + moduleDescriptor.getKey() + "': " + error.getMessage() + ". This error is usually caused by your" + " plugin using a imported component class that itself relies on other packages in the product. You can probably fix this by" + " adding the missing class's package to your <Import-Package> instructions; for more details on how to fix this, see" + " http://confluence.atlassian.com/x/QRS-Cg .");
104 throw error;
105 }
106 catch (LinkageError error)
107 {
108 log.error("Detected an error (LinkageError) instantiating the module for plugin '" + moduleDescriptor.getPlugin().getKey() + "'" + " for module '" + moduleDescriptor.getKey() + "': " + error.getMessage() + ". This error is usually caused by your" + " plugin including copies of libraries in META-INF/lib unnecessarily. For more details on how to fix this, see" + " http://confluence.atlassian.com/x/yQEhCw .");
109 throw error;
110 }
111 catch (RuntimeException ex)
112 {
113 if (ex.getClass().getSimpleName().equals("UnsatisfiedDependencyException"))
114 {
115 log.error("Detected an error instantiating the module via Spring. This usually means that you haven't created a " + "<component-import> for the interface you're trying to use. See http://confluence.atlassian.com/x/kgL3CQ " + " for more details.");
116 }
117 throw ex;
118 }
119
120 if (result != null)
121 {
122 return (T) result;
123 }
124 else
125 {
126 throw new PluginParseException("Unable to create module instance from '" + className + "'");
127 }
128 }
129
130
131 private ModuleReference getBeanReference(String className)
132 {
133 String prefix = "class";
134 final int prefixIndex = className.indexOf(":");
135 if (prefixIndex != -1)
136 {
137 prefix = className.substring(0, prefixIndex);
138 className = className.substring(prefixIndex + 1);
139 }
140 return new ModuleReference(prefix, className);
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155 @Deprecated
156 public <T> Class<T> guessModuleClass(final String name, final ModuleDescriptor<T> moduleDescriptor) throws ModuleClassNotFoundException
157 {
158 Validate.notNull(name, "The class name cannot be null");
159 Validate.notNull(moduleDescriptor, "The module descriptor cannot be null");
160
161 final ModuleReference moduleReference = getBeanReference(name);
162
163 final ModuleFactory moduleFactory = getModuleFactoryForPrefix(moduleReference, moduleDescriptor);
164 Class<T> result = null;
165 if (moduleFactory instanceof ClassPrefixModuleFactory)
166 {
167 result = ((ClassPrefixModuleFactory) moduleFactory).getModuleClass(moduleReference.beanIdentifier, moduleDescriptor);
168 }
169
170 return result;
171
172 }
173
174 private static class ModuleReference
175 {
176 public String prefix;
177 public String beanIdentifier;
178
179 ModuleReference(String prefix, String beanIdentifier)
180 {
181 this.prefix = prefix;
182 this.beanIdentifier = beanIdentifier;
183 }
184 }
185 }