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