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 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 .");
105 throw error;
106 }
107 catch (LinkageError error)
108 {
109 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 .");
110 throw error;
111 }
112 catch (RuntimeException ex)
113 {
114 if (ex.getClass().getSimpleName().equals("UnsatisfiedDependencyException"))
115 {
116 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.");
117 }
118 throw ex;
119 }
120
121 if (result != null)
122 {
123 return (T) result;
124 }
125 else
126 {
127 throw new PluginParseException("Unable to create module instance from '" + className + "'");
128 }
129 }
130
131
132 private ModuleReference getBeanReference(String className)
133 {
134 String prefix = "class";
135 final int prefixIndex = className.indexOf(":");
136 if (prefixIndex != -1)
137 {
138 prefix = className.substring(0, prefixIndex);
139 className = className.substring(prefixIndex + 1);
140 }
141 return new ModuleReference(prefix, className);
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156 @Deprecated
157 public <T> Class<T> guessModuleClass(final String name, final ModuleDescriptor<T> moduleDescriptor) throws ModuleClassNotFoundException
158 {
159 checkNotNull(name, "The class name cannot be null");
160 checkNotNull(moduleDescriptor, "The module descriptor cannot be null");
161
162 final ModuleReference moduleReference = getBeanReference(name);
163
164 final ModuleFactory moduleFactory = getModuleFactoryForPrefix(moduleReference, moduleDescriptor);
165 Class<T> result = null;
166 if (moduleFactory instanceof ClassPrefixModuleFactory)
167 {
168 result = ((ClassPrefixModuleFactory) moduleFactory).getModuleClass(moduleReference.beanIdentifier, moduleDescriptor);
169 }
170
171 return result;
172
173 }
174
175 private static class ModuleReference
176 {
177 public String prefix;
178 public String beanIdentifier;
179
180 ModuleReference(String prefix, String beanIdentifier)
181 {
182 this.prefix = prefix;
183 this.beanIdentifier = beanIdentifier;
184 }
185 }
186 }