001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.apt.utils;
043:
044: import java.io.File;
045: import java.io.BufferedOutputStream;
046: import java.io.BufferedInputStream;
047: import java.io.DataInput;
048: import java.io.DataOutput;
049: import java.io.FileOutputStream;
050: import java.io.FileInputStream;
051: import java.io.IOException;
052: import java.io.ObjectInputStream;
053: import java.io.ObjectOutputStream;
054: import java.util.Map;
055: import java.util.Map.Entry;
056: import org.netbeans.modules.cnd.apt.debug.APTTraceFlags;
057: import org.netbeans.modules.cnd.apt.impl.support.APTBaseMacroMap;
058: import org.netbeans.modules.cnd.apt.impl.support.APTFileMacroMap;
059: import org.netbeans.modules.cnd.apt.impl.support.APTIncludeHandlerImpl;
060: import org.netbeans.modules.cnd.apt.impl.support.APTMacroImpl;
061: import org.netbeans.modules.cnd.apt.impl.support.APTMacroMapSnapshot;
062: import org.netbeans.modules.cnd.apt.impl.support.APTPreprocHandlerImpl;
063: import org.netbeans.modules.cnd.apt.structure.APT;
064: import org.netbeans.modules.cnd.apt.support.APTFileBuffer;
065: import org.netbeans.modules.cnd.apt.support.APTIncludeHandler;
066: import org.netbeans.modules.cnd.apt.support.APTMacro;
067: import org.netbeans.modules.cnd.apt.support.APTMacroMap;
068: import org.netbeans.modules.cnd.apt.support.APTPreprocHandler;
069: import org.netbeans.modules.cnd.utils.cache.TextCache;
070:
071: /**
072: * utilities for APT serialization
073: * @author Vladimir Voskresensky
074: */
075: public class APTSerializeUtils {
076:
077: private APTSerializeUtils() {
078: }
079:
080: static public void writeAPT(ObjectOutputStream out, APT apt)
081: throws IOException {
082: out.writeObject(apt);
083: // the tree structure has a lot of siblings =>
084: // StackOverflow exceptions during serialization of "next" field
085: // we try to prevent it by using own procedure of writing
086: // tree structure
087: if (apt != null) {
088: writeTree(out, apt);
089: }
090: }
091:
092: // symmetric to writeObject
093: static public APT readAPT(ObjectInputStream in) throws IOException,
094: ClassNotFoundException {
095: APT apt = (APT) in.readObject();
096: if (apt != null) {
097: // read tree structure into this node
098: readTree(in, apt);
099: }
100: return apt;
101: }
102:
103: ////////////////////////////////////////////////////////////////////////////
104: // we have StackOverflow when serialize APT due to it's tree structure:
105: // to many recurse calls to writeObject on writing "next" field
106: // let's try to reduce depth of recursion by depth of tree
107:
108: private static final int CHILD = 1;
109: private static final int SIBLING = 2;
110: private static final int END_APT = 3;
111:
112: static private void writeTree(ObjectOutputStream out, APT root)
113: throws IOException {
114: assert (root != null) : "there must be something to write"; // NOI18N
115: APT node = root;
116: do {
117: APT child = node.getFirstChild();
118: if (child != null) {
119: // due to not huge depth of the tree
120: // write child without optimization
121: out.writeInt(CHILD);
122: writeAPT(out, child);
123: }
124: node = node.getNextSibling();
125: if (node != null) {
126: // we don't want to use recursion on writing sibling
127: // to prevent StackOverflow,
128: // we use while loop for writing siblings
129: out.writeInt(SIBLING);
130: // write node data
131: out.writeObject(node);
132: }
133: } while (node != null);
134: out.writeInt(END_APT);
135: }
136:
137: static private void readTree(ObjectInputStream in, APT root)
138: throws IOException, ClassNotFoundException {
139: assert (root != null) : "there must be something to read"; // NOI18N
140: APT node = root;
141: do {
142: int kind = in.readInt();
143: switch (kind) {
144: case END_APT:
145: return;
146: case CHILD:
147: node.setFirstChild(readAPT(in));
148: break;
149: case SIBLING:
150: APT sibling = (APT) in.readObject();
151: node.setNextSibling(sibling);
152: node = sibling;
153: break;
154: default:
155: assert (false);
156: }
157: } while (node != null);
158: }
159:
160: private static int fileIndex = 0;
161:
162: static public APT testAPTSerialization(APTFileBuffer buffer, APT apt) {
163: File file = buffer.getFile();
164: APT aptRead = null;
165: // testing caching ast
166: String prefix = "cnd_apt_" + (fileIndex++); // NOI18N
167: String suffix = file.getName();
168: try {
169: File out = File.createTempFile(prefix, suffix);
170: if (false)
171: System.out.println("...saving APT of file "
172: + file.getAbsolutePath() + " into tmp file "
173: + out); // NOI18N
174: long astTime = System.currentTimeMillis();
175: // write
176: ObjectOutputStream oos = new ObjectOutputStream(
177: new BufferedOutputStream(new FileOutputStream(out),
178: APTTraceFlags.BUF_SIZE));
179: try {
180: writeAPT(oos, apt);
181: } finally {
182: oos.close();
183: }
184: long writeTime = System.currentTimeMillis() - astTime;
185: if (false)
186: System.out.println("saved APT of file "
187: + file.getAbsolutePath() + " withing "
188: + writeTime + "ms"); // NOI18N
189: astTime = System.currentTimeMillis();
190: // read
191: ObjectInputStream ois = new ObjectInputStream(
192: new BufferedInputStream(new FileInputStream(out),
193: APTTraceFlags.BUF_SIZE));
194: try {
195: aptRead = readAPT(ois);
196: } catch (ClassNotFoundException ex) {
197: ex.printStackTrace();
198: } finally {
199: ois.close();
200: }
201: long readTime = System.currentTimeMillis() - astTime;
202: if (false)
203: System.out.println("read APT of file "
204: + file.getAbsolutePath() + " withing "
205: + readTime + "ms"); // NOI18N
206: out.delete();
207: } catch (IOException ex) {
208: ex.printStackTrace();
209: }
210: return aptRead;
211: }
212:
213: ////////////////////////////////////////////////////////////////////////////
214: // persistence support
215:
216: public static void writeSystemMacroMap(APTMacroMap macroMap,
217: DataOutput output) throws IOException {
218: //throw new UnsupportedOperationException("Not yet supported"); // NOI18N
219: }
220:
221: public static APTMacroMap readSystemMacroMap(DataInput input)
222: throws IOException {
223: //throw new UnsupportedOperationException("Not yet supported"); // NOI18N
224: return null;
225: }
226:
227: public static void writeMacroMapState(APTMacroMap.State state,
228: DataOutput output) throws IOException {
229: assert state != null;
230: if (state instanceof APTFileMacroMap.FileStateImpl) {
231: output.writeInt(MACRO_MAP_FILE_STATE_IMPL);
232: ((APTFileMacroMap.FileStateImpl) state).write(output);
233: } else {
234: assert state instanceof APTBaseMacroMap.StateImpl;
235: output.writeInt(MACRO_MAP_STATE_IMPL);
236: ((APTBaseMacroMap.StateImpl) state).write(output);
237: }
238: }
239:
240: public static APTMacroMap.State readMacroMapState(DataInput input)
241: throws IOException {
242: int handler = input.readInt();
243: APTMacroMap.State state;
244: if (handler == MACRO_MAP_FILE_STATE_IMPL) {
245: state = new APTFileMacroMap.FileStateImpl(input);
246: } else {
247: assert handler == MACRO_MAP_STATE_IMPL;
248: state = new APTBaseMacroMap.StateImpl(input);
249: }
250: return state;
251: }
252:
253: public static void writeIncludeState(APTIncludeHandler.State state,
254: DataOutput output) throws IOException {
255: assert state != null;
256: assert state instanceof APTIncludeHandlerImpl.StateImpl;
257: ((APTIncludeHandlerImpl.StateImpl) state).write(output);
258: }
259:
260: public static APTIncludeHandler.State readIncludeState(
261: DataInput input) throws IOException {
262: APTIncludeHandler.State state = new APTIncludeHandlerImpl.StateImpl(
263: input);
264: return state;
265: }
266:
267: public static void writePreprocState(APTPreprocHandler.State state,
268: DataOutput output) throws IOException {
269: assert state != null;
270: if (state instanceof APTPreprocHandlerImpl.StateImpl) {
271: output.writeInt(PREPROC_STATE_STATE_IMPL);
272: ((APTPreprocHandlerImpl.StateImpl) state).write(output);
273: } else {
274: throw new IllegalArgumentException(
275: "unknown preprocessor state" + state); //NOI18N
276: }
277: }
278:
279: public static APTPreprocHandler.State readPreprocState(
280: DataInput input) throws IOException {
281: int handler = input.readInt();
282: APTPreprocHandler.State out;
283: switch (handler) {
284: case PREPROC_STATE_STATE_IMPL:
285: out = new APTPreprocHandlerImpl.StateImpl(input);
286: break;
287: default:
288: throw new IllegalArgumentException(
289: "unknown preprocessor state handler" + handler); //NOI18N
290: }
291: return out;
292: }
293:
294: ////////////////////////////////////////////////////////////////////////////
295: // persist snapshots
296:
297: public static void writeSnapshot(APTMacroMapSnapshot snap,
298: DataOutput output) throws IOException {
299: // FIXUP: we do not support yet writing snapshots!
300: if (snap == null || true) {
301: output.writeInt(NULL_POINTER);
302: } else {
303: output.writeInt(MACRO_MAP_SNAPSHOT);
304: snap.write(output);
305: }
306: }
307:
308: public static APTMacroMapSnapshot readSnapshot(DataInput input)
309: throws IOException {
310: int handler = input.readInt();
311: APTMacroMapSnapshot snap = null;
312: if (handler != NULL_POINTER) {
313: assert handler == MACRO_MAP_SNAPSHOT;
314: snap = new APTMacroMapSnapshot(input);
315: }
316: return snap;
317: }
318:
319: public static void writeStringToMacroMap(
320: Map<String, APTMacro> macros, DataOutput output)
321: throws IOException {
322: assert macros != null;
323: output.writeInt(macros.size());
324: for (Entry<String, APTMacro> entry : macros.entrySet()) {
325: assert entry != null;
326: String key = entry.getKey();
327: assert key != null;
328: output.writeUTF(key);
329: APTMacro macro = entry.getValue();
330: assert macro != null;
331: writeMacro(macro, output);
332: }
333: }
334:
335: public static void readStringToMacroMap(
336: Map<String, APTMacro> macros, DataInput input)
337: throws IOException {
338: int collSize = input.readInt();
339: for (int i = 0; i < collSize; ++i) {
340: String key = TextCache.getString(input.readUTF())
341: .toString();
342: assert key != null;
343: APTMacro macro = readMacro(input);
344: assert macro != null;
345: macros.put(key, macro);
346: }
347: }
348:
349: private static void writeMacro(APTMacro macro, DataOutput output)
350: throws IOException {
351: assert macro != null;
352: if (macro == APTMacroMapSnapshot.UNDEFINED_MACRO) {
353: output.writeInt(UNDEFINED_MACRO);
354: } else if (macro instanceof APTMacroImpl) {
355: output.writeInt(MACRO_IMPL);
356: ((APTMacroImpl) macro).write(output);
357: }
358: }
359:
360: private static APTMacro readMacro(DataInput input)
361: throws IOException {
362: int handler = input.readInt();
363: APTMacro macro;
364: if (handler == UNDEFINED_MACRO) {
365: macro = APTMacroMapSnapshot.UNDEFINED_MACRO;
366: } else {
367: assert handler == MACRO_IMPL;
368: macro = new APTMacroImpl(input);
369: }
370: return macro;
371: }
372:
373: private static final int NULL_POINTER = -1;
374: private static final int MACRO_MAP_STATE_IMPL = 1;
375: private static final int MACRO_MAP_FILE_STATE_IMPL = MACRO_MAP_STATE_IMPL + 1;
376: private static final int PREPROC_STATE_STATE_IMPL = MACRO_MAP_FILE_STATE_IMPL + 1;
377: private static final int MACRO_MAP_SNAPSHOT = PREPROC_STATE_STATE_IMPL + 1;
378: private static final int UNDEFINED_MACRO = MACRO_MAP_SNAPSHOT + 1;
379: private static final int MACRO_IMPL = UNDEFINED_MACRO + 1;
380:
381: }
|