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 Logger log = LoggerFactory.getLogger(PrefixDelegatingModuleFactory.class);
35 private final Map<String, ModuleFactory> delegateModuleFactories;
36
37 public PrefixDelegatingModuleFactory(Set<PrefixModuleFactory> delegates) {
38 Map<String, ModuleFactory> factories = new HashMap<String, ModuleFactory>();
39 for (PrefixModuleFactory factory : delegates) {
40 factories.put(factory.getPrefix(), factory);
41 }
42 this.delegateModuleFactories = factories;
43 }
44
45 public void addPrefixModuleFactory(PrefixModuleFactory prefixModuleFactory) {
46 delegateModuleFactories.put(prefixModuleFactory.getPrefix(), prefixModuleFactory);
47 }
48
49
50
51
52
53
54
55
56 protected ModuleFactory getModuleFactoryForPrefix(final ModuleReference moduleReference, ModuleDescriptor<?> moduleDescriptor) {
57 ModuleFactory moduleFactory = delegateModuleFactories.get(moduleReference.prefix);
58 if (moduleFactory == null) {
59 Plugin plugin = moduleDescriptor.getPlugin();
60 if (plugin instanceof ContainerManagedPlugin) {
61 Collection<PrefixModuleFactory> containerFactories = ((ContainerManagedPlugin) plugin).getContainerAccessor().getBeansOfType(PrefixModuleFactory.class);
62 for (PrefixModuleFactory prefixModuleFactory : containerFactories) {
63 if (moduleReference.prefix.equals(prefixModuleFactory.getPrefix())) {
64 moduleFactory = prefixModuleFactory;
65 break;
66 }
67 }
68 }
69 }
70
71 return moduleFactory;
72 }
73
74
75 public <T> T createModule(String className, final ModuleDescriptor<T> moduleDescriptor) throws PluginParseException {
76 checkNotNull(className, "The className cannot be null");
77 checkNotNull(moduleDescriptor, "The moduleDescriptor cannot be null");
78
79 final ModuleReference moduleReference = getBeanReference(className);
80
81 Object result = null;
82
83 final ModuleFactory moduleFactory = getModuleFactoryForPrefix(moduleReference, moduleDescriptor);
84 if (moduleFactory == null) {
85 throw new PluginParseException("Failed to create a module. Prefix '" + moduleReference.prefix + "' not supported");
86 }
87 try {
88 result = moduleFactory.createModule(moduleReference.beanIdentifier, moduleDescriptor);
89 } catch (NoClassDefFoundError error) {
90
91 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 .");
92 throw error;
93 } catch (LinkageError error) {
94
95 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 .");
96 throw error;
97 } catch (RuntimeException ex) {
98 if (ex.getClass().getSimpleName().equals("UnsatisfiedDependencyException")) {
99
100 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.");
101 }
102 throw ex;
103 }
104
105 if (result != null) {
106 return (T) result;
107 } else {
108 throw new PluginParseException("Unable to create module instance from '" + className + "'");
109 }
110 }
111
112
113 private ModuleReference getBeanReference(String className) {
114 String prefix = "class";
115 final int prefixIndex = className.indexOf(":");
116 if (prefixIndex != -1) {
117 prefix = className.substring(0, prefixIndex);
118 className = className.substring(prefixIndex + 1);
119 }
120 return new ModuleReference(prefix, className);
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135 @Deprecated
136 public <T> Class<T> guessModuleClass(final String name, final ModuleDescriptor<T> moduleDescriptor) throws ModuleClassNotFoundException {
137 checkNotNull(name, "The class name cannot be null");
138 checkNotNull(moduleDescriptor, "The module descriptor cannot be null");
139
140 final ModuleReference moduleReference = getBeanReference(name);
141
142 final ModuleFactory moduleFactory = getModuleFactoryForPrefix(moduleReference, moduleDescriptor);
143 Class<T> result = null;
144 if (moduleFactory instanceof ClassPrefixModuleFactory) {
145 result = ((ClassPrefixModuleFactory) moduleFactory).getModuleClass(moduleReference.beanIdentifier, moduleDescriptor);
146 }
147
148 return result;
149
150 }
151
152 private static class ModuleReference {
153 public String prefix;
154 public String beanIdentifier;
155
156 ModuleReference(String prefix, String beanIdentifier) {
157 this.prefix = prefix;
158 this.beanIdentifier = beanIdentifier;
159 }
160 }
161 }