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.nuxeo.ecm.core.api.DocumentModel; 036import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService; 037import org.nuxeo.ecm.core.schema.DocumentType; 038import org.nuxeo.ecm.core.schema.SchemaManager; 039import org.nuxeo.ecm.core.schema.SchemaManagerImpl; 040import org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfiguration; 041import org.nuxeo.runtime.api.Framework; 042import org.nuxeo.runtime.model.ComponentContext; 043import org.nuxeo.runtime.model.ComponentInstance; 044import org.nuxeo.runtime.model.ComponentName; 045import org.nuxeo.runtime.model.DefaultComponent; 046 047public class TypeService extends DefaultComponent implements TypeManager { 048 049 public static final ComponentName ID = new ComponentName("org.nuxeo.ecm.platform.types.TypeService"); 050 051 public static final String DEFAULT_CATEGORY = "misc"; 052 053 public static final String HIDDEN_IN_CREATION = "create"; 054 055 private TypeRegistry typeRegistry; 056 057 private Runnable recomputeCallback; 058 059 @Override 060 public void activate(ComponentContext context) { 061 typeRegistry = new TypeRegistry(); 062 recomputeCallback = typeRegistry::recomputeTypes; 063 SchemaManagerImpl schemaManager = (SchemaManagerImpl) Framework.getService(SchemaManager.class); 064 schemaManager.registerRecomputeCallback(recomputeCallback); 065 } 066 067 @Override 068 public void deactivate(ComponentContext context) { 069 SchemaManagerImpl schemaManager = (SchemaManagerImpl)Framework.getService(SchemaManager.class); 070 schemaManager.unregisterRecomputeCallback(recomputeCallback); 071 typeRegistry = null; 072 } 073 074 @Override 075 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 076 if (extensionPoint.equals("types")) { 077 typeRegistry.addContribution((Type) contribution); 078 } 079 } 080 081 @Override 082 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 083 if (extensionPoint.equals("types")) { 084 typeRegistry.removeContribution((Type) contribution); 085 } 086 } 087 088 public TypeRegistry getTypeRegistry() { 089 return typeRegistry; 090 } 091 092 // Service implementation for TypeManager interface 093 094 @Override 095 public String[] getSuperTypes(String typeName) { 096 SchemaManager schemaMgr = Framework.getService(SchemaManager.class); 097 DocumentType type = schemaMgr.getDocumentType(typeName); 098 if (type == null) { 099 return null; 100 } 101 type = (DocumentType) type.getSuperType(); 102 List<String> superTypes = new ArrayList<String>(); 103 while (type != null) { 104 superTypes.add(type.getName()); 105 type = (DocumentType) type.getSuperType(); 106 } 107 return superTypes.toArray(new String[superTypes.size()]); 108 } 109 110 @Override 111 public Type getType(String typeName) { 112 return typeRegistry.getType(typeName); 113 } 114 115 @Override 116 public boolean hasType(String typeName) { 117 return typeRegistry.hasType(typeName); 118 } 119 120 @Override 121 public Collection<Type> getTypes() { 122 Collection<Type> types = new ArrayList<Type>(); 123 types.addAll(typeRegistry.getTypes()); 124 return types; 125 } 126 127 @Override 128 public Collection<Type> getAllowedSubTypes(String typeName) { 129 return getAllowedSubTypes(typeName, null); 130 } 131 132 @Override 133 public Collection<Type> getAllowedSubTypes(String typeName, DocumentModel currentDoc) { 134 Collection<Type> allowed = new ArrayList<Type>(); 135 Type type = getType(typeName); 136 if (type != null) { 137 Map<String, SubType> allowedSubTypes = type.getAllowedSubTypes(); 138 if (currentDoc != null) { 139 allowedSubTypes = filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 140 } 141 for (String subTypeName : allowedSubTypes.keySet()) { 142 Type subType = getType(subTypeName); 143 if (subType != null) { 144 allowed.add(subType); 145 } 146 } 147 } 148 return allowed; 149 } 150 151 @Override 152 public Collection<Type> findAllAllowedSubTypesFrom(String typeName) { 153 return findAllAllowedSubTypesFrom(typeName, null, null); 154 } 155 156 @Override 157 public Collection<Type> findAllAllowedSubTypesFrom(String typeName, DocumentModel currentDoc) { 158 return findAllAllowedSubTypesFrom(typeName, currentDoc, null); 159 } 160 161 protected Collection<Type> findAllAllowedSubTypesFrom(String typeName, DocumentModel currentDoc, 162 List<String> alreadyProcessedTypes) { 163 if (alreadyProcessedTypes == null) { 164 alreadyProcessedTypes = new ArrayList<String>(); 165 } 166 Set<Type> allAllowedSubTypes = new HashSet<Type>(); 167 168 Collection<Type> allowedSubTypes = getAllowedSubTypes(typeName, currentDoc); 169 allAllowedSubTypes.addAll(allowedSubTypes); 170 alreadyProcessedTypes.add(typeName); 171 for (Type subType : allowedSubTypes) { 172 if (!alreadyProcessedTypes.contains(subType.getId())) { 173 allAllowedSubTypes.addAll(findAllAllowedSubTypesFrom(subType.getId(), currentDoc, alreadyProcessedTypes)); 174 } 175 } 176 177 return allAllowedSubTypes; 178 } 179 180 protected UITypesConfiguration getConfiguration(DocumentModel currentDoc) { 181 LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class); 182 return localConfigurationService.getConfiguration(UITypesConfiguration.class, UI_TYPES_CONFIGURATION_FACET, 183 currentDoc); 184 } 185 186 @Override 187 public Map<String, List<Type>> getTypeMapForDocumentType(String typeName, DocumentModel currentDoc) { 188 Type type = getType(typeName); 189 if (type != null) { 190 Map<String, List<Type>> docTypesMap = new HashMap<String, List<Type>>(); 191 Map<String, SubType> allowedSubTypes = type.getAllowedSubTypes(); 192 allowedSubTypes = filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 193 for (Map.Entry<String, SubType> entry : allowedSubTypes.entrySet()) { 194 if (canCreate(entry.getValue())) { 195 Type subType = getType(entry.getKey()); 196 if (subType != null) { 197 String key = subType.getCategory(); 198 if (key == null) { 199 key = DEFAULT_CATEGORY; 200 } 201 if (!docTypesMap.containsKey(key)) { 202 docTypesMap.put(key, new ArrayList<Type>()); 203 } 204 docTypesMap.get(key).add(subType); 205 } 206 } 207 } 208 return docTypesMap; 209 } 210 return new HashMap<String, List<Type>>(); 211 } 212 213 @Override 214 public boolean canCreate(String typeName, String containerTypeName) { 215 Type containerType = getType(containerTypeName); 216 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 217 return canCreate(typeName, allowedSubTypes); 218 } 219 220 @Override 221 public boolean canCreate(String typeName, String containerTypeName, DocumentModel currentDoc) { 222 Map<String, SubType> allowedSubTypes = getFilteredAllowedSubTypes(containerTypeName, currentDoc); 223 return canCreate(typeName, allowedSubTypes); 224 } 225 226 protected Map<String, SubType> getFilteredAllowedSubTypes(String containerTypeName, DocumentModel currentDoc) { 227 Type containerType = getType(containerTypeName); 228 if (containerType == null) { 229 return Collections.emptyMap(); 230 } 231 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 232 return filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 233 } 234 235 protected boolean canCreate(String typeName, Map<String, SubType> allowedSubTypes) { 236 if (!isAllowedSubType(typeName, allowedSubTypes)) { 237 return false; 238 } 239 240 SubType subType = allowedSubTypes.get(typeName); 241 return canCreate(subType); 242 } 243 244 protected boolean canCreate(SubType subType) { 245 List<String> hidden = subType.getHidden(); 246 return !(hidden != null && hidden.contains(HIDDEN_IN_CREATION)); 247 } 248 249 @Override 250 public boolean isAllowedSubType(String typeName, String containerTypeName) { 251 Type containerType = getType(containerTypeName); 252 if (containerType == null) { 253 return false; 254 } 255 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 256 return isAllowedSubType(typeName, allowedSubTypes); 257 } 258 259 protected boolean isAllowedSubType(String typeName, Map<String, SubType> allowedSubTypes) { 260 for (String subTypeName : allowedSubTypes.keySet()) { 261 if (subTypeName.equals(typeName)) { 262 return true; 263 } 264 } 265 return false; 266 } 267 268 @Override 269 public boolean isAllowedSubType(String typeName, String containerTypeName, DocumentModel currentDoc) { 270 Map<String, SubType> allowedSubTypes = getFilteredAllowedSubTypes(containerTypeName, currentDoc); 271 return isAllowedSubType(typeName, allowedSubTypes); 272 } 273 274 protected Map<String, SubType> filterSubTypesFromConfiguration(Map<String, SubType> allowedSubTypes, 275 DocumentModel currentDoc) { 276 UITypesConfiguration uiTypesConfiguration = getConfiguration(currentDoc); 277 if (uiTypesConfiguration != null) { 278 allowedSubTypes = uiTypesConfiguration.filterSubTypes(allowedSubTypes); 279 } 280 return allowedSubTypes; 281 } 282 283}