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