/*
* (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Anahide Tchertchian
*/
package org.nuxeo.ecm.platform.forms.layout.core.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.LayoutTypeDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetType;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.converters.LayoutDefinitionConverter;
import org.nuxeo.ecm.platform.forms.layout.api.converters.WidgetDefinitionConverter;
import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetTypeImpl;
import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore;
import org.nuxeo.ecm.platform.forms.layout.core.registries.LayoutConverterRegistry;
import org.nuxeo.ecm.platform.forms.layout.core.registries.LayoutDefinitionRegistry;
import org.nuxeo.ecm.platform.forms.layout.core.registries.LayoutTypeDefinitionRegistry;
import org.nuxeo.ecm.platform.forms.layout.core.registries.WidgetConverterRegistry;
import org.nuxeo.ecm.platform.forms.layout.core.registries.WidgetDefinitionRegistry;
import org.nuxeo.ecm.platform.forms.layout.core.registries.WidgetTypeDefinitionRegistry;
import org.nuxeo.ecm.platform.forms.layout.core.registries.WidgetTypeRegistry;
import org.nuxeo.ecm.platform.forms.layout.descriptors.LayoutConverterDescriptor;
import org.nuxeo.ecm.platform.forms.layout.descriptors.LayoutDescriptor;
import org.nuxeo.ecm.platform.forms.layout.descriptors.LayoutTypeDescriptor;
import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetConverterDescriptor;
import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetDescriptor;
import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetTypeDescriptor;
import org.nuxeo.runtime.model.ComponentInstance;
import org.nuxeo.runtime.model.DefaultComponent;
/**
* @author Anahide Tchertchian
* @since 5.5
*/
public class LayoutStoreImpl extends DefaultComponent implements LayoutStore {
private static final Log log = LogFactory.getLog(LayoutStoreImpl.class);
private static final long serialVersionUID = 1L;
public static final String WIDGET_TYPES_EP_NAME = "widgettypes";
/**
* @since 6.0
*/
public static final String LAYOUT_TYPES_EP_NAME = "layouttypes";
public static final String WIDGETS_EP_NAME = "widgets";
public static final String LAYOUTS_EP_NAME = "layouts";
public static final String LAYOUT_CONVERTERS_EP_NAME = "layoutConverters";
public static final String WIDGET_CONVERTERS_EP_NAME = "widgetConverters";
protected final Map<String, WidgetTypeRegistry> widgetTypesByCat;
protected final Map<String, WidgetTypeDefinitionRegistry> widgetTypeDefsByCat;
protected final Map<String, LayoutTypeDefinitionRegistry> layoutTypeDefsByCat;
protected final Map<String, LayoutDefinitionRegistry> layoutsByCat;
protected final Map<String, WidgetDefinitionRegistry> widgetsByCat;
protected final Map<String, WidgetConverterRegistry> widgetConvertersByCat;
protected final Map<String, LayoutConverterRegistry> layoutConvertersByCat;
public LayoutStoreImpl() {
widgetTypeDefsByCat = new HashMap<String, WidgetTypeDefinitionRegistry>();
layoutTypeDefsByCat = new HashMap<String, LayoutTypeDefinitionRegistry>();
widgetTypesByCat = new HashMap<String, WidgetTypeRegistry>();
layoutsByCat = new HashMap<String, LayoutDefinitionRegistry>();
widgetsByCat = new HashMap<String, WidgetDefinitionRegistry>();
widgetConvertersByCat = new HashMap<String, WidgetConverterRegistry>();
layoutConvertersByCat = new HashMap<String, LayoutConverterRegistry>();
}
// Runtime component API
@Override
public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
if (extensionPoint.equals(WIDGET_TYPES_EP_NAME)) {
WidgetTypeDescriptor desc = (WidgetTypeDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot register widget type '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
registerWidgetType(cat, desc.getWidgetTypeDefinition());
}
}
} else if (extensionPoint.equals(LAYOUT_TYPES_EP_NAME)) {
LayoutTypeDescriptor desc = (LayoutTypeDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot register layout type '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
registerLayoutType(cat, desc.getLayoutTypeDefinition());
}
}
} else if (extensionPoint.equals(LAYOUTS_EP_NAME)) {
LayoutDescriptor desc = (LayoutDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot register layout '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
registerLayout(cat, desc.getLayoutDefinition());
}
}
} else if (extensionPoint.equals(WIDGETS_EP_NAME)) {
WidgetDescriptor desc = (WidgetDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot register widget '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
registerWidget(cat, desc.getWidgetDefinition());
}
}
} else if (extensionPoint.equals(LAYOUT_CONVERTERS_EP_NAME)) {
LayoutConverterDescriptor desc = (LayoutConverterDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot register layout converter '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
registerLayoutConverter(cat, desc);
}
}
} else if (extensionPoint.equals(WIDGET_CONVERTERS_EP_NAME)) {
WidgetConverterDescriptor desc = (WidgetConverterDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot register widget converter '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
registerWidgetConverter(cat, desc);
}
}
} else {
log.error(String.format("Unknown extension point %s, can't register !", extensionPoint));
}
}
@Override
public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
if (extensionPoint.equals(WIDGET_TYPES_EP_NAME)) {
WidgetTypeDescriptor desc = (WidgetTypeDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot unregister widget type '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
unregisterWidgetType(cat, desc.getWidgetTypeDefinition());
}
}
} else if (extensionPoint.equals(LAYOUT_TYPES_EP_NAME)) {
LayoutTypeDescriptor desc = (LayoutTypeDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot unregister layout type '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
unregisterLayoutType(cat, desc.getLayoutTypeDefinition());
}
}
} else if (extensionPoint.equals(LAYOUTS_EP_NAME)) {
LayoutDescriptor desc = (LayoutDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot unregister layout '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
unregisterLayout(cat, desc.getLayoutDefinition());
}
}
} else if (extensionPoint.equals(WIDGETS_EP_NAME)) {
WidgetDescriptor desc = (WidgetDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot unregister widget '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
unregisterWidget(cat, desc.getWidgetDefinition());
}
}
} else if (extensionPoint.equals(LAYOUT_CONVERTERS_EP_NAME)) {
LayoutConverterDescriptor desc = (LayoutConverterDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot register layout converter '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
unregisterLayoutConverter(cat, desc);
}
}
} else if (extensionPoint.equals(WIDGET_CONVERTERS_EP_NAME)) {
WidgetConverterDescriptor desc = (WidgetConverterDescriptor) contribution;
String[] categories = desc.getCategories();
if (categories == null || categories.length == 0) {
log.error(String.format("Cannot register widget converter '%s': no category found", desc.getName()));
} else {
for (String cat : categories) {
unregisterWidgetConverter(cat, desc);
}
}
} else {
log.error(String.format("Unknown extension point %s, can't unregister !", extensionPoint));
}
}
// Categories
@Override
public List<String> getCategories() {
Set<String> cats = new HashSet<String>();
cats.addAll(widgetTypeDefsByCat.keySet());
cats.addAll(widgetTypesByCat.keySet());
cats.addAll(layoutsByCat.keySet());
cats.addAll(widgetsByCat.keySet());
List<String> res = new ArrayList<String>();
res.addAll(cats);
Collections.sort(res);
return res;
}
// widget types
public void registerWidgetType(String category, WidgetTypeDefinition desc) {
String name = desc.getName();
String className = desc.getHandlerClassName();
Class<?> widgetTypeClass = null;
if (className != null) {
try {
widgetTypeClass = LayoutStoreImpl.class.getClassLoader().loadClass(className);
} catch (ReflectiveOperationException e) {
log.error("Caught error when instantiating widget type handler", e);
return;
}
}
// override only if handler class was resolved correctly
if (widgetTypesByCat.containsKey(name) || widgetTypeDefsByCat.containsKey(name)) {
log.warn(String.format("Overriding definition for widget type %s", name));
widgetTypesByCat.remove(name);
widgetTypeDefsByCat.remove(name);
}
WidgetTypeImpl widgetType = new WidgetTypeImpl(name, widgetTypeClass, desc.getProperties());
widgetType.setAliases(desc.getAliases());
WidgetTypeRegistry typeReg = widgetTypesByCat.get(category);
if (typeReg == null) {
typeReg = new WidgetTypeRegistry(category);
widgetTypesByCat.put(category, typeReg);
}
typeReg.addContribution(widgetType);
WidgetTypeDefinitionRegistry defReg = widgetTypeDefsByCat.get(category);
if (defReg == null) {
defReg = new WidgetTypeDefinitionRegistry(category);
widgetTypeDefsByCat.put(category, defReg);
}
defReg.addContribution(desc);
log.info(String.format("Registered widget type '%s' for category '%s' ", name, category));
}
public void unregisterWidgetType(String category, WidgetTypeDefinition desc) {
String name = desc.getName();
WidgetTypeRegistry typeReg = widgetTypesByCat.get(category);
WidgetTypeDefinitionRegistry defReg = widgetTypeDefsByCat.get(category);
if (typeReg != null && defReg != null) {
// remove corresponding widget type, only reuse name
WidgetType widgetType = new WidgetTypeImpl(name, null, null);
typeReg.removeContribution(widgetType);
defReg.removeContribution(desc);
log.info(String.format("Unregistered widget type '%s' for category '%s' ", name, category));
}
}
// layout types
public void registerLayoutType(String category, LayoutTypeDefinition layoutTypeDef) {
LayoutTypeDefinitionRegistry reg = layoutTypeDefsByCat.get(category);
if (reg == null) {
reg = new LayoutTypeDefinitionRegistry(category);
layoutTypeDefsByCat.put(category, reg);
}
reg.addContribution(layoutTypeDef);
log.info(String.format("Registered layout type '%s' for category '%s' ", layoutTypeDef.getName(), category));
}
public void unregisterLayoutType(String category, LayoutTypeDefinition layoutTypeDef) {
LayoutTypeDefinitionRegistry reg = layoutTypeDefsByCat.get(category);
if (reg != null) {
reg.removeContribution(layoutTypeDef);
log.info(String.format("Unregistered layout type '%s' for category '%s' ", layoutTypeDef.getName(),
category));
}
}
// layouts
public void registerLayout(String category, LayoutDefinition layoutDef) {
LayoutDefinitionRegistry reg = layoutsByCat.get(category);
if (reg == null) {
reg = new LayoutDefinitionRegistry(category);
layoutsByCat.put(category, reg);
}
reg.addContribution(layoutDef);
log.info(String.format("Registered layout '%s' for category '%s' ", layoutDef.getName(), category));
}
public void unregisterLayout(String category, LayoutDefinition layoutDef) {
LayoutDefinitionRegistry reg = layoutsByCat.get(category);
if (reg != null) {
reg.removeContribution(layoutDef);
log.info(String.format("Unregistered layout '%s' for category '%s' ", layoutDef.getName(), category));
}
}
// widgets
public void registerWidget(String category, WidgetDefinition widgetDef) {
WidgetDefinitionRegistry reg = widgetsByCat.get(category);
if (reg == null) {
reg = new WidgetDefinitionRegistry(category);
widgetsByCat.put(category, reg);
}
reg.addContribution(widgetDef);
log.info(String.format("Registered widget '%s' for category '%s' ", widgetDef.getName(), category));
}
public void unregisterWidget(String category, WidgetDefinition widgetDef) {
WidgetDefinitionRegistry reg = widgetsByCat.get(category);
if (reg != null) {
reg.removeContribution(widgetDef);
log.info(String.format("Unregistered widget '%s' for category '%s' ", widgetDef.getName(), category));
}
}
// converter descriptors
public void registerLayoutConverter(String category, LayoutConverterDescriptor layoutConverter) {
LayoutConverterRegistry reg = layoutConvertersByCat.get(category);
if (reg == null) {
reg = new LayoutConverterRegistry(category);
layoutConvertersByCat.put(category, reg);
}
reg.addContribution(layoutConverter);
log.info(String.format("Registered layout converter '%s' for category '%s' ", layoutConverter.getName(),
category));
}
public void unregisterLayoutConverter(String category, LayoutConverterDescriptor layoutConverter) {
LayoutConverterRegistry reg = layoutConvertersByCat.get(category);
if (reg != null) {
reg.removeContribution(layoutConverter);
log.info(String.format("Unregistered layout converter '%s' for category '%s' ", layoutConverter.getName(),
category));
}
}
public void registerWidgetConverter(String category, WidgetConverterDescriptor widgetConverter) {
WidgetConverterRegistry reg = widgetConvertersByCat.get(category);
if (reg == null) {
reg = new WidgetConverterRegistry(category);
widgetConvertersByCat.put(category, reg);
}
reg.addContribution(widgetConverter);
log.info(String.format("Registered widget converter '%s' for category '%s' ", widgetConverter.getName(),
category));
}
public void unregisterWidgetConverter(String category, WidgetConverterDescriptor widgetConverter) {
WidgetConverterRegistry reg = widgetConvertersByCat.get(category);
if (reg != null) {
reg.removeContribution(widgetConverter);
log.info(String.format("Unregistered widget converter '%s' for category '%s' ", widgetConverter.getName(),
category));
}
}
// service api
public WidgetType getWidgetType(String category, String typeName) {
WidgetTypeRegistry reg = widgetTypesByCat.get(category);
if (reg != null) {
return reg.getWidgetType(typeName);
}
return null;
}
@Override
public WidgetTypeDefinition getWidgetTypeDefinition(String category, String typeName) {
WidgetTypeDefinitionRegistry reg = widgetTypeDefsByCat.get(category);
if (reg != null) {
return reg.getDefinition(typeName);
}
return null;
}
@Override
public List<WidgetTypeDefinition> getWidgetTypeDefinitions(String category) {
List<WidgetTypeDefinition> res = new ArrayList<WidgetTypeDefinition>();
WidgetTypeDefinitionRegistry reg = widgetTypeDefsByCat.get(category);
if (reg != null) {
Collection<WidgetTypeDefinition> defs = reg.getDefinitions();
if (defs != null) {
res.addAll(defs);
}
}
return res;
}
@Override
public LayoutTypeDefinition getLayoutTypeDefinition(String category, String typeName) {
LayoutTypeDefinitionRegistry reg = layoutTypeDefsByCat.get(category);
if (reg != null) {
return reg.getDefinition(typeName);
}
return null;
}
@Override
public List<LayoutTypeDefinition> getLayoutTypeDefinitions(String category) {
List<LayoutTypeDefinition> res = new ArrayList<LayoutTypeDefinition>();
LayoutTypeDefinitionRegistry reg = layoutTypeDefsByCat.get(category);
if (reg != null) {
Collection<LayoutTypeDefinition> defs = reg.getDefinitions();
if (defs != null) {
res.addAll(defs);
}
}
return res;
}
public LayoutDefinition getLayoutDefinition(String category, String layoutName) {
LayoutDefinitionRegistry reg = layoutsByCat.get(category);
if (reg != null) {
return reg.getLayoutDefinition(layoutName);
}
return null;
}
public List<String> getLayoutDefinitionNames(String category) {
LayoutDefinitionRegistry reg = layoutsByCat.get(category);
if (reg != null) {
return reg.getLayoutNames();
}
return Collections.emptyList();
}
public WidgetDefinition getWidgetDefinition(String category, String widgetName) {
WidgetDefinitionRegistry reg = widgetsByCat.get(category);
if (reg != null) {
return reg.getWidgetDefinition(widgetName);
}
return null;
}
@Override
public List<LayoutDefinitionConverter> getLayoutConverters(String category) {
List<LayoutDefinitionConverter> res = new ArrayList<LayoutDefinitionConverter>();
List<String> orderedConverterNames = new ArrayList<String>();
LayoutConverterRegistry reg = layoutConvertersByCat.get(category);
if (reg != null) {
List<LayoutConverterDescriptor> descs = reg.getConverters();
// first sort by order
Collections.sort(descs);
// instantiate converter instances
for (LayoutConverterDescriptor desc : descs) {
Class<?> converterClass;
try {
converterClass = LayoutStoreImpl.class.getClassLoader().loadClass(desc.getConverterClassName());
LayoutDefinitionConverter converter = (LayoutDefinitionConverter) converterClass.newInstance();
res.add(converter);
orderedConverterNames.add(desc.getName());
} catch (ReflectiveOperationException e) {
log.error("Caught error when instantiating " + "layout definition converter", e);
}
}
}
if (log.isDebugEnabled()) {
log.debug(String.format("Ordered layout converters for category '%s': %s", category, orderedConverterNames));
}
return res;
}
@Override
public List<WidgetDefinitionConverter> getWidgetConverters(String category) {
List<WidgetDefinitionConverter> res = new ArrayList<WidgetDefinitionConverter>();
List<String> orderedConverterNames = new ArrayList<String>();
WidgetConverterRegistry reg = widgetConvertersByCat.get(category);
if (reg != null) {
List<WidgetConverterDescriptor> descs = reg.getConverters();
// first sort by order
Collections.sort(descs);
// instantiate converter instances
for (WidgetConverterDescriptor desc : descs) {
Class<?> converterClass;
try {
converterClass = LayoutStoreImpl.class.getClassLoader().loadClass(desc.getConverterClassName());
WidgetDefinitionConverter converter = (WidgetDefinitionConverter) converterClass.newInstance();
res.add(converter);
orderedConverterNames.add(desc.getName());
} catch (ReflectiveOperationException e) {
log.error("Caught error when instantiating " + "widget definition converter", e);
}
}
}
if (log.isDebugEnabled()) {
log.debug(String.format("Ordered widget converters for category '%s': %s", category, orderedConverterNames));
}
return res;
}
}