001/* 002 * (C) Copyright 2006-2009 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Stefane Fermigier 016 */ 017package org.nuxeo.ecm.webdav.resource; 018 019import java.io.IOException; 020import java.net.URI; 021import java.net.URISyntaxException; 022 023import javax.servlet.http.HttpServletRequest; 024import javax.ws.rs.DELETE; 025import javax.ws.rs.HEAD; 026import javax.ws.rs.PUT; 027import javax.ws.rs.WebApplicationException; 028import javax.ws.rs.core.Response; 029 030import net.java.dev.webdav.jaxrs.methods.COPY; 031import net.java.dev.webdav.jaxrs.methods.MKCOL; 032import net.java.dev.webdav.jaxrs.methods.MOVE; 033import net.java.dev.webdav.jaxrs.methods.PROPFIND; 034import net.java.dev.webdav.jaxrs.methods.PROPPATCH; 035 036import org.nuxeo.ecm.core.api.Blob; 037import org.nuxeo.ecm.core.api.Blobs; 038import org.nuxeo.ecm.webdav.backend.Backend; 039 040/** 041 * Resource for an unknown (ie non-existing) object. Used so that PUT / MKCOL requests can actually created a document / 042 * folder. Other requests will end up with a 404 error. 043 */ 044public class UnknownResource extends AbstractResource { 045 046 private static final String DS_STORE = ".DS_Store"; 047 048 protected Backend backend; 049 050 public UnknownResource(String path, HttpServletRequest request, Backend backend) { 051 super(path, request); 052 this.backend = backend; 053 } 054 055 /** 056 * PUT over a non-existing resource: create a new file resource. 057 */ 058 @PUT 059 public Response put() throws IOException, URISyntaxException { 060 061 // Special case: ignore some Mac OS X files. 062 // ._ files cannot easily be skipped as the Finder requires them on creation 063 // We only forbid .DS_Store creation for now. 064 if (DS_STORE.equals(name)) { 065 throw new WebApplicationException(Response.Status.CONFLICT); 066 } 067 068 ensureParentExists(); 069 String contentType = request.getContentType(); 070 if (contentType == null) { 071 contentType = "application/octet-stream"; 072 } 073 Blob content = Blobs.createBlob(request.getInputStream(), contentType, null); 074 content.setFilename(name); 075 backend.createFile(parentPath, name, content); 076 backend.saveChanges(); 077 return Response.created(new URI(request.getRequestURI())).build(); 078 } 079 080 /** 081 * MKCOL over a non-existing resource: create a new folder resource. 082 */ 083 @MKCOL 084 public Response mkcol() throws IOException, URISyntaxException { 085 ensureParentExists(); 086 backend.createFolder(parentPath, name); 087 backend.saveChanges(); 088 return Response.created(new URI(request.getRequestURI())).build(); 089 } 090 091 // All these methods should raise an error 404 092 093 @DELETE 094 public Response delete() { 095 throw new WebApplicationException(Response.Status.NOT_FOUND); 096 } 097 098 @COPY 099 public Response copy() { 100 throw new WebApplicationException(Response.Status.NOT_FOUND); 101 } 102 103 @MOVE 104 public Response move() { 105 throw new WebApplicationException(Response.Status.NOT_FOUND); 106 } 107 108 @PROPFIND 109 public Response propfind() { 110 throw new WebApplicationException(Response.Status.NOT_FOUND); 111 } 112 113 @PROPPATCH 114 public Response proppatch() { 115 throw new WebApplicationException(Response.Status.NOT_FOUND); 116 } 117 118 @HEAD 119 public Response head() { 120 throw new WebApplicationException(Response.Status.NOT_FOUND); 121 } 122 123 // Utility 124 125 private void ensureParentExists() { 126 if (!backend.exists(parentPath)) { 127 throw new WebApplicationException(Response.Status.CONFLICT); 128 } 129 } 130 131}