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.text.StringEscapeUtils;
053import org.apache.commons.logging.Log;
054import org.apache.commons.logging.LogFactory;
055import org.nuxeo.ecm.core.api.DocumentModel;
056import org.nuxeo.ecm.webdav.EscapeUtils;
057import org.nuxeo.ecm.webdav.backend.Backend;
058import org.nuxeo.ecm.webdav.jaxrs.IsFolder;
059import org.nuxeo.ecm.webdav.jaxrs.Util;
060
061/**
062 * A resource for folder-like objects in the repository.
063 */
064public class FolderResource extends ExistingResource {
065
066    private static final Log log = LogFactory.getLog(FolderResource.class);
067
068    public FolderResource(String path, DocumentModel doc, HttpServletRequest request, Backend backend) {
069        super(path, doc, request, backend);
070    }
071
072    @GET
073    @Produces("text/html")
074    public String get() {
075        StringBuilder sb = new StringBuilder();
076        sb.append("<html><body><p>");
077        sb.append("Folder listing for ");
078        sb.append(StringEscapeUtils.escapeHtml4(path));
079        sb.append("/");
080        sb.append("</p>\n<ul>\n");
081        List<DocumentModel> children = backend.getChildren(doc.getRef());
082        for (DocumentModel child : children) {
083            String name = backend.getDisplayName(child);
084            sb.append("<li><a href=\"");
085            sb.append(StringEscapeUtils.escapeHtml4(EscapeUtils.encodePath(name)));
086            if (child.isFolder()) {
087                sb.append("/");
088            }
089            sb.append("\">");
090            sb.append(StringEscapeUtils.escapeHtml4(name));
091            sb.append("</a></li>\n");
092        }
093        sb.append("</ul></body>\n");
094        return sb.toString();
095    }
096
097    @PROPFIND
098    @Produces({ "application/xml", "text/xml" })
099    public Response propfind(@Context UriInfo uriInfo, @HeaderParam("depth") String depth)
100            throws IOException, JAXBException {
101
102        if (depth == null) {
103            depth = "1";
104        }
105
106        Unmarshaller u = Util.getUnmarshaller();
107
108        Prop prop = null;
109        if (request.getInputStream() != null && request.getContentLength() > 0) {
110            PropFind propFind;
111            try {
112                propFind = (PropFind) u.unmarshal(request.getInputStream());
113            } catch (JAXBException e) {
114                log.error(e);
115                // FIXME: check this is the right response code
116                return Response.status(400).build();
117            }
118            prop = propFind.getProp();
119            // Util.printAsXml(prop);
120        }
121
122        final net.java.dev.webdav.jaxrs.xml.elements.Response response;
123        response = createResponse(doc, uriInfo, prop, false);
124
125        if (!doc.isFolder() || depth.equals("0")) {
126            return Response.status(207).entity(new MultiStatus(response)).build();
127        }
128
129        List<net.java.dev.webdav.jaxrs.xml.elements.Response> responses = new ArrayList<>();
130        responses.add(response);
131
132        List<DocumentModel> children = backend.getChildren(doc.getRef());
133        for (DocumentModel child : children) {
134            net.java.dev.webdav.jaxrs.xml.elements.Response childResponse;
135            childResponse = createResponse(child, uriInfo, prop);
136
137            responses.add(childResponse);
138        }
139
140        MultiStatus st = new MultiStatus(
141                responses.toArray(new net.java.dev.webdav.jaxrs.xml.elements.Response[responses.size()]));
142        // printXml(st);
143        return Response.status(207).entity(st).build();
144    }
145
146    protected net.java.dev.webdav.jaxrs.xml.elements.Response createResponse(DocumentModel doc, UriInfo uriInfo,
147            Prop prop) {
148        return createResponse(doc, uriInfo, prop, true);
149    }
150
151    protected net.java.dev.webdav.jaxrs.xml.elements.Response createResponse(DocumentModel doc, UriInfo uriInfo,
152            Prop prop, boolean append) {
153        PropStatBuilderExt props = getPropStatBuilderExt(doc, uriInfo);
154        PropStat propStatFound = props.build();
155        PropStat propStatNotFound = null;
156        if (prop != null) {
157            propStatNotFound = props.notFound(prop);
158        }
159
160        net.java.dev.webdav.jaxrs.xml.elements.Response response;
161        UriBuilder uriBuilder = uriInfo.getRequestUriBuilder();
162        if (append) {
163            String path = EscapeUtils.encodePath(backend.getDisplayName(doc));
164            uriBuilder.path(path);
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}