001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.ecm.platform.types; 023 024import static org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfigurationConstants.UI_TYPES_CONFIGURATION_FACET; 025 026import java.util.ArrayList; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.HashMap; 030import java.util.HashSet; 031import java.util.List; 032import java.util.Map; 033import java.util.Set; 034 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037import org.nuxeo.ecm.core.api.DocumentModel; 038import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService; 039import org.nuxeo.ecm.core.schema.DocumentType; 040import org.nuxeo.ecm.core.schema.SchemaManager; 041import org.nuxeo.ecm.core.schema.SchemaManagerImpl; 042import org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfiguration; 043import org.nuxeo.runtime.api.Framework; 044import org.nuxeo.runtime.model.ComponentContext; 045import org.nuxeo.runtime.model.ComponentInstance; 046import org.nuxeo.runtime.model.ComponentName; 047import org.nuxeo.runtime.model.DefaultComponent; 048 049public class TypeService extends DefaultComponent implements TypeManager { 050 051 public static final ComponentName ID = new ComponentName("org.nuxeo.ecm.platform.types.TypeService"); 052 053 private static final Log log = LogFactory.getLog(TypeService.class); 054 055 public static String DEFAULT_CATEGORY = "misc"; 056 057 public static final String HIDDEN_IN_CREATION = "create"; 058 059 private TypeRegistry typeRegistry; 060 061 private Runnable recomputeCallback; 062 063 @Override 064 public void activate(ComponentContext context) { 065 typeRegistry = new TypeRegistry(); 066 recomputeCallback = typeRegistry::recomputeTypes; 067 SchemaManagerImpl schemaManager = (SchemaManagerImpl) Framework.getService(SchemaManager.class); 068 schemaManager.registerRecomputeCallback(recomputeCallback); 069 } 070 071 @Override 072 public void deactivate(ComponentContext context) { 073 SchemaManagerImpl schemaManager = (SchemaManagerImpl)Framework.getService(SchemaManager.class); 074 schemaManager.unregisterRecomputeCallback(recomputeCallback); 075 typeRegistry = null; 076 } 077 078 @Override 079 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 080 if (extensionPoint.equals("types")) { 081 typeRegistry.addContribution((Type) contribution); 082 } 083 } 084 085 @Override 086 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 087 if (extensionPoint.equals("types")) { 088 typeRegistry.removeContribution((Type) contribution); 089 } 090 } 091 092 public TypeRegistry getTypeRegistry() { 093 return typeRegistry; 094 } 095 096 // Service implementation for TypeManager interface 097 098 @Override 099 public String[] getSuperTypes(String typeName) { 100 SchemaManager schemaMgr = Framework.getService(SchemaManager.class); 101 DocumentType type = schemaMgr.getDocumentType(typeName); 102 if (type == null) { 103 return null; 104 } 105 type = (DocumentType) type.getSuperType(); 106 List<String> superTypes = new ArrayList<String>(); 107 while (type != null) { 108 superTypes.add(type.getName()); 109 type = (DocumentType) type.getSuperType(); 110 } 111 return superTypes.toArray(new String[superTypes.size()]); 112 } 113 114 @Override 115 public Type getType(String typeName) { 116 return typeRegistry.getType(typeName); 117 } 118 119 @Override 120 public boolean hasType(String typeName) { 121 return typeRegistry.hasType(typeName); 122 } 123 124 @Override 125 public Collection<Type> getTypes() { 126 Collection<Type> types = new ArrayList<Type>(); 127 types.addAll(typeRegistry.getTypes()); 128 return types; 129 } 130 131 @Override 132 public Collection<Type> getAllowedSubTypes(String typeName) { 133 return getAllowedSubTypes(typeName, null); 134 } 135 136 @Override 137 public Collection<Type> getAllowedSubTypes(String typeName, DocumentModel currentDoc) { 138 Collection<Type> allowed = new ArrayList<Type>(); 139 Type type = getType(typeName); 140 if (type != null) { 141 Map<String, SubType> allowedSubTypes = type.getAllowedSubTypes(); 142 if (currentDoc != null) { 143 allowedSubTypes = filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 144 } 145 for (String subTypeName : allowedSubTypes.keySet()) { 146 Type subType = getType(subTypeName); 147 if (subType != null) { 148 allowed.add(subType); 149 } 150 } 151 } 152 return allowed; 153 } 154 155 @Override 156 public Collection<Type> findAllAllowedSubTypesFrom(String typeName) { 157 return findAllAllowedSubTypesFrom(typeName, null, null); 158 } 159 160 @Override 161 public Collection<Type> findAllAllowedSubTypesFrom(String typeName, DocumentModel currentDoc) { 162 return findAllAllowedSubTypesFrom(typeName, currentDoc, null); 163 } 164 165 protected Collection<Type> findAllAllowedSubTypesFrom(String typeName, DocumentModel currentDoc, 166 List<String> alreadyProcessedTypes) { 167 if (alreadyProcessedTypes == null) { 168 alreadyProcessedTypes = new ArrayList<String>(); 169 } 170 Set<Type> allAllowedSubTypes = new HashSet<Type>(); 171 172 Collection<Type> allowedSubTypes = getAllowedSubTypes(typeName, currentDoc); 173 allAllowedSubTypes.addAll(allowedSubTypes); 174 alreadyProcessedTypes.add(typeName); 175 for (Type subType : allowedSubTypes) { 176 if (!alreadyProcessedTypes.contains(subType.getId())) { 177 allAllowedSubTypes.addAll(findAllAllowedSubTypesFrom(subType.getId(), currentDoc, alreadyProcessedTypes)); 178 } 179 } 180 181 return allAllowedSubTypes; 182 } 183 184 protected UITypesConfiguration getConfiguration(DocumentModel currentDoc) { 185 LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class); 186 return localConfigurationService.getConfiguration(UITypesConfiguration.class, UI_TYPES_CONFIGURATION_FACET, 187 currentDoc); 188 } 189 190 @Override 191 public Map<String, List<Type>> getTypeMapForDocumentType(String typeName, DocumentModel currentDoc) { 192 Type type = getType(typeName); 193 if (type != null) { 194 Map<String, List<Type>> docTypesMap = new HashMap<String, List<Type>>(); 195 Map<String, SubType> allowedSubTypes = type.getAllowedSubTypes(); 196 allowedSubTypes = filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 197 for (Map.Entry<String, SubType> entry : allowedSubTypes.entrySet()) { 198 if (canCreate(entry.getValue())) { 199 Type subType = getType(entry.getKey()); 200 if (subType != null) { 201 String key = subType.getCategory(); 202 if (key == null) { 203 key = DEFAULT_CATEGORY; 204 } 205 if (!docTypesMap.containsKey(key)) { 206 docTypesMap.put(key, new ArrayList<Type>()); 207 } 208 docTypesMap.get(key).add(subType); 209 } 210 } 211 } 212 return docTypesMap; 213 } 214 return new HashMap<String, List<Type>>(); 215 } 216 217 @Override 218 public boolean canCreate(String typeName, String containerTypeName) { 219 Type containerType = getType(containerTypeName); 220 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 221 return canCreate(typeName, allowedSubTypes); 222 } 223 224 @Override 225 public boolean canCreate(String typeName, String containerTypeName, DocumentModel currentDoc) { 226 Map<String, SubType> allowedSubTypes = getFilteredAllowedSubTypes(containerTypeName, currentDoc); 227 return canCreate(typeName, allowedSubTypes); 228 } 229 230 protected Map<String, SubType> getFilteredAllowedSubTypes(String containerTypeName, DocumentModel currentDoc) { 231 Type containerType = getType(containerTypeName); 232 if (containerType == null) { 233 return Collections.emptyMap(); 234 } 235 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 236 return filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 237 } 238 239 protected boolean canCreate(String typeName, Map<String, SubType> allowedSubTypes) { 240 if (!isAllowedSubType(typeName, allowedSubTypes)) { 241 return false; 242 } 243 244 SubType subType = allowedSubTypes.get(typeName); 245 return canCreate(subType); 246 } 247 248 protected boolean canCreate(SubType subType) { 249 List<String> hidden = subType.getHidden(); 250 return !(hidden != null && hidden.contains(HIDDEN_IN_CREATION)); 251 } 252 253 @Override 254 public boolean isAllowedSubType(String typeName, String containerTypeName) { 255 Type containerType = getType(containerTypeName); 256 if (containerType == null) { 257 return false; 258 } 259 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 260 return isAllowedSubType(typeName, allowedSubTypes); 261 } 262 263 protected boolean isAllowedSubType(String typeName, Map<String, SubType> allowedSubTypes) { 264 for (String subTypeName : allowedSubTypes.keySet()) { 265 if (subTypeName.equals(typeName)) { 266 return true; 267 } 268 } 269 return false; 270 } 271 272 @Override 273 public boolean isAllowedSubType(String typeName, String containerTypeName, DocumentModel currentDoc) { 274 Map<String, SubType> allowedSubTypes = getFilteredAllowedSubTypes(containerTypeName, currentDoc); 275 return isAllowedSubType(typeName, allowedSubTypes); 276 } 277 278 protected Map<String, SubType> filterSubTypesFromConfiguration(Map<String, SubType> allowedSubTypes, 279 DocumentModel currentDoc) { 280 UITypesConfiguration uiTypesConfiguration = getConfiguration(currentDoc); 281 if (uiTypesConfiguration != null) { 282 allowedSubTypes = uiTypesConfiguration.filterSubTypes(allowedSubTypes); 283 } 284 return allowedSubTypes; 285 } 286 287}