View Javadoc

1   package com.atlassian.plugin.osgi.factory;
2   
3   import com.atlassian.plugin.DefaultModuleDescriptorFactory;
4   import com.atlassian.plugin.ModuleDescriptor;
5   import com.atlassian.plugin.ModuleDescriptorFactory;
6   import com.atlassian.plugin.descriptors.ChainModuleDescriptorFactory;
7   import com.atlassian.plugin.hostcontainer.DefaultHostContainer;
8   import com.atlassian.plugin.osgi.external.ListableModuleDescriptorFactory;
9   import com.atlassian.plugin.osgi.factory.descriptor.ComponentImportModuleDescriptor;
10  import com.atlassian.plugin.osgi.factory.descriptor.ComponentModuleDescriptor;
11  import com.atlassian.plugin.osgi.factory.descriptor.ModuleTypeModuleDescriptor;
12  import org.osgi.util.tracker.ServiceTracker;
13  import org.slf4j.Logger;
14  import org.slf4j.LoggerFactory;
15  
16  import java.util.ArrayList;
17  import java.util.Collection;
18  import java.util.List;
19  
20  /**
21   * Builds a {@link ModuleDescriptorFactory} suitable for building {@link ModuleDescriptor} instances in an OSGi context
22   * for {@link OsgiPlugin} instances.
23   * The result will be able to handle, in the following order:
24   * <ul>
25   * <li>OSGi-specific module descriptors like component, component-import, and module-type</li>
26   * <li>Product-provided module descriptors</li>
27   * <li>Any module descriptor factories exposed as OSGi services</li>
28   * <li>Unknown module descriptors</li>
29   * </ul>
30   *
31   * @since 2.7.0
32   */
33  public class OsgiChainedModuleDescriptorFactoryCreator
34  {
35      private final ServiceTrackerFactory serviceTrackerFactory;
36      private final ModuleDescriptorFactory transformedDescriptorFactory = new DefaultModuleDescriptorFactory(new DefaultHostContainer())
37      {{
38          addModuleDescriptor("component", ComponentModuleDescriptor.class);
39          addModuleDescriptor("component-import", ComponentImportModuleDescriptor.class);
40          addModuleDescriptor("module-type", ModuleTypeModuleDescriptor.class);
41      }};
42      private static final Logger log = LoggerFactory.getLogger(OsgiChainedModuleDescriptorFactoryCreator.class);
43  
44      private volatile ServiceTracker moduleDescriptorFactoryTracker;
45  
46      public static interface ServiceTrackerFactory
47      {
48  
49          ServiceTracker create(String className);
50      }
51  
52      public static interface ResourceLocator
53      {
54          boolean doesResourceExist(String name);
55      }
56  
57      public OsgiChainedModuleDescriptorFactoryCreator(ServiceTrackerFactory serviceTrackerFactory)
58      {
59          this.serviceTrackerFactory = serviceTrackerFactory;
60      }
61  
62      public ModuleDescriptorFactory create(ResourceLocator resourceLocator, ModuleDescriptorFactory originalModuleDescriptorFactory)
63      {
64          // we really don't want two of these
65          synchronized (this)
66          {
67              if (moduleDescriptorFactoryTracker == null)
68              {
69                  moduleDescriptorFactoryTracker = serviceTrackerFactory.create(ModuleDescriptorFactory.class.getName());
70              }
71          }
72  
73          List<ModuleDescriptorFactory> factories = new ArrayList<ModuleDescriptorFactory>();
74  
75          factories.add(transformedDescriptorFactory);
76          factories.add(originalModuleDescriptorFactory);
77          Object[] serviceObjs = moduleDescriptorFactoryTracker.getServices();
78  
79          Collection<ModuleDescriptorFactory> wrappedListable = new ArrayList<ModuleDescriptorFactory>();
80  
81          // Add all the dynamic module descriptor factories registered as osgi services
82          if (serviceObjs != null)
83          {
84              for (Object fac : serviceObjs)
85              {
86                  ModuleDescriptorFactory dynFactory = (ModuleDescriptorFactory) fac;
87  
88                  // don't add Listable descriptor factories (module-type users) as the module type could get disabled
89                  // between here and when the plugin is actually looking for listable factories
90                  if (!(dynFactory instanceof ListableModuleDescriptorFactory))
91                  {
92                      factories.add((ModuleDescriptorFactory) fac);
93                  }
94                  else
95                  {
96                      for (Class<ModuleDescriptor<?>> descriptor : ((ListableModuleDescriptorFactory)dynFactory).getModuleDescriptorClasses())
97                      {
98                          // This will only work for classes not in inner jars and breaks on first non-match
99                          if (!resourceLocator.doesResourceExist(descriptor.getName().replace('.','/') + ".class"))
100                         {
101                             wrappedListable.add(new UnavailableModuleDescriptorRequiringRestartFallbackFactory((ModuleDescriptorFactory) fac));
102                             break;
103                         }
104                     }
105                 }
106             }
107         }
108 
109         factories.add(new ChainModuleDescriptorFactory(wrappedListable));
110 
111         // Catch all unknown descriptors as unrecognised
112         factories.add(new UnrecognisedModuleDescriptorFallbackFactory());
113 
114         return new ChainModuleDescriptorFactory(factories);
115     }
116 }