/*
* (C) Copyright 2006-2007 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:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.nuxeo.ecm.platform.types;
import static org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfigurationConstants.UI_TYPES_CONFIGURATION_FACET;
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.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService;
import org.nuxeo.ecm.core.schema.DocumentType;
import org.nuxeo.ecm.core.schema.SchemaManager;
import org.nuxeo.ecm.core.schema.SchemaManagerImpl;
import org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfiguration;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.model.ComponentContext;
import org.nuxeo.runtime.model.ComponentInstance;
import org.nuxeo.runtime.model.ComponentName;
import org.nuxeo.runtime.model.DefaultComponent;
public class TypeService extends DefaultComponent implements TypeManager {
public static final ComponentName ID = new ComponentName("org.nuxeo.ecm.platform.types.TypeService");
private static final Log log = LogFactory.getLog(TypeService.class);
public static String DEFAULT_CATEGORY = "misc";
public static final String HIDDEN_IN_CREATION = "create";
private TypeRegistry typeRegistry;
private Runnable recomputeCallback;
@Override
public void activate(ComponentContext context) {
typeRegistry = new TypeRegistry();
recomputeCallback = typeRegistry::recomputeTypes;
SchemaManagerImpl schemaManager = (SchemaManagerImpl) Framework.getService(SchemaManager.class);
schemaManager.registerRecomputeCallback(recomputeCallback);
}
@Override
public void deactivate(ComponentContext context) {
SchemaManagerImpl schemaManager = (SchemaManagerImpl)Framework.getService(SchemaManager.class);
schemaManager.unregisterRecomputeCallback(recomputeCallback);
typeRegistry = null;
}
@Override
public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
if (extensionPoint.equals("types")) {
typeRegistry.addContribution((Type) contribution);
}
}
@Override
public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
if (extensionPoint.equals("types")) {
typeRegistry.removeContribution((Type) contribution);
}
}
public TypeRegistry getTypeRegistry() {
return typeRegistry;
}
// Service implementation for TypeManager interface
@Override
public String[] getSuperTypes(String typeName) {
SchemaManager schemaMgr = Framework.getService(SchemaManager.class);
DocumentType type = schemaMgr.getDocumentType(typeName);
if (type == null) {
return null;
}
type = (DocumentType) type.getSuperType();
List<String> superTypes = new ArrayList<String>();
while (type != null) {
superTypes.add(type.getName());
type = (DocumentType) type.getSuperType();
}
return superTypes.toArray(new String[superTypes.size()]);
}
@Override
public Type getType(String typeName) {
return typeRegistry.getType(typeName);
}
@Override
public boolean hasType(String typeName) {
return typeRegistry.hasType(typeName);
}
@Override
public Collection<Type> getTypes() {
Collection<Type> types = new ArrayList<Type>();
types.addAll(typeRegistry.getTypes());
return types;
}
@Override
public Collection<Type> getAllowedSubTypes(String typeName) {
return getAllowedSubTypes(typeName, null);
}
@Override
public Collection<Type> getAllowedSubTypes(String typeName, DocumentModel currentDoc) {
Collection<Type> allowed = new ArrayList<Type>();
Type type = getType(typeName);
if (type != null) {
Map<String, SubType> allowedSubTypes = type.getAllowedSubTypes();
if (currentDoc != null) {
allowedSubTypes = filterSubTypesFromConfiguration(allowedSubTypes, currentDoc);
}
for (String subTypeName : allowedSubTypes.keySet()) {
Type subType = getType(subTypeName);
if (subType != null) {
allowed.add(subType);
}
}
}
return allowed;
}
@Override
public Collection<Type> findAllAllowedSubTypesFrom(String typeName) {
return findAllAllowedSubTypesFrom(typeName, null, null);
}
@Override
public Collection<Type> findAllAllowedSubTypesFrom(String typeName, DocumentModel currentDoc) {
return findAllAllowedSubTypesFrom(typeName, currentDoc, null);
}
protected Collection<Type> findAllAllowedSubTypesFrom(String typeName, DocumentModel currentDoc,
List<String> alreadyProcessedTypes) {
if (alreadyProcessedTypes == null) {
alreadyProcessedTypes = new ArrayList<String>();
}
Set<Type> allAllowedSubTypes = new HashSet<Type>();
Collection<Type> allowedSubTypes = getAllowedSubTypes(typeName, currentDoc);
allAllowedSubTypes.addAll(allowedSubTypes);
alreadyProcessedTypes.add(typeName);
for (Type subType : allowedSubTypes) {
if (!alreadyProcessedTypes.contains(subType.getId())) {
allAllowedSubTypes.addAll(findAllAllowedSubTypesFrom(subType.getId(), currentDoc, alreadyProcessedTypes));
}
}
return allAllowedSubTypes;
}
protected UITypesConfiguration getConfiguration(DocumentModel currentDoc) {
LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class);
return localConfigurationService.getConfiguration(UITypesConfiguration.class, UI_TYPES_CONFIGURATION_FACET,
currentDoc);
}
@Override
public Map<String, List<Type>> getTypeMapForDocumentType(String typeName, DocumentModel currentDoc) {
Type type = getType(typeName);
if (type != null) {
Map<String, List<Type>> docTypesMap = new HashMap<String, List<Type>>();
Map<String, SubType> allowedSubTypes = type.getAllowedSubTypes();
allowedSubTypes = filterSubTypesFromConfiguration(allowedSubTypes, currentDoc);
for (Map.Entry<String, SubType> entry : allowedSubTypes.entrySet()) {
if (canCreate(entry.getValue())) {
Type subType = getType(entry.getKey());
if (subType != null) {
String key = subType.getCategory();
if (key == null) {
key = DEFAULT_CATEGORY;
}
if (!docTypesMap.containsKey(key)) {
docTypesMap.put(key, new ArrayList<Type>());
}
docTypesMap.get(key).add(subType);
}
}
}
return docTypesMap;
}
return new HashMap<String, List<Type>>();
}
@Override
public boolean canCreate(String typeName, String containerTypeName) {
Type containerType = getType(containerTypeName);
Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes();
return canCreate(typeName, allowedSubTypes);
}
@Override
public boolean canCreate(String typeName, String containerTypeName, DocumentModel currentDoc) {
Map<String, SubType> allowedSubTypes = getFilteredAllowedSubTypes(containerTypeName, currentDoc);
return canCreate(typeName, allowedSubTypes);
}
protected Map<String, SubType> getFilteredAllowedSubTypes(String containerTypeName, DocumentModel currentDoc) {
Type containerType = getType(containerTypeName);
if (containerType == null) {
return Collections.emptyMap();
}
Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes();
return filterSubTypesFromConfiguration(allowedSubTypes, currentDoc);
}
protected boolean canCreate(String typeName, Map<String, SubType> allowedSubTypes) {
if (!isAllowedSubType(typeName, allowedSubTypes)) {
return false;
}
SubType subType = allowedSubTypes.get(typeName);
return canCreate(subType);
}
protected boolean canCreate(SubType subType) {
List<String> hidden = subType.getHidden();
return !(hidden != null && hidden.contains(HIDDEN_IN_CREATION));
}
@Override
public boolean isAllowedSubType(String typeName, String containerTypeName) {
Type containerType = getType(containerTypeName);
if (containerType == null) {
return false;
}
Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes();
return isAllowedSubType(typeName, allowedSubTypes);
}
protected boolean isAllowedSubType(String typeName, Map<String, SubType> allowedSubTypes) {
for (String subTypeName : allowedSubTypes.keySet()) {
if (subTypeName.equals(typeName)) {
return true;
}
}
return false;
}
@Override
public boolean isAllowedSubType(String typeName, String containerTypeName, DocumentModel currentDoc) {
Map<String, SubType> allowedSubTypes = getFilteredAllowedSubTypes(containerTypeName, currentDoc);
return isAllowedSubType(typeName, allowedSubTypes);
}
protected Map<String, SubType> filterSubTypesFromConfiguration(Map<String, SubType> allowedSubTypes,
DocumentModel currentDoc) {
UITypesConfiguration uiTypesConfiguration = getConfiguration(currentDoc);
if (uiTypesConfiguration != null) {
allowedSubTypes = uiTypesConfiguration.filterSubTypes(allowedSubTypes);
}
return allowedSubTypes;
}
}