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}