1 package com.atlassian.plugin.module;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4 import com.atlassian.plugin.Plugin;
5 import com.atlassian.plugin.PluginParseException;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8
9 import java.util.Collection;
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.Set;
13
14 import static com.google.common.base.Preconditions.checkNotNull;
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public class PrefixDelegatingModuleFactory implements ModuleFactory
34 {
35 Logger log = LoggerFactory.getLogger(PrefixDelegatingModuleFactory.class);
36 private final Map<String, ModuleFactory> delegateModuleFactories;
37
38 public PrefixDelegatingModuleFactory(Set<PrefixModuleFactory> delegates)
39 {
40 Map<String, ModuleFactory> factories = new HashMap<String, ModuleFactory>();
41 for (PrefixModuleFactory factory : delegates)
42 {
43 factories.put(factory.getPrefix(), factory);
44 }
45 this.delegateModuleFactories = factories;
46 }
47
48 public void addPrefixModuleFactory(PrefixModuleFactory prefixModuleFactory)
49 {
50 delegateModuleFactories.put(prefixModuleFactory.getPrefix(), prefixModuleFactory);
51 }
52
53
54
55
56
57
58
59
60 protected ModuleFactory getModuleFactoryForPrefix(final ModuleReference moduleReference, ModuleDescriptor<?> moduleDescriptor)
61 {
62 ModuleFactory moduleFactory = delegateModuleFactories.get(moduleReference.prefix);
63 if (moduleFactory == null)
64 {
65 Plugin plugin = moduleDescriptor.getPlugin();
66 if (plugin instanceof ContainerManagedPlugin)
67 {
68 Collection<PrefixModuleFactory> containerFactories = ((ContainerManagedPlugin) plugin).getContainerAccessor().getBeansOfType(PrefixModuleFactory.class);
69 for (PrefixModuleFactory prefixModuleFactory : containerFactories)
70 {
71 if (moduleReference.prefix.equals(prefixModuleFactory.getPrefix()))
72 {
73 moduleFactory = prefixModuleFactory;
74 break;
75 }
76 }
77 }
78 }
79
80 return moduleFactory;
81 }
82
83
84 public <T> T createModule(String className, final ModuleDescriptor<T> moduleDescriptor) throws PluginParseException
85 {
86 checkNotNull(className, "The className cannot be null");
87 checkNotNull(moduleDescriptor, "The moduleDescriptor cannot be null");
88
89 final ModuleReference moduleReference = getBeanReference(className);
90
91 Object result = null;
92
93 final ModuleFactory moduleFactory = getModuleFactoryForPrefix(moduleReference, moduleDescriptor);
94 if (moduleFactory == null)
95 {
96 throw new PluginParseException("Failed to create a module. Prefix '" + moduleReference.prefix + "' not supported");
97 }
98 try
99 {
100 result = moduleFactory.createModule(moduleReference.beanIdentifier, moduleDescriptor);
101 }
102 catch (NoClassDefFoundError error)
103 {
104
105 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 https://developer.atlassian.com/display/DOCS/NoClassDefFoundError .");
106 throw error;
107 }
108 catch (LinkageError error)
109 {
110
111 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" + " https://developer.atlassian.com/x/EgAN .");
112 throw error;
113 }
114 catch (RuntimeException ex)
115 {
116 if (ex.getClass().getSimpleName().equals("UnsatisfiedDependencyException"))
117 {
118
119 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. https://developer.atlassian.com/x/TAEr " + " for more details.");
120 }
121 throw ex;
122 }
123
124 if (result != null)
125 {
126 return (T) result;
127 }
128 else
129 {
130 throw new PluginParseException("Unable to create module instance from '" + className + "'");
131 }
132 }
133
134
135 private ModuleReference getBeanReference(String className)
136 {
137 String prefix = "class";
138 final int prefixIndex = className.indexOf(":");
139 if (prefixIndex != -1)
140 {
141 prefix = className.substring(0, prefixIndex);
142 className = className.substring(prefixIndex + 1);
143 }
144 return new ModuleReference(prefix, className);
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159 @Deprecated
160 public <T> Class<T> guessModuleClass(final String name, final ModuleDescriptor<T> moduleDescriptor) throws ModuleClassNotFoundException
161 {
162 checkNotNull(name, "The class name cannot be null");
163 checkNotNull(moduleDescriptor, "The module descriptor cannot be null");
164
165 final ModuleReference moduleReference = getBeanReference(name);
166
167 final ModuleFactory moduleFactory = getModuleFactoryForPrefix(moduleReference, moduleDescriptor);
168 Class<T> result = null;
169 if (moduleFactory instanceof ClassPrefixModuleFactory)
170 {
171 result = ((ClassPrefixModuleFactory) moduleFactory).getModuleClass(moduleReference.beanIdentifier, moduleDescriptor);
172 }
173
174 return result;
175
176 }
177
178 private static class ModuleReference
179 {
180 public String prefix;
181 public String beanIdentifier;
182
183 ModuleReference(String prefix, String beanIdentifier)
184 {
185 this.prefix = prefix;
186 this.beanIdentifier = beanIdentifier;
187 }
188 }
189 }