View Javadoc
1   /*
2    * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package javax.sql.rowset.serial;
27  
28  import java.sql.*;
29  import javax.sql.*;
30  import java.io.*;
31  import java.math.*;
32  import java.util.Arrays;
33  import java.util.Map;
34  import java.util.Vector;
35  
36  import javax.sql.rowset.*;
37  
38  /**
39   * A serialized mapping in the Java programming language of an SQL
40   * structured type. Each attribute that is not already serialized
41   * is mapped to a serialized form, and if an attribute is itself
42   * a structured type, each of its attributes that is not already
43   * serialized is mapped to a serialized form.
44   * <P>
45   * In addition, the structured type is custom mapped to a class in the
46   * Java programming language if there is such a mapping, as are
47   * its attributes, if appropriate.
48   * <P>
49   * The <code>SerialStruct</code> class provides a constructor for creating
50   * an instance from a <code>Struct</code> object, a method for retrieving
51   * the SQL type name of the SQL structured type in the database, and methods
52   * for retrieving its attribute values.
53   *
54   * <h3> Thread safety </h3>
55   *
56   * A SerialStruct is not safe for use by multiple concurrent threads.  If a
57   * SerialStruct is to be used by more than one thread then access to the
58   * SerialStruct should be controlled by appropriate synchronization.
59   *
60   */
61  public class SerialStruct implements Struct, Serializable, Cloneable {
62  
63  
64      /**
65       * The SQL type name for the structured type that this
66       * <code>SerialStruct</code> object represents.  This is the name
67       * used in the SQL definition of the SQL structured type.
68       *
69       * @serial
70       */
71      private String SQLTypeName;
72  
73      /**
74       * An array of <code>Object</code> instances in  which each
75       * element is an attribute of the SQL structured type that this
76       * <code>SerialStruct</code> object represents.  The attributes are
77       * ordered according to their order in the definition of the
78       * SQL structured type.
79       *
80       * @serial
81       */
82      private Object attribs[];
83  
84      /**
85       * Constructs a <code>SerialStruct</code> object from the given
86       * <code>Struct</code> object, using the given <code>java.util.Map</code>
87       * object for custom mapping the SQL structured type or any of its
88       * attributes that are SQL structured types.
89       *
90       * @param in an instance of {@code Struct}
91       * @param map a <code>java.util.Map</code> object in which
92       *        each entry consists of 1) a <code>String</code> object
93       *        giving the fully qualified name of a UDT and 2) the
94       *        <code>Class</code> object for the <code>SQLData</code> implementation
95       *        that defines how the UDT is to be mapped
96       * @throws SerialException if an error occurs
97       * @see java.sql.Struct
98       */
99       public SerialStruct(Struct in, Map<String,Class<?>> map)
100          throws SerialException
101      {
102 
103         try {
104 
105         // get the type name
106         SQLTypeName = in.getSQLTypeName();
107         System.out.println("SQLTypeName: " + SQLTypeName);
108 
109         // get the attributes of the struct
110         attribs = in.getAttributes(map);
111 
112         /*
113          * the array may contain further Structs
114          * and/or classes that have been mapped,
115          * other types that we have to serialize
116          */
117         mapToSerial(map);
118 
119         } catch (SQLException e) {
120             throw new SerialException(e.getMessage());
121         }
122     }
123 
124      /**
125       * Constructs a <code>SerialStruct</code> object from the
126       * given <code>SQLData</code> object, using the given type
127       * map to custom map it to a class in the Java programming
128       * language.  The type map gives the SQL type and the class
129       * to which it is mapped.  The <code>SQLData</code> object
130       * defines the class to which the SQL type will be mapped.
131       *
132       * @param in an instance of the <code>SQLData</code> class
133       *           that defines the mapping of the SQL structured
134       *           type to one or more objects in the Java programming language
135       * @param map a <code>java.util.Map</code> object in which
136       *        each entry consists of 1) a <code>String</code> object
137       *        giving the fully qualified name of a UDT and 2) the
138       *        <code>Class</code> object for the <code>SQLData</code> implementation
139       *        that defines how the UDT is to be mapped
140       * @throws SerialException if an error occurs
141       */
142     public SerialStruct(SQLData in, Map<String,Class<?>> map)
143         throws SerialException
144     {
145 
146         try {
147 
148         //set the type name
149         SQLTypeName = in.getSQLTypeName();
150 
151         Vector<Object> tmp = new Vector<>();
152         in.writeSQL(new SQLOutputImpl(tmp, map));
153         attribs = tmp.toArray();
154 
155         } catch (SQLException e) {
156             throw new SerialException(e.getMessage());
157         }
158     }
159 
160 
161     /**
162      * Retrieves the SQL type name for this <code>SerialStruct</code>
163      * object. This is the name used in the SQL definition of the
164      * structured type
165      *
166      * @return a <code>String</code> object representing the SQL
167      *         type name for the SQL structured type that this
168      *         <code>SerialStruct</code> object represents
169      * @throws SerialException if an error occurs
170      */
171     public String getSQLTypeName() throws SerialException {
172         return SQLTypeName;
173     }
174 
175     /**
176      * Retrieves an array of <code>Object</code> values containing the
177      * attributes of the SQL structured type that this
178      * <code>SerialStruct</code> object represents.
179      *
180      * @return an array of <code>Object</code> values, with each
181      *         element being an attribute of the SQL structured type
182      *         that this <code>SerialStruct</code> object represents
183      * @throws SerialException if an error occurs
184      */
185     public Object[]  getAttributes() throws SerialException {
186         Object[] val = this.attribs;
187         return (val == null) ? null : Arrays.copyOf(val, val.length);
188     }
189 
190     /**
191      * Retrieves the attributes for the SQL structured type that
192      * this <code>SerialStruct</code> represents as an array of
193      * <code>Object</code> values, using the given type map for
194      * custom mapping if appropriate.
195      *
196      * @param map a <code>java.util.Map</code> object in which
197      *        each entry consists of 1) a <code>String</code> object
198      *        giving the fully qualified name of a UDT and 2) the
199      *        <code>Class</code> object for the <code>SQLData</code> implementation
200      *        that defines how the UDT is to be mapped
201      * @return an array of <code>Object</code> values, with each
202      *         element being an attribute of the SQL structured
203      *         type that this <code>SerialStruct</code> object
204      *         represents
205      * @throws SerialException if an error occurs
206      */
207     public Object[] getAttributes(Map<String,Class<?>> map)
208         throws SerialException
209     {
210         Object[] val = this.attribs;
211         return (val == null) ? null : Arrays.copyOf(val, val.length);
212     }
213 
214 
215     /**
216      * Maps attributes of an SQL structured type that are not
217      * serialized to a serialized form, using the given type map
218      * for custom mapping when appropriate.  The following types
219      * in the Java programming language are mapped to their
220      * serialized forms:  <code>Struct</code>, <code>SQLData</code>,
221      * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>, and
222      * <code>Array</code>.
223      * <P>
224      * This method is called internally and is not used by an
225      * application programmer.
226      *
227      * @param map a <code>java.util.Map</code> object in which
228      *        each entry consists of 1) a <code>String</code> object
229      *        giving the fully qualified name of a UDT and 2) the
230      *        <code>Class</code> object for the <code>SQLData</code> implementation
231      *        that defines how the UDT is to be mapped
232      * @throws SerialException if an error occurs
233      */
234     private void mapToSerial(Map<String,Class<?>> map) throws SerialException {
235 
236         try {
237 
238         for (int i = 0; i < attribs.length; i++) {
239             if (attribs[i] instanceof Struct) {
240                 attribs[i] = new SerialStruct((Struct)attribs[i], map);
241             } else if (attribs[i] instanceof SQLData) {
242                 attribs[i] = new SerialStruct((SQLData)attribs[i], map);
243             } else if (attribs[i] instanceof Blob) {
244                 attribs[i] = new SerialBlob((Blob)attribs[i]);
245             } else if (attribs[i] instanceof Clob) {
246                 attribs[i] = new SerialClob((Clob)attribs[i]);
247             } else if (attribs[i] instanceof Ref) {
248                 attribs[i] = new SerialRef((Ref)attribs[i]);
249             } else if (attribs[i] instanceof java.sql.Array) {
250                 attribs[i] = new SerialArray((java.sql.Array)attribs[i], map);
251             }
252         }
253 
254         } catch (SQLException e) {
255             throw new SerialException(e.getMessage());
256         }
257         return;
258     }
259 
260     /**
261      * Compares this SerialStruct to the specified object.  The result is
262      * {@code true} if and only if the argument is not {@code null} and is a
263      * {@code SerialStruct} object whose attributes are identical to this
264      * object's attributes
265      *
266      * @param  obj The object to compare this {@code SerialStruct} against
267      *
268      * @return {@code true} if the given object represents a {@code SerialStruct}
269      *          equivalent to this SerialStruct, {@code false} otherwise
270      *
271      */
272     public boolean equals(Object obj) {
273         if (this == obj) {
274             return true;
275         }
276         if (obj instanceof SerialStruct) {
277             SerialStruct ss = (SerialStruct)obj;
278             return SQLTypeName.equals(ss.SQLTypeName) &&
279                     Arrays.equals(attribs, ss.attribs);
280         }
281         return false;
282     }
283 
284     /**
285      * Returns a hash code for this {@code SerialStruct}. The hash code for a
286      * {@code SerialStruct} object is computed using the hash codes
287      * of the attributes of the {@code SerialStruct} object and its
288      * {@code SQLTypeName}
289      *
290      * @return  a hash code value for this object.
291      */
292     public int hashCode() {
293         return ((31 + Arrays.hashCode(attribs)) * 31) * 31
294                 + SQLTypeName.hashCode();
295     }
296 
297     /**
298      * Returns a clone of this {@code SerialStruct}. The copy will contain a
299      * reference to a clone of the underlying attribs array, not a reference
300      * to the original underlying attribs array of this {@code SerialStruct} object.
301      *
302      * @return  a clone of this SerialStruct
303      */
304     public Object clone() {
305         try {
306             SerialStruct ss = (SerialStruct) super.clone();
307             ss.attribs = Arrays.copyOf(attribs, attribs.length);
308             return ss;
309         } catch (CloneNotSupportedException ex) {
310             // this shouldn't happen, since we are Cloneable
311             throw new InternalError();
312         }
313 
314     }
315 
316     /**
317      * readObject is called to restore the state of the {@code SerialStruct} from
318      * a stream.
319      */
320     private void readObject(ObjectInputStream s)
321             throws IOException, ClassNotFoundException {
322 
323        ObjectInputStream.GetField fields = s.readFields();
324        Object[] tmp = (Object[])fields.get("attribs", null);
325        attribs = tmp == null ? null : tmp.clone();
326        SQLTypeName = (String)fields.get("SQLTypeName", null);
327     }
328 
329     /**
330      * writeObject is called to save the state of the {@code SerialStruct}
331      * to a stream.
332      */
333     private void writeObject(ObjectOutputStream s)
334             throws IOException, ClassNotFoundException {
335 
336         ObjectOutputStream.PutField fields = s.putFields();
337         fields.put("attribs", attribs);
338         fields.put("SQLTypeName", SQLTypeName);
339         s.writeFields();
340     }
341 
342     /**
343      * The identifier that assists in the serialization of this
344      * <code>SerialStruct</code> object.
345      */
346     static final long serialVersionUID = -8322445504027483372L;
347 }