/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.seam.wiki.core.plugin.binding.lacewiki;
import org.dom4j.Element;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.*;
import org.jboss.seam.log.Log;
import org.jboss.seam.wiki.core.exception.InvalidWikiConfigurationException;
import org.jboss.seam.wiki.core.plugin.PluginRegistry;
import org.jboss.seam.wiki.core.plugin.PluginCacheManager;
import org.jboss.seam.wiki.core.plugin.metamodel.MacroPluginModule;
import org.jboss.seam.wiki.core.plugin.metamodel.*;
import org.jboss.seam.wiki.core.plugin.metamodel.PluginModule;
import org.jboss.seam.wiki.preferences.PreferenceVisibility;
import org.jboss.seam.wiki.preferences.metamodel.PreferenceEntity;
import org.jboss.seam.wiki.preferences.metamodel.PreferenceRegistry;
import java.util.*;
/**
* Parses and binds plugin.xml metadata to plugin metamodel.
*
* @author Christian Bauer
*/
@Name("pluginBinder")
@Scope(ScopeType.APPLICATION)
@Startup
public class PluginBinder extends org.jboss.seam.wiki.core.plugin.binding.PluginBinder {
@Logger
Log log;
@In
PreferenceRegistry preferenceRegistry;
@In
Map<String,String> messages;
@Create
public void readDescriptors() {
log.debug("reading deployment descriptors as XML...");
descriptors = PluginDeploymentHandler.instance().getDescriptorsAsXmlElements();
}
Map<String, Element> descriptors = new HashMap<String, Element>();
public void bindPlugins(PluginRegistry registry) {
log.debug("installing plugins from XML descriptors: " + descriptors.size());
for (Map.Entry<String, Element> descriptor : descriptors.entrySet()) {
log.debug("installing deployment descriptor: " + descriptor.getKey());
Element root = descriptor.getValue();
String pluginKey = root.attributeValue("key");
log.debug("binding plugin: " + descriptor.getKey());
Plugin plugin = new Plugin(descriptor.getKey(), pluginKey);
log.debug("plugin descriptor package path: " + plugin.getDescriptorPackagePath());
registry.addPlugin(pluginKey, plugin);
String pluginLabel = root.attributeValue("label");
if (pluginLabel == null) pluginLabel = getMessage(plugin.getKey()+".label");
plugin.setLabel(pluginLabel);
bindPluginInfo(root, plugin);
bindMacroPluginModules(registry, root, plugin);
bindProfilePluginModules(registry, root, plugin);
}
bindMacroParameters(registry);
}
private void bindPluginInfo(Element root, Plugin plugin) {
List<Element> pluginInfos = root.elements("plugin-info");
if (pluginInfos.size() == 1) {
PluginInfo pluginInfo = new PluginInfo();
pluginInfo.setVersion(pluginInfos.get(0).attributeValue("version"));
String description = pluginInfos.get(0).attributeValue("description");
if (description == null) description = getMessage(plugin.getKey()+".description");
pluginInfo.setDescription(description);
List<Element> applicationVersions = pluginInfos.get(0).elements("application-version");
if (applicationVersions.size() == 1) {
pluginInfo.setApplicationVersion(
applicationVersions.get(0).attributeValue("min"),
applicationVersions.get(0).attributeValue("max")
);
}
List<Element> vendors = pluginInfos.get(0).elements("vendor");
if (vendors.size() == 1) {
pluginInfo.setVendor(
vendors.get(0).attributeValue("name"),
vendors.get(0).attributeValue("url")
);
}
plugin.setPluginInfo(pluginInfo);
}
}
private void bindMacroPluginModules(PluginRegistry registry, Element root, Plugin plugin) {
// Iterate through the XML descriptor and bind every <macro> to corresponding metamodel instances
List<Element> macroPlugins = root.elements("macro");
for (Element descriptor : macroPlugins) {
String moduleKey = descriptor.attributeValue("key");
MacroPluginModule module = new MacroPluginModule(plugin, moduleKey);
log.debug("binding macro plugin module: " + module.getFullyQualifiedKey());
bindLabelDescription(descriptor, module, plugin);
bindMacroApplicableTo(descriptor, module);
bindMacroRenderOptions(descriptor, module);
bindSkins(descriptor, module);
bindCacheRegions(descriptor, module);
String macroName = descriptor.attributeValue("name");
if (registry.getMacroPluginModulesByMacroName().containsKey(macroName)) {
throw new InvalidWikiConfigurationException("Duplicate macro name, needs to be globally unique: " + macroName);
}
module.setName(macroName);
// Finally, bind it
plugin.getModules().add(module);
registry.getMacroPluginModulesByKey().put(module.getFullyQualifiedKey(), module);
registry.getMacroPluginModulesByMacroName().put(module.getName(), module);
}
}
private void bindProfilePluginModules(PluginRegistry registry, Element root, Plugin plugin) {
// Iterate through the XML descriptor and bind every <profile> to corresponding metamodel instances
List<Element> profilePlugins = root.elements("profile");
for (Element descriptor : profilePlugins) {
String moduleKey = descriptor.attributeValue("key");
ProfilePluginModule module = new ProfilePluginModule(plugin, moduleKey);
log.debug("binding profile plugin module: " + module.getFullyQualifiedKey());
bindLabelDescription(descriptor, module, plugin);
bindSkins(descriptor, module);
module.setTemplate(descriptor.attributeValue("template"));
module.setPriority(new Integer(descriptor.attributeValue("priority")));
// Finally, bind it
plugin.getModules().add(module);
registry.getProfilePluginModulesByPriority().add(module);
}
}
private void bindLabelDescription(Element descriptor, PluginModule module, Plugin plugin) {
String label = descriptor.attributeValue("label");
if (label == null) label = getMessage(plugin.getKey() + "." + module.getKey() + ".label");
module.setLabel(label);
String description = descriptor.attributeValue("description");
if (description == null) description = getMessage(plugin.getKey() + "." + module.getKey() + ".description");
module.setDescription(description);
}
private void bindCacheRegions(Element descriptor, PluginModule module) {
Element cacheRegionsDescriptor = descriptor.element("cache-regions");
if (cacheRegionsDescriptor != null) {
List<Element> cacheRegions = cacheRegionsDescriptor.elements("cache-region");
if (cacheRegions.size() > 0) {
for (Element cacheRegion : cacheRegions) {
String unqualifiedCacheRegionName = cacheRegion.attributeValue("name");
module.addFragmentCacheRegion(unqualifiedCacheRegionName);
List<Element> invalidationEvents = cacheRegion.elements("invalidation-event");
if (invalidationEvents != null) {
for (Element invalidationEvent : invalidationEvents) {
String eventName = invalidationEvent.attributeValue("name");
PluginCacheManager.registerBinding(
eventName,
module.getQualifiedCacheRegionName(unqualifiedCacheRegionName)
);
}
}
}
}
}
}
private void bindSkins(Element descriptor, PluginModule module) {
Element skins = descriptor.element("skins");
if (skins != null) bindSkin(skins, module);
}
private void bindSkin(Element descriptor, PluginModule module) {
List<Element> skins = descriptor.elements("skin");
if (skins.size() > 0) {
String[] skinNames = new String[skins.size()];
for (int i = 0; i < skins.size(); i++)
skinNames[i] = skins.get(i).attributeValue("name");
module.setSkins(skinNames);
}
}
private void bindMacroApplicableTo(Element descriptor, MacroPluginModule module) {
Element applicableTo = descriptor.element("applicable-to");
if (applicableTo != null) {
boolean header = Boolean.parseBoolean(applicableTo.attributeValue("header"));
boolean content = Boolean.parseBoolean(applicableTo.attributeValue("content"));
boolean footer = Boolean.parseBoolean(applicableTo.attributeValue("footer"));
List<MacroPluginModule.DocumentArea> applicableList = new ArrayList<MacroPluginModule.DocumentArea>();
if (header) applicableList.add(MacroPluginModule.DocumentArea.HEADER);
if (content) applicableList.add(MacroPluginModule.DocumentArea.CONTENT);
if (footer) applicableList.add(MacroPluginModule.DocumentArea.FOOTER);
MacroPluginModule.DocumentArea[] applicableArray = new MacroPluginModule.DocumentArea[applicableList.size()];
module.setApplicableTo(applicableList.toArray(applicableArray));
}
}
private void bindMacroRenderOptions(Element descriptor, MacroPluginModule module) {
Element renderOptions = descriptor.element("render-options");
if (renderOptions != null) {
List<MacroPluginModule.RenderOption> renderOptionList =
new ArrayList<MacroPluginModule.RenderOption>();
List<Element> options = renderOptions.elements();
for (Element option : options) {
if (option.getName().equals("singleton"))
renderOptionList.add(MacroPluginModule.RenderOption.SINGLETON);
}
MacroPluginModule.RenderOption[] renderOptionArray =
new MacroPluginModule.RenderOption[renderOptionList.size()];
module.setRenderOptions(renderOptionList.toArray(renderOptionArray));
}
}
private void bindMacroParameters(PluginRegistry registry) {
// Iterate through all @Preference entities, look for instanceType() values (which are fully qualified macro keys)
Set<PreferenceEntity> entitiesWithInstanceProperties =
preferenceRegistry.getPreferenceEntities(PreferenceVisibility.INSTANCE);
for (PreferenceEntity entity : entitiesWithInstanceProperties) {
if (entity.getMappedTo() != null && entity.getMappedTo().length() > 0) {
// All INSTANCE properties of this entity are for one macro, ignore whatever is configured on the properties
String macroPluginKey = entity.getMappedTo();
MacroPluginModule macroPluginModule = registry.getMacroPluginModulesByKey().get(macroPluginKey);
if (macroPluginModule != null) {
log.debug("binding all INSTANCE properties as parameters of macro '" + macroPluginModule.getName() +"': " + entity);
macroPluginModule.setPreferenceEntity(entity);
} else {
throw new InvalidWikiConfigurationException(
"Configured mapping to macro module '"+macroPluginKey+"' not found for " + entity
);
}
} else {
// Some INSTANCE properties are for one macro, others for other macros, so we need to mix and match
for (PreferenceEntity.Property property : entity.getPropertiesInstanceVisible()) {
if (property.getMappedTo() == null || property.getMappedTo().length() == 0) continue;
String macroPluginKey = property.getMappedTo();
MacroPluginModule macroPluginModule = registry.getMacroPluginModulesByKey().get(macroPluginKey);
if (macroPluginModule != null) {
log.debug("binding INSTANCE property as parameter of macro '" + macroPluginModule.getName() +"': " + property);
macroPluginModule.setPreferenceEntity(entity);
macroPluginModule.getParameters().add(property);
} else {
throw new InvalidWikiConfigurationException(
"Configured mapping to macro module '"+macroPluginKey+"' not found for " + property + " in " + entity
);
}
}
}
}
}
private String getMessage(String key) {
String message = messages.get(key);
if (message.equals(key)) {
throw new InvalidWikiConfigurationException("Could not find message key for label/description: " + key);
}
return message;
}
}