001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.caching.util;
017:
018: import org.geotools.feature.Feature;
019: import org.geotools.feature.FeatureType;
020: import org.geotools.feature.IllegalAttributeException;
021:
022: import java.io.IOException;
023: import java.io.ObjectInputStream;
024: import java.io.ObjectOutputStream;
025:
026: import java.util.ArrayList;
027: import java.util.Collection;
028: import java.util.Iterator;
029: import java.util.List;
030:
031: /** Simple marshaller that can write features to an ObjectOutputStream.
032: * Feature is not Serializable, but this is based on the idea that most attributes object are Serializable
033: * (JTS geometries are Serializable), and that attributes which are not simple, are either a collection we can iterate through, or another Feature.
034: * Serialization is then achieved recursively.
035: * Unmarshalling implies to know the FeatureType of the marshalled feature.
036: *
037: * Storage format : Header,
038: * Attributes
039: *
040: * Header := int : FeatureType hashCode,
041: * String : FeatureType name,
042: * String : Feature ID,
043: * int : number of attributes
044: * Attributes := [Attribute]
045: * Attribute := int : multiplicity, or O if simple, or -1 if FeatureAttribute,
046: * Object|Feature|[Attribute] : attribute value
047: *
048: * This implementation does not have the ambition of being robust.
049: *
050: * @task test with other FeatureType than DefaultFeatureType
051: * @task add method marshall(Feature, ByteArrayOutputStream) and unmarshall(ByteArrayOutputStream), or create sub class.
052: *
053: * @author Christophe Rousson, SoC 2007, CRG-ULAVAL
054: *
055: */
056: public class FeatureMarshaller {
057: /**
058: * marker to indicate an attribute is a feature in the serialized form
059: */
060: public static final int FEATURE = -1;
061:
062: /**
063: * @task should be made final, and remove default constructor and type setter ?
064: */
065: private FeatureType type;
066:
067: /** Default constructor.
068: * User must call setType() to set the FeatureType
069: * before any attempt to marshall/unmarshall a feature.
070: */
071: public FeatureMarshaller() {
072: type = null;
073: }
074:
075: /** Creates a new instance of this marshaller
076: *
077: * @param t the FeatureType this marshaller can marshall/unmarsahll
078: */
079: public FeatureMarshaller(FeatureType t) {
080: this .type = t;
081: }
082:
083: /** FeatureType getter
084: * @return the FeatureType this marshaller marshalls/unmarshalls
085: */
086: public FeatureType getType() {
087: return type;
088: }
089:
090: /** FeatureType setter
091: * @param t the FeatureType to use for next marshall/unmarshall ops.
092: */
093: public void setType(FeatureType t) {
094: this .type = t;
095: }
096:
097: /** Marshall a feature into a stream.
098: *
099: * @param f the Feature to marshall
100: * @param s the stream to write to
101: * @throws IOException
102: */
103: public void marshall(Feature f, ObjectOutputStream s)
104: throws IOException {
105: if (!type.equals(f.getFeatureType())) {
106: throw new IOException("Wrong feature type : "
107: + f.getFeatureType());
108: }
109:
110: s.writeInt(f.getFeatureType().hashCode());
111: s.writeObject(f.getFeatureType().getTypeName());
112: s.writeObject(f.getID());
113:
114: int natt = f.getNumberOfAttributes();
115: s.writeInt(natt);
116:
117: for (int i = 0; i < natt; i++) {
118: marshallComplexAttribute(f.getAttribute(i), s);
119: }
120: }
121:
122: /** Marshall an attribute into a stream.
123: *
124: * @task test object is instance of Serializable
125: *
126: * @param o an attribute value which is Serializable, or a feature, or a collection
127: * @param s the stream to write to
128: * @throws IOException
129: */
130: protected void marshallComplexAttribute(Object o,
131: ObjectOutputStream s) throws IOException {
132: if (o instanceof Collection) {
133: Collection c = (Collection) o;
134: s.writeInt(c.size());
135:
136: for (Iterator it = c.iterator(); it.hasNext();) {
137: Object nxt = it.next();
138: marshallComplexAttribute(nxt, s);
139: }
140: } else if (o instanceof Feature) {
141: s.writeInt(FEATURE);
142: marshall((Feature) o, s);
143: } else {
144: s.writeInt(0);
145: s.writeObject(o);
146: }
147: }
148:
149: /** Inverse operation of marshall : read a feature from a stream.
150: *
151: * @param s the stream to read from
152: * @return the unmarshalled feature
153: * @throws IOException
154: * @throws ClassNotFoundException
155: * @throws IllegalAttributeException
156: */
157: public Feature unmarshall(ObjectInputStream s) throws IOException,
158: ClassNotFoundException, IllegalAttributeException {
159: int typeHash = s.readInt();
160: String typeName = (String) s.readObject();
161: String fid = (String) s.readObject();
162: int natt = s.readInt();
163:
164: if (!(typeHash == type.hashCode())
165: && (typeName.equals(type.getTypeName()))
166: && (natt == type.getAttributeCount())) {
167: throw new IOException("Schema error");
168: }
169:
170: List atts = new ArrayList();
171:
172: for (int i = 0; i < natt; i++) {
173: atts.addAll(unmarshallComplexAttribute(s));
174: }
175:
176: return type.create(atts.toArray(), fid);
177: }
178:
179: /** Read attribute values from a stream.
180: *
181: * @param s the stream to read from
182: * @return a list of attribute values, possibly a singleton, if attribute's multiplicity is 1
183: * @throws IOException
184: * @throws ClassNotFoundException
185: * @throws IllegalAttributeException
186: */
187: protected List unmarshallComplexAttribute(ObjectInputStream s)
188: throws IOException, ClassNotFoundException,
189: IllegalAttributeException {
190: int m = s.readInt();
191: List atts = new ArrayList();
192:
193: if (m == 0) {
194: atts.add(s.readObject());
195: } else if (m == FEATURE) {
196: Feature f = unmarshall(s);
197: atts.add(f);
198: } else {
199: for (int i = 0; i < m; i++) {
200: atts.addAll(unmarshallComplexAttribute(s));
201: }
202: }
203:
204: return atts;
205: }
206: }
|