/activeobjects-plugin/src/main/java/com/atlassian/activeobjects/plugin/ActiveObjectModuleDescriptor.java

https://bitbucket.org/activeobjects/ao-plugin · Java · 214 lines · 167 code · 30 blank · 17 comment · 8 complexity · 7b1ae533fb711d54c3839139ee19966e MD5 · raw file

  1. package com.atlassian.activeobjects.plugin;
  2. import com.atlassian.activeobjects.ActiveObjectsPluginException;
  3. import com.atlassian.activeobjects.EntitiesValidator;
  4. import com.atlassian.activeobjects.admin.PluginInfo;
  5. import com.atlassian.activeobjects.admin.PluginToTablesMapping;
  6. import com.atlassian.activeobjects.config.ActiveObjectsConfiguration;
  7. import com.atlassian.activeobjects.config.ActiveObjectsConfigurationFactory;
  8. import com.atlassian.activeobjects.external.ActiveObjectsUpgradeTask;
  9. import com.atlassian.activeobjects.osgi.OsgiServiceUtils;
  10. import com.atlassian.plugin.Plugin;
  11. import com.atlassian.plugin.PluginParseException;
  12. import com.atlassian.plugin.descriptors.AbstractModuleDescriptor;
  13. import com.atlassian.plugin.module.ContainerManagedPlugin;
  14. import com.atlassian.plugin.module.ModuleFactory;
  15. import com.atlassian.plugin.osgi.factory.OsgiPlugin;
  16. import com.google.common.base.Function;
  17. import com.google.common.collect.Iterables;
  18. import com.google.common.collect.Lists;
  19. import com.google.common.collect.Sets;
  20. import net.java.ao.RawEntity;
  21. import net.java.ao.schema.TableNameConverter;
  22. import org.dom4j.Element;
  23. import org.osgi.framework.Bundle;
  24. import org.osgi.framework.ServiceRegistration;
  25. import org.slf4j.Logger;
  26. import org.slf4j.LoggerFactory;
  27. import java.util.List;
  28. import java.util.Set;
  29. import static com.google.common.base.Preconditions.checkNotNull;
  30. import static com.google.common.collect.Lists.newLinkedList;
  31. /**
  32. * <p>The module descriptor for active objects.</p>
  33. * <p>This parses the 'ao' module definition and registers a 'bundle specific'
  34. * {@link com.atlassian.activeobjects.config.ActiveObjectsConfiguration configuration}
  35. * as an OSGi service.</p>
  36. * <p>This configuration is then looked up when the active object service is requested by the given bundle
  37. * through a &lt;component-import ... &gt; module to configure the service appropriately.</p>
  38. */
  39. public class ActiveObjectModuleDescriptor extends AbstractModuleDescriptor<Object> {
  40. private final Logger logger = LoggerFactory.getLogger(this.getClass());
  41. private final ActiveObjectsConfigurationFactory configurationFactory;
  42. private final OsgiServiceUtils osgiUtils;
  43. private final EntitiesValidator entitiesValidator;
  44. private final PluginToTablesMapping pluginToTablesMapping;
  45. /**
  46. * The service registration for the active objects configuration, defined by this plugin.
  47. */
  48. private ServiceRegistration activeObjectsConfigurationServiceRegistration;
  49. private ServiceRegistration tableNameConverterServiceRegistration;
  50. private ActiveObjectsConfiguration configuration;
  51. ActiveObjectModuleDescriptor(ModuleFactory moduleFactory,
  52. ActiveObjectsConfigurationFactory configurationFactory,
  53. OsgiServiceUtils osgiUtils,
  54. PluginToTablesMapping pluginToTablesMapping,
  55. EntitiesValidator entitiesValidator) {
  56. super(moduleFactory);
  57. this.configurationFactory = checkNotNull(configurationFactory);
  58. this.osgiUtils = checkNotNull(osgiUtils);
  59. this.pluginToTablesMapping = checkNotNull(pluginToTablesMapping);
  60. this.entitiesValidator = checkNotNull(entitiesValidator);
  61. }
  62. @Override
  63. public void init(Plugin plugin, Element element) throws PluginParseException {
  64. super.init(plugin, element);
  65. final Set<Class<? extends RawEntity<?>>> entities = getEntities(element);
  66. final List<ActiveObjectsUpgradeTask> upgradeTasks = getUpgradeTasks(element);
  67. configuration = getActiveObjectsConfiguration(getNameSpace(element), entities, upgradeTasks);
  68. final Set<Class<? extends RawEntity<?>>> entityClasses = entitiesValidator.check(entities, configuration.getNameConverters());
  69. recordTables(entityClasses, configuration.getNameConverters().getTableNameConverter());
  70. }
  71. private List<ActiveObjectsUpgradeTask> getUpgradeTasks(Element element) {
  72. final List<Element> upgradeTask = getSubElements(element, "upgradeTask");
  73. final List<Class<ActiveObjectsUpgradeTask>> classes = Lists.transform(upgradeTask, new Function<Element, Class<ActiveObjectsUpgradeTask>>() {
  74. @Override
  75. public Class<ActiveObjectsUpgradeTask> apply(Element utElement) {
  76. final String upgradeTaskClass = utElement.getText().trim();
  77. logger.debug("Found upgrade task class <{}>", upgradeTaskClass);
  78. return getUpgradeTaskClass(upgradeTaskClass);
  79. }
  80. });
  81. if (!(getPlugin() instanceof ContainerManagedPlugin)) {
  82. throw new ActiveObjectsPluginException("Plugin " + getPlugin().getKey() + " " + getPlugin().getClass().getCanonicalName() + " is not a ContainerManagedPlugin, cannot wire context");
  83. }
  84. final ContainerManagedPlugin plugin = (ContainerManagedPlugin) getPlugin();
  85. return Lists.transform(classes, new Function<Class<ActiveObjectsUpgradeTask>, ActiveObjectsUpgradeTask>() {
  86. @Override
  87. public ActiveObjectsUpgradeTask apply(Class<ActiveObjectsUpgradeTask> upgradeTaskClass) {
  88. return plugin.getContainerAccessor().createBean(upgradeTaskClass);
  89. }
  90. });
  91. }
  92. private Class<ActiveObjectsUpgradeTask> getUpgradeTaskClass(String upgradeTask) {
  93. try {
  94. return getPlugin().loadClass(upgradeTask, getClass());
  95. } catch (ClassNotFoundException e) {
  96. throw new ActiveObjectsPluginException(e);
  97. }
  98. }
  99. private void recordTables(final Set<Class<? extends RawEntity<?>>> entityClasses, final TableNameConverter tableNameConverter) {
  100. pluginToTablesMapping.add(PluginInfo.of(getPlugin()), Lists.transform(newLinkedList(entityClasses), new Function<Class<? extends RawEntity<?>>, String>() {
  101. @Override
  102. public String apply(Class<? extends RawEntity<?>> from) {
  103. return tableNameConverter.getName(from);
  104. }
  105. }));
  106. }
  107. @Override
  108. public void enabled() {
  109. super.enabled();
  110. if (tableNameConverterServiceRegistration == null) {
  111. tableNameConverterServiceRegistration = osgiUtils.registerService(getBundle(), TableNameConverter.class, configuration.getNameConverters().getTableNameConverter());
  112. }
  113. if (activeObjectsConfigurationServiceRegistration == null) {
  114. activeObjectsConfigurationServiceRegistration = osgiUtils.registerService(getBundle(), ActiveObjectsConfiguration.class, configuration);
  115. }
  116. }
  117. @Override
  118. public void disabled() {
  119. unregister(activeObjectsConfigurationServiceRegistration);
  120. activeObjectsConfigurationServiceRegistration = null;
  121. unregister(tableNameConverterServiceRegistration);
  122. tableNameConverterServiceRegistration = null;
  123. super.disabled();
  124. }
  125. @Override
  126. public Object getModule() {
  127. return null; // no module
  128. }
  129. public ActiveObjectsConfiguration getConfiguration() {
  130. return configuration;
  131. }
  132. private ActiveObjectsConfiguration getActiveObjectsConfiguration(String namespace, Set<Class<? extends RawEntity<?>>> entities, List<ActiveObjectsUpgradeTask> upgradeTasks) {
  133. return configurationFactory.getConfiguration(getBundle(), namespace, entities, upgradeTasks);
  134. }
  135. private void unregister(ServiceRegistration serviceRegistration) {
  136. if (serviceRegistration != null) {
  137. try {
  138. serviceRegistration.unregister();
  139. } catch (IllegalStateException ignored) {
  140. logger.debug("Service has already been unregistered", ignored);
  141. }
  142. }
  143. }
  144. /**
  145. * The table name space is either the custom namespace set by the product, or the bundle symbolic name
  146. *
  147. * @param element the 'ao' descriptor element
  148. * @return the name space for names
  149. */
  150. private String getNameSpace(Element element) {
  151. final String custom = element.attributeValue("namespace");
  152. return custom != null ? custom : getBundle().getSymbolicName();
  153. }
  154. private Set<Class<? extends RawEntity<?>>> getEntities(Element element) {
  155. return Sets.newHashSet(Iterables.transform(getEntityClassNames(element), new Function<String, Class<? extends RawEntity<?>>>() {
  156. public Class<? extends RawEntity<?>> apply(String entityClassName) {
  157. return getEntityClass(entityClassName);
  158. }
  159. }));
  160. }
  161. private Class<? extends RawEntity<?>> getEntityClass(String entityClassName) {
  162. try {
  163. return getPlugin().loadClass(entityClassName, getClass());
  164. } catch (ClassNotFoundException e) {
  165. throw new ActiveObjectsPluginException(e);
  166. }
  167. }
  168. private Iterable<String> getEntityClassNames(Element element) {
  169. return Iterables.transform(getSubElements(element, "entity"), new Function<Element, String>() {
  170. public String apply(Element entityElement) {
  171. final String entityClassName = entityElement.getText().trim();
  172. logger.debug("Found entity class <{}>", entityClassName);
  173. return entityClassName;
  174. }
  175. });
  176. }
  177. private Bundle getBundle() {
  178. return ((OsgiPlugin) getPlugin()).getBundle();
  179. }
  180. @SuppressWarnings("unchecked")
  181. private static List<Element> getSubElements(Element element, String name) {
  182. return element.elements(name);
  183. }
  184. }