View Javadoc

1   /**
2    * Copyright (c) 2011, University of Konstanz, Distributed Systems Group
3    * All rights reserved.
4    * 
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    * * Redistributions of source code must retain the above copyright
8    * notice, this list of conditions and the following disclaimer.
9    * * Redistributions in binary form must reproduce the above copyright
10   * notice, this list of conditions and the following disclaimer in the
11   * documentation and/or other materials provided with the distribution.
12   * * Neither the name of the University of Konstanz nor the
13   * names of its contributors may be used to endorse or promote products
14   * derived from this software without specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  
28  /**
29   * 
30   */
31  package org.treetank.service.jaxrx.util;
32  
33  import java.io.IOException;
34  import java.io.OutputStream;
35  
36  import javax.ws.rs.WebApplicationException;
37  import javax.ws.rs.core.Response;
38  
39  import org.treetank.access.NodeReadTrx;
40  import org.treetank.access.conf.SessionConfiguration;
41  import org.treetank.access.conf.StandardSettings;
42  import org.treetank.api.IStorage;
43  import org.treetank.api.INodeReadTrx;
44  import org.treetank.api.ISession;
45  import org.treetank.axis.AbsAxis;
46  import org.treetank.exception.TTException;
47  import org.treetank.service.xml.xpath.XPathAxis;
48  
49  /**
50   * This class is responsible to offer XPath processing functions for REST.
51   * 
52   * @author Patrick Lang, Lukas Lewandowski, University of Konstanz.
53   * 
54   */
55  public class RestXPathProcessor {
56  
57      /**
58       * This field the begin result element of a XQuery or XPath expression.
59       */
60      private static transient String beginResult = "<jaxrx:result xmlns:jaxrx=\"http://jaxrx.org/\">";
61  
62      /**
63       * This field the end result element of a XQuery or XPath expression.
64       */
65      private static transient String endResult = "</jaxrx:result>";
66  
67      /**
68       * Path to storage.
69       */
70      private final IStorage mDatabase;
71  
72      /**
73       * 
74       * Constructor.
75       * 
76       * @param pDatabase
77       *            path to the storage
78       */
79      public RestXPathProcessor(final IStorage pDatabase) {
80          mDatabase = pDatabase;
81      }
82  
83      /**
84       * Getting part of the XML based on a XPath query
85       * 
86       * @param resourceName
87       *            where the content should be extracted
88       * @param xpath
89       *            contains XPath query
90       * @param nodeid
91       *            To response the resource with a restid for each node ( <code>true</code>) or without (
92       *            <code>false</code>).
93       * @param revision
94       *            The revision of the requested resource. If <code>null</code>,
95       *            than response the latest revision.
96       * @param output
97       *            The OutputStream reference which have to be modified and
98       *            returned
99       * @return the queried XML fragment
100      * @throws IOException
101      *             The exception occurred.
102      * @throws TTException
103      */
104     public OutputStream getXpathResource(final String resourceName, final String xpath, final boolean nodeid,
105         final Long revision, final OutputStream output, final boolean wrapResult) throws IOException,
106         TTException {
107 
108         // work around because of query root char '/'
109         String qQuery = xpath;
110         if (xpath.charAt(0) == '/')
111             qQuery = ".".concat(xpath);
112         if (mDatabase.existsResource(resourceName)) {
113             if (wrapResult) {
114                 output.write(beginResult.getBytes());
115                 doXPathRes(resourceName, revision, output, nodeid, qQuery);
116                 output.write(endResult.getBytes());
117             } else {
118                 doXPathRes(resourceName, revision, output, nodeid, qQuery);
119             }
120 
121         } else {
122             throw new WebApplicationException(Response.Status.NOT_FOUND);
123         }
124         return output;
125     }
126 
127     /**
128      * Getting part of the XML based on a XPath query
129      * 
130      * @param resourceName
131      *            where the content should be extracted
132      * 
133      * @param query
134      *            contains XPath query
135      * @param rId
136      *            To response the resource with a restid for each node ( <code>true</code>) or without (
137      *            <code>false</code>).
138      * @param doRevision
139      *            The revision of the requested resource. If <code>null</code>,
140      *            than response the latest revision.
141      * @param output
142      *            The OutputStream reference which have to be modified and
143      *            returned
144      * @param doNodeId
145      *            specifies whether node id should be shown
146      * @param doWrap
147      *            output of result elements
148      * @throws TTException
149      */
150     public void getXpathResource(final String resourceName, final long rId, final String query,
151         final boolean doNodeId, final Long doRevision, final OutputStream output, final boolean doWrap)
152         throws TTException {
153 
154         // work around because of query root char '/'
155         String qQuery = query;
156         if (query.charAt(0) == '/')
157             qQuery = ".".concat(query);
158 
159         ISession session = null;
160         INodeReadTrx rtx = null;
161         try {
162             if (mDatabase.existsResource(resourceName)) {
163                 session = mDatabase.getSession(new SessionConfiguration(resourceName, StandardSettings.KEY));
164                 // Creating a transaction
165 
166                 if (doRevision == null) {
167                     rtx = new NodeReadTrx(session.beginBucketRtx(session.getMostRecentVersion()));
168                 } else {
169                     rtx = new NodeReadTrx(session.beginBucketRtx(doRevision));
170                 }
171 
172                 final boolean exist = rtx.moveTo(rId);
173                 if (exist) {
174                     final AbsAxis axis = new XPathAxis(rtx, qQuery);
175                     if (doWrap) {
176                         output.write(beginResult.getBytes());
177                         for (final long key : axis) {
178                             WorkerHelper.serializeXML(session, output, false, doNodeId, key, doRevision)
179                                 .call();
180                         }
181 
182                         output.write(endResult.getBytes());
183                     } else {
184                         for (final long key : axis) {
185                             WorkerHelper.serializeXML(session, output, false, doNodeId, key, doRevision)
186                                 .call();
187                         }
188 
189                     }
190                 } else {
191                     throw new WebApplicationException(404);
192                 }
193             }
194 
195         } catch (final Exception globExcep) {
196             throw new WebApplicationException(globExcep, Response.Status.INTERNAL_SERVER_ERROR);
197         } 
198     }
199 
200     /**
201      * This method performs an XPath evaluation and writes it to a given output
202      * stream.
203      * 
204      * @param resource
205      *            The existing resource.
206      * @param revision
207      *            The revision of the requested document.
208      * @param output
209      *            The output stream where the results are written.
210      * @param nodeid
211      *            <code>true</code> if node id's have to be delivered. <code>false</code> otherwise.
212      * @param xpath
213      *            The XPath expression.
214      * @throws TTException
215      */
216     private void doXPathRes(final String resource, final Long revision, final OutputStream output,
217         final boolean nodeid, final String xpath) throws TTException {
218         // Storage connection to treetank
219         ISession session = null;
220         INodeReadTrx rtx = null;
221         try {
222             if (mDatabase.existsResource(resource)) {
223                 session = mDatabase.getSession(new SessionConfiguration(resource, StandardSettings.KEY));
224                 // Creating a transaction
225                 if (revision == null) {
226                     rtx = new NodeReadTrx(session.beginBucketRtx(session.getMostRecentVersion()));
227                 } else {
228                     rtx = new NodeReadTrx(session.beginBucketRtx(revision));
229                 }
230 
231                 final AbsAxis axis = new XPathAxis(rtx, xpath);
232                 for (final long key : axis) {
233                     WorkerHelper.serializeXML(session, output, false, nodeid, key, revision).call();
234                 }
235             }
236         } catch (final Exception globExcep) {
237             throw new WebApplicationException(globExcep, Response.Status.INTERNAL_SERVER_ERROR);
238         } finally {
239             WorkerHelper.closeRTX(rtx, session);
240 
241         }
242     }
243 }