KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > watson > ElementTreeWriter


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
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  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.watson;
12
13 import java.io.*;
14 import java.util.*;
15 import org.eclipse.core.internal.dtree.*;
16 import org.eclipse.core.runtime.*;
17
18 /** <code>ElementTreeWriter</code> flattens an ElementTree
19  * onto a data output stream.
20  *
21  * <p>This writer generates the most up-to-date format
22  * of a saved element tree (cf. readers, which must usually also
23  * deal with backward compatibility issues). The flattened
24  * representation always includes a format version number.
25  *
26  * <p>The writer has an <code>IElementInfoFactory</code>,
27  * which it consults for writing element infos.
28  *
29  * <p>Element tree writers are thread-safe; several
30  * threads may share a single writer.
31  *
32  */

33 public class ElementTreeWriter {
34     /**
35      * The current format version number.
36      */

37     public static final int CURRENT_FORMAT = 1;
38
39     /**
40      * Constant representing infinite depth
41      */

42     public static final int D_INFINITE = DataTreeWriter.D_INFINITE;
43
44     /**
45      * For writing DeltaDataTrees
46      */

47     protected DataTreeWriter dataTreeWriter;
48
49     /**
50      * Constructs a new element tree writer that works for
51      * the given element info flattener.
52      */

53     public ElementTreeWriter(final IElementInfoFlattener flattener) {
54
55         /* wrap the IElementInfoFlattener in an IDataFlattener */
56         IDataFlattener f = new IDataFlattener() {
57             public void writeData(IPath path, Object JavaDoc data, DataOutput output) throws IOException {
58                 // never write the root node of an ElementTree
59
//because it contains the parent backpointer.
60
if (!Path.ROOT.equals(path)) {
61                     flattener.writeElement(path, data, output);
62                 }
63             }
64
65             public Object JavaDoc readData(IPath path, DataInput input) {
66                 return null;
67             }
68         };
69         dataTreeWriter = new DataTreeWriter(f);
70     }
71
72     /**
73      * Sorts the given array of trees so that the following rules are true:
74      * - The first tree has no parent
75      * - No tree has an ancestor with a greater index in the array.
76      * If there are no missing parents in the given trees array, this means
77      * that in the resulting array, the i'th tree's parent will be tree i-1.
78      * The input tree array may contain duplicate trees.
79      * The sort order is written to the given output stream.
80      */

81     protected ElementTree[] sortTrees(ElementTree[] trees, DataOutput output) throws IOException {
82
83         /* the sorted list */
84         int numTrees = trees.length;
85         ElementTree[] sorted = new ElementTree[numTrees];
86         int[] order = new int[numTrees];
87
88         /* first build a table of ElementTree -> Vector of Integers(indices in trees array) */
89         HashMap table = new HashMap(numTrees * 2 + 1);
90         for (int i = 0; i < trees.length; i++) {
91             List indices = (List) table.get(trees[i]);
92             if (indices == null) {
93                 indices = new ArrayList();
94                 table.put(trees[i], indices);
95             }
96             indices.add(new Integer JavaDoc(i));
97         }
98
99         /* find the oldest tree (a descendent of all other trees) */
100         ElementTree oldest = trees[ElementTree.findOldest(trees)];
101
102         /**
103          * Walk through the chain of trees from oldest to newest,
104          * adding them to the sorted list as we go.
105          */

106         int i = numTrees - 1;
107         while (i >= 0) {
108             /* add all instances of the current oldest tree to the sorted list */
109             List indices = (List) table.remove(oldest);
110             for (Enumeration e = Collections.enumeration(indices); e.hasMoreElements();) {
111                 Integer JavaDoc next = (Integer JavaDoc) e.nextElement();
112                 sorted[i] = oldest;
113                 order[i] = next.intValue();
114                 i--;
115             }
116             if (i >= 0) {
117                 /* find the next tree in the list */
118                 ElementTree parent = oldest.getParent();
119                 while (table.get(parent) == null) {
120                     parent = parent.getParent();
121                 }
122                 oldest = parent;
123             }
124         }
125
126         /* write the order array */
127         for (i = 0; i < numTrees; i++) {
128             writeNumber(order[i], output);
129         }
130         return sorted;
131     }
132
133     /**
134      * Writes the delta describing the changes that have to be made
135      * to newerTree to obtain olderTree.
136      *
137      * @param path The path of the subtree to write. All nodes on the path above
138      * the subtree are represented as empty nodes.
139      * @param depth The depth of the subtree to write. A depth of zero writes a
140      * single node, and a depth of D_INFINITE writes the whole subtree.
141      * @param output The stream to write the subtree to.
142      */

143     public void writeDelta(ElementTree olderTree, ElementTree newerTree, IPath path, int depth, final DataOutput output, IElementComparator comparator) throws IOException {
144
145         /* write the version number */
146         writeNumber(CURRENT_FORMAT, output);
147
148         /**
149          * Note that in current ElementTree usage, the newest
150          * tree is the complete tree, and older trees are just
151          * deltas on the new tree.
152          */

153         DeltaDataTree completeTree = newerTree.getDataTree();
154         DeltaDataTree derivedTree = olderTree.getDataTree();
155         DeltaDataTree deltaToWrite = null;
156
157         deltaToWrite = completeTree.forwardDeltaWith(derivedTree, comparator);
158
159         Assert.isTrue(deltaToWrite.isImmutable());
160         dataTreeWriter.writeTree(deltaToWrite, path, depth, output);
161     }
162
163     /**
164      * Writes an array of ElementTrees to the given output stream.
165      * @param trees A chain of ElementTrees, where on tree in the list is
166      * complete, and all other trees are deltas on the previous tree in the list.
167      * @param path The path of the subtree to write. All nodes on the path above
168      * the subtree are represented as empty nodes.
169      * @param depth The depth of the subtree to write. A depth of zero writes a
170      * single node, and a depth of D_INFINITE writes the whole subtree.
171      * @param output The stream to write the subtree to.
172      
173      */

174     public void writeDeltaChain(ElementTree[] trees, IPath path, int depth, DataOutput output, IElementComparator comparator) throws IOException {
175         /* Write the format version number */
176         writeNumber(CURRENT_FORMAT, output);
177
178         /* Write the number of trees */
179         int treeCount = trees.length;
180         writeNumber(treeCount, output);
181
182         if (treeCount <= 0) {
183             return;
184         }
185
186         /**
187          * Sort the trees in ancestral order,
188          * which writes the tree order to the output
189          */

190         ElementTree[] sortedTrees = sortTrees(trees, output);
191
192         /* Write the complete tree */
193         writeTree(sortedTrees[0], path, depth, output);
194
195         /* Write the deltas for each of the remaining trees */
196         for (int i = 1; i < treeCount; i++) {
197             writeDelta(sortedTrees[i], sortedTrees[i - 1], path, depth, output, comparator);
198         }
199     }
200
201     /**
202      * Writes an integer in a compact format biased towards
203      * small non-negative numbers. Numbers between
204      * 0 and 254 inclusive occupy 1 byte; other numbers occupy 5 bytes.
205      */

206     protected void writeNumber(int number, DataOutput output) throws IOException {
207         if (number >= 0 && number < 0xff) {
208             output.writeByte(number);
209         } else {
210             output.writeByte(0xff);
211             output.writeInt(number);
212         }
213     }
214
215     /**
216      * Writes all or some of an element tree to an output stream.
217      * This always writes the most current version of the element tree
218      * file format, whereas the reader supports multiple versions.
219      *
220      * @param tree The tree to write
221      * @param path The path of the subtree to write. All nodes on the path above
222      * the subtree are represented as empty nodes.
223      * @param depth The depth of the subtree to write. A depth of zero writes a
224      * single node, and a depth of D_INFINITE writes the whole subtree.
225      * @param output The stream to write the subtree to.
226      */

227     public void writeTree(ElementTree tree, IPath path, int depth, final DataOutput output) throws IOException {
228
229         /* Write the format version number. */
230         writeNumber(CURRENT_FORMAT, output);
231
232         /* This actually just copies the root node, which is what we want */
233         DeltaDataTree subtree = new DeltaDataTree(tree.getDataTree().copyCompleteSubtree(Path.ROOT));
234
235         dataTreeWriter.writeTree(subtree, path, depth, output);
236     }
237 }
238
Popular Tags