001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id$ 018 */ 019 020package org.nuxeo.ecm.platform.types; 021 022import static org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfigurationConstants.UI_TYPES_CONFIGURATION_FACET; 023 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.HashMap; 028import java.util.HashSet; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 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.platform.types.localconfiguration.UITypesConfiguration; 040import org.nuxeo.runtime.api.Framework; 041import org.nuxeo.runtime.model.ComponentContext; 042import org.nuxeo.runtime.model.ComponentInstance; 043import org.nuxeo.runtime.model.ComponentName; 044import org.nuxeo.runtime.model.DefaultComponent; 045 046public class TypeService extends DefaultComponent implements TypeManager { 047 048 public static final ComponentName ID = new ComponentName("org.nuxeo.ecm.platform.types.TypeService"); 049 050 private static final Log log = LogFactory.getLog(TypeService.class); 051 052 public static String DEFAULT_CATEGORY = "misc"; 053 054 public static final String HIDDEN_IN_CREATION = "create"; 055 056 private TypeRegistry typeRegistry; 057 058 @Override 059 public void activate(ComponentContext context) { 060 typeRegistry = new TypeRegistry(); 061 } 062 063 @Override 064 public void deactivate(ComponentContext context) { 065 typeRegistry = null; 066 } 067 068 @Override 069 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 070 if (extensionPoint.equals("types")) { 071 typeRegistry.addContribution((Type) contribution); 072 } 073 } 074 075 @Override 076 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 077 if (extensionPoint.equals("types")) { 078 typeRegistry.removeContribution((Type) contribution); 079 } 080 } 081 082 public TypeRegistry getTypeRegistry() { 083 return typeRegistry; 084 } 085 086 // Service implementation for TypeManager interface 087 088 @Override 089 public String[] getSuperTypes(String typeName) { 090 SchemaManager schemaMgr = Framework.getService(SchemaManager.class); 091 DocumentType type = schemaMgr.getDocumentType(typeName); 092 if (type == null) { 093 return null; 094 } 095 type = (DocumentType) type.getSuperType(); 096 List<String> superTypes = new ArrayList<String>(); 097 while (type != null) { 098 superTypes.add(type.getName()); 099 type = (DocumentType) type.getSuperType(); 100 } 101 return superTypes.toArray(new String[superTypes.size()]); 102 } 103 104 @Override 105 public Type getType(String typeName) { 106 return typeRegistry.getType(typeName); 107 } 108 109 @Override 110 public boolean hasType(String typeName) { 111 return typeRegistry.hasType(typeName); 112 } 113 114 @Override 115 public Collection<Type> getTypes() { 116 Collection<Type> types = new ArrayList<Type>(); 117 types.addAll(typeRegistry.getTypes()); 118 return types; 119 } 120 121 @Override 122 public Collection<Type> getAllowedSubTypes(String typeName) { 123 return getAllowedSubTypes(typeName, null); 124 } 125 126 @Override 127 public Collection<Type> getAllowedSubTypes(String typeName, DocumentModel currentDoc) { 128 Collection<Type> allowed = new ArrayList<Type>(); 129 Type type = getType(typeName); 130 if (type != null) { 131 Map<String, SubType> allowedSubTypes = type.getAllowedSubTypes(); 132 if (currentDoc != null) { 133 allowedSubTypes = filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 134 } 135 for (String subTypeName : allowedSubTypes.keySet()) { 136 Type subType = getType(subTypeName); 137 if (subType != null) { 138 allowed.add(subType); 139 } 140 } 141 } 142 return allowed; 143 } 144 145 @Override 146 public Collection<Type> findAllAllowedSubTypesFrom(String typeName) { 147 return findAllAllowedSubTypesFrom(typeName, null, null); 148 } 149 150 @Override 151 public Collection<Type> findAllAllowedSubTypesFrom(String typeName, DocumentModel currentDoc) { 152 return findAllAllowedSubTypesFrom(typeName, currentDoc, null); 153 } 154 155 protected Collection<Type> findAllAllowedSubTypesFrom(String typeName, DocumentModel currentDoc, 156 List<String> alreadyProcessedTypes) { 157 if (alreadyProcessedTypes == null) { 158 alreadyProcessedTypes = new ArrayList<String>(); 159 } 160 Set<Type> allAllowedSubTypes = new HashSet<Type>(); 161 162 Collection<Type> allowedSubTypes = getAllowedSubTypes(typeName, currentDoc); 163 allAllowedSubTypes.addAll(allowedSubTypes); 164 alreadyProcessedTypes.add(typeName); 165 for (Type subType : allowedSubTypes) { 166 if (!alreadyProcessedTypes.contains(subType.getId())) { 167 allAllowedSubTypes.addAll(findAllAllowedSubTypesFrom(subType.getId(), currentDoc, alreadyProcessedTypes)); 168 } 169 } 170 171 return allAllowedSubTypes; 172 } 173 174 protected UITypesConfiguration getConfiguration(DocumentModel currentDoc) { 175 LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class); 176 return localConfigurationService.getConfiguration(UITypesConfiguration.class, UI_TYPES_CONFIGURATION_FACET, 177 currentDoc); 178 } 179 180 @Override 181 public Map<String, List<Type>> getTypeMapForDocumentType(String typeName, DocumentModel currentDoc) { 182 Type type = getType(typeName); 183 if (type != null) { 184 Map<String, List<Type>> docTypesMap = new HashMap<String, List<Type>>(); 185 Map<String, SubType> allowedSubTypes = type.getAllowedSubTypes(); 186 allowedSubTypes = filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 187 for (Map.Entry<String, SubType> entry : allowedSubTypes.entrySet()) { 188 if (canCreate(entry.getValue())) { 189 Type subType = getType(entry.getKey()); 190 if (subType != null) { 191 String key = subType.getCategory(); 192 if (key == null) { 193 key = DEFAULT_CATEGORY; 194 } 195 if (!docTypesMap.containsKey(key)) { 196 docTypesMap.put(key, new ArrayList<Type>()); 197 } 198 docTypesMap.get(key).add(subType); 199 } 200 } 201 } 202 return docTypesMap; 203 } 204 return new HashMap<String, List<Type>>(); 205 } 206 207 @Override 208 public boolean canCreate(String typeName, String containerTypeName) { 209 Type containerType = getType(containerTypeName); 210 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 211 return canCreate(typeName, allowedSubTypes); 212 } 213 214 @Override 215 public boolean canCreate(String typeName, String containerTypeName, DocumentModel currentDoc) { 216 Map<String, SubType> allowedSubTypes = getFilteredAllowedSubTypes(containerTypeName, currentDoc); 217 return canCreate(typeName, allowedSubTypes); 218 } 219 220 protected Map<String, SubType> getFilteredAllowedSubTypes(String containerTypeName, DocumentModel currentDoc) { 221 Type containerType = getType(containerTypeName); 222 if (containerType == null) { 223 return Collections.emptyMap(); 224 } 225 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 226 return filterSubTypesFromConfiguration(allowedSubTypes, currentDoc); 227 } 228 229 protected boolean canCreate(String typeName, Map<String, SubType> allowedSubTypes) { 230 if (!isAllowedSubType(typeName, allowedSubTypes)) { 231 return false; 232 } 233 234 SubType subType = allowedSubTypes.get(typeName); 235 return canCreate(subType); 236 } 237 238 protected boolean canCreate(SubType subType) { 239 List<String> hidden = subType.getHidden(); 240 return !(hidden != null && hidden.contains(HIDDEN_IN_CREATION)); 241 } 242 243 @Override 244 public boolean isAllowedSubType(String typeName, String containerTypeName) { 245 Type containerType = getType(containerTypeName); 246 if (containerType == null) { 247 return false; 248 } 249 Map<String, SubType> allowedSubTypes = containerType.getAllowedSubTypes(); 250 return isAllowedSubType(typeName, allowedSubTypes); 251 } 252 253 protected boolean isAllowedSubType(String typeName, Map<String, SubType> allowedSubTypes) { 254 for (String subTypeName : allowedSubTypes.keySet()) { 255 if (subTypeName.equals(typeName)) { 256 return true; 257 } 258 } 259 return false; 260 } 261 262 @Override 263 public boolean isAllowedSubType(String typeName, String containerTypeName, DocumentModel currentDoc) { 264 Map<String, SubType> allowedSubTypes = getFilteredAllowedSubTypes(containerTypeName, currentDoc); 265 return isAllowedSubType(typeName, allowedSubTypes); 266 } 267 268 protected Map<String, SubType> filterSubTypesFromConfiguration(Map<String, SubType> allowedSubTypes, 269 DocumentModel currentDoc) { 270 UITypesConfiguration uiTypesConfiguration = getConfiguration(currentDoc); 271 if (uiTypesConfiguration != null) { 272 allowedSubTypes = uiTypesConfiguration.filterSubTypes(allowedSubTypes); 273 } 274 return allowedSubTypes; 275 } 276 277}