001/* 002 * (C) Copyright 2006-2009 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 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.ecm.webdav.resource; 023 024import static javax.ws.rs.core.Response.Status.OK; 025 026import java.io.IOException; 027import java.net.URI; 028import java.net.URISyntaxException; 029import java.net.URLEncoder; 030 031import javax.servlet.http.HttpServletRequest; 032import javax.ws.rs.GET; 033import javax.ws.rs.PUT; 034import javax.ws.rs.Produces; 035import javax.ws.rs.core.Context; 036import javax.ws.rs.core.Response; 037import javax.ws.rs.core.UriInfo; 038import javax.xml.bind.JAXBException; 039import javax.xml.bind.Unmarshaller; 040 041import net.java.dev.webdav.jaxrs.methods.PROPFIND; 042import net.java.dev.webdav.jaxrs.xml.elements.HRef; 043import net.java.dev.webdav.jaxrs.xml.elements.LockEntry; 044import net.java.dev.webdav.jaxrs.xml.elements.LockScope; 045import net.java.dev.webdav.jaxrs.xml.elements.LockType; 046import net.java.dev.webdav.jaxrs.xml.elements.MultiStatus; 047import net.java.dev.webdav.jaxrs.xml.elements.Prop; 048import net.java.dev.webdav.jaxrs.xml.elements.PropFind; 049import net.java.dev.webdav.jaxrs.xml.elements.PropStat; 050import net.java.dev.webdav.jaxrs.xml.elements.Status; 051import net.java.dev.webdav.jaxrs.xml.properties.SupportedLock; 052 053import org.apache.commons.logging.Log; 054import org.apache.commons.logging.LogFactory; 055import org.nuxeo.ecm.core.api.Blob; 056import org.nuxeo.ecm.core.api.Blobs; 057import org.nuxeo.ecm.core.api.DocumentModel; 058import org.nuxeo.ecm.core.api.NuxeoException; 059import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 060import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder; 061import org.nuxeo.ecm.webdav.backend.Backend; 062import org.nuxeo.ecm.webdav.jaxrs.Util; 063 064/** 065 * Resource representing a file-like object in the repository. (I.e. not a folder). 066 */ 067public class FileResource extends ExistingResource { 068 069 private static final Log log = LogFactory.getLog(FileResource.class); 070 071 public FileResource(String path, DocumentModel doc, HttpServletRequest request, Backend backend) { 072 super(path, doc, request, backend); 073 } 074 075 @GET 076 public Object get() { 077 BlobHolder bh = doc.getAdapter(BlobHolder.class); 078 Blob blob = bh == null ? null : bh.getBlob(); 079 if (blob == null) { 080 return Response.ok("").build(); 081 } 082 String mimeType = blob.getMimeType(); 083 if (mimeType.equals("???")) { 084 mimeType = "application/octet-stream"; 085 } 086 // provide full DocumentBlobHolder context if possible, to give more info when calling the DownloadService 087 Object entity = bh instanceof DocumentBlobHolder ? bh : blob; 088 return Response.ok(entity).type(mimeType).build(); 089 } 090 091 @PUT 092 public Response put() { 093 if (backend.isLocked(doc.getRef()) && !backend.canUnlock(doc.getRef())) { 094 return Response.status(423).build(); 095 } 096 097 try { 098 Blob content = Blobs.createBlob(request.getInputStream()); 099 String contentType = request.getContentType(); 100 if (contentType == null) { 101 contentType = "application/octet-stream"; 102 } 103 content.setMimeType(contentType); 104 content.setFilename(name); 105 106 backend.updateDocument(doc, name, content); 107 try { 108 return Response.created(new URI(URLEncoder.encode(path, "UTF8"))).build(); 109 } catch (URISyntaxException e) { 110 throw new NuxeoException(e); 111 } 112 } catch (IOException e) { 113 log.error("Error during PUT method execution", e); 114 return Response.status(409).build(); 115 } 116 } 117 118 @PROPFIND 119 @Produces({ "application/xml", "text/xml" }) 120 public Response propfind(@Context UriInfo uriInfo) throws IOException, JAXBException { 121 122 Unmarshaller u = Util.getUnmarshaller(); 123 124 Prop prop = null; 125 if (request.getInputStream() != null && request.getContentLength() > 0) { 126 PropFind propFind; 127 try { 128 propFind = (PropFind) u.unmarshal(request.getInputStream()); 129 } catch (JAXBException e) { 130 return Response.status(400).build(); 131 } 132 prop = propFind.getProp(); 133 } 134 // Util.printAsXml(prop); 135 136 PropStatBuilderExt props = getPropStatBuilderExt(doc, uriInfo); 137 PropStat propStatFound = props.build(); 138 PropStat propStatNotFound = null; 139 if (prop != null) { 140 propStatNotFound = props.notFound(prop); 141 } 142 143 net.java.dev.webdav.jaxrs.xml.elements.Response response; 144 URI uri = uriInfo.getRequestUri(); 145 PropStat filePropStat = new PropStat(new Prop(new SupportedLock(new LockEntry(LockScope.EXCLUSIVE, 146 LockType.WRITE))), new Status(OK)); 147 if (doc.isLocked()) { 148 PropStat lockDiscoveryPropStat = new PropStat(new Prop(getLockDiscovery(doc, uriInfo)), new Status(OK)); 149 if (propStatNotFound != null) { 150 response = new net.java.dev.webdav.jaxrs.xml.elements.Response(new HRef(uri), null, null, null, 151 filePropStat, propStatFound, propStatNotFound, lockDiscoveryPropStat); 152 } else { 153 response = new net.java.dev.webdav.jaxrs.xml.elements.Response(new HRef(uri), null, null, null, 154 filePropStat, propStatFound, lockDiscoveryPropStat); 155 } 156 } else { 157 if (propStatNotFound != null) { 158 response = new net.java.dev.webdav.jaxrs.xml.elements.Response(new HRef(uri), null, null, null, 159 filePropStat, propStatFound, propStatNotFound); 160 } else { 161 response = new net.java.dev.webdav.jaxrs.xml.elements.Response(new HRef(uri), null, null, null, 162 filePropStat, propStatFound); 163 } 164 } 165 166 MultiStatus st = new MultiStatus(response); 167 return Response.status(207).entity(st).build(); 168 } 169 170}