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  
43      private volatile ServiceTracker moduleDescriptorFactoryTracker;
44  
45      public static interface ServiceTrackerFactory
46      {
47  
48          ServiceTracker create(String className);
49      }
50  
51      public static interface ResourceLocator
52      {
53          boolean doesResourceExist(String name);
54      }
55  
56      public OsgiChainedModuleDescriptorFactoryCreator(ServiceTrackerFactory serviceTrackerFactory)
57      {
58          this.serviceTrackerFactory = serviceTrackerFactory;
59      }
60  
61      public ModuleDescriptorFactory create(ResourceLocator resourceLocator, ModuleDescriptorFactory originalModuleDescriptorFactory)
62      {
63          // we really don't want two of these
64          synchronized (this)
65          {
66              if (moduleDescriptorFactoryTracker == null)
67              {
68                  moduleDescriptorFactoryTracker = serviceTrackerFactory.create(ModuleDescriptorFactory.class.getName());
69              }
70          }
71  
72          List<ModuleDescriptorFactory> factories = new ArrayList<ModuleDescriptorFactory>();
73  
74          factories.add(transformedDescriptorFactory);
75          factories.add(originalModuleDescriptorFactory);
76          Object[] serviceObjs = moduleDescriptorFactoryTracker.getServices();
77  
78          Collection<ModuleDescriptorFactory> wrappedListable = new ArrayList<ModuleDescriptorFactory>();
79  
80          // Add all the dynamic module descriptor factories registered as osgi services
81          if (serviceObjs != null)
82          {
83              for (Object fac : serviceObjs)
84              {
85                  ModuleDescriptorFactory dynFactory = (ModuleDescriptorFactory) fac;
86  
87                  // don't add Listable descriptor factories (module-type users) as the module type could get disabled
88                  // between here and when the plugin is actually looking for listable factories
89                  if (!(dynFactory instanceof ListableModuleDescriptorFactory))
90                  {
91                      factories.add((ModuleDescriptorFactory) fac);
92                  }
93                  else
94                  {
95                      for (Class<? extends ModuleDescriptor> descriptor : ((ListableModuleDescriptorFactory)dynFactory).getModuleDescriptorClasses())
96                      {
97                          // This will only work for classes not in inner jars and breaks on first non-match
98                          if (!resourceLocator.doesResourceExist(descriptor.getName().replace('.','/') + ".class"))
99                          {
100                             wrappedListable.add(new UnavailableModuleDescriptorRequiringRestartFallbackFactory((ModuleDescriptorFactory) fac));
101                             break;
102                         }
103                     }
104                 }
105             }
106         }
107 
108         factories.add(new ChainModuleDescriptorFactory(wrappedListable));
109 
110         // Catch all unknown descriptors as unrecognised
111         factories.add(new UnrecognisedModuleDescriptorFallbackFactory());
112 
113         return new ChainModuleDescriptorFactory(factories);
114     }
115 }