1 package com.atlassian.plugin.schema.impl;
2
3 import com.atlassian.plugin.ModuleDescriptor;
4 import com.atlassian.plugin.ModuleDescriptorFactory;
5 import com.atlassian.plugin.Plugin;
6 import com.atlassian.plugin.PluginParseException;
7 import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
8 import com.atlassian.plugin.descriptors.CannotDisable;
9 import com.atlassian.plugin.hostcontainer.HostContainer;
10 import com.atlassian.plugin.module.ModuleFactory;
11 import com.atlassian.plugin.osgi.external.ListableModuleDescriptorFactory;
12 import com.atlassian.plugin.osgi.factory.OsgiPlugin;
13 import com.atlassian.plugin.schema.descriptor.DescribedModuleDescriptorFactory;
14 import com.atlassian.plugin.schema.spi.DocumentBasedSchema;
15 import com.atlassian.plugin.schema.spi.Schema;
16 import com.atlassian.plugin.schema.spi.SchemaFactory;
17 import com.atlassian.plugin.schema.spi.SchemaTransformer;
18 import com.atlassian.util.concurrent.NotNull;
19 import com.google.common.base.Function;
20 import com.google.common.collect.Lists;
21 import org.dom4j.Element;
22 import org.osgi.framework.Bundle;
23 import org.osgi.framework.BundleContext;
24
25 import static com.google.common.base.Preconditions.checkNotNull;
26 import static java.util.Collections.emptyList;
27
28
29
30
31
32 @CannotDisable
33 public class DescribedModuleTypeModuleDescriptor extends AbstractModuleDescriptor<DescribedModuleDescriptorFactory>
34 {
35 private static final String[] PUBLIC_INTERFACES = new String[]{
36 ModuleDescriptorFactory.class.getName(),
37 ListableModuleDescriptorFactory.class.getName(),
38 DescribedModuleDescriptorFactory.class.getName()
39 };
40
41 private final HostContainer hostContainer;
42 private final BundleContext bundleContext;
43 private String schemaFactoryClassName;
44 private String type;
45 private String schemaTransformerClassName;
46 private String maxOccurs;
47 private Iterable<String> requiredPermissions;
48 private Iterable<String> optionalPermissions;
49
50
51 public DescribedModuleTypeModuleDescriptor(HostContainer hostContainer, BundleContext bundleContext)
52 {
53 super(ModuleFactory.LEGACY_MODULE_FACTORY);
54 this.hostContainer = hostContainer;
55 this.bundleContext = bundleContext;
56 }
57
58 @Override
59 public void init(@NotNull Plugin plugin, @NotNull Element element) throws PluginParseException
60 {
61 super.init(plugin, element);
62 this.type = getOptionalAttribute(element, "type", getKey());
63 this.schemaFactoryClassName = getOptionalAttribute(element, "schema-factory-class", null);
64 this.schemaTransformerClassName = getOptionalAttribute(element, "schema-transformer-class", null);
65 this.maxOccurs = getOptionalAttribute(element, "max-occurs", "unbounded");
66 this.requiredPermissions = getPermissions(element.element("required-permissions"));
67 this.optionalPermissions = getPermissions(element.element("optional-permissions"));
68 }
69
70 private Iterable<String> getPermissions(Element element)
71 {
72 if (element != null)
73 {
74 return Lists.transform(element.elements("permission"), new Function<Element, String>()
75 {
76 @Override
77 public String apply(Element input)
78 {
79 return input.getTextTrim();
80 }
81 });
82 }
83 return emptyList();
84 }
85
86 @Override
87 public void enabled()
88 {
89 super.enabled();
90 Bundle bundle = findBundleForPlugin(bundleContext, getPluginKey());
91 checkNotNull(bundle, "Cannot find bundle for plugin " + getPluginKey());
92
93 SchemaTransformer schemaTransformer = schemaTransformerClassName != null
94 ? hostContainer.create(findClass(schemaTransformerClassName, SchemaTransformer.class))
95 : SchemaTransformer.IDENTITY;
96 SchemaFactory schemaFactory = schemaFactoryClassName != null
97 ? hostContainer.create(findClass(schemaFactoryClassName, SchemaFactory.class))
98 : buildSingleton(DocumentBasedSchema.builder(type)
99 .setPlugin(getPlugin())
100 .setName(getName() != null ? getName() : getKey())
101 .setDescription(getDescription() != null ? getDescription() : "")
102 .setTransformer(schemaTransformer)
103 .setMaxOccurs(maxOccurs)
104 .setRequiredPermissions(requiredPermissions)
105 .setOptionalPermissions(optionalPermissions)
106 .build());
107
108 DescribedModuleDescriptorFactory factory = new DefaultDescribedModuleDescriptorFactory((OsgiPlugin) plugin, type,
109 findClass(moduleClassName, ModuleDescriptor.class), schemaFactory);
110 bundle.getBundleContext().registerService(PUBLIC_INTERFACES, factory, null);
111 }
112
113 private <T> Class<? extends T> findClass(String className, Class<T> castTo)
114 {
115 checkNotNull(className);
116 Class<T> clazz = null;
117 try
118 {
119 clazz = plugin.loadClass(className, getClass());
120 }
121 catch (ClassNotFoundException e)
122 {
123 throw new PluginParseException("Unable to find class " + className);
124 }
125 return clazz.asSubclass(castTo);
126 }
127
128 @Override
129 public DescribedModuleDescriptorFactory getModule()
130 {
131 return moduleFactory.createModule(moduleClassName, this);
132 }
133
134 private SchemaFactory buildSingleton(final Schema schema)
135 {
136 return new SchemaFactory()
137 {
138 @Override
139 public Schema getSchema()
140 {
141 return schema;
142 }
143 };
144 }
145
146 private static Bundle findBundleForPlugin(BundleContext bundleContext, String pluginKey)
147 {
148 for (Bundle bundle : bundleContext.getBundles())
149 {
150 String maybePluginKey = (String) bundle.getHeaders().get(OsgiPlugin.ATLASSIAN_PLUGIN_KEY);
151 if (pluginKey.equals(maybePluginKey))
152 {
153 return bundle;
154 }
155 }
156 return null;
157 }
158
159 public static String getOptionalAttribute(Element e, String name, Object defaultValue)
160 {
161 String value = e.attributeValue(name);
162 return value != null ? value :
163 defaultValue != null ? defaultValue.toString() : null;
164 }
165 }