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  package org.treetank.service.xml.serialize;
29  
30  import java.util.Arrays;
31  import java.util.Stack;
32  import java.util.concurrent.Callable;
33  
34  import org.treetank.access.NodeReadTrx;
35  import org.treetank.api.INodeReadTrx;
36  import org.treetank.api.ISession;
37  import org.treetank.axis.AbsAxis;
38  import org.treetank.axis.DescendantAxis;
39  import org.treetank.exception.TTException;
40  import org.treetank.exception.TTIOException;
41  import org.treetank.node.IConstants;
42  import org.treetank.node.interfaces.IStructNode;
43  
44  /**
45   * Class implements main serialization algorithm. Other classes can extend it.
46   * 
47   * @author Johannes Lichtenberger, University of Konstanz
48   * 
49   */
50  abstract class AbsSerializer implements Callable<Void> {
51  
52      /** Treetank session {@link ISession}. */
53      protected final ISession mSession;
54  
55      /** Stack for reading end element. */
56      protected final Stack<Long> mStack;
57  
58      /** Array with versions to print. */
59      protected final long[] mVersions;
60  
61      /** Root node key of subtree to shredder. */
62      protected final long mNodeKey;
63  
64      /**
65       * Constructor.
66       * 
67       * @param paramSession
68       *            {@link ISession}.
69       * @param paramVersions
70       *            versions which should be serialized: -
71       */
72      public AbsSerializer(final ISession paramSession, final long... paramVersions) {
73          this(paramSession, 0, paramVersions);
74      }
75  
76      /**
77       * Constructor.
78       * 
79       * @param paramSession
80       *            {@link ISession}.
81       * @param paramKey
82       *            Key of root node from which to shredder the subtree.
83       * @param paramVersions
84       *            versions which should be serialized: -
85       */
86      public AbsSerializer(final ISession paramSession, final long paramKey, final long... paramVersions) {
87          mStack = new Stack<Long>();
88          mVersions = paramVersions;
89          mSession = paramSession;
90          mNodeKey = paramKey;
91      }
92  
93      /**
94       * Serialize the storage.
95       * 
96       * @return null.
97       * @throws TTException
98       *             if can't call serailzer
99       */
100     public Void call() throws TTException {
101         emitStartDocument();
102 
103         long[] versionsToUse;
104 
105         // if there are no versions specified, take the last one, of not version==0
106         if (mVersions.length == 0) {
107             if (mSession.getMostRecentVersion() > 0) {
108                 versionsToUse = new long[] {
109                     mSession.getMostRecentVersion()
110                 };
111             }// revision 0 = bootstrapped page
112             else {
113                 versionsToUse = new long[0];
114             }
115         } // if there is any negative number specified, take the entire range of versions, otherwise take the
116           // parameter
117         else {
118             // sort the versions first
119             Arrays.sort(mVersions);
120             if (mVersions[0] < 0) {
121                 versionsToUse = new long[(int)mSession.getMostRecentVersion() - 1];
122 
123                 for (int i = 0; i < versionsToUse.length; i++) {
124                     versionsToUse[i] = i + 1;
125                 }
126 
127             }// otherwise take the versions as requested as params
128             else {
129                 int index = Arrays.binarySearch(mVersions, 1);
130                 versionsToUse = Arrays.copyOfRange(mVersions, index, mVersions.length);
131             }
132         }
133 
134         for (int i = 0; i < versionsToUse.length; i++) {
135 
136             INodeReadTrx rtx = new NodeReadTrx(mSession.beginBucketRtx(versionsToUse[i]));
137 
138             if (versionsToUse == null || mVersions.length > 1) {
139                 emitStartManualElement(i);
140             }
141 
142             rtx.moveTo(mNodeKey);
143 
144             final AbsAxis descAxis = new DescendantAxis(rtx, true);
145 
146             // Setup primitives.
147             boolean closeElements = false;
148             long key = rtx.getNode().getDataKey();
149 
150             // Iterate over all nodes of the subtree including self.
151             while (descAxis.hasNext()) {
152                 key = descAxis.next();
153                 IStructNode currentStruc = (IStructNode)rtx.getNode();
154 
155                 // Emit all pending end elements.
156                 if (closeElements) {
157                     while (!mStack.empty() && mStack.peek() != currentStruc.getLeftSiblingKey()) {
158                         rtx.moveTo(mStack.pop());
159                         emitEndElement(rtx);
160                         rtx.moveTo(key);
161                     }
162                     if (!mStack.empty()) {
163                         rtx.moveTo(mStack.pop());
164                         emitEndElement(rtx);
165                     }
166                     rtx.moveTo(key);
167                     closeElements = false;
168                 }
169                 // Emit node.
170                 emitStartElement(rtx);
171                 // Push end element to stack if we are a start element with
172                 // children.
173                 if (currentStruc.getKind() == IConstants.ELEMENT && currentStruc.hasFirstChild()) {
174                     mStack.push(rtx.getNode().getDataKey());
175                 }
176 
177                 // Remember to emit all pending end elements from stack if
178                 // required.
179                 if (!currentStruc.hasFirstChild() && !currentStruc.hasRightSibling()) {
180                     closeElements = true;
181                 }
182 
183             }
184 
185             // Finally emit all pending end elements.
186             while (!mStack.empty()) {
187                 rtx.moveTo(mStack.pop());
188                 emitEndElement(rtx);
189             }
190 
191             if (versionsToUse == null || mVersions.length > 1) {
192                 emitEndManualElement(i);
193             }
194         }
195         emitEndDocument();
196 
197         return null;
198     }
199 
200     /** Emit start document. */
201     protected abstract void emitStartDocument();
202 
203     /**
204      * Emit start tag.
205      * 
206      * @param pRTX
207      *            Treetank reading transaction {@link INodeReadTrx}.
208      */
209     protected abstract void emitStartElement(final INodeReadTrx pRTX) throws TTIOException;
210 
211     /**
212      * Emit end tag.
213      * 
214      * @param paramRTX
215      *            Treetank reading transaction {@link INodeReadTrx}.
216      */
217     protected abstract void emitEndElement(final INodeReadTrx paramRTX);
218 
219     /**
220      * Emit a start tag, which specifies a revision.
221      * 
222      * @param paramVersion
223      *            The revision to serialize.
224      */
225     protected abstract void emitStartManualElement(final long paramVersion);
226 
227     /**
228      * Emit an end tag, which specifies a revision.
229      * 
230      * @param paramVersion
231      *            The revision to serialize.
232      */
233     protected abstract void emitEndManualElement(final long paramVersion);
234 
235     /** Emit end document. */
236     protected abstract void emitEndDocument();
237 }