View Javadoc

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   * Descriptor that allows described module descriptor factories to be configured in XML.  Main value
30   * is the ability to reuse the name and description of the module descriptor configuration.
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 }