blob: 195d3eebc415637267e5a2f9bc80ab070feaad42 [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.opencmis.server.impl.atompub;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLStreamException;
import org.apache.opencmis.commons.api.TypeDefinition;
import org.apache.opencmis.commons.api.TypeDefinitionContainer;
import org.apache.opencmis.commons.enums.BaseObjectTypeIds;
import org.apache.opencmis.commons.exceptions.CmisInvalidArgumentException;
import org.apache.opencmis.commons.exceptions.CmisRuntimeException;
import org.apache.opencmis.commons.impl.Constants;
import org.apache.opencmis.commons.impl.ReturnVersion;
import org.apache.opencmis.commons.impl.UrlBuilder;
import org.apache.opencmis.commons.provider.ObjectData;
import org.apache.opencmis.commons.provider.ObjectInFolderContainer;
import org.apache.opencmis.commons.provider.PropertiesData;
import org.apache.opencmis.commons.provider.PropertyData;
import org.apache.opencmis.server.spi.ObjectInfo;
import org.apache.opencmis.server.spi.ObjectInfoHolder;
import org.apache.opencmis.server.spi.RenditionInfo;
/**
* This class contains operations used by all services.
*
* @author <a href="mailto:fmueller@opentext.com">Florian M&uuml;ller</a>
*
*/
public final class AtomPubUtils {
public static final String RESOURCE_CHILDREN = "children";
public static final String RESOURCE_DESCENDANTS = "descendants";
public static final String RESOURCE_FOLDERTREE = "foldertree";
public static final String RESOURCE_TYPE = "type";
public static final String RESOURCE_TYPES = "types";
public static final String RESOURCE_TYPESDESC = "typedesc";
public static final String RESOURCE_ENTRY = "entry";
public static final String RESOURCE_PARENTS = "parents";
public static final String RESOURCE_VERSIONS = "versions";
public static final String RESOURCE_ALLOWABLEACIONS = "allowableactions";
public static final String RESOURCE_ACL = "acl";
public static final String RESOURCE_POLICIES = "policies";
public static final String RESOURCE_RELATIONSHIPS = "relationships";
public static final String RESOURCE_OBJECTBYID = "id";
public static final String RESOURCE_OBJECTBYPATH = "path";
public static final String RESOURCE_QUERY = "query";
public static final String RESOURCE_CHECKEDOUT = "checkedout";
public static final String RESOURCE_UNFILED = "unfiled";
public static final String RESOURCE_CHANGES = "changes";
public static final String RESOURCE_CONTENT = "content";
public static final BigInteger PAGE_SIZE = BigInteger.valueOf(100);
public static final String TYPE_AUTHOR = "unknown";
/**
* Private constructor.
*/
private AtomPubUtils() {
}
/**
* Compiles the base URL for links, collections and templates.
*/
public static UrlBuilder compileBaseUrl(HttpServletRequest request, String repositoryId) {
UrlBuilder url = new UrlBuilder(request.getScheme(), request.getServerName(), request
.getServerPort(), null);
url.addPath(request.getContextPath());
url.addPath(request.getServletPath());
if (repositoryId != null) {
url.addPath(repositoryId);
}
return url;
}
/**
* Compiles a URL for links, collections and templates.
*/
public static String compileUrl(UrlBuilder baseUrl, String resource, String id) {
return compileUrlBuilder(baseUrl, resource, id).toString();
}
/**
* Compiles a URL for links, collections and templates.
*/
public static UrlBuilder compileUrlBuilder(UrlBuilder baseUrl, String resource, String id) {
UrlBuilder url = new UrlBuilder(baseUrl);
url.addPath(resource);
if (id != null) {
url.addParameter("id", id);
}
return url;
}
// -------------------------------------------------------------------------
// --- parameters ---
// -------------------------------------------------------------------------
/**
* Extracts a string parameter.
*/
@SuppressWarnings("unchecked")
public static String getStringParameter(HttpServletRequest request, String name) {
if (name == null) {
return null;
}
Map<String, String[]> parameters = (Map<String, String[]>) request.getParameterMap();
for (Map.Entry<String, String[]> parameter : parameters.entrySet()) {
if (name.equalsIgnoreCase(parameter.getKey())) {
if (parameter.getValue() == null) {
return null;
}
return parameter.getValue()[0];
}
}
return null;
}
/**
* Extracts a boolean parameter (with default).
*/
public static boolean getBooleanParameter(HttpServletRequest request, String name, boolean def) {
String value = getStringParameter(request, name);
if (value == null) {
return def;
}
return Boolean.valueOf(value);
}
/**
* Extracts a boolean parameter.
*/
public static Boolean getBooleanParameter(HttpServletRequest request, String name) {
String value = getStringParameter(request, name);
if (value == null) {
return null;
}
return Boolean.valueOf(value);
}
/**
* Extracts an integer parameter (with default).
*/
public static BigInteger getBigIntegerParameter(HttpServletRequest request, String name, long def) {
BigInteger result = getBigIntegerParameter(request, name);
if (result == null) {
result = BigInteger.valueOf(def);
}
return result;
}
/**
* Extracts an integer parameter.
*/
public static BigInteger getBigIntegerParameter(HttpServletRequest request, String name) {
String value = getStringParameter(request, name);
if (value == null) {
return null;
}
try {
return new BigInteger(value);
}
catch (Exception e) {
throw new CmisInvalidArgumentException("Invalid parameter '" + name + "'!");
}
}
/**
* Extracts an enum parameter.
*/
@SuppressWarnings("unchecked")
public static <T> T getEnumParameter(HttpServletRequest request, String name, Class<T> clazz) {
String value = getStringParameter(request, name);
if (value == null) {
return null;
}
try {
Method m = clazz.getMethod("fromValue", new Class[] { String.class });
return (T) m.invoke(null, new Object[] { value });
}
catch (Exception e) {
if (e instanceof IllegalArgumentException) {
throw new CmisInvalidArgumentException("Invalid parameter '" + name + "'!");
}
throw new CmisRuntimeException(e.getMessage(), e);
}
}
/**
* Extracts a property from an object.
*/
@SuppressWarnings("unchecked")
public static <T> T getProperty(ObjectData object, String name, Class<T> clazz) {
if (object == null) {
return null;
}
PropertiesData propData = object.getProperties();
if (propData == null) {
return null;
}
Map<String, PropertyData<?>> properties = propData.getProperties();
if (properties == null) {
return null;
}
PropertyData<?> property = properties.get(name);
if (property == null) {
return null;
}
Object value = property.getFirstValue();
if (!clazz.isInstance(value)) {
return null;
}
return (T) value;
}
// -------------------------------------------------------------------------
// --- entry builder ---
// -------------------------------------------------------------------------
/**
* Writes the a object entry.
*/
public static void writeObjectEntry(AtomEntry entry, ObjectData object,
ObjectInfoHolder infoHolder, List<ObjectInFolderContainer> children, String repositoryId,
String pathSegment, String relativePathSegment, UrlBuilder baseUrl, boolean isRoot)
throws XMLStreamException, JAXBException {
if ((object == null) || (infoHolder == null)) {
throw new CmisRuntimeException("Object or Object Info not set!");
}
ObjectInfo info = infoHolder.getObjectInfo(object.getId());
if (info == null) {
throw new CmisRuntimeException("Object Info not found!");
}
// start
entry.startEntry(isRoot);
// write object
String contentSrc = null;
if (info.hasContent()) {
UrlBuilder contentSrcBuilder = compileUrlBuilder(baseUrl, RESOURCE_CONTENT, info.getId());
if (info.getFileName() != null) {
contentSrcBuilder.addPath(info.getFileName());
}
contentSrc = contentSrcBuilder.toString();
}
entry.writeObject(object, info, contentSrc, info.getContentType(), pathSegment,
relativePathSegment);
// write links
entry.writeServiceLink(baseUrl.toString(), repositoryId);
entry.writeSelfLink(compileUrl(baseUrl, RESOURCE_ENTRY, info.getId()), info.getId());
entry.writeEnclosureLink(compileUrl(baseUrl, RESOURCE_ENTRY, info.getId()));
entry.writeEditLink(compileUrl(baseUrl, RESOURCE_ENTRY, info.getId()));
entry.writeDescribedByLink(compileUrl(baseUrl, RESOURCE_TYPE, info.getTypeId()));
entry.writeAllowableActionsLink(compileUrl(baseUrl, RESOURCE_ALLOWABLEACIONS, info.getId()));
if (info.hasParent()) {
entry.writeUpLink(compileUrl(baseUrl, RESOURCE_PARENTS, info.getId()),
Constants.MEDIATYPE_FEED);
}
if (info.getBaseType() == BaseObjectTypeIds.CMIS_FOLDER) {
entry.writeDownLink(compileUrl(baseUrl, RESOURCE_CHILDREN, info.getId()),
Constants.MEDIATYPE_FEED);
if (info.supportsDescendants()) {
entry.writeDownLink(compileUrl(baseUrl, RESOURCE_DESCENDANTS, info.getId()),
Constants.MEDIATYPE_DESCENDANTS);
}
if (info.supportsFolderTree()) {
entry.writeFolderTreeLink(compileUrl(baseUrl, RESOURCE_FOLDERTREE, info.getId()));
}
}
if (info.getVersionSeriesId() != null) {
entry.writeVersionHistoryLink(compileUrl(baseUrl, RESOURCE_VERSIONS, info
.getVersionSeriesId()));
}
if (!info.isCurrentVersion()) {
UrlBuilder cvUrl = compileUrlBuilder(baseUrl, RESOURCE_ENTRY, info.getId());
cvUrl.addParameter(Constants.PARAM_RETURN_VERSION, ReturnVersion.LATEST);
entry.writeEditLink(cvUrl.toString());
}
if (contentSrc != null) {
entry.writeEditMediaLink(contentSrc, info.getContentType());
}
if (info.getWorkingCopyId() != null) {
entry.writeWorkingCopyLink(compileUrl(baseUrl, RESOURCE_ENTRY, info.getWorkingCopyId()));
}
if (info.getWorkingCopyOriginalId() != null) {
entry.writeViaLink(compileUrl(baseUrl, RESOURCE_ENTRY, info.getWorkingCopyOriginalId()));
}
if (info.getRenditionInfos() != null) {
for (RenditionInfo ri : info.getRenditionInfos()) {
entry.writeAlternateLink(compileUrl(baseUrl, RESOURCE_CONTENT, ri.getId()), ri
.getContenType(), ri.getKind(), ri.getTitle(), ri.getLength());
}
}
if (info.hasAcl()) {
entry.writeAclLink(compileUrl(baseUrl, RESOURCE_ACL, info.getId()));
}
if (info.supportsPolicies()) {
entry.writeAclLink(compileUrl(baseUrl, RESOURCE_POLICIES, info.getId()));
}
if (info.supportsRelationships()) {
entry.writeRelationshipsLink(compileUrl(baseUrl, RESOURCE_RELATIONSHIPS, info.getId()));
}
if (info.getRelationshipSourceIds() != null) {
for (String id : info.getRelationshipSourceIds()) {
entry.writeRelationshipSourceLink(compileUrl(baseUrl, RESOURCE_ENTRY, id));
}
}
if (info.getRelationshipTargetIds() != null) {
for (String id : info.getRelationshipTargetIds()) {
entry.writeRelationshipTargetLink(compileUrl(baseUrl, RESOURCE_ENTRY, id));
}
}
// write children
if ((children != null) && (children.size() > 0)) {
writeObjectChildren(entry, info, children, infoHolder, repositoryId, baseUrl);
}
// we are done
entry.endEntry();
}
/**
* Writes an objects entry children feed.
*/
public static void writeObjectChildren(AtomEntry entry, ObjectInfo folderInfo,
List<ObjectInFolderContainer> children, ObjectInfoHolder infoHolder, String repositoryId,
UrlBuilder baseUrl) throws XMLStreamException, JAXBException {
// start
AtomFeed feed = new AtomFeed(entry.getWriter());
feed.startChildren();
feed.startFeed(false);
// write basic Atom feed elements
feed.writeFeedElements(folderInfo.getId(), folderInfo.getCreatedBy(), folderInfo.getName(),
folderInfo.getLastModificationDate(), null, null);
// write links
feed.writeServiceLink(baseUrl.toString(), repositoryId);
feed.writeSelfLink(compileUrl(baseUrl, RESOURCE_DESCENDANTS, folderInfo.getId()), null);
feed.writeViaLink(compileUrl(baseUrl, RESOURCE_ENTRY, folderInfo.getId()));
feed.writeDownLink(compileUrl(baseUrl, RESOURCE_CHILDREN, folderInfo.getId()),
Constants.MEDIATYPE_FEED);
feed.writeDownLink(compileUrl(baseUrl, RESOURCE_FOLDERTREE, folderInfo.getId()),
Constants.MEDIATYPE_DESCENDANTS);
feed.writeUpLink(compileUrl(baseUrl, RESOURCE_PARENTS, folderInfo.getId()),
Constants.MEDIATYPE_FEED);
for (ObjectInFolderContainer container : children) {
if ((container != null) && (container.getObject() != null)) {
writeObjectEntry(entry, container.getObject().getObject(), infoHolder, container
.getChildren(), repositoryId, container.getObject().getPathSegment(), null, baseUrl,
false);
}
}
// we are done
feed.endFeed();
feed.endChildren();
}
/**
* Writes the a type entry.
*/
public static void writeTypeEntry(AtomEntry entry, TypeDefinition type,
List<TypeDefinitionContainer> children, String repositoryId, UrlBuilder baseUrl,
boolean isRoot) throws XMLStreamException, JAXBException {
// start
entry.startEntry(isRoot);
// write type
entry.writeType(type);
// write links
entry.writeServiceLink(baseUrl.toString(), repositoryId);
entry.writeSelfLink(compileUrl(baseUrl, RESOURCE_TYPE, type.getId()), type.getId());
entry.writeEnclosureLink(compileUrl(baseUrl, RESOURCE_TYPE, type.getId()));
if (type.getParentId() != null) {
entry.writeUpLink(compileUrl(baseUrl, RESOURCE_TYPE, type.getParentId()),
Constants.MEDIATYPE_ENTRY);
}
UrlBuilder downLink = compileUrlBuilder(baseUrl, RESOURCE_TYPES, null);
downLink.addParameter(Constants.PARAM_TYPE_ID, type.getId());
entry.writeDownLink(downLink.toString(), Constants.MEDIATYPE_CHILDREN);
entry.writeDescribedByLink(compileUrl(baseUrl, RESOURCE_TYPE, type.getBaseId().value()));
// write children
if ((children != null) && (children.size() > 0)) {
writeTypeChildren(entry, type, children, repositoryId, baseUrl);
}
// we are done
entry.endEntry();
}
/**
* Writes the a type entry children feed.
*/
private static void writeTypeChildren(AtomEntry entry, TypeDefinition type,
List<TypeDefinitionContainer> children, String repositoryId, UrlBuilder baseUrl)
throws XMLStreamException, JAXBException {
// start
AtomFeed feed = new AtomFeed(entry.getWriter());
feed.startChildren();
feed.startFeed(false);
// write basic Atom feed elements
feed.writeFeedElements(type.getId(), TYPE_AUTHOR, type.getDisplayName(),
new GregorianCalendar(), null, null);
feed.writeServiceLink(baseUrl.toString(), repositoryId);
UrlBuilder selfLink = compileUrlBuilder(baseUrl, RESOURCE_TYPESDESC, null);
selfLink.addParameter(Constants.PARAM_TYPE_ID, type.getId());
feed.writeSelfLink(selfLink.toString(), type.getId());
feed.writeViaLink(compileUrl(baseUrl, RESOURCE_TYPE, type.getId()));
UrlBuilder downLink = compileUrlBuilder(baseUrl, RESOURCE_TYPES, null);
downLink.addParameter(Constants.PARAM_TYPE_ID, type.getId());
feed.writeDownLink(downLink.toString(), Constants.MEDIATYPE_FEED);
if (type.getParentId() != null) {
feed.writeUpLink(compileUrl(baseUrl, RESOURCE_TYPE, type.getParentId()),
Constants.MEDIATYPE_ENTRY);
}
// write tree
for (TypeDefinitionContainer container : children) {
if ((container != null) && (container.getTypeDefinition() != null)) {
writeTypeEntry(entry, container.getTypeDefinition(), container.getChildren(), repositoryId,
baseUrl, false);
}
}
// we are done
feed.endFeed();
feed.endChildren();
}
}