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.pd;
031:
032: import java.util.ArrayList;
033: import java.util.Iterator;
034: import java.util.List;
035:
036: import de.intarsys.pdf.cos.COSArray;
037: import de.intarsys.pdf.cos.COSBasedObject;
038: import de.intarsys.pdf.cos.COSDictionary;
039: import de.intarsys.pdf.cos.COSDocument;
040: import de.intarsys.pdf.cos.COSName;
041: import de.intarsys.pdf.cos.COSNull;
042: import de.intarsys.pdf.cos.COSObject;
043: import de.intarsys.pdf.cos.COSRuntimeException;
044: import de.intarsys.pdf.parser.COSLoadException;
045:
046: /**
047: * This is the abstract superclass for all complex PD level objects.
048: *
049: * <p>
050: * PD Level objects provide the PDF semantics on top of the basic datatypes of
051: * COS Level objects. PDObject provides generic methods used along all subtypes.
052: * <p>
053: * PDObjects should be created only using the factory methods of their meta
054: * classes to ensure the semantics implemented in the PD layer, as for example
055: * PD object identity, subclass selection or proper initialization. <br>
056: * Example: <br>
057: * <code>
058: * PDPage page = (PDPage)PDPage.META.createNew();
059: * </code>
060: * </p>
061: */
062: abstract public class PDObject extends COSBasedObject {
063: /**
064: * The meta class implementation
065: */
066: static public class MetaClass extends COSBasedObject.MetaClass {
067: protected MetaClass(Class instanceClass) {
068: super (instanceClass);
069: }
070: }
071:
072: /** The meta class instance */
073: static public final MetaClass META = new MetaClass(MetaClass.class
074: .getDeclaringClass());
075:
076: // keys
077: static public final COSName DK_Type = COSName.constant("Type"); //
078:
079: public static final COSName DK_Subtype = COSName
080: .constant("Subtype");
081:
082: /**
083: * Create the receiver class from an already defined {@link COSDictionary}.
084: * NEVER use the constructor directly.
085: *
086: * @param object
087: * the PDDocument containing the new object
088: */
089: protected PDObject(COSObject object) {
090: super (object);
091: }
092:
093: /**
094: * Convenience method to access fields in {@link COSDictionary} based
095: * {@link PDObject} instances. This method supports "inheritance" on
096: * hierarchical structured {@link PDObject} instances. It returns the field
097: * either from the receiver or one of the known descendants.
098: *
099: * @param name
100: * the field to read
101: *
102: * @return the content of the named field in the PD object or one of its
103: * descendants - COSNull is the field is not found
104: */
105: public COSObject cosGetFieldDescendant(COSName name) {
106: COSObject cosBase = cosGetField(name);
107: if (cosBase.isNull()) {
108: List children = getGenericChildren();
109: if (children != null) {
110: for (Iterator i = children.iterator(); i.hasNext();) {
111: PDObject child = (PDObject) i.next();
112: cosBase = child.cosGetFieldDescendant(name);
113: if (!cosBase.isNull()) {
114: return cosBase;
115: }
116: }
117: }
118: }
119: return cosBase;
120: }
121:
122: /**
123: * Convenience method to access fields in {@link COSDictionary} based
124: * {@link PDObject} instances.
125: * <p>
126: * This method supports "inheritance" on hierarchical structured
127: * {@link PDObject} instances. It returns the field either from the receiver
128: * or one of its parents.
129: *
130: * @param name
131: * the field to read
132: *
133: * @return the content of the named field in the PD object or one of its
134: * parents - COSNull if the field is not found
135: */
136: public COSObject cosGetFieldInheritable(COSName name) {
137: COSObject cosBase = cosGetField(name);
138: if (cosBase.isNull() && (getGenericParent() != null)) {
139: return getGenericParent().cosGetFieldInheritable(name);
140: }
141: return cosBase;
142: }
143:
144: /**
145: * Convenience method to access inherited fields in {@link COSDictionary}
146: * based {@link PDObject} instances.
147: * <p>
148: * This method supports "inheritance" on hierarchical structured
149: * {@link PDObject} instances. It returns the inherited field value from one
150: * of the receiver's parents or {@link COSNull}.
151: *
152: * @param name
153: * the field to read
154: *
155: * @return the content of the named field in one of the receivers parents -
156: * COSNull if the field is not found
157: */
158: public COSObject cosGetFieldInherited(COSName name) {
159: if (getGenericParent() != null) {
160: return getGenericParent().cosGetFieldInheritable(name);
161: }
162: return COSNull.NULL;
163: }
164:
165: /**
166: * The /Subtype field of this {@link PDObject} or null. This method is not
167: * supported on {@link PDObject} instances that are not based on a
168: * {@link COSDictionary}
169: *
170: * @return The /Subtype field of this.
171: */
172: final public COSName cosGetSubtype() {
173: return cosGetDict().get(DK_Subtype).asName();
174: }
175:
176: /**
177: * The /Type field of this {@link PDObject} or null. This method is not
178: * supported on {@link PDObject} instances that are not based on a
179: * {@link COSDictionary}
180: *
181: * @return The /Type field of this.
182: */
183: final public COSName cosGetType() {
184: return cosGetField(DK_Type).asName();
185: }
186:
187: /**
188: * Convenience method to access fields in {@link COSDictionary} based
189: * {@link PDObject} instances. This method supports "inheritance" on
190: * hierarchical structured {@link PDObject} instances. It removes a field in
191: * the receiver and all its descendants.
192: *
193: * @param name
194: * the field to remove from the receiver
195: * @return The object previously associated with <code>name</code> in this
196: */
197: public COSObject cosRemoveFieldInheritable(COSName name) {
198: COSObject result = cosRemoveField(name);
199: List children = getGenericChildren();
200: if (children != null) {
201: for (Iterator i = children.iterator(); i.hasNext();) {
202: PDObject child = (PDObject) i.next();
203: child.cosRemoveFieldInheritable(name);
204: }
205: }
206: return result;
207: }
208:
209: /**
210: * Convenience method to access fields in {@link COSDictionary} based
211: * {@link PDObject} instances. This method supports "inheritance" on
212: * hierarchical structured {@link PDObject} instances. It sets a field value
213: * in the receiver when the field is inheritable. This method removes the
214: * field from every child to make sure it uses the inherited value.
215: *
216: * @param name
217: * the field to set
218: * @param cosObj
219: * the object to set in the field
220: * @return The object previously associated with <code>name</code> in this
221: */
222: public COSObject cosSetFieldInheritable(COSName name,
223: COSObject cosObj) {
224: COSObject result = cosSetField(name, cosObj);
225: List children = getGenericChildren();
226: if (children != null) {
227: for (Iterator i = children.iterator(); i.hasNext();) {
228: PDObject child = (PDObject) i.next();
229: child.cosRemoveFieldInheritable(name);
230: }
231: }
232: return result;
233: }
234:
235: /**
236: * Set the /Subtype field of this {@link PDObject}. This method is not
237: * supported on {@link PDObject} instances that are not based on a
238: * {@link COSDictionary}
239: *
240: * @return The /Subtype previously associated with this.
241: */
242: final public COSName cosSetSubtype(COSName newType) {
243: return cosSetField(DK_Subtype, newType).asName();
244: }
245:
246: /**
247: * Set the /Type field of this {@link PDObject}. This method is not
248: * supported on {@link PDObject} instances that are not based on a
249: * {@link COSDictionary}
250: *
251: * @return The /Type previously associated with this.
252: */
253: final public COSName cosSetType(COSName newType) {
254: return cosSetField(DK_Type, newType).asName();
255: }
256:
257: /**
258: * Try the best in finding the PDDocument for this PDObject.
259: *
260: * @return Try the best in finding the PDDocument for this PDObject.
261: */
262: public PDDocument getDoc() {
263: COSDocument cosDoc = cosGetObject().getDoc();
264: if (cosDoc == null) {
265: return null;
266: }
267: try {
268: return PDDocument.createFromCos(cosDoc);
269: } catch (COSLoadException e) {
270: throw new COSRuntimeException(e);
271: }
272: }
273:
274: /**
275: * Get a collection of {@link PDObject} children if the receiver is a node
276: * in a hierarchical structure (like page nodes or form fields).
277: *
278: * <p>
279: * This enables the generic implementation of inherited field values and so
280: * on.
281: * </p>
282: *
283: * <p>
284: * A concrete PDObject implementation supporting inheritance should
285: * implement this method.
286: * </p>
287: *
288: * @return A collection of {@link PDObject} children if the receiver is a
289: * node in a hierarchical structure .
290: */
291: public List getGenericChildren() {
292: return null;
293: }
294:
295: /**
296: * The parent of the receiver if it is a node in a hierarchical structure
297: * (like page nodes or form fields).
298: *
299: * <p>
300: * A concrete PDObject implementation supporting inheritance should
301: * implement this method.
302: * </p>
303: *
304: * @return The parent of the receiver if it is a node in a hierarchical
305: * structure (like page nodes or form fields).
306: */
307: public PDObject getGenericParent() {
308: return null;
309: }
310:
311: protected List getPDObjects(COSName key,
312: COSBasedObject.MetaClass metaclass, boolean addListener) {
313: COSArray array = cosGetField(key).asArray();
314: if (array != null) {
315: List result = new ArrayList();
316: Iterator i = array.iterator();
317: while (i.hasNext()) {
318: COSBasedObject pdObject = metaclass
319: .createFromCos((COSObject) i.next());
320: if (pdObject != null) {
321: result.add(pdObject);
322: }
323: }
324: if (addListener) {
325: array.addObjectListener(this );
326: }
327: return result;
328: }
329: return null;
330: }
331:
332: protected COSName cosGetExpectedSubtype() {
333: return null;
334: }
335:
336: protected COSName cosGetExpectedType() {
337: return null;
338: }
339:
340: protected void initializeFromScratch() {
341: super .initializeFromScratch();
342: COSName type = cosGetExpectedType();
343: if (type != null) {
344: cosSetField(DK_Type, type.copyShallow());
345: }
346: COSName subtype = cosGetExpectedSubtype();
347: if (subtype != null) {
348: cosSetField(DK_Subtype, subtype.copyShallow());
349: }
350: }
351:
352: /**
353: * Set the parent of the receiver if it is a node in a hierarchical
354: * structure (like page nodes or form fields).
355: *
356: * <p>
357: * A concrete PDObject implementation supporting inheritance should
358: * implement this method.
359: * </p>
360: *
361: * @param parent
362: * The new parent object.
363: */
364: public void setGenericParent(PDObject parent) {
365: // do nothing by default
366: }
367:
368: protected void setPDObjects(COSName key, List list) {
369: if (list == null) {
370: cosRemoveField(key);
371: return;
372: }
373: COSArray array = cosGetField(key).asArray();
374: if (array == null) {
375: array = COSArray.create();
376: } else {
377: array.clear();
378: }
379: for (Iterator i = list.iterator(); i.hasNext();) {
380: array.add(((PDObject) i.next()).cosGetDict());
381: }
382: cosSetField(key, array);
383: }
384:
385: /*
386: * (non-Javadoc)
387: *
388: * @see java.lang.Object#toString()
389: */
390: public String toString() {
391: if (cosGetObject() == null) {
392: return "a " + getClass().getName();
393: }
394: if (cosGetObject().isIndirect()) {
395: return "[" + cosGetObject().getIndirectObject().toString()
396: + "] " + getClass().getName();
397: }
398: return "a " + getClass().getName();
399: }
400: }
|