001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.cos;
031:
032: import java.io.IOException;
033: import java.util.Map;
034: import de.intarsys.pdf.parser.COSLoadException;
035: import de.intarsys.pdf.st.STDocument;
036:
037: /**
038: * An object representing an indirect object within a COSDocument.
039: *
040: * <p>
041: * Actually you should not override equals or hash without really knowing what
042: * you do. Portions of the implementation depend on indirect objects being real
043: * unique.
044: * </p>
045: */
046: public class COSIndirectObject extends COSDocumentElement implements
047: ICOSContainer {
048: /**
049: * The referenced COS object.
050: *
051: * <p>
052: * If this is null, the object itself is not yet read from the file (or
053: * already swapped to a file).
054: * </p>
055: */
056: private COSObject object;
057:
058: /** The document hosting the indirect object. */
059: private COSDocument doc;
060:
061: /**
062: * The storage level document for the indirect object
063: */
064: private STDocument stDoc;
065:
066: /** The key of the object if already assigned */
067: private COSObjectKey key;
068:
069: /**
070: * Flag if this object is out of sync with the storage, i.e. the object was
071: * changed or newly created.
072: */
073: private boolean dirty = false;
074:
075: /**
076: * Flag if the object referenced should be encrypted, if the document itself
077: * is encrypted.
078: */
079: private boolean encryptOnWrite = true;
080:
081: /**
082: * number of known references.
083: */
084: private int referenceCount = 0;
085:
086: protected COSIndirectObject() {
087: super ();
088: }
089:
090: protected COSIndirectObject(COSIndirectObject indirectObject) {
091: super ();
092: this .dirty = indirectObject.dirty;
093: this .doc = indirectObject.doc;
094: this .encryptOnWrite = indirectObject.encryptOnWrite;
095: this .key = indirectObject.key;
096: this .stDoc = indirectObject.stDoc;
097: this .referenceCount = indirectObject.referenceCount;
098: }
099:
100: public static COSIndirectObject create(STDocument stDoc,
101: COSObjectKey key) {
102: COSIndirectObject ref = new COSIndirectObject();
103: ref.setKey(key);
104: ref.registerWith(stDoc);
105: return ref;
106: }
107:
108: /**
109: * Create an indirection for object.
110: *
111: * @param object
112: * The object that should be indirect.
113: *
114: * @return The new indirect object.
115: */
116: public static COSIndirectObject create(COSObject object) {
117: COSIndirectObject ref = new COSIndirectObject();
118: ref.setDirty(true);
119: object.getContainer().register(ref);
120: // set object after registration as it should need no recursive
121: // registration
122: ref.object = object;
123: object.basicSetContainer(ref);
124: return ref;
125: }
126:
127: /*
128: * (non-Javadoc)
129: *
130: * @see de.intarsys.pdf.cos.COSDocumentElement#getDoc()
131: */
132: public COSDocument getDoc() {
133: return doc;
134: }
135:
136: /**
137: * The key for this.
138: *
139: * @return The key for this.
140: */
141: public COSObjectKey getKey() {
142: if (key == null) {
143: if (stGetDoc() != null) {
144: key = stGetDoc().createObjectKey();
145: }
146: }
147: return key;
148: }
149:
150: /**
151: * Set the object for this reference. The reference is already registered
152: * with the document, the object is provided "lazy" by the storage.
153: *
154: * @param newObject
155: * the new object to set
156: */
157: public void setObject(COSObject newObject) {
158: COSObject oldObject = object;
159: this .object = newObject;
160: if (oldObject != null) {
161: // completely destroy connection to old object - no longer reachable
162: oldObject.basicSetContainer(COSObject.NULL_CONTAINER);
163: }
164: // set new container and register newObject
165: newObject.basicSetContainer(this );
166: if (doc != null) {
167: newObject.registerWith(doc);
168: }
169: }
170:
171: /**
172: * The object represented by this.
173: *
174: * @return The object represented by this.
175: */
176: public COSObject getObject() {
177: return object;
178: }
179:
180: /*
181: * (non-Javadoc)
182: *
183: * @see de.intarsys.pdf.cos.COSDocumentElement#isReference()
184: */
185: public boolean isReference() {
186: return true;
187: }
188:
189: /*
190: * (non-Javadoc)
191: *
192: * @see de.intarsys.pdf.cos.COSDocumentElement#copyShallowNested()
193: */
194: protected COSDocumentElement copyShallowNested() {
195: return this ;
196: }
197:
198: /*
199: * (non-Javadoc)
200: *
201: * @see de.intarsys.pdf.cos.ICOSContainer#willChange(de.intarsys.pdf.cos.COSObject)
202: */
203: public void willChange(COSObject change) {
204: if (getDoc() != null) {
205: getDoc().willChange(change);
206: }
207: setDirty(true);
208: }
209:
210: /**
211: * Set the dirty state of the indirect object
212: */
213: public void setDirty(boolean pDirty) {
214: if (pDirty && (stGetDoc() != null)) {
215: stGetDoc().addChangedReference(this );
216: }
217: this .dirty = pDirty;
218: }
219:
220: /**
221: * <code>true</code> if the object graph referenced by this is changed.
222: *
223: * @return <code>true</code> if the object graph referenced by this is
224: * changed.
225: */
226: public boolean isDirty() {
227: return dirty;
228: }
229:
230: /*
231: * (non-Javadoc)
232: *
233: * @see de.intarsys.pdf.cos.COSDocumentElement#dereference()
234: */
235: synchronized public COSObject dereference() {
236: if (object == null) {
237: swapIn();
238: }
239: return object;
240: }
241:
242: /*
243: * (non-Javadoc)
244: *
245: * @see de.intarsys.pdf.cos.COSDocumentElement#isSwapped()
246: */
247: public boolean isSwapped() {
248: return object == null;
249: }
250:
251: protected void swapIn() {
252: try {
253: COSObject loadedObject = stGetDoc().load(this );
254: if (loadedObject == null) {
255: loadedObject = COSNull.create();
256: }
257: setObject(loadedObject);
258: } catch (IOException e) {
259: throw new COSSwapException(
260: "io error reading object " + getKey(), e); //$NON-NLS-1$
261: } catch (COSLoadException e) {
262: throw new COSSwapException(
263: "parse error reading object " + getKey(), e); //$NON-NLS-1$
264: }
265: }
266:
267: protected void swapOut() {
268: object = null;
269: }
270:
271: /*
272: * (non-Javadoc)
273: *
274: * @see java.lang.Object#toString()
275: */
276: public String toString() {
277: return "" + key + "->"; //$NON-NLS-1$ //$NON-NLS-2$
278: }
279:
280: /**
281: * see copyDeep()
282: *
283: * <p>
284: * This method keeps track of already copied objects to deal with cyclic
285: * references.
286: * </p>
287: *
288: * @see de.intarsys.pdf.cos.COSObject#copyDeep()
289: */
290: protected COSObject copyDeep(Map copied) {
291: COSObject result = (COSObject) copied.get(this );
292: if (result == null) {
293: result = dereference().copyDeep(copied);
294: }
295: return result;
296: }
297:
298: /*
299: * (non-Javadoc)
300: *
301: * @see de.intarsys.pdf.cos.ICOSContainer#register(de.intarsys.pdf.cos.COSObject)
302: */
303: public void register(COSDocumentElement pObject) {
304: if (doc != null) {
305: pObject.registerWith(doc);
306: }
307: }
308:
309: /**
310: * Assign a {@link COSObjectKey} to this.
311: *
312: * @param key
313: * The new key.
314: */
315: public void setKey(COSObjectKey key) {
316: this .key = key;
317: }
318:
319: /*
320: * (non-Javadoc)
321: *
322: * @see de.intarsys.pdf.cos.COSDocumentElement#accept(de.intarsys.pdf.cos.ICOSObjectVisitor)
323: */
324: public Object accept(ICOSObjectVisitor visitor)
325: throws COSVisitorException {
326: return visitor.visitFromIndirectObject(this );
327: }
328:
329: /**
330: * @return <code>true</code> if the referenced object should be encrypted.
331: * The default is true;
332: */
333: public boolean isEncryptOnWrite() {
334: return encryptOnWrite;
335: }
336:
337: /**
338: * Flag the referenced object to be encrypted, if the document itself is
339: * encrypted. The default is true.
340: *
341: * @param encryptOnWrite
342: */
343: public void setEncryptOnWrite(boolean encryptOnWrite) {
344: this .encryptOnWrite = encryptOnWrite;
345: }
346:
347: /**
348: * The ST level document.
349: *
350: * @return The ST level document.
351: */
352: public STDocument stGetDoc() {
353: return stDoc;
354: }
355:
356: /**
357: * @param pSTDoc
358: */
359: public void registerWith(STDocument pSTDoc) {
360: this .stDoc = pSTDoc;
361: pSTDoc.addObjectReference(this );
362: if (dirty) {
363: pSTDoc.addChangedReference(this );
364: }
365: }
366:
367: /*
368: * (non-Javadoc)
369: *
370: * @see de.intarsys.pdf.cos.ICOSContainer#referenceIndirect(de.intarsys.pdf.cos.COSObject)
371: */
372: public COSIndirectObject referenceIndirect(COSObject pObject) {
373: return this ;
374: }
375:
376: /*
377: * (non-Javadoc)
378: *
379: * @see de.intarsys.pdf.cos.ICOSContainer#associate(de.intarsys.pdf.cos.ICOSContainer,
380: * de.intarsys.pdf.cos.COSObject)
381: */
382: public ICOSContainer associate(ICOSContainer newContainer,
383: COSObject pObject) {
384: newContainer.register(this );
385: referenceCount++;
386: return this ;
387: }
388:
389: /*
390: * (non-Javadoc)
391: *
392: * @see de.intarsys.pdf.cos.ICOSContainer#disassociate(de.intarsys.pdf.cos.ICOSContainer,
393: * de.intarsys.pdf.cos.COSObject)
394: */
395: public ICOSContainer disassociate(ICOSContainer oldContainer,
396: COSObject pObject) {
397: referenceCount--;
398: return this ;
399: }
400:
401: /*
402: * (non-Javadoc)
403: *
404: * @see de.intarsys.pdf.cos.COSDocumentElement#addContainer(de.intarsys.pdf.cos.ICOSContainer)
405: */
406: protected ICOSContainer addContainer(ICOSContainer container) {
407: return associate(container, getObject());
408: }
409:
410: /*
411: * (non-Javadoc)
412: *
413: * @see de.intarsys.pdf.cos.COSDocumentElement#removeContainer(de.intarsys.pdf.cos.ICOSContainer)
414: */
415: protected ICOSContainer removeContainer(ICOSContainer oldContainer) {
416: return disassociate(oldContainer, getObject());
417: }
418:
419: /*
420: * (non-Javadoc)
421: *
422: * @see de.intarsys.pdf.cos.COSDocumentElement#containable(de.intarsys.pdf.cos.COSDocumentElement)
423: */
424: public COSDocumentElement containable() {
425: return this ;
426: }
427:
428: /*
429: * (non-Javadoc)
430: *
431: * @see de.intarsys.pdf.cos.ICOSContainer#containable(de.intarsys.pdf.cos.COSObject)
432: */
433: public COSDocumentElement containable(COSObject pObject) {
434: return this ;
435: }
436:
437: /*
438: * (non-Javadoc)
439: *
440: * @see de.intarsys.pdf.cos.COSDocumentElement#registerWith(de.intarsys.pdf.cos.COSDocument)
441: */
442: protected void registerWith(COSDocument newDoc) {
443: if (doc == null) {
444: doc = newDoc;
445: registerWith(newDoc.stGetDoc());
446: // register descendents
447: if (getObject() != null) {
448: getObject().registerWith(doc);
449: }
450: } else {
451: if (doc != newDoc) {
452: throw new IllegalStateException(
453: "You can not merge objects from different documents"); //$NON-NLS-1$
454: }
455: }
456: }
457:
458: /*
459: * (non-Javadoc)
460: *
461: * @see de.intarsys.pdf.cos.ICOSContainer#referenceCount()
462: */
463: public int referenceCount() {
464: return referenceCount;
465: }
466:
467: /*
468: * (non-Javadoc)
469: *
470: * @see de.intarsys.pdf.cos.ICOSContainer#storeStateContainer()
471: */
472: public ICOSContainer saveStateContainer() {
473: return new COSIndirectObject(this );
474: }
475:
476: /*
477: * (non-Javadoc)
478: *
479: * @see de.intarsys.pdf.cos.ICOSContainer#restoreStateContainer(de.intarsys.pdf.cos.ICOSContainer)
480: */
481: public ICOSContainer restoreStateContainer(ICOSContainer container) {
482: COSIndirectObject indirectObject = (COSIndirectObject) container;
483: this .dirty = indirectObject.dirty;
484: // this.doc = indirectObject.doc;
485: // this.encryptOnWrite = indirectObject.encryptOnWrite;
486: // this.key = indirectObject.key;
487: // this.stDoc = indirectObject.stDoc;
488: this.referenceCount = indirectObject.referenceCount;
489: return this;
490: }
491: }
|