001: /*
002: * $RCSfile: RandomAccessFileControl.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.4 $
041: * $Date: 2007/02/09 17:20:29 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.scenegraph.io.retained;
046:
047: import java.io.RandomAccessFile;
048: import java.io.IOException;
049: import java.io.DataOutput;
050: import java.io.DataInput;
051:
052: import javax.media.j3d.BranchGroup;
053: import javax.media.j3d.CapabilityNotSetException;
054: import javax.media.j3d.Canvas3D;
055:
056: import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.SceneGraphObjectState;
057: import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.NodeComponentState;
058: import com.sun.j3d.utils.scenegraph.io.state.javax.media.j3d.BranchGroupState;
059: import com.sun.j3d.utils.scenegraph.io.UnsupportedUniverseException;
060: import com.sun.j3d.utils.universe.SimpleUniverse;
061: import com.sun.j3d.utils.universe.ConfiguredUniverse;
062:
063: public class RandomAccessFileControl extends Controller {
064:
065: protected String FILE_IDENT = new String("j3dff");
066:
067: private long user_data;
068: private long universe_config;
069:
070: private long symbol_table;
071:
072: private RandomAccessFile raf;
073:
074: private int branchGraphCount = 0;
075:
076: private boolean writeMode = false;
077: private Object userData;
078:
079: /** Creates new RandomAccessFileControl */
080: public RandomAccessFileControl() {
081: super ();
082: symbolTable = new SymbolTable(this );
083: }
084:
085: /**
086: * Create the file and write the inital header information
087: */
088: public void createFile(java.io.File file, SimpleUniverse universe,
089: boolean writeUniverseContent, String description,
090: java.io.Serializable userData) throws IOException,
091: UnsupportedUniverseException, CapabilityNotSetException {
092:
093: raf = new RandomAccessFile(file, "rw");
094: writeMode = true;
095:
096: raf.seek(0);
097: raf.writeUTF(FILE_IDENT);
098:
099: raf.seek(20);
100: raf.writeInt(outputFileVersion);
101:
102: raf.seek(BRANCH_GRAPH_COUNT);
103: raf.writeInt(0); // Place holder to branch graph count
104:
105: raf.seek(FILE_DESCRIPTION);
106:
107: if (description == null)
108: description = "";
109: raf.writeUTF(description);
110:
111: try {
112: writeSerializedData(raf, userData);
113:
114: universe_config = raf.getFilePointer();
115: writeUniverse(raf, universe, writeUniverseContent);
116: } catch (SGIORuntimeException e) {
117: throw new IOException(e.getMessage());
118: }
119: }
120:
121: /**
122: * Open the file for reading
123: */
124: public void openFile(java.io.File file) throws IOException {
125: raf = new RandomAccessFile(file, "r");
126: writeMode = false;
127:
128: raf.seek(0);
129: String ident = raf.readUTF();
130:
131: if (ident.equals("demo_j3f"))
132: throw new IOException(
133: "Use Java 3D Fly Through I/O instead of Java 3D Scenegraph I/O");
134:
135: if (!ident.equals("j3dff"))
136: throw new IOException(
137: "This is a Stream - use SceneGraphStreamReader instead");
138:
139: raf.seek(20);
140: currentFileVersion = raf.readInt();
141:
142: if (currentFileVersion > outputFileVersion) {
143: throw new IOException(
144: "Unsupported file version. This file was written using a new version of the SceneGraph IO API, please update your installtion to the latest version");
145: }
146:
147: // readFileDescription sets user_data
148: String description = readFileDescription();
149:
150: raf.seek(BRANCH_GRAPH_COUNT);
151: branchGraphCount = raf.readInt();
152: //System.out.println("BranchGraph count : "+branchGraphCount );
153:
154: raf.seek(UNIVERSE_CONFIG_PTR);
155: universe_config = raf.readLong();
156:
157: raf.seek(SYMBOL_TABLE_PTR);
158: symbol_table = raf.readLong();
159:
160: ConfiguredUniverse universe;
161:
162: raf.seek(symbol_table);
163: symbolTable.readTable(raf, false);
164: raf.seek(user_data);
165:
166: userData = readSerializedData(raf);
167: }
168:
169: public ConfiguredUniverse readUniverse(boolean attachBranchGraphs,
170: Canvas3D canvas) throws IOException {
171: raf.seek(universe_config);
172: return readUniverse(raf, attachBranchGraphs, canvas);
173: }
174:
175: public Object getUserData() {
176: return userData;
177: }
178:
179: /**
180: * Read the set of branchgraps.
181: *
182: * Used by readUniverse
183: *
184: * RandomAccessFileControl will read the graphs in the array,
185: * StreamControl will read all graphs in the stream
186: */
187: protected void readBranchGraphs(int[] graphs) throws IOException {
188: for (int i = 0; i < graphs.length; i++) {
189: readBranchGraph(graphs[i]);
190: }
191: }
192:
193: /**
194: * Return the number of branchgraphs in the file
195: */
196: public int getBranchGraphCount() {
197: return symbolTable.getBranchGraphCount();
198: }
199:
200: public void writeBranchGraph(BranchGroup bg,
201: java.io.Serializable userData) throws IOException {
202: long filePointer = raf.getFilePointer();
203: raf.writeInt(0); // Node count
204: try {
205: writeSerializedData(raf, userData); // Size and byte[]
206:
207: //System.out.println("Actual Write at "+raf.getFilePointer() );
208:
209: SymbolTableData symbol = symbolTable.getSymbol(bg);
210:
211: if (symbol == null) {
212: symbol = symbolTable.createSymbol(bg);
213: symbol.branchGraphID = -1; // This is a new BranchGraph so set the ID to -1
214: } // which will cause setBranchGraphRoot to assign a new ID.
215:
216: symbolTable.setBranchGraphRoot(symbol, filePointer);
217:
218: symbolTable.startUnsavedNodeComponentFrame();
219: SceneGraphObjectState state = createState(bg, symbol);
220: //System.out.println(state);
221: try {
222: writeObject(raf, state);
223: writeNodeComponents(raf);
224: } catch (IOException e) {
225: e.printStackTrace();
226: }
227: symbolTable.endUnsavedNodeComponentFrame();
228: } catch (SGIORuntimeException e) {
229: throw new IOException(e.getMessage());
230: }
231:
232: }
233:
234: public BranchGroup[] readBranchGraph(int graphID)
235: throws IOException {
236: //System.out.print("Loading graph "+graphID+" : "); // TODO - remove
237: try {
238: int[] dependencies = symbolTable
239: .getBranchGraphDependencies(graphID);
240:
241: //System.out.println("Dependencies ");
242: //for(int i=0; i<dependencies.length; i++)
243: // System.out.print( dependencies[i]+" "); // TODO - remove
244: //System.out.println();
245:
246: BranchGroupState[] states = new BranchGroupState[dependencies.length + 1];
247: BranchGroup[] ret = new BranchGroup[states.length];
248: states[0] = readSingleBranchGraph(graphID);
249:
250: for (int i = 0; i < dependencies.length; i++) {
251: states[i + 1] = readSingleBranchGraph(dependencies[i]);
252: }
253:
254: for (int i = 0; i < states.length; i++) {
255: if (!states[i].getSymbol().graphBuilt) {
256: states[i].buildGraph();
257: states[i].getSymbol().graphBuilt = true;
258: }
259: ret[i] = (BranchGroup) states[i].getNode();
260: }
261:
262: symbolTable.clearUnshared(); // Remove all unshared symbols
263:
264: return ret;
265: } catch (SGIORuntimeException e) {
266: throw new IOException(e.getMessage());
267: }
268: }
269:
270: /**
271: * Read and return all the graphs in the file
272: */
273: public BranchGroup[] readAllBranchGraphs() throws IOException {
274: int size = getBranchGraphCount();
275: BranchGroupState[] states = new BranchGroupState[size];
276: BranchGroup[] ret = new BranchGroup[size];
277:
278: try {
279: for (int i = 0; i < size; i++) {
280: states[i] = readSingleBranchGraph(i);
281: }
282:
283: for (int i = 0; i < states.length; i++) {
284: if (!states[i].getSymbol().graphBuilt) {
285: states[i].buildGraph();
286: states[i].getSymbol().graphBuilt = true;
287: }
288: ret[i] = (BranchGroup) states[i].getNode();
289: }
290:
291: symbolTable.clearUnshared(); // Remove all unshared symbols
292: } catch (SGIORuntimeException e) {
293: throw new IOException(e.getMessage());
294: }
295:
296: return ret;
297: }
298:
299: /**
300: * Read the specified branchgraph but do NOT call buildGraph
301: */
302: private BranchGroupState readSingleBranchGraph(int graphID)
303: throws IOException {
304: SymbolTableData symbol = symbolTable
305: .getBranchGraphRoot(graphID);
306:
307: if (symbol.nodeState != null) {
308: return (BranchGroupState) symbol.nodeState;
309: }
310:
311: raf.seek(symbolTable.getBranchGraphFilePosition(graphID));
312:
313: return readNextBranchGraph();
314: }
315:
316: /**
317: * Read the next userData and BranchGraph structure in the file
318: * at the current position
319: */
320: private BranchGroupState readNextBranchGraph() throws IOException {
321: int nodeCount = raf.readInt();
322: skipUserData(raf);
323:
324: BranchGroupState state = null;
325: try {
326: state = (BranchGroupState) readObject(raf);
327:
328: readNodeComponents(raf);
329:
330: } catch (IOException e) {
331: e.printStackTrace();
332: }
333:
334: return state;
335: }
336:
337: public Object readBranchGraphUserData(int graphID)
338: throws IOException {
339: try {
340: raf.seek(symbolTable.getBranchGraphFilePosition(graphID));
341:
342: int nodeCount = raf.readInt();
343: return readSerializedData(raf);
344: } catch (SGIORuntimeException e) {
345: throw new IOException(e.getMessage());
346: }
347: }
348:
349: /**
350: * Write all the unsaved NodeComponents and SharedGroups to DataOutput.
351: * Mark all the NodeComponents as saved.
352: */
353: protected void writeNodeComponents(DataOutput out)
354: throws IOException {
355: // The RandomAccessFileControl version sets throws the pointer to
356: // the next NodeComponent correctly
357: long ptrLoc = 0L;
358:
359: java.util.ListIterator list = symbolTable
360: .getUnsavedNodeComponents();
361: out.writeInt(symbolTable.getUnsavedNodeComponentsSize());
362: while (list.hasNext()) {
363: SymbolTableData symbol = (SymbolTableData) list.next();
364:
365: out.writeInt(symbol.nodeID);
366: ptrLoc = raf.getFilePointer();
367: out.writeLong(0L); // Pointer to next NodeComponent
368:
369: writeObject(out, symbol.getNodeState());
370:
371: long ptr = raf.getFilePointer();
372: raf.seek(ptrLoc);
373: out.writeLong(ptr);
374: raf.seek(ptr);
375: }
376: }
377:
378: /**
379: * Read in all the node components in this block
380: */
381: protected void readNodeComponents(DataInput in) throws IOException {
382: int count = in.readInt();
383:
384: for (int i = 0; i < count; i++) {
385: int nodeID = in.readInt();
386: long nextNC = in.readLong();
387: if (symbolTable.isLoaded(nodeID)) {
388: // Skip this object
389: raf.seek(nextNC);
390: } else {
391: // Reading the objects will register them in the symbol table
392: SceneGraphObjectState nodeComponent = readObject(in);
393: }
394: }
395: }
396:
397: //static java.util.LinkedList objSizeTracker = new java.util.LinkedList();
398:
399: public void writeObject(DataOutput out, SceneGraphObjectState obj)
400: throws IOException {
401: symbolTable.setFilePosition(raf.getFilePointer(), obj);
402: try {
403: // These commented out lines will display the size of each object
404: // as it's written to the file
405:
406: //long start = raf.getFilePointer();
407:
408: //int childStart = objSizeTracker.size();
409:
410: super .writeObject(out, obj);
411:
412: //long size = raf.getFilePointer()-start;
413: //while( childStart!=objSizeTracker.size() )
414: // size -= ((Long)objSizeTracker.removeLast()).longValue();
415:
416: //String name = obj.getClass().getName();
417: //System.out.println( name.substring( name.lastIndexOf('.')+1, name.length() )+" size "+size);
418:
419: //objSizeTracker.addLast( new Long( size ));
420:
421: } catch (SGIORuntimeException e) {
422: throw new IOException(e.getMessage());
423: }
424: }
425:
426: public String readFileDescription() throws IOException {
427: raf.seek(FILE_DESCRIPTION);
428: String ret = raf.readUTF();
429:
430: user_data = raf.getFilePointer();
431: return ret;
432: }
433:
434: /**
435: * Used by SymbolTable to load a node component that is not in current
436: * graph
437: */
438: public void loadNodeComponent(SymbolTableData symbol)
439: throws IOException {
440: try {
441: raf.seek(symbol.filePosition);
442: readObject(raf);
443: } catch (SGIORuntimeException e) {
444: throw new IOException(e.getMessage());
445: }
446: }
447:
448: /**
449: * Loads the specified SharedGroup
450: */
451: public void loadSharedGroup(SymbolTableData symbol)
452: throws IOException {
453: try {
454: raf.seek(symbol.filePosition);
455: readObject(raf);
456: } catch (SGIORuntimeException e) {
457: throw new IOException(e.getMessage());
458: }
459: }
460:
461: public void close() throws IOException {
462: try {
463: if (writeMode)
464: writeClose();
465:
466: //System.out.println("File size at close "+raf.length() );
467: raf.close();
468: super .reset();
469: } catch (SGIORuntimeException e) {
470: throw new IOException(e.getMessage());
471: }
472:
473: }
474:
475: /**
476: * Write all the pointers etc
477: */
478: private void writeClose() throws IOException {
479: symbol_table = raf.getFilePointer();
480: super .getSymbolTable().writeTable(raf);
481:
482: //System.out.println("Symbol table size "+(raf.getFilePointer()-symbol_table));
483:
484: raf.seek(UNIVERSE_CONFIG_PTR);
485: raf.writeLong(universe_config);
486: raf.seek(SYMBOL_TABLE_PTR);
487: raf.writeLong(symbol_table);
488: raf.seek(BRANCH_GRAPH_COUNT);
489: raf.writeInt(symbolTable.getBranchGraphCount());
490: }
491:
492: public long getFilePointer() {
493: try {
494: return raf.getFilePointer();
495: } catch (IOException e) {
496: }
497: return 0;
498: }
499:
500: /**
501: * Given a branchgraph, return the corresponding index of the graph
502: * in the file. Returns -1 if graph not found.
503: */
504: public int getBranchGraphPosition(BranchGroup graph) {
505: SymbolTableData symbol = symbolTable.getSymbol(graph);
506: if (symbol != null)
507: return symbol.branchGraphID;
508: return -1;
509: }
510: }
|