001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Florent Guillaume 011 */ 012package org.nuxeo.ecm.core.opencmis.impl.server; 013 014import static org.apache.chemistry.opencmis.commons.BasicPermissions.ALL; 015import static org.apache.chemistry.opencmis.commons.BasicPermissions.READ; 016import static org.apache.chemistry.opencmis.commons.BasicPermissions.WRITE; 017import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_ADD_POLICY_OBJECT; 018import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_ADD_POLICY_POLICY; 019import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_ADD_TO_FOLDER_FOLDER; 020import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_ADD_TO_FOLDER_OBJECT; 021import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_APPLY_ACL_OBJECT; 022import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CANCEL_CHECKOUT_DOCUMENT; 023import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CHECKIN_DOCUMENT; 024import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CHECKOUT_DOCUMENT; 025import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CREATE_DOCUMENT_FOLDER; 026import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CREATE_FOLDER_FOLDER; 027import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CREATE_RELATIONSHIP_SOURCE; 028import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_CREATE_RELATIONSHIP_TARGET; 029import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_DELETE_CONTENT_DOCUMENT; 030import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_DELETE_OBJECT; 031import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_DELETE_TREE_FOLDER; 032import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_ACL_OBJECT; 033import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_ALL_VERSIONS_VERSION_SERIES; 034import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_APPLIED_POLICIES_OBJECT; 035import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_CHILDREN_FOLDER; 036import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_DESCENDENTS_FOLDER; 037import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_FOLDER_PARENT_OBJECT; 038import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_OBJECT_RELATIONSHIPS_OBJECT; 039import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_PARENTS_FOLDER; 040import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_GET_PROPERTIES_OBJECT; 041import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_MOVE_OBJECT; 042import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_MOVE_SOURCE; 043import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_MOVE_TARGET; 044import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_REMOVE_FROM_FOLDER_FOLDER; 045import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_REMOVE_FROM_FOLDER_OBJECT; 046import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_REMOVE_POLICY_OBJECT; 047import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_REMOVE_POLICY_POLICY; 048import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_SET_CONTENT_DOCUMENT; 049import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_UPDATE_PROPERTIES_OBJECT; 050import static org.apache.chemistry.opencmis.commons.data.PermissionMapping.CAN_VIEW_CONTENT_OBJECT; 051 052import java.lang.reflect.Field; 053import java.math.BigInteger; 054import java.util.ArrayList; 055import java.util.Arrays; 056import java.util.Collection; 057import java.util.Collections; 058import java.util.HashMap; 059import java.util.HashSet; 060import java.util.LinkedList; 061import java.util.List; 062import java.util.Map; 063import java.util.Map.Entry; 064import java.util.Set; 065 066import javax.servlet.http.HttpServletRequest; 067 068import org.apache.chemistry.opencmis.commons.data.CreatablePropertyTypes; 069import org.apache.chemistry.opencmis.commons.data.ExtensionFeature; 070import org.apache.chemistry.opencmis.commons.data.NewTypeSettableAttributes; 071import org.apache.chemistry.opencmis.commons.data.PermissionMapping; 072import org.apache.chemistry.opencmis.commons.data.RepositoryInfo; 073import org.apache.chemistry.opencmis.commons.definitions.PermissionDefinition; 074import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition; 075import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer; 076import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList; 077import org.apache.chemistry.opencmis.commons.enums.AclPropagation; 078import org.apache.chemistry.opencmis.commons.enums.BaseTypeId; 079import org.apache.chemistry.opencmis.commons.enums.CapabilityAcl; 080import org.apache.chemistry.opencmis.commons.enums.CapabilityChanges; 081import org.apache.chemistry.opencmis.commons.enums.CapabilityContentStreamUpdates; 082import org.apache.chemistry.opencmis.commons.enums.CapabilityJoin; 083import org.apache.chemistry.opencmis.commons.enums.CapabilityQuery; 084import org.apache.chemistry.opencmis.commons.enums.CapabilityRenditions; 085import org.apache.chemistry.opencmis.commons.enums.CmisVersion; 086import org.apache.chemistry.opencmis.commons.enums.SupportedPermissions; 087import org.apache.chemistry.opencmis.commons.impl.dataobjects.AclCapabilitiesDataImpl; 088import org.apache.chemistry.opencmis.commons.impl.dataobjects.CreatablePropertyTypesImpl; 089import org.apache.chemistry.opencmis.commons.impl.dataobjects.NewTypeSettableAttributesImpl; 090import org.apache.chemistry.opencmis.commons.impl.dataobjects.PermissionDefinitionDataImpl; 091import org.apache.chemistry.opencmis.commons.impl.dataobjects.PermissionMappingDataImpl; 092import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryCapabilitiesImpl; 093import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryInfoImpl; 094import org.apache.chemistry.opencmis.commons.server.CallContext; 095import org.nuxeo.ecm.core.api.security.PermissionProvider; 096import org.nuxeo.ecm.core.api.security.SecurityConstants; 097import org.nuxeo.ecm.core.opencmis.impl.util.TypeManagerImpl; 098import org.nuxeo.ecm.core.schema.DocumentType; 099import org.nuxeo.ecm.core.schema.SchemaManager; 100import org.nuxeo.ecm.core.schema.types.CompositeType; 101import org.nuxeo.ecm.core.schema.types.Schema; 102import org.nuxeo.ecm.core.security.DefaultPermissionProvider; 103import org.nuxeo.ecm.core.security.PermissionVisibilityDescriptor; 104import org.nuxeo.runtime.api.Framework; 105 106/** 107 * Information about a Nuxeo repository. 108 */ 109public class NuxeoRepository { 110 111 public static final String NUXEO_VERSION_PROP = "org.nuxeo.distribution.version"; 112 113 public static final String NUXEO_URL_PROP = "nuxeo.url"; 114 115 public static final String SUPPORTS_JOINS_PROP = "org.nuxeo.cmis.joins"; 116 117 public static final String ELASTICSEARCH_PROP = "org.nuxeo.cmis.elasticsearch"; 118 119 private static final String NUXEO_CONTEXT_PATH_PROP = "org.nuxeo.ecm.contextPath"; 120 121 private static final String NUXEO_CONTEXT_PATH_DEFAULT = "/nuxeo"; 122 123 private static final String X_FORWARDED_HOST = "x-forwarded-host"; 124 125 private static final String NUXEO_VH_HEADER = "nuxeo-virtual-host"; 126 127 private static final String VH_PARAM = "nuxeo.virtual.host"; 128 129 public static final String NUXEO_READ_REMOVE = "ReadRemove"; 130 131 protected final String repositoryId; 132 133 protected final String rootFolderId; 134 135 protected boolean supportsJoins; 136 137 protected boolean useElasticsearch; 138 139 protected TypeManagerImpl typeManager; 140 141 public NuxeoRepository(String repositoryId, String rootFolderId) { 142 this.repositoryId = repositoryId; 143 this.rootFolderId = rootFolderId; 144 if (Framework.isBooleanPropertyTrue(SUPPORTS_JOINS_PROP)) { 145 setSupportsJoins(true); 146 } 147 if (Framework.isBooleanPropertyTrue(ELASTICSEARCH_PROP)) { 148 setUseElasticsearch(true); 149 } 150 } 151 152 public void setSupportsJoins(boolean supportsJoins) { 153 this.supportsJoins = supportsJoins; 154 } 155 156 public boolean supportsJoins() { 157 return supportsJoins; 158 } 159 160 public void setUseElasticsearch(boolean useElasticsearch) { 161 this.useElasticsearch = useElasticsearch; 162 } 163 164 public boolean useElasticsearch() { 165 return useElasticsearch; 166 } 167 168 public String getId() { 169 return repositoryId; 170 } 171 172 // no need to have it synchronized 173 public TypeManagerImpl getTypeManager() { 174 if (typeManager == null) { 175 typeManager = initializeTypes(); 176 } 177 return typeManager; 178 } 179 180 protected static TypeManagerImpl initializeTypes() { 181 SchemaManager schemaManager = Framework.getService(SchemaManager.class); 182 // scan the types to find super/inherited relationships 183 Map<String, List<String>> typesChildren = new HashMap<String, List<String>>(); 184 for (DocumentType dt : schemaManager.getDocumentTypes()) { 185 org.nuxeo.ecm.core.schema.types.Type st = dt.getSuperType(); 186 if (st == null) { 187 continue; 188 } 189 String name = st.getName(); 190 List<String> siblings = typesChildren.get(name); 191 if (siblings == null) { 192 siblings = new LinkedList<String>(); 193 typesChildren.put(name, siblings); 194 } 195 siblings.add(dt.getName()); 196 } 197 // convert the transitive closure for Folder and Document subtypes 198 Set<String> done = new HashSet<String>(); 199 TypeManagerImpl typeManager = new TypeManagerImpl(); 200 typeManager.addTypeDefinition(NuxeoTypeHelper.constructCmisBase(BaseTypeId.CMIS_DOCUMENT, schemaManager)); 201 typeManager.addTypeDefinition(NuxeoTypeHelper.constructCmisBase(BaseTypeId.CMIS_FOLDER, schemaManager)); 202 typeManager.addTypeDefinition(NuxeoTypeHelper.constructCmisBase(BaseTypeId.CMIS_RELATIONSHIP, schemaManager)); 203 typeManager.addTypeDefinition(NuxeoTypeHelper.constructCmisBase(BaseTypeId.CMIS_SECONDARY, schemaManager)); 204 addTypesRecursively(typeManager, NuxeoTypeHelper.NUXEO_DOCUMENT, typesChildren, done, schemaManager); 205 addTypesRecursively(typeManager, NuxeoTypeHelper.NUXEO_FOLDER, typesChildren, done, schemaManager); 206 addTypesRecursively(typeManager, NuxeoTypeHelper.NUXEO_RELATION, typesChildren, done, schemaManager); 207 addSecondaryTypes(typeManager, schemaManager); 208 return typeManager; 209 } 210 211 protected static void addTypesRecursively(TypeManagerImpl typeManager, String name, 212 Map<String, List<String>> typesChildren, Set<String> done, SchemaManager schemaManager) { 213 if (done.contains(name)) { 214 return; 215 } 216 done.add(name); 217 DocumentType dt = schemaManager.getDocumentType(name); 218 String parentTypeId = NuxeoTypeHelper.getParentTypeId(dt); 219 if (parentTypeId != null) { 220 TypeDefinitionContainer parentType = typeManager.getTypeById(parentTypeId); 221 if (parentType == null) { 222 // if parent was ignored, reparent under cmis:document 223 parentTypeId = BaseTypeId.CMIS_DOCUMENT.value(); 224 } else { 225 if (parentType.getTypeDefinition().getBaseTypeId() != BaseTypeId.CMIS_FOLDER && dt.isFolder()) { 226 // reparent Folderish but child of Document under 227 // cmis:folder 228 parentTypeId = BaseTypeId.CMIS_FOLDER.value(); 229 } 230 } 231 typeManager.addTypeDefinition(NuxeoTypeHelper.constructDocumentType(dt, parentTypeId)); 232 } 233 // recurse in children 234 List<String> children = typesChildren.get(name); 235 if (children == null) { 236 return; 237 } 238 for (String sub : children) { 239 addTypesRecursively(typeManager, sub, typesChildren, done, schemaManager); 240 } 241 } 242 243 protected static void addSecondaryTypes(TypeManagerImpl typeManager, SchemaManager schemaManager) { 244 for (CompositeType type : schemaManager.getFacets()) { 245 typeManager.addTypeDefinition(NuxeoTypeHelper.constructSecondaryType(type), false); 246 } 247 } 248 249 public String getRootFolderId() { 250 return rootFolderId; 251 } 252 253 public RepositoryInfo getRepositoryInfo(String latestChangeLogToken, CallContext callContext) { 254 RepositoryInfoImpl repositoryInfo = new RepositoryInfoImpl(); 255 repositoryInfo.setId(repositoryId); 256 repositoryInfo.setName("Nuxeo Repository " + repositoryId); 257 repositoryInfo.setDescription("Nuxeo Repository " + repositoryId); 258 repositoryInfo.setCmisVersionSupported(CmisVersion.CMIS_1_1.value()); 259 repositoryInfo.setPrincipalAnonymous("Guest"); // TODO 260 repositoryInfo.setPrincipalAnyone(SecurityConstants.EVERYONE); 261 repositoryInfo.setThinClientUri(getBaseURL(callContext)); 262 repositoryInfo.setChangesIncomplete(Boolean.FALSE); 263 repositoryInfo.setChangesOnType(Arrays.asList(BaseTypeId.CMIS_DOCUMENT, BaseTypeId.CMIS_FOLDER)); 264 repositoryInfo.setLatestChangeLogToken(latestChangeLogToken); 265 repositoryInfo.setVendorName("Nuxeo"); 266 repositoryInfo.setProductName("Nuxeo OpenCMIS Connector"); 267 String version = Framework.getProperty(NUXEO_VERSION_PROP, "5.5 dev"); 268 repositoryInfo.setProductVersion(version); 269 repositoryInfo.setRootFolder(rootFolderId); 270 repositoryInfo.setExtensionFeature(Collections.<ExtensionFeature> emptyList()); 271 272 // capabilities 273 274 RepositoryCapabilitiesImpl caps = new RepositoryCapabilitiesImpl(); 275 caps.setAllVersionsSearchable(Boolean.TRUE); 276 caps.setCapabilityAcl(CapabilityAcl.MANAGE); 277 caps.setCapabilityChanges(CapabilityChanges.OBJECTIDSONLY); 278 caps.setCapabilityContentStreamUpdates(CapabilityContentStreamUpdates.PWCONLY); 279 caps.setCapabilityJoin(supportsJoins ? CapabilityJoin.INNERANDOUTER : CapabilityJoin.NONE); 280 caps.setCapabilityQuery(CapabilityQuery.BOTHCOMBINED); 281 caps.setCapabilityRendition(CapabilityRenditions.READ); 282 caps.setIsPwcSearchable(Boolean.TRUE); 283 caps.setIsPwcUpdatable(Boolean.TRUE); 284 caps.setSupportsGetDescendants(Boolean.TRUE); 285 caps.setSupportsGetFolderTree(Boolean.TRUE); 286 caps.setSupportsMultifiling(Boolean.FALSE); 287 caps.setSupportsUnfiling(Boolean.FALSE); 288 caps.setSupportsVersionSpecificFiling(Boolean.FALSE); 289 caps.setNewTypeSettableAttributes(new NewTypeSettableAttributesImpl()); 290 caps.setCreatablePropertyTypes(new CreatablePropertyTypesImpl()); 291 repositoryInfo.setCapabilities(caps); 292 293 // ACL capabilities 294 295 AclCapabilitiesDataImpl aclCaps = new AclCapabilitiesDataImpl(); 296 aclCaps.setAclPropagation(AclPropagation.PROPAGATE); 297 aclCaps.setSupportedPermissions(SupportedPermissions.REPOSITORY); 298 299 List<PermissionDefinition> permDefs = new ArrayList<PermissionDefinition>(); 300 addPermissionDefinitions(permDefs); 301 aclCaps.setPermissionDefinitionData(permDefs); 302 303 Map<String, PermissionMapping> permMap = new HashMap<String, PermissionMapping>(); 304 addPermissionMapping(permMap, CAN_GET_DESCENDENTS_FOLDER, READ); 305 addPermissionMapping(permMap, CAN_GET_CHILDREN_FOLDER, READ); 306 addPermissionMapping(permMap, CAN_GET_PARENTS_FOLDER, READ); 307 addPermissionMapping(permMap, CAN_GET_FOLDER_PARENT_OBJECT, READ); 308 addPermissionMapping(permMap, CAN_CREATE_DOCUMENT_FOLDER, WRITE); 309 addPermissionMapping(permMap, CAN_CREATE_FOLDER_FOLDER, WRITE); 310 // no CAN_CREATE_POLICY_FOLDER due to spec bug 311 addPermissionMapping(permMap, CAN_CREATE_RELATIONSHIP_SOURCE, READ); 312 addPermissionMapping(permMap, CAN_CREATE_RELATIONSHIP_TARGET, READ); 313 addPermissionMapping(permMap, CAN_GET_PROPERTIES_OBJECT, READ); 314 addPermissionMapping(permMap, CAN_VIEW_CONTENT_OBJECT, READ); 315 addPermissionMapping(permMap, CAN_UPDATE_PROPERTIES_OBJECT, WRITE); 316 addPermissionMapping(permMap, CAN_MOVE_OBJECT, WRITE); 317 addPermissionMapping(permMap, CAN_MOVE_TARGET, WRITE); 318 addPermissionMapping(permMap, CAN_MOVE_SOURCE, WRITE); 319 addPermissionMapping(permMap, CAN_DELETE_OBJECT, WRITE); 320 addPermissionMapping(permMap, CAN_DELETE_TREE_FOLDER, WRITE); 321 addPermissionMapping(permMap, CAN_SET_CONTENT_DOCUMENT, WRITE); 322 addPermissionMapping(permMap, CAN_DELETE_CONTENT_DOCUMENT, WRITE); 323 addPermissionMapping(permMap, CAN_ADD_TO_FOLDER_OBJECT, WRITE); 324 addPermissionMapping(permMap, CAN_ADD_TO_FOLDER_FOLDER, WRITE); 325 addPermissionMapping(permMap, CAN_REMOVE_FROM_FOLDER_OBJECT, WRITE); 326 addPermissionMapping(permMap, CAN_REMOVE_FROM_FOLDER_FOLDER, WRITE); 327 addPermissionMapping(permMap, CAN_CHECKOUT_DOCUMENT, WRITE); 328 addPermissionMapping(permMap, CAN_CANCEL_CHECKOUT_DOCUMENT, WRITE); 329 addPermissionMapping(permMap, CAN_CHECKIN_DOCUMENT, WRITE); 330 addPermissionMapping(permMap, CAN_GET_ALL_VERSIONS_VERSION_SERIES, READ); 331 addPermissionMapping(permMap, CAN_GET_OBJECT_RELATIONSHIPS_OBJECT, READ); 332 addPermissionMapping(permMap, CAN_ADD_POLICY_OBJECT, WRITE); 333 addPermissionMapping(permMap, CAN_ADD_POLICY_POLICY, WRITE); 334 addPermissionMapping(permMap, CAN_REMOVE_POLICY_OBJECT, WRITE); 335 addPermissionMapping(permMap, CAN_REMOVE_POLICY_POLICY, WRITE); 336 addPermissionMapping(permMap, CAN_GET_APPLIED_POLICIES_OBJECT, READ); 337 addPermissionMapping(permMap, CAN_GET_ACL_OBJECT, READ); 338 addPermissionMapping(permMap, CAN_APPLY_ACL_OBJECT, ALL); 339 aclCaps.setPermissionMappingData(permMap); 340 341 repositoryInfo.setAclCapabilities(aclCaps); 342 343 return repositoryInfo; 344 } 345 346 @SuppressWarnings("unchecked") 347 protected static void addPermissionDefinitions(List<PermissionDefinition> permDefs) { 348 addPermissionDefinition(permDefs, READ, "Read"); // = Nuxeo Read 349 addPermissionDefinition(permDefs, WRITE, "Write"); // = Nuxeo ReadWrite 350 addPermissionDefinition(permDefs, ALL, "All"); // = Nuxeo Everything 351 addPermissionDefinition(permDefs, NUXEO_READ_REMOVE, "Remove"); 352 353 Set<String> done = new HashSet<>(); 354 done.add(SecurityConstants.READ); 355 done.add(SecurityConstants.READ_WRITE); 356 done.add(SecurityConstants.EVERYTHING); 357 done.add(NUXEO_READ_REMOVE); 358 359 /* 360 * Add Nuxeo-specific permissions registered through the permissionsVisibility extension point. 361 */ 362 363 DefaultPermissionProvider permissionProvider = (DefaultPermissionProvider) Framework.getService(PermissionProvider.class); 364 permissionProvider.getUserVisiblePermissionDescriptors(); // init var 365 Map<String, PermissionVisibilityDescriptor> map; 366 try { 367 Field f; 368 f = DefaultPermissionProvider.class.getDeclaredField("mergedPermissionsVisibility"); 369 f.setAccessible(true); 370 map = (Map<String, PermissionVisibilityDescriptor>) f.get(permissionProvider); 371 } catch (NoSuchFieldException | SecurityException | IllegalAccessException e) { 372 throw new RuntimeException(e); 373 } 374 // iterate for all types regisited, not just the default "" 375 for (Entry<String, PermissionVisibilityDescriptor> en : map.entrySet()) { 376 for (String permission : en.getValue().getSortedItems()) { 377 if (!done.add(permission)) { 378 continue; 379 } 380 addPermissionDefinition(permDefs, permission, permission); 381 } 382 } 383 } 384 385 protected static void addPermissionDefinition(List<PermissionDefinition> permDefs, String permission, 386 String description) { 387 PermissionDefinitionDataImpl pd = new PermissionDefinitionDataImpl(); 388 pd.setId(permission); 389 pd.setDescription(description); 390 permDefs.add(pd); 391 } 392 393 protected static void addPermissionMapping(Map<String, PermissionMapping> permMap, String key, String permission) { 394 PermissionMappingDataImpl pm = new PermissionMappingDataImpl(); 395 pm.setKey(key); 396 pm.setPermissions(Collections.singletonList(permission)); 397 permMap.put(key, pm); 398 } 399 400 // Structures are not copied when returned 401 public TypeDefinition getTypeDefinition(String typeId) { 402 TypeDefinitionContainer typec = getTypeManager().getTypeById(typeId); 403 return typec == null ? null : typec.getTypeDefinition(); 404 } 405 406 public boolean hasType(String typeId) { 407 return getTypeManager().hasType(typeId); 408 } 409 410 // Structures are not copied when returned 411 public TypeDefinitionList getTypeChildren(String typeId, Boolean includePropertyDefinitions, BigInteger maxItems, 412 BigInteger skipCount) { 413 return getTypeManager().getTypeChildren(typeId, includePropertyDefinitions, maxItems, skipCount); 414 } 415 416 public List<TypeDefinitionContainer> getTypeDescendants(String typeId, int depth, Boolean includePropertyDefinitions) { 417 return getTypeManager().getTypeDescendants(typeId, depth, includePropertyDefinitions); 418 } 419 420 /** Returns the server base URL (including context). */ 421 private static String getBaseURL(CallContext callContext) { 422 HttpServletRequest request = (HttpServletRequest) callContext.get(CallContext.HTTP_SERVLET_REQUEST); 423 if (request != null) { 424 String baseURL = getServerURL(request); 425 String contextPath = request.getContextPath(); 426 if (contextPath == null) { 427 contextPath = Framework.getProperty(NUXEO_CONTEXT_PATH_PROP, NUXEO_CONTEXT_PATH_DEFAULT); 428 } 429 // add context path 430 return baseURL + contextPath + '/'; 431 } else { 432 return Framework.getProperty(NUXEO_URL_PROP); 433 } 434 } 435 436 /** 437 * Returns the server URL according to virtual hosting headers (without trailing slash). 438 */ 439 private static String getServerURL(HttpServletRequest request) { 440 String url = null; 441 // Detect Nuxeo specific header for VH 442 String nuxeoVH = request.getHeader(NUXEO_VH_HEADER); 443 if (nuxeoVH == null) { 444 nuxeoVH = Framework.getProperty(VH_PARAM); 445 } 446 if (nuxeoVH != null && nuxeoVH.startsWith("http")) { 447 url = nuxeoVH; 448 } else { 449 // default values 450 String scheme = request.getScheme(); 451 String serverName = request.getServerName(); 452 int serverPort = request.getServerPort(); 453 // Detect virtual hosting based in standard header 454 String forwardedHost = request.getHeader(X_FORWARDED_HOST); 455 if (forwardedHost != null) { 456 if (forwardedHost.contains(":")) { 457 String[] split = forwardedHost.split(":"); 458 serverName = split[0]; 459 serverPort = Integer.parseInt(split[1]); 460 } else { 461 serverName = forwardedHost; 462 serverPort = 80; // fallback 463 } 464 } 465 url = buildURL(scheme, serverName, serverPort); 466 } 467 // strip trailing slash 468 if (url.endsWith("/")) { 469 url = url.substring(0, url.length() - 1); 470 } 471 return url; 472 } 473 474 /** Builds an URL (without trailing slash). */ 475 private static String buildURL(String scheme, String serverName, int serverPort) { 476 StringBuilder sb = new StringBuilder(); 477 sb.append(scheme); 478 sb.append("://"); 479 sb.append(serverName); 480 if (serverPort != 0) { 481 if ("http".equals(scheme) && serverPort != 80 || "https".equals(scheme) && serverPort != 443) { 482 sb.append(':'); 483 sb.append(serverPort); 484 } 485 } 486 return sb.toString(); 487 } 488 489}