001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2007
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.war.webdav;
034:
035: import com.flexive.shared.FxSharedUtils;
036: import com.flexive.war.webdav.catalina.XMLWriter;
037: import org.w3c.dom.Document;
038: import org.w3c.dom.Element;
039: import org.w3c.dom.Node;
040: import org.w3c.dom.NodeList;
041: import org.xml.sax.InputSource;
042:
043: import javax.servlet.ServletException;
044: import javax.servlet.http.HttpServletRequest;
045: import javax.servlet.http.HttpServletResponse;
046: import javax.xml.parsers.DocumentBuilder;
047: import java.io.ByteArrayInputStream;
048: import java.io.IOException;
049: import java.util.Vector;
050:
051: /**
052: * PROPFIND - Used to retrieve properties, persisted as XML, from a resource.
053: *
054: * @author Gregor Schober (gregor.schober@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
055: * @version $Rev: 1 $
056: */
057: class OperationPropFind extends Operation {
058:
059: // Find types
060: private static enum FIND_BY {
061: PROPERTY, PROPERTY_NAMES, ALL_PROP
062: }
063:
064: // Default and infinity depth, set to 3 to limit tree brwosing
065: static final int INFINITY = 3;
066:
067: private int depth;
068: private String properties[];
069: private FIND_BY type = null;
070:
071: /**
072: * Constructor.
073: *
074: * @param req the request
075: * @param resp the response
076: * @throws ServletException if a exception occurs
077: */
078: public OperationPropFind(HttpServletRequest req,
079: HttpServletResponse resp, boolean readonly)
080: throws ServletException {
081:
082: super (req, resp, readonly);
083:
084: // Propfind depth
085: String depthStr = req.getHeader("Depth");
086: depth = (depthStr == null || depthStr
087: .equalsIgnoreCase("infinity")) ? INFINITY : Integer
088: .parseInt(depthStr);
089: Node propNode = determineType();
090: properties = getProperties(propNode);
091:
092: if (debug)
093: System.out.println(this .toString());
094: }
095:
096: /**
097: * Writes the propfind response to the client
098: *
099: * @throws IOException
100: */
101: public void writeResponse() throws IOException {
102: if (debug)
103: System.out.println("++ Requesting:" + path);
104: if (path.endsWith("/index.jsp")) {
105: path = path.substring(0, path.lastIndexOf("/index.jsp"));
106: if (debug)
107: System.out.println("Adjusted path to [" + path + "]");
108: }
109: FxDavEntry res = null;
110: try {
111: res = FxWebDavServlet.getDavContext().getResource(
112: this .request, path);
113: } catch (Exception exc) {
114: if (debug)
115: System.err.println("Failed to lookup '" + path + "': "
116: + exc.getMessage());
117: }
118: if (res == null) { //check if application server 'magically' added a welcome file
119: if ("index.jsp".equals(path)) {
120: path = "";
121: } else if (path != null && path.endsWith("/index.jsp")) {
122: path = path
123: .substring(0, path.lastIndexOf("/index.jsp"));
124: } else {
125: response.sendError(HttpServletResponse.SC_NOT_FOUND,
126: path);
127: return;
128: }
129: //try again
130: writeResponse();
131: return;
132: }
133: // Start to write the response
134: response.setStatus(FxWebDavStatus.SC_MULTI_STATUS);
135: response.setContentType("text/xml; charset=UTF-8");
136: // Create multistatus object
137: XMLWriter generatedXML = new XMLWriter(response.getWriter());
138: generatedXML.writeXMLHeader();
139: generatedXML.writeElement(null, "multistatus"
140: + generateNamespaceDeclarations(), XMLWriter.OPENING);
141: handleElement(generatedXML, path, res, 1);
142: generatedXML.writeElement(null, "multistatus",
143: XMLWriter.CLOSING);
144: // if (debug) System.out.println(generatedXML.toString());
145: generatedXML.sendData();
146: }
147:
148: /**
149: * @param generatedXML
150: * @param dr
151: */
152: private void handleElement(XMLWriter generatedXML, String path,
153: FxDavEntry dr, final int curDepth) {
154: // if( debug ) System.out.println("Processing [" + dr.toString() + "] depth: "+curDepth+"/"+depth);
155: switch (type) {
156: case ALL_PROP:
157: case PROPERTY:
158: dr.writeProperties(generatedXML, path, properties);
159: break;
160: case PROPERTY_NAMES:
161: dr.writePropertyNames(generatedXML, path);
162: break;
163: }
164: // Do recursion if needed
165: if (dr.isCollection() && curDepth <= depth) {
166: FxDavEntry[] children = FxWebDavServlet.getDavContext()
167: .getChildren(this .request, path);
168: if (children != null) {
169: for (FxDavEntry child : children) {
170: handleElement(generatedXML, path + "/"
171: + child.getDisplayname(), child,
172: curDepth + 1);
173: }
174: }
175: }
176: }
177:
178: /**
179: * Generate the namespace declarations.
180: */
181: private String generateNamespaceDeclarations() {
182: return " xmlns=\"" + DEFAULT_NAMESPACE + "\"";
183: }
184:
185: /**
186: * Get the requested properties.
187: *
188: * @param propNode
189: * @return the requested properties
190: */
191: private String[] getProperties(final Node propNode)
192: throws ServletException {
193: if (type == FIND_BY.PROPERTY) {
194: Vector<String> props = new Vector<String>();
195: NodeList childList = propNode.getChildNodes();
196: for (int i = 0; i < childList.getLength(); i++) {
197: Node currentNode = childList.item(i);
198: switch (currentNode.getNodeType()) {
199: case Node.TEXT_NODE:
200: break;
201: case Node.ELEMENT_NODE:
202: String nodeName = currentNode.getNodeName();
203: if (nodeName.indexOf(':') != -1) {
204: props.addElement(nodeName.substring(nodeName
205: .indexOf(':') + 1));
206: } else {
207: props.addElement(nodeName);
208: }
209: break;
210: default:
211: throw new ServletException("Unknown element:"
212: + currentNode.getNodeName());
213: }
214: }
215: return props.toArray(new String[props.size()]);
216: }
217: return FxDavResource.ALL_PROPS;
218: }
219:
220: /**
221: * Determine the propfind type.
222: *
223: * @return the node if type is PROPERTY.
224: */
225: private Node determineType() {
226:
227: final String srequest = FxWebDavServlet
228: .inputStreamToString(request);
229: if (srequest.length() > 0) {
230: ByteArrayInputStream bais = null;
231: try {
232: DocumentBuilder documentBuilder = FxWebDavServlet
233: .getDocumentbuilder();
234: bais = new ByteArrayInputStream(FxSharedUtils
235: .getBytes(srequest));
236: //Document document = documentBuilder.parse(new InputSource(request.getInputStream()));
237: Document document = documentBuilder
238: .parse(new InputSource(bais));
239: Element rootElement = document.getDocumentElement();
240: NodeList childList = rootElement.getChildNodes();
241: for (int i = 0; i < childList.getLength(); i++) {
242: Node currentNode = childList.item(i);
243: switch (currentNode.getNodeType()) {
244: case Node.TEXT_NODE:
245: break;
246: case Node.ELEMENT_NODE:
247: if (currentNode.getNodeName().endsWith("prop")) {
248: type = FIND_BY.PROPERTY;
249: properties = null;
250: return currentNode;
251: } else if (currentNode.getNodeName().endsWith(
252: "propname")) {
253: type = FIND_BY.PROPERTY_NAMES;
254: properties = null;
255: return null;
256: } else if (currentNode.getNodeName().endsWith(
257: "allprop")) {
258: type = FIND_BY.ALL_PROP;
259: properties = FxDavResource.ALL_PROPS;
260: return null;
261: } else {
262: // nothing
263: }
264: default:
265: throw new ServletException("Unknown node: "
266: + currentNode.getNodeName());
267: }
268: }
269: return null;
270: } catch (Exception exc) {
271: /* ignore and use fallback */
272: } finally {
273: if (bais != null) {
274: try {
275: bais.close();
276: } catch (Exception e) {/*ignore*/
277: }
278: }
279: }
280: }
281:
282: // Fallback
283: type = FIND_BY.ALL_PROP;
284: properties = FxDavResource.ALL_PROPS;
285: return null;
286:
287: }
288:
289: /**
290: * String representation of the object.
291: *
292: * @return a string representation of the object
293: */
294: public String toString() {
295: return "PROPFIND: path:" + path + ";depth:" + depth + ";type:"
296: + type;
297: }
298:
299: }
|