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.util.ArrayList;
029import java.util.List;
030
031import javax.servlet.http.HttpServletRequest;
032import javax.ws.rs.GET;
033import javax.ws.rs.HeaderParam;
034import javax.ws.rs.Produces;
035import javax.ws.rs.core.Context;
036import javax.ws.rs.core.Response;
037import javax.ws.rs.core.UriBuilder;
038import javax.ws.rs.core.UriInfo;
039import javax.xml.bind.JAXBException;
040import javax.xml.bind.Unmarshaller;
041
042import net.java.dev.webdav.jaxrs.methods.PROPFIND;
043import net.java.dev.webdav.jaxrs.xml.elements.HRef;
044import net.java.dev.webdav.jaxrs.xml.elements.MultiStatus;
045import net.java.dev.webdav.jaxrs.xml.elements.Prop;
046import net.java.dev.webdav.jaxrs.xml.elements.PropFind;
047import net.java.dev.webdav.jaxrs.xml.elements.PropStat;
048import net.java.dev.webdav.jaxrs.xml.elements.Status;
049import net.java.dev.webdav.jaxrs.xml.properties.LockDiscovery;
050import net.java.dev.webdav.jaxrs.xml.properties.SupportedLock;
051
052import org.apache.commons.httpclient.URIException;
053import org.apache.commons.httpclient.util.URIUtil;
054import org.apache.commons.lang.StringEscapeUtils;
055import org.apache.commons.logging.Log;
056import org.apache.commons.logging.LogFactory;
057import org.nuxeo.ecm.core.api.DocumentModel;
058import org.nuxeo.ecm.webdav.backend.Backend;
059import org.nuxeo.ecm.webdav.jaxrs.IsFolder;
060import org.nuxeo.ecm.webdav.jaxrs.Util;
061
062/**
063 * A resource for folder-like objects in the repository.
064 */
065public class FolderResource extends ExistingResource {
066
067    private static final Log log = LogFactory.getLog(FolderResource.class);
068
069    public FolderResource(String path, DocumentModel doc, HttpServletRequest request, Backend backend) {
070        super(path, doc, request, backend);
071    }
072
073    @GET
074    @Produces("text/html")
075    public String get() {
076        StringBuilder sb = new StringBuilder();
077        sb.append("<html><body><p>");
078        sb.append("Folder listing for ");
079        sb.append(path);
080        sb.append("/");
081        sb.append("</p>\n<ul>\n");
082        List<DocumentModel> children = backend.getChildren(doc.getRef());
083        for (DocumentModel child : children) {
084            String name = backend.getDisplayName(child);
085            String qname = StringEscapeUtils.escapeHtml(name);
086            sb.append("<li><a href=\"");
087            sb.append(qname);
088            if (child.isFolder()) {
089                sb.append("/");
090            }
091            sb.append("\">");
092            sb.append(qname);
093            sb.append("</a></li>\n");
094        }
095        sb.append("</ul></body>\n");
096        return sb.toString();
097    }
098
099    @PROPFIND
100    public Response propfind(@Context UriInfo uriInfo, @HeaderParam("depth") String depth) throws IOException,
101            JAXBException {
102
103        if (depth == null) {
104            depth = "1";
105        }
106
107        Unmarshaller u = Util.getUnmarshaller();
108
109        Prop prop = null;
110        if (request.getInputStream() != null && request.getContentLength() > 0) {
111            PropFind propFind;
112            try {
113                propFind = (PropFind) u.unmarshal(request.getInputStream());
114            } catch (JAXBException e) {
115                log.error(e);
116                // FIXME: check this is the right response code
117                return Response.status(400).build();
118            }
119            prop = propFind.getProp();
120            // Util.printAsXml(prop);
121        }
122
123        final net.java.dev.webdav.jaxrs.xml.elements.Response response;
124        response = createResponse(doc, uriInfo, prop, false);
125
126        if (!doc.isFolder() || depth.equals("0")) {
127            return Response.status(207).entity(new MultiStatus(response)).build();
128        }
129
130        List<net.java.dev.webdav.jaxrs.xml.elements.Response> responses = new ArrayList<net.java.dev.webdav.jaxrs.xml.elements.Response>();
131        responses.add(response);
132
133        List<DocumentModel> children = backend.getChildren(doc.getRef());
134        for (DocumentModel child : children) {
135            net.java.dev.webdav.jaxrs.xml.elements.Response childResponse;
136            childResponse = createResponse(child, uriInfo, prop);
137
138            responses.add(childResponse);
139        }
140
141        MultiStatus st = new MultiStatus(
142                responses.toArray(new net.java.dev.webdav.jaxrs.xml.elements.Response[responses.size()]));
143        // printXml(st);
144        return Response.status(207).entity(st).build();
145    }
146
147    protected net.java.dev.webdav.jaxrs.xml.elements.Response createResponse(DocumentModel doc, UriInfo uriInfo,
148            Prop prop) throws URIException {
149        return createResponse(doc, uriInfo, prop, true);
150    }
151
152    protected net.java.dev.webdav.jaxrs.xml.elements.Response createResponse(DocumentModel doc, UriInfo uriInfo,
153            Prop prop, boolean append) throws URIException {
154        PropStatBuilderExt props = getPropStatBuilderExt(doc, uriInfo);
155        PropStat propStatFound = props.build();
156        PropStat propStatNotFound = null;
157        if (prop != null) {
158            propStatNotFound = props.notFound(prop);
159        }
160
161        net.java.dev.webdav.jaxrs.xml.elements.Response response;
162        UriBuilder uriBuilder = uriInfo.getRequestUriBuilder();
163        if (append) {
164            uriBuilder.path(URIUtil.encodePath(backend.getDisplayName(doc)));
165        }
166        URI uri = uriBuilder.build();
167        if (doc.isFolder()) {
168            PropStat folderPropStat = new PropStat(
169                    new Prop(new LockDiscovery(), new SupportedLock(), new IsFolder("t")), new Status(OK));
170            if (propStatNotFound != null) {
171                response = new net.java.dev.webdav.jaxrs.xml.elements.Response(new HRef(uri), null, null, null,
172                        propStatFound, propStatNotFound, folderPropStat);
173            } else {
174                response = new net.java.dev.webdav.jaxrs.xml.elements.Response(new HRef(uri), null, null, null,
175                        propStatFound, folderPropStat);
176            }
177        } else {
178            if (propStatNotFound != null) {
179                response = new net.java.dev.webdav.jaxrs.xml.elements.Response(new HRef(uri), null, null, null,
180                        propStatFound, propStatNotFound);
181            } else {
182                response = new net.java.dev.webdav.jaxrs.xml.elements.Response(new HRef(uri), null, null, null,
183                        propStatFound);
184            }
185        }
186        return response;
187    }
188
189}