View Javadoc

1   /*
2    * Copyright (c) 2006-2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.danube.webdav.xml.dav.response;
14  
15  import org.abstracthorizon.danube.http.HTTPConnection;
16  import org.abstracthorizon.danube.http.Status;
17  import org.abstracthorizon.danube.http.util.IOUtils;
18  import org.abstracthorizon.danube.webdav.util.NamespacesProvider;
19  import org.abstracthorizon.danube.webdav.xml.dav.HRef;
20  
21  import java.io.PrintWriter;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  /**
26   * This class represents multistatus response tag as defined in RFC-2518.
27   * It can render multistatus response xml but also can set {@link HTTPConnection} headers
28   * in a simple no content response or render partial content as required by some
29   * functions.
30   *
31   * @author Daniel Sendula
32   */
33  public class MultiStatus {
34  
35      /** Mutlistatus response status 207 */
36      public static final Status MULTISTATUS_RESPONSE = new Status("207", "Multistatus response");
37  
38      /** HTTP connection status is going to render response to */
39      protected HTTPConnection httpConnection;
40  
41      /** Is stauts already sent to the connection */
42      protected boolean committed = false;
43  
44      /** Is it header response only or proper multistatus xml */
45      protected boolean headerResponse = false;
46  
47      /** Namespace provider */
48      protected NamespacesProvider provider;
49  
50      /** List of responses */
51      protected List<Response> responses = new ArrayList<Response>();
52  
53      /**
54       * Constructor
55       * @param provider namespace provider
56       * @param connection connection to be rendered to
57       */
58      public MultiStatus(NamespacesProvider provider, HTTPConnection connection) {
59          this.provider = provider;
60          this.httpConnection = connection;
61      }
62  
63      /**
64       * Sets commit flag to <code>true</code>
65       */
66      public void commit() {
67          committed = true;
68      }
69  
70      /**
71       * Returns commited flag
72       * @return commited flag
73       */
74      public boolean isCommitted() {
75          return committed;
76      }
77  
78      /**
79       * Returns is it header only response
80       * @return <code>true</code> if it is header only response
81       */
82      public boolean isHeaderResponse() {
83          return headerResponse;
84      }
85  
86      /**
87       * Returns responses
88       * @return responses
89       */
90      public List<Response> getResponses() {
91          return responses;
92      }
93  
94      /**
95       * Returns http connection
96       * @return http connection
97       */
98      public HTTPConnection getHTTPConnection() {
99          return httpConnection;
100     }
101 
102     /**
103      * Returns http connection's response protocol
104      * @return http connection's response protocol
105      */
106     public String getResponseProtocol() {
107         return httpConnection.getResponseProtocol();
108     }
109 
110     /**
111      * Renders with <code>true</code> for force mutlistatus flag
112      */
113     public void render() {
114         render(true);
115     }
116 
117     /**
118      * Renders this object to http connection
119      *
120      * @param forceMultistatus if <code>true</code> then it is rendered as mutlistatus. Otherwise it can
121      * return header only or partial xml response
122      */
123     public void render(boolean forceMultistatus) {
124         if (responses.size() > 0) {
125             if (!forceMultistatus && !committed && (responses.size() == 1)/* && !responses.get(0).isDefined()*/) {
126                 headerResponse = true;
127             }
128             commit();
129             if (headerResponse) {
130                 Response response = responses.get(0);
131                 Status status = response.getStatus();
132                 if (response.isDefined()) {
133                     httpConnection.getResponseHeaders().putOnly("Content-Type", "text/xml; charset=\"utf-8\"");
134                     PrintWriter writer = (PrintWriter)httpConnection.adapt(PrintWriter.class);
135 
136                     // TODO what to do if more then one propstat is available???
137                     writer.println("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
138                     Propstat propStat = response.getPropStats().get(0);
139                     propStat.getProp().renderWithNamespaces(writer, provider);
140                 } else if (status != null) {
141                     httpConnection.setResponseStatus(status);
142                 } else {
143                     // ERROR
144                     throw new RuntimeException("Wrong response nether status nor propstats were defined");
145                 }
146             } else {
147                 httpConnection.getResponseHeaders().putOnly("Content-Type", "text/xml; charset=\"utf-8\"");
148                 httpConnection.setResponseStatus(MULTISTATUS_RESPONSE);
149                 PrintWriter writer = (PrintWriter)httpConnection.adapt(PrintWriter.class);
150                 writer.println("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
151                 writer.append("<D:multistatus ");
152                 renderNamespaces(writer, provider);
153                 writer.println(">");
154                 for (Response response : responses) {
155                     response.render(writer, provider);
156                 }
157                 writer.println("</D:multistatus>");
158             }
159         }
160     }
161 
162     /**
163      * Renders namespaces
164      *
165      * @param writer writer
166      * @param provider namespace provider
167      */
168     public static void renderNamespaces(PrintWriter writer, NamespacesProvider provider) {
169         String[] urls = provider.getDefinedURLs();
170         for (int i = 0; i < urls.length; i++) {
171             if (i > 0) {
172                 writer.append(' ');
173             }
174             writer.append("xmlns:").append(provider.getAssignedPrefix(urls[i])).append("=\"");
175             writer.append(urls[i]).append('"');
176         }
177     }
178 
179     /**
180      * Adds simple response
181      *
182      * @param status status
183      * @return new response
184      */
185     public Response addSimpleResponse(Status status) {
186         Response response = new Response(this, newHRef());
187         response.setStatus(status);
188         getResponses().add(response);
189         return response;
190     }
191 
192     /**
193      * Creates new response with href of request's URL
194      * @return new response
195      */
196     public Response newResponse() {
197         HRef href = newHRef();
198         Response response = new Response(this, href);
199         getResponses().add(response);
200         return response;
201     }
202 
203     /**
204      * Creates new response with href of relative path of request's URL
205      * @param path relative path from request's URL
206      * @return new response
207      */
208     public Response newResponse(String path) {
209         HRef href = newHRef(path);
210         Response response = new Response(this, href);
211         getResponses().add(response);
212         return response;
213     }
214 
215     /**
216      * Creates new href of request's URL
217      * @return new href
218      */
219     public HRef newHRef() {
220         HRef href = new HRef(httpConnection.getRequestURI());
221 //        HRef href = new HRef(connection.getComponentResourcePath());
222         return href;
223     }
224 
225     /**
226      * Creates new href of relative path of request's URL
227      * @param path path
228      * @return new href
229      */
230     public HRef newHRef(String path) {
231         String uri = IOUtils.addPaths(httpConnection.getRequestURI(), path);
232 //        String uri = IOUtils.addPaths(connection.getComponentResourcePath(), path);
233         HRef href = new HRef(uri);
234         return href;
235     }
236 }