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
26package javax.sql.rowset.serial;
27
28import java.sql.*;
29import javax.sql.*;
30import java.io.*;
31import java.math.*;
32import java.util.Arrays;
33import java.util.Map;
34import java.util.Vector;
35
36import 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 * @since 1.5
61 */
62public class SerialStruct implements Struct, Serializable, Cloneable {
63
64
65    /**
66     * The SQL type name for the structured type that this
67     * <code>SerialStruct</code> object represents.  This is the name
68     * used in the SQL definition of the SQL structured type.
69     *
70     * @serial
71     */
72    private String SQLTypeName;
73
74    /**
75     * An array of <code>Object</code> instances in  which each
76     * element is an attribute of the SQL structured type that this
77     * <code>SerialStruct</code> object represents.  The attributes are
78     * ordered according to their order in the definition of the
79     * SQL structured type.
80     *
81     * @serial
82     */
83    private Object attribs[];
84
85    /**
86     * Constructs a <code>SerialStruct</code> object from the given
87     * <code>Struct</code> object, using the given <code>java.util.Map</code>
88     * object for custom mapping the SQL structured type or any of its
89     * attributes that are SQL structured types.
90     *
91     * @param in an instance of {@code Struct}
92     * @param map a <code>java.util.Map</code> object in which
93     *        each entry consists of 1) a <code>String</code> object
94     *        giving the fully qualified name of a UDT and 2) the
95     *        <code>Class</code> object for the <code>SQLData</code> implementation
96     *        that defines how the UDT is to be mapped
97     * @throws SerialException if an error occurs
98     * @see java.sql.Struct
99     */
100     public SerialStruct(Struct in, Map<String,Class<?>> map)
101         throws SerialException
102     {
103
104        try {
105
106        // get the type name
107        SQLTypeName = in.getSQLTypeName();
108        System.out.println("SQLTypeName: " + SQLTypeName);
109
110        // get the attributes of the struct
111        attribs = in.getAttributes(map);
112
113        /*
114         * the array may contain further Structs
115         * and/or classes that have been mapped,
116         * other types that we have to serialize
117         */
118        mapToSerial(map);
119
120        } catch (SQLException e) {
121            throw new SerialException(e.getMessage());
122        }
123    }
124
125     /**
126      * Constructs a <code>SerialStruct</code> object from the
127      * given <code>SQLData</code> object, using the given type
128      * map to custom map it to a class in the Java programming
129      * language.  The type map gives the SQL type and the class
130      * to which it is mapped.  The <code>SQLData</code> object
131      * defines the class to which the SQL type will be mapped.
132      *
133      * @param in an instance of the <code>SQLData</code> class
134      *           that defines the mapping of the SQL structured
135      *           type to one or more objects in the Java programming language
136      * @param map a <code>java.util.Map</code> object in which
137      *        each entry consists of 1) a <code>String</code> object
138      *        giving the fully qualified name of a UDT and 2) the
139      *        <code>Class</code> object for the <code>SQLData</code> implementation
140      *        that defines how the UDT is to be mapped
141      * @throws SerialException if an error occurs
142      */
143    public SerialStruct(SQLData in, Map<String,Class<?>> map)
144        throws SerialException
145    {
146
147        try {
148
149        //set the type name
150        SQLTypeName = in.getSQLTypeName();
151
152        Vector<Object> tmp = new Vector<>();
153        in.writeSQL(new SQLOutputImpl(tmp, map));
154        attribs = tmp.toArray();
155
156        } catch (SQLException e) {
157            throw new SerialException(e.getMessage());
158        }
159    }
160
161
162    /**
163     * Retrieves the SQL type name for this <code>SerialStruct</code>
164     * object. This is the name used in the SQL definition of the
165     * structured type
166     *
167     * @return a <code>String</code> object representing the SQL
168     *         type name for the SQL structured type that this
169     *         <code>SerialStruct</code> object represents
170     * @throws SerialException if an error occurs
171     */
172    public String getSQLTypeName() throws SerialException {
173        return SQLTypeName;
174    }
175
176    /**
177     * Retrieves an array of <code>Object</code> values containing the
178     * attributes of the SQL structured type that this
179     * <code>SerialStruct</code> object represents.
180     *
181     * @return an array of <code>Object</code> values, with each
182     *         element being an attribute of the SQL structured type
183     *         that this <code>SerialStruct</code> object represents
184     * @throws SerialException if an error occurs
185     */
186    public Object[]  getAttributes() throws SerialException {
187        Object[] val = this.attribs;
188        return (val == null) ? null : Arrays.copyOf(val, val.length);
189    }
190
191    /**
192     * Retrieves the attributes for the SQL structured type that
193     * this <code>SerialStruct</code> represents as an array of
194     * <code>Object</code> values, using the given type map for
195     * custom mapping if appropriate.
196     *
197     * @param map a <code>java.util.Map</code> object in which
198     *        each entry consists of 1) a <code>String</code> object
199     *        giving the fully qualified name of a UDT and 2) the
200     *        <code>Class</code> object for the <code>SQLData</code> implementation
201     *        that defines how the UDT is to be mapped
202     * @return an array of <code>Object</code> values, with each
203     *         element being an attribute of the SQL structured
204     *         type that this <code>SerialStruct</code> object
205     *         represents
206     * @throws SerialException if an error occurs
207     */
208    public Object[] getAttributes(Map<String,Class<?>> map)
209        throws SerialException
210    {
211        Object[] val = this.attribs;
212        return (val == null) ? null : Arrays.copyOf(val, val.length);
213    }
214
215
216    /**
217     * Maps attributes of an SQL structured type that are not
218     * serialized to a serialized form, using the given type map
219     * for custom mapping when appropriate.  The following types
220     * in the Java programming language are mapped to their
221     * serialized forms:  <code>Struct</code>, <code>SQLData</code>,
222     * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>, and
223     * <code>Array</code>.
224     * <P>
225     * This method is called internally and is not used by an
226     * application programmer.
227     *
228     * @param map a <code>java.util.Map</code> object in which
229     *        each entry consists of 1) a <code>String</code> object
230     *        giving the fully qualified name of a UDT and 2) the
231     *        <code>Class</code> object for the <code>SQLData</code> implementation
232     *        that defines how the UDT is to be mapped
233     * @throws SerialException if an error occurs
234     */
235    private void mapToSerial(Map<String,Class<?>> map) throws SerialException {
236
237        try {
238
239        for (int i = 0; i < attribs.length; i++) {
240            if (attribs[i] instanceof Struct) {
241                attribs[i] = new SerialStruct((Struct)attribs[i], map);
242            } else if (attribs[i] instanceof SQLData) {
243                attribs[i] = new SerialStruct((SQLData)attribs[i], map);
244            } else if (attribs[i] instanceof Blob) {
245                attribs[i] = new SerialBlob((Blob)attribs[i]);
246            } else if (attribs[i] instanceof Clob) {
247                attribs[i] = new SerialClob((Clob)attribs[i]);
248            } else if (attribs[i] instanceof Ref) {
249                attribs[i] = new SerialRef((Ref)attribs[i]);
250            } else if (attribs[i] instanceof java.sql.Array) {
251                attribs[i] = new SerialArray((java.sql.Array)attribs[i], map);
252            }
253        }
254
255        } catch (SQLException e) {
256            throw new SerialException(e.getMessage());
257        }
258        return;
259    }
260
261    /**
262     * Compares this SerialStruct to the specified object.  The result is
263     * {@code true} if and only if the argument is not {@code null} and is a
264     * {@code SerialStruct} object whose attributes are identical to this
265     * object's attributes
266     *
267     * @param  obj The object to compare this {@code SerialStruct} against
268     *
269     * @return {@code true} if the given object represents a {@code SerialStruct}
270     *          equivalent to this SerialStruct, {@code false} otherwise
271     *
272     */
273    public boolean equals(Object obj) {
274        if (this == obj) {
275            return true;
276        }
277        if (obj instanceof SerialStruct) {
278            SerialStruct ss = (SerialStruct)obj;
279            return SQLTypeName.equals(ss.SQLTypeName) &&
280                    Arrays.equals(attribs, ss.attribs);
281        }
282        return false;
283    }
284
285    /**
286     * Returns a hash code for this {@code SerialStruct}. The hash code for a
287     * {@code SerialStruct} object is computed using the hash codes
288     * of the attributes of the {@code SerialStruct} object and its
289     * {@code SQLTypeName}
290     *
291     * @return  a hash code value for this object.
292     */
293    public int hashCode() {
294        return ((31 + Arrays.hashCode(attribs)) * 31) * 31
295                + SQLTypeName.hashCode();
296    }
297
298    /**
299     * Returns a clone of this {@code SerialStruct}. The copy will contain a
300     * reference to a clone of the underlying attribs array, not a reference
301     * to the original underlying attribs array of this {@code SerialStruct} object.
302     *
303     * @return  a clone of this SerialStruct
304     */
305    public Object clone() {
306        try {
307            SerialStruct ss = (SerialStruct) super.clone();
308            ss.attribs = Arrays.copyOf(attribs, attribs.length);
309            return ss;
310        } catch (CloneNotSupportedException ex) {
311            // this shouldn't happen, since we are Cloneable
312            throw new InternalError();
313        }
314
315    }
316
317    /**
318     * readObject is called to restore the state of the {@code SerialStruct} from
319     * a stream.
320     */
321    private void readObject(ObjectInputStream s)
322            throws IOException, ClassNotFoundException {
323
324       ObjectInputStream.GetField fields = s.readFields();
325       Object[] tmp = (Object[])fields.get("attribs", null);
326       attribs = tmp == null ? null : tmp.clone();
327       SQLTypeName = (String)fields.get("SQLTypeName", null);
328    }
329
330    /**
331     * writeObject is called to save the state of the {@code SerialStruct}
332     * to a stream.
333     */
334    private void writeObject(ObjectOutputStream s)
335            throws IOException, ClassNotFoundException {
336
337        ObjectOutputStream.PutField fields = s.putFields();
338        fields.put("attribs", attribs);
339        fields.put("SQLTypeName", SQLTypeName);
340        s.writeFields();
341    }
342
343    /**
344     * The identifier that assists in the serialization of this
345     * <code>SerialStruct</code> object.
346     */
347    static final long serialVersionUID = -8322445504027483372L;
348}
349