1 package org.andromda.core.namespace;
2
3 import java.io.InputStream;
4 import java.net.URL;
5 import java.text.Collator;
6 import java.util.ArrayList;
7 import java.util.Collection;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.HashMap;
11 import java.util.LinkedHashMap;
12 import java.util.List;
13 import java.util.Map;
14 import org.andromda.core.common.AndroMDALogger;
15 import org.andromda.core.common.ComponentContainer;
16 import org.andromda.core.common.Merger;
17 import org.andromda.core.common.ResourceFinder;
18 import org.andromda.core.common.ResourceUtils;
19 import org.andromda.core.common.XmlObjectFactory;
20 import org.andromda.core.configuration.Namespaces;
21 import org.andromda.core.profile.Profile;
22 import org.apache.commons.io.IOUtils;
23 import org.apache.commons.lang.StringUtils;
24
25
26
27
28
29
30
31 public class NamespaceComponents
32 {
33
34
35
36 private static NamespaceComponents instance;
37
38
39
40
41
42
43 public static final NamespaceComponents instance()
44 {
45 if (instance == null)
46 {
47 final XmlObjectFactory factory = XmlObjectFactory.getInstance(NamespaceComponents.class);
48 instance = (NamespaceComponents)factory.getObject(ResourceUtils.getResource(CONFIGURATION_URI));
49 }
50 return instance;
51 }
52
53
54
55
56 private static final String CONFIGURATION_URI = "META-INF/andromda/namespace-components.xml";
57
58
59
60
61
62
63
64 public NamespaceComponents()
65 {
66 }
67
68
69
70
71 public void discover()
72 {
73 AndroMDALogger.info("- discovering namespaces -");
74
75 final XmlObjectFactory registryFactory = XmlObjectFactory.getInstance(NamespaceRegistry.class);
76 final ComponentContainer container = ComponentContainer.instance();
77
78
79 final Map<NamespaceRegistry, URL> registryMap = this.discoverAllRegistries();
80 final List<NamespaceRegistry> registries = new ArrayList<NamespaceRegistry>(registryMap.keySet());
81 Collections.sort(
82 registries,
83 new NamespaceRegistryComparator());
84 for (NamespaceRegistry registry : registries)
85 {
86 final URL resource = registryMap.get(registry);
87 final String registryName = registry.getName();
88
89
90 if (!this.registeredNamespaceResources.contains(resource))
91 {
92 final Namespaces namespaces = Namespaces.instance();
93 final String namespace = registry.isShared() ? Namespaces.DEFAULT : registry.getName();
94
95
96 final Merger merger = Merger.instance();
97 boolean requiresMerge = merger.requiresMerge(namespace);
98 if (requiresMerge)
99 {
100 registry =
101 (NamespaceRegistry) registryFactory.getObject(
102 merger.getMergedString(
103 ResourceUtils.getContents(resource),
104 namespace), resource);
105 }
106
107
108 registry.addResourceRoot(this.getNamespaceResourceRoot(resource));
109
110
111 if (!this.registeredRegistries.contains(registryName))
112 {
113 AndroMDALogger.info("found namespace --> '" + registryName + '\'');
114 this.registeredRegistries.add(registryName);
115 }
116
117 final NamespaceRegistry existingRegistry = namespaces.getRegistry(registryName);
118 if (existingRegistry != null)
119 {
120
121
122 registry.copy(existingRegistry);
123 }
124
125
126 namespaces.addRegistry(registry);
127 final String[] components = registry.getRegisteredComponents();
128 for (final String componentName : components)
129 {
130 final Component component = this.getComponent(componentName);
131 if (component == null)
132 {
133 throw new NamespaceComponentsException('\'' + componentName +
134 "' is not a valid namespace component");
135 }
136
137
138 component.addPaths(registry.getPaths(component.getName()));
139 if (!container.isRegisteredByNamespace(
140 registryName,
141 component.getType()))
142 {
143 AndroMDALogger.info(" + registering component '" + componentName + '\'');
144 final XmlObjectFactory componentFactory = XmlObjectFactory.getInstance(component.getType());
145 final URL componentResource =
146 this.getNamespaceResource(
147 registry.getResourceRoots(),
148 component.getPaths());
149 if (componentResource == null)
150 {
151 throw new NamespaceComponentsException('\'' + componentName +
152 "' is not a valid component within namespace '" + namespace + "' (the " +
153 componentName + "'s descriptor can not be found)");
154 }
155 NamespaceComponent namespaceComponent =
156 (NamespaceComponent) componentFactory.getObject(componentResource);
157
158
159 if (requiresMerge)
160 {
161 namespaceComponent =
162 (NamespaceComponent) componentFactory.getObject(
163 merger.getMergedString(
164 ResourceUtils.getContents(componentResource),
165 namespace));
166 }
167
168 namespaceComponent.setNamespace(registryName);
169 namespaceComponent.setResource(componentResource);
170 container.registerComponentByNamespace(
171 registryName,
172 component.getType(),
173 namespaceComponent);
174 }
175 }
176 }
177 this.registeredNamespaceResources.add(resource);
178 }
179
180
181 Profile.instance().initialize();
182 }
183
184
185
186
187
188
189
190 private Map<NamespaceRegistry, URL> discoverAllRegistries()
191 {
192 final Map<NamespaceRegistry, URL> registries = new HashMap<NamespaceRegistry, URL>();
193 final URL[] resources = ResourceFinder.findResources(this.getPath());
194 final XmlObjectFactory registryFactory = XmlObjectFactory.getInstance(NamespaceRegistry.class);
195 if (resources != null)
196 {
197 for (final URL resource : resources)
198 {
199 final NamespaceRegistry registry = (NamespaceRegistry) registryFactory.getObject(resource);
200 registries.put(
201 registry,
202 resource);
203 }
204 }
205 return registries;
206 }
207
208
209
210
211 private Collection<URL> registeredNamespaceResources = new ArrayList<URL>();
212
213
214
215
216 private Collection<String> registeredRegistries = new ArrayList<String>();
217
218
219
220
221
222
223
224
225
226
227 private URL getNamespaceResource(
228 final URL[] resourceRoots,
229 final String[] paths)
230 {
231 URL namespaceResource = null;
232 if (resourceRoots != null)
233 {
234 for (final URL resource : resourceRoots)
235 {
236 for (final String path : paths)
237 {
238 InputStream stream = null;
239 try
240 {
241 namespaceResource = new URL(ResourceUtils.normalizePath(resource + path));
242 stream = namespaceResource.openStream();
243 }
244 catch (final Throwable throwable)
245 {
246 namespaceResource = null;
247 }
248 finally
249 {
250 IOUtils.closeQuietly(stream);
251 }
252
253
254 if (namespaceResource != null)
255 {
256 break;
257 }
258 }
259
260
261 if (namespaceResource != null)
262 {
263 break;
264 }
265 }
266 }
267 return namespaceResource;
268 }
269
270
271
272
273
274
275
276
277
278 private URL getNamespaceResourceRoot(final URL resource)
279 {
280 final String resourcePath = resource != null ? resource.toString().replace(
281 '\\',
282 '/') : null;
283 return ResourceUtils.toURL(StringUtils.replace(
284 resourcePath,
285 this.path,
286 ""));
287 }
288
289
290
291
292 private String path;
293
294
295
296
297
298
299 public String getPath()
300 {
301 return this.path;
302 }
303
304
305
306
307
308
309 public void setPath(String path)
310 {
311 this.path = path;
312 }
313
314
315
316
317 private final Map<String, Component> components = new LinkedHashMap<String, Component>();
318
319
320
321
322
323
324 public void addComponent(final Component component)
325 {
326 if (component != null)
327 {
328 this.components.put(
329 component.getName(),
330 component);
331 }
332 }
333
334
335
336
337 public void shutdown()
338 {
339 this.components.clear();
340 this.registeredNamespaceResources.clear();
341 this.registeredRegistries.clear();
342 NamespaceComponents.instance = null;
343 }
344
345
346
347
348
349
350
351 private Component getComponent(final String name)
352 {
353 return this.components.get(name);
354 }
355
356
357
358
359 private static final class NamespaceRegistryComparator
360 implements Comparator<NamespaceRegistry>
361 {
362 private final Collator collator = Collator.getInstance();
363
364 NamespaceRegistryComparator()
365 {
366 collator.setStrength(Collator.PRIMARY);
367 }
368
369 public int compare(
370 final NamespaceRegistry objectA,
371 final NamespaceRegistry objectB)
372 {
373 return collator.compare(
374 objectA.getName(),
375 objectB.getName());
376 }
377 }
378 }