001/* 002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * dmetzler 018 */ 019package org.nuxeo.ecm.restapi.server.jaxrs; 020 021import java.util.List; 022 023import javax.ws.rs.Consumes; 024import javax.ws.rs.DELETE; 025import javax.ws.rs.GET; 026import javax.ws.rs.POST; 027import javax.ws.rs.PUT; 028import javax.ws.rs.Path; 029import javax.ws.rs.Produces; 030import javax.ws.rs.core.Context; 031import javax.ws.rs.core.HttpHeaders; 032import javax.ws.rs.core.MediaType; 033import javax.ws.rs.core.Response; 034import javax.ws.rs.core.Response.Status; 035 036import org.apache.commons.lang.StringUtils; 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039import org.nuxeo.ecm.core.api.CoreSession; 040import org.nuxeo.ecm.core.api.DocumentModel; 041import org.nuxeo.ecm.core.api.DocumentRef; 042import org.nuxeo.ecm.core.api.NuxeoException; 043import org.nuxeo.ecm.core.api.PathRef; 044import org.nuxeo.ecm.core.api.VersioningOption; 045import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentModelJsonReader; 046import org.nuxeo.ecm.core.rest.DocumentObject; 047import org.nuxeo.ecm.core.versioning.VersioningService; 048import org.nuxeo.ecm.restapi.jaxrs.io.RestConstants; 049import org.nuxeo.ecm.webengine.WebException; 050import org.nuxeo.ecm.webengine.model.WebObject; 051 052/** 053 * This object basically overrides the default DocumentObject that doesn't know how to produce/consume JSON 054 * 055 * @since 5.7.2 056 */ 057 058@WebObject(type = "Document") 059@Produces({ "application/json+nxentity", "application/json+esentity", MediaType.APPLICATION_JSON }) 060public class JSONDocumentObject extends DocumentObject { 061 062 private static final String APPLICATION_JSON_NXENTITY = "application/json+nxentity"; 063 064 protected static final Log log = LogFactory.getLog(JSONDocumentObject.class); 065 066 private boolean isVersioning; 067 068 @Override 069 @GET 070 public DocumentModel doGet() { 071 return doc; 072 } 073 074 /** 075 * @return the document or the last version document in case of versioning handled 076 */ 077 @PUT 078 @Consumes({ APPLICATION_JSON_NXENTITY, "application/json" }) 079 public DocumentModel doPut(DocumentModel inputDoc, @Context HttpHeaders headers) { 080 DocumentModelJsonReader.applyPropertyValues(inputDoc, doc); 081 CoreSession session = ctx.getCoreSession(); 082 versioningDocFromHeaderIfExists(headers); 083 doc = session.saveDocument(doc); 084 session.save(); 085 return isVersioning ? session.getLastDocumentVersion(doc.getRef()) : doc; 086 } 087 088 @POST 089 @Consumes({ APPLICATION_JSON_NXENTITY, "application/json" }) 090 public Response doPost(DocumentModel inputDoc) { 091 CoreSession session = ctx.getCoreSession(); 092 093 if (StringUtils.isBlank(inputDoc.getType()) || StringUtils.isBlank(inputDoc.getName())) { 094 return Response.status(Status.BAD_REQUEST).entity("type or name property is missing").build(); 095 } 096 097 DocumentModel createdDoc = session.createDocumentModel(doc.getPathAsString(), inputDoc.getName(), 098 inputDoc.getType()); 099 DocumentModelJsonReader.applyPropertyValues(inputDoc, createdDoc); 100 createdDoc = session.createDocument(createdDoc); 101 session.save(); 102 return Response.ok(createdDoc).status(Status.CREATED).build(); 103 } 104 105 @DELETE 106 public Response doDelete() { 107 super.doDelete(); 108 return Response.noContent().build(); 109 } 110 111 @Override 112 @Path("@search") 113 public Object search() { 114 return ctx.newAdapter(this, "search"); 115 } 116 117 @Override 118 public DocumentObject newDocument(String path) { 119 try { 120 PathRef pathRef = new PathRef(doc.getPath().append(path).toString()); 121 DocumentModel doc = ctx.getCoreSession().getDocument(pathRef); 122 return (DocumentObject) ctx.newObject("Document", doc); 123 } catch (NuxeoException e) { 124 throw WebException.wrap(e); 125 } 126 } 127 128 @Override 129 public DocumentObject newDocument(DocumentRef ref) { 130 try { 131 DocumentModel doc = ctx.getCoreSession().getDocument(ref); 132 return (DocumentObject) ctx.newObject("Document", doc); 133 } catch (NuxeoException e) { 134 throw WebException.wrap(e); 135 } 136 } 137 138 @Override 139 public DocumentObject newDocument(DocumentModel doc) { 140 return (DocumentObject) ctx.newObject("Document", doc); 141 } 142 143 /** 144 * In case of version option header presence, checkin the related document 145 * 146 * @param headers X-Versioning-Option Header 147 */ 148 private void versioningDocFromHeaderIfExists(HttpHeaders headers) { 149 isVersioning = false; 150 List<String> versionHeader = headers.getRequestHeader(RestConstants.X_VERSIONING_OPTION); 151 if (versionHeader != null && versionHeader.size() != 0) { 152 VersioningOption versioningOption = VersioningOption.valueOf(versionHeader.get(0).toUpperCase()); 153 if (versioningOption != null && !versioningOption.equals(VersioningOption.NONE)) { 154 doc.putContextData(VersioningService.VERSIONING_OPTION, versioningOption); 155 isVersioning = true; 156 } 157 } 158 } 159}