blob: f66cf32fa30c4cad834c7da13f5c064454b87d4c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.chemistry.opencmis.server.impl.atompub;
import java.math.BigInteger;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.chemistry.opencmis.commons.data.RepositoryCapabilities;
import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
import org.apache.chemistry.opencmis.commons.enums.CapabilityChanges;
import org.apache.chemistry.opencmis.commons.enums.CapabilityQuery;
import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
import org.apache.chemistry.opencmis.commons.impl.Constants;
import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
import org.apache.chemistry.opencmis.commons.server.CallContext;
import org.apache.chemistry.opencmis.commons.server.CmisService;
import org.apache.chemistry.opencmis.server.impl.CallContextImpl;
import org.apache.chemistry.opencmis.server.shared.TempStoreOutputStreamFactory;
/**
* Repository Service operations.
*/
public class RepositoryService {
/**
* Renders the service document.
*/
public static class GetRepositories extends AbstractAtomPubServiceCall {
public void serve(CallContext context, CmisService service, String repositoryId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
assert context != null;
assert service != null;
assert request != null;
assert response != null;
// get parameters
repositoryId = getStringParameter(request, Constants.PARAM_REPOSITORY_ID);
// execute
List<RepositoryInfo> infoDataList = null;
if (stopBeforeService(service)) {
return;
}
if (repositoryId == null) {
infoDataList = service.getRepositoryInfos(null);
} else {
infoDataList = Collections.singletonList(service.getRepositoryInfo(repositoryId, null));
if (context instanceof CallContextImpl) {
((CallContextImpl) context).put(CallContext.REPOSITORY_ID, repositoryId);
}
}
if (stopAfterService(service)) {
return;
}
// set headers
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(Constants.MEDIATYPE_SERVICE);
// write XML
ServiceDocument serviceDoc = new ServiceDocument();
serviceDoc.startDocument(response.getOutputStream(), getNamespaces(service));
serviceDoc.startServiceDocument();
if (infoDataList != null) {
CmisVersion cmisVersion = context.getCmisVersion();
for (RepositoryInfo infoData : infoDataList) {
if (infoData == null) {
continue;
}
String repId = infoData.getId();
UrlBuilder baseUrl = compileBaseUrl(request, repId);
boolean supportsQuery = false;
boolean supportsUnFiling = false;
boolean supportsMultifiling = false;
boolean supportsFolderTree = false;
boolean supportsRootDescendants = false;
boolean supportsChanges = false;
if (infoData.getCapabilities() != null) {
RepositoryCapabilities cap = infoData.getCapabilities();
if (cap.getQueryCapability() != null) {
supportsQuery = (cap.getQueryCapability() != CapabilityQuery.NONE);
}
if (cap.isUnfilingSupported() != null) {
supportsUnFiling = cap.isUnfilingSupported();
}
if (cap.isMultifilingSupported() != null) {
supportsMultifiling = cap.isMultifilingSupported();
}
if (cap.isGetFolderTreeSupported() != null) {
supportsFolderTree = cap.isGetFolderTreeSupported();
}
if (cap.isGetDescendantsSupported() != null) {
supportsRootDescendants = cap.isGetDescendantsSupported();
}
if (cap.getChangesCapability() != null) {
supportsChanges = (cap.getChangesCapability() != CapabilityChanges.NONE);
}
}
serviceDoc.startWorkspace(infoData.getId());
// add collections
// - root collection
serviceDoc.writeCollection(compileUrl(baseUrl, RESOURCE_CHILDREN, infoData.getRootFolderId()),
Constants.COLLECTION_ROOT, "Root Collection", Constants.MEDIATYPE_ENTRY,
Constants.MEDIATYPE_CMISATOM);
// - types collection
serviceDoc.writeCollection(compileUrl(baseUrl, RESOURCE_TYPES, null), Constants.COLLECTION_TYPES,
"Types Collection", "");
// - query collection
if (supportsQuery) {
serviceDoc.writeCollection(compileUrl(baseUrl, RESOURCE_QUERY, null),
Constants.COLLECTION_QUERY, "Query Collection", Constants.MEDIATYPE_QUERY);
}
// - checked out collection collection
serviceDoc.writeCollection(compileUrl(baseUrl, RESOURCE_CHECKEDOUT, null),
Constants.COLLECTION_CHECKEDOUT, "Checked Out Collection", Constants.MEDIATYPE_CMISATOM);
// - unfiled collection collection
if (supportsUnFiling || supportsMultifiling) {
serviceDoc.writeCollection(compileUrl(baseUrl, RESOURCE_UNFILED, null),
Constants.COLLECTION_UNFILED, "Unfiled Collection", Constants.MEDIATYPE_CMISATOM);
}
// - bulk update collection
serviceDoc.writeCollection(compileUrl(baseUrl, RESOURCE_BULK_UPDATE, null),
Constants.COLLECTION_BULK_UPDATE, "Bulk Update Collection", Constants.MEDIATYPE_CMISATOM);
// add repository info
serviceDoc.writeRepositoryInfo(infoData, cmisVersion);
// add links
// - types descendants
serviceDoc.writeLink(Constants.REP_REL_TYPEDESC, compileUrl(baseUrl, RESOURCE_TYPESDESC, null),
Constants.MEDIATYPE_FEED, null);
// - folder tree
if (supportsFolderTree) {
serviceDoc.writeLink(Constants.REP_REL_FOLDERTREE,
compileUrl(baseUrl, RESOURCE_FOLDERTREE, infoData.getRootFolderId()),
Constants.MEDIATYPE_DESCENDANTS, null);
}
// - root descendants
if (supportsRootDescendants) {
serviceDoc.writeLink(Constants.REP_REL_ROOTDESC,
compileUrl(baseUrl, RESOURCE_DESCENDANTS, infoData.getRootFolderId()),
Constants.MEDIATYPE_DESCENDANTS, infoData.getRootFolderId());
}
// - changes
if (supportsChanges) {
serviceDoc.writeLink(Constants.REP_REL_CHANGES, compileUrl(baseUrl, RESOURCE_CHANGES, null),
Constants.MEDIATYPE_FEED, null);
}
// add URI templates
// - object by id
String url = compileUrl(baseUrl, RESOURCE_OBJECTBYID, null)
+ "?id={id}&filter={filter}&includeAllowableActions={includeAllowableActions}"
+ "&includeACL={includeACL}&includePolicyIds={includePolicyIds}"
+ "&includeRelationships={includeRelationships}&renditionFilter={renditionFilter}";
serviceDoc.writeUriTemplate(url, Constants.TEMPLATE_OBJECT_BY_ID, Constants.MEDIATYPE_ENTRY);
// - object by path
url = compileUrl(baseUrl, RESOURCE_OBJECTBYPATH, null)
+ "?path={path}&filter={filter}&includeAllowableActions={includeAllowableActions}"
+ "&includeACL={includeACL}&includePolicyIds={includePolicyIds}"
+ "&includeRelationships={includeRelationships}&renditionFilter={renditionFilter}";
serviceDoc.writeUriTemplate(url, Constants.TEMPLATE_OBJECT_BY_PATH, Constants.MEDIATYPE_ENTRY);
// - type by id
url = compileUrl(baseUrl, RESOURCE_TYPE, null) + "?id={id}";
serviceDoc.writeUriTemplate(url, Constants.TEMPLATE_TYPE_BY_ID, Constants.MEDIATYPE_ENTRY);
// - query
if (supportsQuery) {
url = compileUrl(baseUrl, RESOURCE_QUERY, null)
+ "?q={q}&searchAllVersions={searchAllVersions}&includeAllowableActions={includeAllowableActions}"
+ "&includeRelationships={includeRelationships}&maxItems={maxItems}&skipCount={skipCount}";
serviceDoc.writeUriTemplate(url, Constants.TEMPLATE_QUERY, Constants.MEDIATYPE_FEED);
}
serviceDoc.endWorkspace();
}
}
serviceDoc.endServiceDocument();
serviceDoc.endDocument();
}
}
/**
* Renders a type children collection.
*/
public static class GetTypeChildren extends AbstractAtomPubServiceCall {
public void serve(CallContext context, CmisService service, String repositoryId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
assert context != null;
assert service != null;
assert repositoryId != null;
assert request != null;
assert response != null;
// get parameters
String typeId = getStringParameter(request, Constants.PARAM_TYPE_ID);
boolean includePropertyDefinitions = getBooleanParameter(request, Constants.PARAM_PROPERTY_DEFINITIONS,
false);
BigInteger maxItems = getBigIntegerParameter(request, Constants.PARAM_MAX_ITEMS);
BigInteger skipCount = getBigIntegerParameter(request, Constants.PARAM_SKIP_COUNT);
// execute
if (stopBeforeService(service)) {
return;
}
TypeDefinitionList typeList = service.getTypeChildren(repositoryId, typeId, includePropertyDefinitions,
maxItems, skipCount, null);
if (stopAfterService(service)) {
return;
}
BigInteger numItems = (typeList == null ? null : typeList.getNumItems());
Boolean hasMoreItems = (typeList == null ? null : typeList.hasMoreItems());
String parentTypeId = null;
String typeName = "Type Children";
// in order to get the parent type, we need the type definition of
// this type as well
if (typeId != null) {
TypeDefinition typeDefinition = service.getTypeDefinition(repositoryId, typeId, null);
parentTypeId = (typeDefinition == null ? null : typeDefinition.getParentTypeId());
typeName = (typeDefinition == null ? typeId : typeDefinition.getDisplayName());
}
// write XML
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(Constants.MEDIATYPE_FEED);
AtomFeed feed = new AtomFeed();
feed.startDocument(response.getOutputStream(), getNamespaces(service));
feed.startFeed(true);
// write basic Atom feed elements
feed.writeFeedElements(typeId, null, TYPE_AUTHOR, typeName, new GregorianCalendar(), null, numItems);
// write links
UrlBuilder baseUrl = compileBaseUrl(request, repositoryId);
feed.writeServiceLink(baseUrl.toString(), repositoryId);
UrlBuilder selfLink = compileUrlBuilder(baseUrl, RESOURCE_TYPES, null);
selfLink.addParameter(Constants.PARAM_TYPE_ID, typeId);
selfLink.addParameter(Constants.PARAM_PROPERTY_DEFINITIONS, includePropertyDefinitions);
selfLink.addParameter(Constants.PARAM_MAX_ITEMS, maxItems);
selfLink.addParameter(Constants.PARAM_SKIP_COUNT, skipCount);
feed.writeSelfLink(selfLink.toString(), typeId);
feed.writeViaLink(compileUrl(baseUrl, RESOURCE_TYPE, typeId));
UrlBuilder downLink = compileUrlBuilder(baseUrl, RESOURCE_TYPESDESC, null);
downLink.addParameter(Constants.PARAM_TYPE_ID, typeId);
feed.writeDownLink(downLink.toString(), Constants.MEDIATYPE_DESCENDANTS);
if (parentTypeId != null) {
feed.writeUpLink(compileUrl(baseUrl, RESOURCE_TYPE, parentTypeId), Constants.MEDIATYPE_ENTRY);
}
// write paging links
UrlBuilder pagingUrl = compileUrlBuilder(baseUrl, RESOURCE_TYPES, null);
pagingUrl.addParameter(Constants.PARAM_TYPE_ID, typeId);
pagingUrl.addParameter(Constants.PARAM_PROPERTY_DEFINITIONS, includePropertyDefinitions);
feed.writePagingLinks(pagingUrl, maxItems, skipCount, numItems, hasMoreItems, PAGE_SIZE);
// write collection
UrlBuilder collectionUrl = compileUrlBuilder(baseUrl, RESOURCE_TYPES, null);
collectionUrl.addParameter(Constants.PARAM_TYPE_ID, typeId);
feed.writeCollection(collectionUrl.toString(), null, "Types Collection", "");
// write type entries
if ((typeList != null) && (typeList.getList() != null)) {
AtomEntry entry = new AtomEntry(feed.getWriter());
for (TypeDefinition type : typeList.getList()) {
writeTypeEntry(entry, type, null, repositoryId, baseUrl, false, context.getCmisVersion());
}
}
// write extensions
feed.writeExtensions(typeList);
// we are done
feed.endFeed();
feed.endDocument();
}
}
/**
* Renders a type descendants feed.
*/
public static class GetTypeDescendants extends AbstractAtomPubServiceCall {
public void serve(CallContext context, CmisService service, String repositoryId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
assert context != null;
assert service != null;
assert repositoryId != null;
assert request != null;
assert response != null;
// get parameters
String typeId = getStringParameter(request, Constants.PARAM_TYPE_ID);
BigInteger depth = getBigIntegerParameter(request, Constants.PARAM_DEPTH);
boolean includePropertyDefinitions = getBooleanParameter(request, Constants.PARAM_PROPERTY_DEFINITIONS,
false);
// execute
if (stopBeforeService(service)) {
return;
}
List<TypeDefinitionContainer> typeTree = service.getTypeDescendants(repositoryId, typeId, depth,
includePropertyDefinitions, null);
if (stopAfterService(service)) {
return;
}
String parentTypeId = null;
String typeName = "Type Children";
// in order to get the parent type, we need the type definition of
// this type as well
if (typeId != null) {
TypeDefinition typeDefinition = service.getTypeDefinition(repositoryId, typeId, null);
parentTypeId = (typeDefinition == null ? null : typeDefinition.getParentTypeId());
typeName = (typeDefinition == null ? typeId : typeDefinition.getDisplayName());
}
// write XML
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(Constants.MEDIATYPE_FEED);
AtomFeed feed = new AtomFeed();
feed.startDocument(response.getOutputStream(), getNamespaces(service));
feed.startFeed(true);
// write basic Atom feed elements
feed.writeFeedElements(typeId, null, TYPE_AUTHOR, typeName, new GregorianCalendar(), null, null);
// write links
UrlBuilder baseUrl = compileBaseUrl(request, repositoryId);
feed.writeServiceLink(baseUrl.toString(), repositoryId);
UrlBuilder selfLink = compileUrlBuilder(baseUrl, RESOURCE_TYPESDESC, null);
selfLink.addParameter(Constants.PARAM_TYPE_ID, typeId);
selfLink.addParameter(Constants.PARAM_DEPTH, depth);
selfLink.addParameter(Constants.PARAM_PROPERTY_DEFINITIONS, includePropertyDefinitions);
feed.writeSelfLink(selfLink.toString(), typeId);
feed.writeViaLink(compileUrl(baseUrl, RESOURCE_TYPE, typeId));
UrlBuilder downLink = compileUrlBuilder(baseUrl, RESOURCE_TYPES, null);
downLink.addParameter(Constants.PARAM_TYPE_ID, typeId);
feed.writeDownLink(downLink.toString(), Constants.MEDIATYPE_FEED);
if (parentTypeId != null) {
feed.writeUpLink(compileUrl(baseUrl, RESOURCE_TYPE, parentTypeId), Constants.MEDIATYPE_ENTRY);
}
// write tree
if (typeTree != null) {
AtomEntry entry = new AtomEntry(feed.getWriter());
for (TypeDefinitionContainer container : typeTree) {
if ((container != null) && (container.getTypeDefinition() != null)) {
writeTypeEntry(entry, container.getTypeDefinition(), container.getChildren(), repositoryId,
baseUrl, false, context.getCmisVersion());
}
}
}
// we are done
feed.endFeed();
feed.endDocument();
}
}
/**
* Renders a type definition.
*/
public static class GetTypeDefinition extends AbstractAtomPubServiceCall {
public void serve(CallContext context, CmisService service, String repositoryId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
assert context != null;
assert service != null;
assert repositoryId != null;
assert request != null;
assert response != null;
// get parameters
String typeId = getStringParameter(request, Constants.PARAM_ID);
// execute
if (stopBeforeService(service)) {
return;
}
TypeDefinition type = service.getTypeDefinition(repositoryId, typeId, null);
if (stopAfterService(service)) {
return;
}
// write XML
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(Constants.MEDIATYPE_ENTRY);
AtomEntry entry = new AtomEntry();
entry.startDocument(response.getOutputStream(), getNamespaces(service));
writeTypeEntry(entry, type, null, repositoryId, compileBaseUrl(request, repositoryId), true,
context.getCmisVersion());
entry.endDocument();
}
}
/**
* Creates a type.
*/
public static class CreateType extends AbstractAtomPubServiceCall {
public void serve(CallContext context, CmisService service, String repositoryId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
assert context != null;
assert service != null;
assert repositoryId != null;
assert request != null;
assert response != null;
// parse entry
TempStoreOutputStreamFactory streamFactory = (TempStoreOutputStreamFactory) context
.get(CallContext.STREAM_FACTORY);
AtomEntryParser parser = new AtomEntryParser(streamFactory);
parser.parse(request.getInputStream());
// execute
TypeDefinition newType = null;
try {
if (stopBeforeService(service)) {
return;
}
newType = service.createType(repositoryId, parser.getTypeDefinition(), null);
if (stopAfterService(service)) {
return;
}
} finally {
parser.release();
}
// set headers
UrlBuilder baseUrl = compileBaseUrl(request, repositoryId);
response.setStatus(HttpServletResponse.SC_CREATED);
response.setContentType(Constants.MEDIATYPE_ENTRY);
response.setHeader("Location", compileUrl(baseUrl, RESOURCE_TYPE, newType.getId()));
// write XML
AtomEntry entry = new AtomEntry();
entry.startDocument(response.getOutputStream(), getNamespaces(service));
writeTypeEntry(entry, newType, null, repositoryId, compileBaseUrl(request, repositoryId), true,
context.getCmisVersion());
entry.endDocument();
}
}
/**
* Updates a type.
*/
public static class UpdateType extends AbstractAtomPubServiceCall {
public void serve(CallContext context, CmisService service, String repositoryId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
assert context != null;
assert service != null;
assert repositoryId != null;
assert request != null;
assert response != null;
// parse entry
TempStoreOutputStreamFactory streamFactory = (TempStoreOutputStreamFactory) context
.get(CallContext.STREAM_FACTORY);
AtomEntryParser parser = new AtomEntryParser(streamFactory);
parser.parse(request.getInputStream());
// execute
TypeDefinition newType = null;
try {
if (stopBeforeService(service)) {
return;
}
newType = service.updateType(repositoryId, parser.getTypeDefinition(), null);
if (stopAfterService(service)) {
return;
}
} finally {
parser.release();
}
// set headers
UrlBuilder baseUrl = compileBaseUrl(request, repositoryId);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(Constants.MEDIATYPE_ENTRY);
response.setHeader("Location", compileUrl(baseUrl, RESOURCE_TYPE, newType.getId()));
// write XML
AtomEntry entry = new AtomEntry();
entry.startDocument(response.getOutputStream(), getNamespaces(service));
writeTypeEntry(entry, newType, null, repositoryId, compileBaseUrl(request, repositoryId), true,
context.getCmisVersion());
entry.endDocument();
}
}
/**
* Deletes a type.
*/
public static class DeleteType extends AbstractAtomPubServiceCall {
public void serve(CallContext context, CmisService service, String repositoryId, HttpServletRequest request,
HttpServletResponse response) throws Exception {
assert context != null;
assert service != null;
assert repositoryId != null;
assert request != null;
assert response != null;
// get parameters
String typeId = getStringParameter(request, Constants.PARAM_ID);
// execute
if (stopBeforeService(service)) {
return;
}
service.deleteType(repositoryId, typeId, null);
if (stopAfterService(service)) {
return;
}
// set headers
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
}
}