/** * Copyright (C) 2010 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xcmis.restatom; import org.apache.abdera.factory.Factory; import org.apache.abdera.model.Document; import org.apache.abdera.model.Link; import org.apache.abdera.model.Service; import org.apache.abdera.model.Workspace; import org.apache.abdera.parser.stax.FOMExtensibleElement; import org.apache.abdera.protocol.server.CollectionInfo; import org.apache.abdera.protocol.server.RequestContext; import org.apache.abdera.protocol.server.ResponseContext; import org.apache.abdera.protocol.server.WorkspaceInfo; import org.apache.abdera.protocol.server.context.BaseResponseContext; import org.apache.abdera.protocol.server.context.ResponseContextException; import org.apache.abdera.protocol.server.servlet.ServletRequestContext; import org.apache.commons.fileupload.FileItem; import org.xcmis.restatom.abdera.AccessControlEntryTypeElement; import org.xcmis.restatom.abdera.AllowableActionsElement; import org.xcmis.restatom.abdera.RepositoryInfoTypeElement; import org.xcmis.restatom.abdera.UriTemplateTypeElement; import org.xcmis.restatom.collections.AbstractCmisCollection; import org.xcmis.restatom.types.CmisUriTemplateType; import org.xcmis.spi.CmisRegistry; import org.xcmis.spi.Connection; import org.xcmis.spi.InvalidArgumentException; import org.xcmis.spi.ObjectNotFoundException; import org.xcmis.spi.UpdateConflictException; import org.xcmis.spi.model.AccessControlEntry; import org.xcmis.spi.model.AccessControlPropagation; import org.xcmis.spi.model.AllowableActions; import org.xcmis.spi.model.CapabilityChanges; import org.xcmis.spi.model.RepositoryCapabilities; import org.xcmis.spi.model.RepositoryInfo; import org.xcmis.spi.model.RepositoryShortInfo; import org.xcmis.spi.model.UnfileObject; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.activation.MimeTypeParseException; import javax.annotation.security.RolesAllowed; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.Response.ResponseBuilder; /** * @author <a href="mailto:andrey.parfonov@exoplatform.com">Andrey Parfonov</a> * @version $Id: AtomCmisService.java 216 2010-02-12 17:19:50Z andrew00x $ */ @Path(AtomCMIS.CMIS_REST_RESOURCE_PATH) public class AtomCmisService { /** The provider. */ protected ProviderImpl provider; /** * Instantiates a new atom cmis service. */ public AtomCmisService(ProviderImpl provider) { this.provider = provider; } @PUT @Path("{repositoryId}/objacl/{objectId}") @Produces("application/cmisacl+xml") public Response addACL(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId, @PathParam("objectId") String objectId) { Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); RequestContext request = initRequestContext(httpRequest); Document<?> doc = request.getDocument(); List<AccessControlEntryTypeElement> listEl = doc.getRoot().getElements(); List<AccessControlEntry> listACE = new ArrayList<AccessControlEntry>(); for (AccessControlEntryTypeElement el : listEl) { listACE.add(el.getACE()); } List<AccessControlEntry> removeACL = new ArrayList<AccessControlEntry>(); connection.applyACL(objectId, listACE, removeACL, AccessControlPropagation.REPOSITORYDETERMINED); List<AccessControlEntry> list = connection.getACL(objectId, false); FOMExtensibleElement accessControlListTypeElement = AbderaFactory.getInstance().getFactory().newElement(AtomCMIS.ACL); for (AccessControlEntry accessControlEntry : list) { AccessControlEntryTypeElement ace = accessControlListTypeElement.addExtension(AtomCMIS.PERMISSION); ace.build(accessControlEntry); } //return Response.status(201).build(); return Response.ok(accessControlListTypeElement).header(HttpHeaders.CACHE_CONTROL, "no-cache").build(); } catch (IOException io) { throw new WebApplicationException(io, createErrorResponse(io, 500)); } catch (Exception t) { throw new WebApplicationException(t, createErrorResponse(t, 500)); } finally { if (connection != null) { connection.close(); } } } @POST @Path("{repositoryId}/types") @RolesAllowed({"administrators"}) public Response addType(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return createItem(repositoryId, httpRequest); } @POST @Path("{repositoryId}/policies/{objectId}") @Produces("application/atom+xml;type=entry") public Response applyPolicy(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return createItem(repositoryId, httpRequest); } @POST @Path("{repositoryId}/checkedout") public Response checkOut(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) throws Exception { return createItem(repositoryId, httpRequest); } @POST @Path("{repositoryId}/children/{folderId}") @Produces("application/atom+xml;type=entry") public Response createChild(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return createItem(repositoryId, httpRequest); } @POST @Path("{repositoryId}/object/{folderId}") @Produces("application/atom+xml;type=entry") public Response createChildObj(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { // Found some clients those use direct object (folder) link for adding child. return createItem(repositoryId, httpRequest); } @POST @Path("{repositoryId}/relationships/{objectId}") @Produces("application/atom+xml;type=entry") public Response createRelationship(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return createItem(repositoryId, httpRequest); } @DELETE @Path("{repositoryId}/file/{objectId}") public Response deleteContentStream(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.deleteMedia(request); return Response.status(abderaResponse.getStatus()).entity(abderaResponse).build(); } finally { if (connection != null) { connection.close(); } } } @DELETE @Path("{repositoryId}/object/{objectId}") public Response deleteObject(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return deleteItem(repositoryId, httpRequest); } @DELETE @Path("{repositoryId}/foldertree/{folderId}") public Response deleteFolderTree(@PathParam("repositoryId") String repositoryId, @PathParam("folderId") String folderId, @QueryParam("unfileObject") String unfileNonfolderObjects, @DefaultValue("false") @QueryParam("continueOnFailure") boolean continueOnFailure) { return deleteDescendants(repositoryId, folderId, unfileNonfolderObjects, continueOnFailure); } @DELETE @Path("{repositoryId}/descendants/{folderId}") public Response deleteDescendants(@PathParam("repositoryId") String repositoryId, @PathParam("folderId") String folderId, @QueryParam("unfileObject") String unfileNonfolderObjects, @DefaultValue("false") @QueryParam("continueOnFailure") boolean continueOnFailure) { UnfileObject unfileObject; try { unfileObject = unfileNonfolderObjects == null ? UnfileObject.DELETE : UnfileObject.fromValue(unfileNonfolderObjects); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Unsupported 'unfileObject' attribute: " + unfileNonfolderObjects); } Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); Boolean deleteAllVersions = true; // TODO : backend (JCR) not support removing just one version. connection.deleteTree(folderId, deleteAllVersions, unfileObject, continueOnFailure); return Response.noContent().build(); } catch (UpdateConflictException uce) { throw new WebApplicationException(uce, createErrorResponse(uce, 409)); } catch (ObjectNotFoundException onfe) { throw new WebApplicationException(onfe, createErrorResponse(onfe, 404)); } catch (InvalidArgumentException iae) { throw new WebApplicationException(iae, createErrorResponse(iae, 400)); } catch (Exception t) { throw new WebApplicationException(t, createErrorResponse(t, 500)); } finally { if (connection != null) { connection.close(); } } } @DELETE @Path("{repositoryId}/types/{typeId}") @RolesAllowed({"administrators"}) public Response deleteType(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return deleteItem(repositoryId, httpRequest); } @GET @Path("{repositoryId}/objacl/{objectId}") @Produces("application/cmisacl+xml") public Response getACL(@PathParam("repositoryId") String repositoryId, @PathParam("objectId") String objectId, @DefaultValue("true") @QueryParam("onlyBasicPermissions") boolean onlyBasicPermissions) { Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); List<AccessControlEntry> list = connection.getACL(objectId, onlyBasicPermissions); FOMExtensibleElement accessControlListTypeElement = AbderaFactory.getInstance().getFactory().newElement(AtomCMIS.ACL); for (AccessControlEntry accessControlEntry : list) { AccessControlEntryTypeElement ace = accessControlListTypeElement.addExtension(AtomCMIS.PERMISSION); ace.build(accessControlEntry); } return Response.ok(accessControlListTypeElement).header(HttpHeaders.CACHE_CONTROL, "no-cache").build(); } catch (InvalidArgumentException iae) { throw new WebApplicationException(iae, createErrorResponse(iae, 400)); } catch (Exception others) { throw new WebApplicationException(others, createErrorResponse(others, 500)); } finally { if (connection != null) { connection.close(); } } } @GET @Path("{repositoryId}/allowableactions/{objectId}") @Produces("application/atom+xml;type=allowableActions") public Response getAllowableActions(@PathParam("repositoryId") String repositoryId, @PathParam("objectId") String objectId) { Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AllowableActions result = connection.getAllowableActions(objectId); AllowableActionsElement el = AbderaFactory.getInstance().getFactory().newElement(AtomCMIS.ALLOWABLE_ACTIONS); el.build(result); return Response.ok(el).header(HttpHeaders.CACHE_CONTROL, "no-cache").build(); } catch (ObjectNotFoundException onfe) { throw new WebApplicationException(onfe, createErrorResponse(onfe, 404)); } catch (InvalidArgumentException iae) { throw new WebApplicationException(iae, createErrorResponse(iae, 400)); } catch (Exception others) { throw new WebApplicationException(others, createErrorResponse(others, 500)); } finally { if (connection != null) { connection.close(); } } } @GET @Path("{repositoryId}/typedescendants") @Produces("application/cmistree+xml") public Response getAllTypeDescendants(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { // The same jobs as 'getTypeDescendants()' but respect URL pattern. return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/types") @Produces("application/atom+xml;type=entry") public Response getAllTypes(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { // The same jobs as 'getTypes()' but respect URL pattern. return getTypes(httpRequest, repositoryId); } @GET // @Path("{repositoryId}/versions/{versionSeriesId}") @Path("{repositoryId}/versions/{versionSeriesId:.+}") @Produces("application/atom+xml;type=entry") public Response getAllVersions(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/policies/{objectId}") public Response getAppliedPolicies(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/changes") public Response getContentChanges(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/checkedout") public Response getCheckedOut(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/children/{folderId}") @Produces("application/atom+xml;type=feed") public Response getChildren(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/file/{documentId}") public Response getContentStream(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.getMedia(request); ResponseBuilder builder = Response.status(abderaResponse.getStatus()); copyAbderaHeaders(builder, abderaResponse); builder.entity(abderaResponse); // Cache-Control headers ? return builder.build(); } finally { if (connection != null) { connection.close(); } } } @GET @Path("{repositoryId}/descendants/{folderId}") @Produces("application/cmistree+xml") public Response getDescendants(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/foldertree/{folderId}") @Produces("application/atom+xml;type=feed") public Response getFolderTree(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/object/{objectId}") @Produces("application/atom+xml;type=entry") public Response getObjectById(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getEntry(repositoryId, httpRequest); } @GET @Path("{repositoryId}/objectbypath") @Produces("application/atom+xml;type=entry") public Response getObjectByPath(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getEntry(repositoryId, httpRequest); } @GET @Path("{repositoryId}/parents/{objectId}") public Response getObjectParents(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/relationships/{objectId}") @Produces("application/atom+xml;type=entry") public Response getRelationships(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/alternate/{documentId}/{streamId}") public Response getRendition(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId, @PathParam("documentId") String documentId) { return getContentStream(httpRequest, repositoryId); } @GET public Response getRepositories(@Context HttpServletRequest httpRequest, @Context UriInfo uriInfo) { String repositoryId = httpRequest.getParameter("repositoryId"); if (repositoryId != null && !repositoryId.isEmpty()) { return makeRepositoryInfoResponse(httpRequest, uriInfo.getBaseUri(), repositoryId); } Service service = AbderaFactory.getInstance().getFactory().newService(); service.declareNS(AtomCMIS.CMISRA_NS_URI, AtomCMIS.CMISRA_PREFIX); Set<RepositoryShortInfo> shortInfos = CmisRegistry.getInstance().getStorageInfos(); RequestContext request = initRequestContext(httpRequest); if (shortInfos != null && !shortInfos.isEmpty()) { for (RepositoryShortInfo info : shortInfos) { Workspace ws = service.addWorkspace(info.getRepositoryId()); ws.setTitle(info.getRepositoryName()); RepositoryInfoTypeElement repoInfoElement = ws.addExtension(AtomCMIS.REPOSITORY_INFO); repoInfoElement.addSimpleExtension(AtomCMIS.REPOSITORY_ID, info.getRepositoryId()); repoInfoElement.addSimpleExtension(AtomCMIS.REPOSITORY_NAME, info.getRepositoryName()); repoInfoElement.addSimpleExtension(AtomCMIS.ROOT_FOLDER_ID, info.getRootFolderId()); String repoPath = UriBuilder.fromUri(uriInfo.getBaseUri()).path(getClass()).path(info.getRepositoryId()).build() .toString(); Collection<CollectionInfo> collectionsInfo = getCollectionsInfo(request); for (CollectionInfo collectionInfo : collectionsInfo) { CmisCollectionInfo cmisCollectionInfo = (CmisCollectionInfo)collectionInfo; String collectionType = cmisCollectionInfo.getCollectionType(); if (AtomCMIS.COLLECTION_TYPE_ROOT.equals(collectionType)) ws.addCollection(((CmisCollectionInfo)collectionInfo).asCollectionElement(request, repoPath, info .getRootFolderId())); else ws.addCollection(((CmisCollectionInfo)collectionInfo).asCollectionElement(request, repoPath)); } includeURITemplates(ws, repoPath); } } return Response.ok().entity(service).header(HttpHeaders.CACHE_CONTROL, "no-cache").type( MediaType.APPLICATION_ATOM_XML).build(); } @GET @Path("{repositoryId}") public Response getRepositoryInfo(@Context HttpServletRequest httpRequest, @Context UriInfo uriInfo, @PathParam("repositoryId") String repositoryId) { String queryRepositoryId = httpRequest.getParameter("repositoryId"); if (queryRepositoryId != null && !queryRepositoryId.isEmpty()) return makeRepositoryInfoResponse(httpRequest, uriInfo.getBaseUri(), queryRepositoryId); return makeRepositoryInfoResponse(httpRequest, uriInfo.getBaseUri(), repositoryId); } private Response makeRepositoryInfoResponse(HttpServletRequest httpRequest, URI baseUri, String repositoryId) { Service service = AbderaFactory.getInstance().getFactory().newService(); service.declareNS(AtomCMIS.CMIS_NS_URI, AtomCMIS.CMIS_PREFIX); service.declareNS(AtomCMIS.CMISRA_NS_URI, AtomCMIS.CMISRA_PREFIX); addCmisRepository(httpRequest, service, repositoryId, baseUri); Document<Service> serviceDocument = service.getDocument(); serviceDocument.setCharset("utf-8"); ResponseContext abderaResponse = new BaseResponseContext<Document<Service>>(serviceDocument); abderaResponse.setStatus(200); return Response.ok(abderaResponse).header(HttpHeaders.CACHE_CONTROL, "no-cache") .type(MediaType.APPLICATION_ATOM_XML).build(); } @GET @Path("{repositoryId}/typebyid/{typeId}") @Produces("application/atom+xml;type=entry") public Response getTypeById(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getEntry(repositoryId, httpRequest); } @GET @Path("{repositoryId}/typedescendants/{typeId}") @Produces("application/cmistree+xml") public Response getTypeDescendants(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @GET @Path("{repositoryId}/types/{typeId}") @Produces("application/atom+xml;type=entry") public Response getTypes(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @POST @Path("{repositoryId}/query") public Response query(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.getFeed(request); ResponseBuilder builder = Response.status(abderaResponse.getStatus() == 200 ? 201 : abderaResponse.getStatus()); copyAbderaHeaders(builder, abderaResponse); builder.header(HttpHeaders.CACHE_CONTROL, "no-cache"); return builder.entity(abderaResponse).build(); } finally { if (connection != null) { connection.close(); } } } @GET @Path("{repositoryId}/query") public Response queryGET(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } @DELETE @Path("{repositoryId}/policies/{objectId}") public Response removePolicy(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return deleteItem(repositoryId, httpRequest); } @PUT @Path("{repositoryId}/file/{objectId}") public Response setContentStream(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.putMedia(request); ResponseBuilder builder = Response.status(abderaResponse.getStatus()); copyAbderaHeaders(builder, abderaResponse); return builder.entity(abderaResponse).build(); } finally { if (connection != null) { connection.close(); } } } @POST @Path("{repositoryId}/file/{objectId}") @Consumes("multipart/form-data") public Response setContentStream(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId, @QueryParam(HttpHeaders.CONTENT_TYPE) String contentType, Iterator<FileItem> files) { if (files.hasNext()) { FileItem file = files.next(); // In fact expected to get just one file. Other items // in iterator may be simple form fields, and we are not // care about it. Just skip all of them. if (!file.isFormField()) { try { // Content-Type passed as query parameter, we do not // wont to use passed by browser. But if parameter does // not exists then try to get media type passed by browser. if (contentType == null) { contentType = file.getContentType(); } RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); collection.putMedia(null, new javax.activation.MimeType(contentType), null, file.getInputStream(), request); return Response.status(201).build(); } finally { if (connection != null) { connection.close(); } } } catch (IOException ioe) { throw new WebApplicationException(ioe, createErrorResponse(ioe, 500)); } catch (ResponseContextException rce) { throw new WebApplicationException(rce, createErrorResponse(rce, rce.getResponseContext().getStatus())); } catch (MimeTypeParseException mte) { throw new WebApplicationException(mte, createErrorResponse(mte, 400)); } } } throw new WebApplicationException(new InvalidArgumentException("Content of document is missing."), 400); } @PUT @Path("{repositoryId}/object/{objectId}") @Produces("application/atom+xml;type=entry") public Response updateProperties(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.putEntry(request); ResponseBuilder builder = Response.status(abderaResponse.getStatus()); copyAbderaHeaders(builder, abderaResponse); return builder.entity(abderaResponse).build(); } finally { if (connection != null) { connection.close(); } } } private void copyAbderaHeaders(ResponseBuilder responseBuilder, ResponseContext abderaResponse) { for (String headerName : abderaResponse.getHeaderNames()) { for (Object v : abderaResponse.getHeaders(headerName)) { // For now just be sure not get errors if RESTful framework. responseBuilder.header(headerName, v.toString()); } } } @POST @Path("{repositoryId}/unfiled") public Response unfile(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) throws Exception { return createItem(repositoryId, httpRequest); } @GET @Path("{repositoryId}/unfiled") public Response getUnfiled(@Context HttpServletRequest httpRequest, @PathParam("repositoryId") String repositoryId) { return getFeed(repositoryId, httpRequest); } private Workspace addCmisRepository(HttpServletRequest httpRequest, Service service, String repositoryId, URI baseUri) { RepositoryInfo repoInfo; Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); repoInfo = connection.getStorage().getRepositoryInfo(); } catch (InvalidArgumentException iae) { throw new WebApplicationException(iae, createErrorResponse(iae, 400)); } catch (Exception others) { throw new WebApplicationException(others, createErrorResponse(others, 500)); } finally { if (connection != null) { connection.close(); } } Workspace ws = service.addWorkspace(repositoryId); ws.setTitle(repoInfo.getRepositoryName()); RepositoryInfoTypeElement repoInfoElement = ws.addExtension(AtomCMIS.REPOSITORY_INFO); repoInfoElement.build(repoInfo); String repoPath = UriBuilder.fromUri(baseUri).path(getClass()).path(repositoryId).build().toString(); RequestContext request = initRequestContext(httpRequest); Collection<CollectionInfo> collectionsInfo = getCollectionsInfo(request); for (CollectionInfo collectionInfo : collectionsInfo) { CmisCollectionInfo cmisCollectionInfo = (CmisCollectionInfo)collectionInfo; String collectionType = cmisCollectionInfo.getCollectionType(); if (AtomCMIS.COLLECTION_TYPE_ROOT.equals(collectionType)) ws.addCollection(((CmisCollectionInfo)collectionInfo).asCollectionElement(request, repoPath, repoInfo .getRootFolderId())); else ws.addCollection(((CmisCollectionInfo)collectionInfo).asCollectionElement(request, repoPath)); } includeURITemplates(ws, repoPath); // Add links Factory factory = AbderaFactory.getInstance().getFactory(); Link typeTypeDescendantsLink = factory.newLink(ws); typeTypeDescendantsLink.setTitle("Type descendants"); typeTypeDescendantsLink.setRel(AtomCMIS.LINK_CMIS_TYPEDESCENDANTS); typeTypeDescendantsLink.setMimeType(AtomCMIS.MEDIATYPE_CMISTREE); typeTypeDescendantsLink.setHref(repoPath + "/typedescendants"); RepositoryCapabilities capabilities = repoInfo.getCapabilities(); if (capabilities.isCapabilityGetDescendants()) { Link descendantsLink = factory.newLink(ws); descendantsLink.setTitle("Root folder descendants"); descendantsLink.setRel(AtomCMIS.LINK_CMIS_ROOTDESCENDANTS); descendantsLink.setMimeType(AtomCMIS.MEDIATYPE_CMISTREE); descendantsLink.setHref(repoPath + "/descendants/" + repoInfo.getRootFolderId()); } if (capabilities.isCapabilityGetFolderTree()) { Link treeLink = factory.newLink(ws); treeLink.setTitle("Root folder tree"); treeLink.setRel(AtomCMIS.LINK_CMIS_FOLDERTREE); treeLink.setMimeType(AtomCMIS.MEDIATYPE_CMISTREE); treeLink.setHref(repoPath + "/foldertree/" + repoInfo.getRootFolderId()); } if (CapabilityChanges.NONE != capabilities.getCapabilityChanges()) { Link treeLink = factory.newLink(ws); treeLink.setTitle("Changes log"); treeLink.setRel(AtomCMIS.LINK_CMIS_CHANGES); treeLink.setMimeType(AtomCMIS.MEDIATYPE_ATOM_FEED); treeLink.setHref(repoPath + "/changes"); } return ws; } private void includeURITemplates(Workspace ws, String repoPath) { // objectbyid template CmisUriTemplateType objectById = new CmisUriTemplateType(); objectById.setMediatype(AtomCMIS.MEDIATYPE_ATOM_ENTRY); objectById.setTemplate(new StringBuilder() // .append(repoPath) // .append("/object/{id}?") // .append("filter={filter}&") // .append("includeAllowableActions={includeAllowableActions}&") // .append("includePolicyIds={includePolicyIds}&") // .append("includeRelationships={includeRelationships}&") // .append("includeACL={includeACL}&") // .append("renditionFilter={renditionFilter}").toString()); objectById.setType(AtomCMIS.URITEMPLATE_OBJECTBYID); UriTemplateTypeElement objectByIdElement = ws.addExtension(AtomCMIS.URITEMPLATE); objectByIdElement.build(objectById); // objectbypath template CmisUriTemplateType objectByPath = new CmisUriTemplateType(); objectByPath.setMediatype(AtomCMIS.MEDIATYPE_ATOM_ENTRY); objectByPath.setTemplate(new StringBuilder() // .append(repoPath) // .append("/objectbypath?")// .append("path={path}&")// .append("filter={filter}&")// .append("includeAllowableActions={includeAllowableActions}&")// .append("includePolicyIds={includePolicyIds}&")// .append("includeRelationships={includeRelationships}&")// .append("includeACL={includeACL}&") // .append("renditionFilter={renditionFilter}").toString()); objectByPath.setType(AtomCMIS.URITEMPLATE_OBJECTBYPATH); UriTemplateTypeElement folderByPathElement = ws.addExtension(AtomCMIS.URITEMPLATE); folderByPathElement.build(objectByPath); // query template CmisUriTemplateType query = new CmisUriTemplateType(); query.setMediatype(AtomCMIS.MEDIATYPE_ATOM_FEED); query.setTemplate(new StringBuilder() // .append(repoPath) // .append("/query?")// .append("q={q}&")// .append("searchAllVersions={searchAllVersions}&") // .append("maxItems={maxItems}&") // .append("skipCount={skipCount}&") // .append("includeAllowableActions={includeAllowableActions}&")// .append("includeRelationships={includeRelationships}").toString()); query.setType(AtomCMIS.URITEMPLATE_QUERY); UriTemplateTypeElement queryElement = ws.addExtension(AtomCMIS.URITEMPLATE); queryElement.build(query); // typebyid template CmisUriTemplateType typeById = new CmisUriTemplateType(); typeById.setMediatype(AtomCMIS.MEDIATYPE_ATOM_ENTRY); typeById.setTemplate(repoPath + "/typebyid/{id}"); typeById.setType(AtomCMIS.URITEMPLATE_TYPEBYID); UriTemplateTypeElement typeByIdElement = ws.addExtension(AtomCMIS.URITEMPLATE); typeByIdElement.build(typeById); // changes CmisUriTemplateType changes = new CmisUriTemplateType(); changes.setMediatype(AtomCMIS.MEDIATYPE_ATOM_FEED); changes.setTemplate(new StringBuilder() // .append(repoPath) // .append("/changes?")// .append("changeLogToken={changeLogToken}&")// .append("includeProperties={includeProperties}&") // .append("includePolicyIds={includePolicyIds}&") // .append("includeACL={includeACL}&") // .append("filter={filter}&")// .append("maxItems={maxItems}").toString()); changes.setType(AtomCMIS.URITEMPLATE_CHANGES); UriTemplateTypeElement changesElement = ws.addExtension(AtomCMIS.URITEMPLATE); changesElement.build(changes); } protected Response createErrorResponse(Throwable t, int status) { return Response.status(status).entity(t.getMessage()).type("text/plain").build(); } protected Response createItem(String repositoryId, HttpServletRequest httpRequest) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.postEntry(request); ResponseBuilder builder = Response.status(abderaResponse.getStatus()); copyAbderaHeaders(builder, abderaResponse); return builder.entity(abderaResponse).build(); } finally { if (connection != null) { connection.close(); } } } protected Response deleteItem(String repositoryId, HttpServletRequest httpRequest) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.deleteEntry(request); ResponseBuilder builder = Response.status(abderaResponse.getStatus()); copyAbderaHeaders(builder, abderaResponse); return builder.entity(abderaResponse).build(); } finally { if (connection != null) { connection.close(); } } } protected AbstractCmisCollection<?> getCollection(RequestContext request, Connection connection) { WorkspaceManagerImpl wm = (WorkspaceManagerImpl)provider.getWorkspaceManager(request); AbstractCmisCollection<?> collection = wm.getCollectionAdapter(request, connection); return collection; } protected Collection<CollectionInfo> getCollectionsInfo(RequestContext request) { Collection<WorkspaceInfo> workspaces = (provider).getWorkspaceManager(request).getWorkspaces(request); Collection<CollectionInfo> collections = workspaces.iterator().next().getCollections(request); return collections; } protected Response getEntry(String repositoryId, HttpServletRequest httpRequest) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.getEntry(request); ResponseBuilder builder = Response.status(abderaResponse.getStatus()); copyAbderaHeaders(builder, abderaResponse); builder.header(HttpHeaders.CACHE_CONTROL, "no-cache"); return builder.entity(abderaResponse).build(); } finally { if (connection != null) { connection.close(); } } } protected Response getFeed(String repositoryId, HttpServletRequest httpRequest) { RequestContext request = initRequestContext(httpRequest); Connection connection = null; try { connection = CmisRegistry.getInstance().getConnection(repositoryId); AbstractCmisCollection<?> collection = getCollection(request, connection); ResponseContext abderaResponse = collection.getFeed(request); ResponseBuilder builder = Response.status(abderaResponse.getStatus()); copyAbderaHeaders(builder, abderaResponse); builder.header(HttpHeaders.CACHE_CONTROL, "no-cache"); return builder.entity(abderaResponse).build(); } finally { if (connection != null) { connection.close(); } } } private RequestContext initRequestContext(HttpServletRequest httpRequest) { return new ServletRequestContext(provider, httpRequest) { @Override public String getTargetPath() { String uri = getUri().toString(); String bpath = getTargetBasePath(); return uri.substring(bpath.length()); } }; } }