1 /*
   2  * Copyright (c) 2003, 2012, 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 java.io.*;
  30 import java.util.*;
  31 
  32 /**
  33  * A serialized mapping of a <code>Ref</code> object, which is the mapping in the
  34  * Java programming language of an SQL <code>REF</code> value.
  35  * <p>
  36  * The <code>SerialRef</code> class provides a constructor  for
  37  * creating a <code>SerialRef</code> instance from a <code>Ref</code>
  38  * object and provides methods for getting and setting the <code>Ref</code> object.
  39  */
  40 public class SerialRef implements Ref, Serializable, Cloneable {
  41 
  42     /**
  43      * String containing the base type name.
  44      * @serial
  45      */
  46     private String baseTypeName;
  47 
  48     /**
  49      * This will store the type <code>Ref</code> as an <code>Object</code>.
  50      */
  51     private Object object;
  52 
  53     /**
  54      * Private copy of the Ref reference.
  55      */
  56     private Ref reference;
  57 
  58     /**
  59      * Constructs a <code>SerialRef</code> object from the given <code>Ref</code>
  60      * object.
  61      *
  62      * @param ref a Ref object; cannot be <code>null</code>
  63      * @throws SQLException if a database access occurs; if <code>ref</code>
  64      *     is <code>null</code>; or if the <code>Ref</code> object returns a
  65      *     <code>null</code> value base type name.
  66      * @throws SerialException if an error occurs serializing the <code>Ref</code>
  67      *     object
  68      */
  69     public SerialRef(Ref ref) throws SerialException, SQLException {
  70         if (ref == null) {
  71             throw new SQLException("Cannot instantiate a SerialRef object " +
  72                 "with a null Ref object");
  73         }
  74         reference = ref;
  75         object = ref;
  76         if (ref.getBaseTypeName() == null) {
  77             throw new SQLException("Cannot instantiate a SerialRef object " +
  78                 "that returns a null base type name");
  79         } else {
  80             baseTypeName = ref.getBaseTypeName();
  81         }
  82     }
  83 
  84     /**
  85      * Returns a string describing the base type name of the <code>Ref</code>.
  86      *
  87      * @return a string of the base type name of the Ref
  88      * @throws SerialException in no Ref object has been set
  89      */
  90     public String getBaseTypeName() throws SerialException {
  91         return baseTypeName;
  92     }
  93 
  94     /**
  95      * Returns an <code>Object</code> representing the SQL structured type
  96      * to which this <code>SerialRef</code> object refers.  The attributes
  97      * of the structured type are mapped according to the given type map.
  98      *
  99      * @param map a <code>java.util.Map</code> object containing zero or
 100      *        more entries, with each entry consisting of 1) a <code>String</code>
 101      *        giving the fully qualified name of a UDT and 2) the
 102      *        <code>Class</code> object for the <code>SQLData</code> implementation
 103      *        that defines how the UDT is to be mapped
 104      * @return an object instance resolved from the Ref reference and mapped
 105      *        according to the supplied type map
 106      * @throws SerialException if an error is encountered in the reference
 107      *        resolution
 108      */
 109     public Object getObject(java.util.Map<String,Class<?>> map)
 110         throws SerialException
 111     {
 112         map = new Hashtable<String, Class<?>>(map);
 113         if (object != null) {
 114             return map.get(object);
 115         } else {
 116             throw new SerialException("The object is not set");
 117         }
 118     }
 119 
 120     /**
 121      * Returns an <code>Object</code> representing the SQL structured type
 122      * to which this <code>SerialRef</code> object refers.
 123      *
 124      * @return an object instance resolved from the Ref reference
 125      * @throws SerialException if an error is encountered in the reference
 126      *         resolution
 127      */
 128     public Object getObject() throws SerialException {
 129 
 130         if (reference != null) {
 131             try {
 132                 return reference.getObject();
 133             } catch (SQLException e) {
 134                 throw new SerialException("SQLException: " + e.getMessage());
 135             }
 136         }
 137 
 138         if (object != null) {
 139             return object;
 140         }
 141 
 142 
 143         throw new SerialException("The object is not set");
 144 
 145     }
 146 
 147     /**
 148      * Sets the SQL structured type that this <code>SerialRef</code> object
 149      * references to the given <code>Object</code> object.
 150      *
 151      * @param obj an <code>Object</code> representing the SQL structured type
 152      *        to be referenced
 153      * @throws SerialException if an error is encountered generating the
 154      * the structured type referenced by this <code>SerialRef</code> object
 155      */
 156     public void setObject(Object obj) throws SerialException {
 157         try {
 158             reference.setObject(obj);
 159         } catch (SQLException e) {
 160             throw new SerialException("SQLException: " + e.getMessage());
 161         }
 162         object = obj;
 163     }
 164 
 165     /**
 166      * Compares this SerialRef to the specified object.  The result is {@code
 167      * true} if and only if the argument is not {@code null} and is a {@code
 168      * SerialRef} object that represents the same object as this
 169      * object.
 170      *
 171      * @param  obj The object to compare this {@code SerialRef} against
 172      *
 173      * @return  {@code true} if the given object represents a {@code SerialRef}
 174      *          equivalent to this SerialRef, {@code false} otherwise
 175      *
 176      */
 177     public boolean equals(Object obj) {
 178         if (this == obj) {
 179             return true;
 180         }
 181         if(obj instanceof SerialRef) {
 182             SerialRef ref = (SerialRef)obj;
 183             if(baseTypeName.equals(ref.baseTypeName)) {
 184                 return object.equals(ref.object);
 185             }
 186         }
 187         return false;
 188     }
 189 
 190     /**
 191      * Returns a hash code for this {@code SerialRef}.
 192      * @return  a hash code value for this object.
 193      */
 194     public int hashCode() {
 195         return (31 + object.hashCode()) * 31 + baseTypeName.hashCode();
 196     }
 197 
 198     /**
 199      * Returns a clone of this {@code SerialRef}. .
 200      * The underlying {@code Ref} object will be set to null.
 201      *  
 202      * @return  a clone of this SerialRef
 203      */ 
 204     public Object clone() {
 205         try {
 206             SerialRef ref = (SerialRef) super.clone();
 207             ref.reference = null;
 208             return ref;
 209         } catch (CloneNotSupportedException ex) {
 210             // this shouldn't happen, since we are Cloneable
 211             throw new InternalError();
 212         }
 213        
 214     }
 215     
 216     /**
 217      * readObject is called to restore the state of the SerialRef from
 218      * a stream.
 219      */
 220     private void readObject(ObjectInputStream s)
 221             throws IOException, ClassNotFoundException {
 222         ObjectInputStream.GetField fields = s.readFields();
 223         object = fields.get("object", null);
 224         baseTypeName = (String) fields.get("baseTypeName", null);     
 225         reference = (Ref) fields.get("reference", null);
 226     }
 227     
 228     /**
 229      * writeObject is called to save the state of the SerialRef
 230      * to a stream.
 231      */
 232     private void writeObject(ObjectOutputStream s)
 233             throws IOException, ClassNotFoundException {
 234 
 235         ObjectOutputStream.PutField fields = s.putFields();
 236         fields.put("baseTypeName", baseTypeName);
 237         fields.put("object", object);
 238         // Note: this check to see if it is an instance of Serializable
 239         // is for backwards compatibiity
 240         fields.put("reference", reference instanceof Serializable ? reference : null);
 241         s.writeFields();    
 242     }
 243 
 244     /**
 245      * The identifier that assists in the serialization of this <code>SerialRef</code>
 246      * object.
 247      */
 248     static final long serialVersionUID = -4727123500609662274L;
 249 
 250 
 251 }