1 /*-
2  * Copyright (c) 2002, 2020 Oracle and/or its affiliates.  All rights reserved.
3  *
4  * See the file LICENSE for license information.
5  *
6  */
7 
8 package com.sleepycat.persist.impl;
9 
10 import java.math.BigDecimal;
11 import java.math.BigInteger;
12 import java.util.IdentityHashMap;
13 
14 import com.sleepycat.compat.DbCompat;
15 import com.sleepycat.persist.raw.RawObject;
16 
17 /**
18  * Base class for EntityInput implementations that type-check RawObject
19  * instances and convert them to regular persistent objects, via the
20  * Format.convertRawObject method.
21  *
22  * The subclass implements readNext which should call checkAndConvert before
23  * returning the final value.
24  *
25  * @author Mark Hayes
26  */
27 abstract class RawAbstractInput extends AbstractInput {
28 
29     private IdentityHashMap converted;
30 
RawAbstractInput(Catalog catalog, boolean rawAccess, IdentityHashMap converted)31     RawAbstractInput(Catalog catalog,
32                      boolean rawAccess,
33                      IdentityHashMap converted) {
34         super(catalog, rawAccess);
35         this.converted = converted;
36     }
37 
readObject()38     public Object readObject()
39         throws RefreshException {
40 
41         return readNext();
42     }
43 
readKeyObject(Format format)44     public Object readKeyObject(Format format)
45         throws RefreshException {
46 
47         return readNext();
48     }
49 
readStringObject()50     public Object readStringObject()
51         throws RefreshException {
52 
53         return readNext();
54     }
55 
registerPriKeyObject(Object o)56     public void registerPriKeyObject(Object o) {
57     }
58 
registerPriStringKeyObject(Object o)59     public void registerPriStringKeyObject(Object o) {
60     }
61 
readArrayLength()62     public int readArrayLength() {
63         throw DbCompat.unexpectedState();
64     }
65 
readEnumConstant(String[] names)66     public int readEnumConstant(String[] names) {
67         throw DbCompat.unexpectedState();
68     }
69 
skipField(Format declaredFormat)70     public void skipField(Format declaredFormat) {
71     }
72 
readNext()73     abstract Object readNext()
74         throws RefreshException;
75 
checkAndConvert(Object o, Format declaredFormat)76     Object checkAndConvert(Object o, Format declaredFormat)
77         throws RefreshException {
78 
79         if (o == null) {
80             if (declaredFormat.isPrimitive()) {
81                 throw new IllegalArgumentException
82                     ("A primitive type may not be null or missing: " +
83                      declaredFormat.getClassName());
84             }
85         } else if (declaredFormat.isSimple()) {
86             if (declaredFormat.isPrimitive()) {
87                 if (o.getClass() !=
88                     declaredFormat.getWrapperFormat().getType()) {
89                     throw new IllegalArgumentException
90                         ("Raw value class: " + o.getClass().getName() +
91                          " must be the wrapper class for a primitive type: " +
92                          declaredFormat.getClassName());
93                 }
94             } else {
95                 if (o.getClass() != declaredFormat.getType()) {
96                     throw new IllegalArgumentException
97                         ("Raw value class: " + o.getClass().getName() +
98                          " must be the declared class for a simple type: " +
99                          declaredFormat.getClassName());
100                 }
101             }
102         } else {
103             if (o instanceof RawObject) {
104                 Object o2 = null;
105                 if (!rawAccess) {
106                     if (converted != null) {
107                         o2 = converted.get(o);
108                     } else {
109                         converted = new IdentityHashMap();
110                     }
111                 }
112                 if (o2 != null) {
113                     o = o2;
114                 } else {
115                     if (!rawAccess) {
116                         o = catalog.convertRawObject((RawObject) o, converted);
117                     }
118                 }
119             } else {
120                 if (!SimpleCatalog.isSimpleType(o.getClass())) {
121                     throw new IllegalArgumentException
122                         ("Raw value class: " + o.getClass().getName() +
123                          " must be RawObject a simple type");
124                 }
125             }
126             if (rawAccess) {
127                 checkRawType(catalog, o, declaredFormat);
128             } else {
129                 if (!declaredFormat.getType().isAssignableFrom(o.getClass())) {
130                     throw new IllegalArgumentException
131                         ("Raw value class: " + o.getClass().getName() +
132                          " is not assignable to type: " +
133                          declaredFormat.getClassName());
134                 }
135             }
136         }
137         return o;
138     }
139 
checkRawType(Catalog catalog, Object o, Format declaredFormat)140     static Format checkRawType(Catalog catalog,
141                                Object o,
142                                Format declaredFormat)
143         throws RefreshException {
144 
145         assert declaredFormat != null;
146         Format format;
147         if (o instanceof RawObject) {
148             format = (Format) ((RawObject) o).getType();
149             /* Ensure a fresh format is used, in case of Replica refresh. */
150             format = catalog.getFormat(format.getId(), false /*expectStored*/);
151         } else {
152             format = catalog.getFormat(o.getClass(),
153                                        false /*checkEntitySubclassIndexes*/);
154             if (!format.isSimple() || format.isEnum()) {
155                 throw new IllegalArgumentException
156                     ("Not a RawObject or a non-enum simple type: " +
157                      format.getClassName());
158             }
159         }
160         if (!format.isAssignableTo(declaredFormat)) {
161             throw new IllegalArgumentException
162                 ("Not a subtype of the field's declared class " +
163                  declaredFormat.getClassName() + ": " +
164                  format.getClassName());
165         }
166         if (!format.isCurrentVersion()) {
167             throw new IllegalArgumentException
168                 ("Raw type version is not current.  Class: " +
169                  format.getClassName() + " Version: " +
170                  format.getVersion());
171         }
172         Format proxiedFormat = format.getProxiedFormat();
173         if (proxiedFormat != null) {
174             format = proxiedFormat;
175         }
176         return format;
177     }
178 
179     /* The following methods are a subset of the methods in TupleInput. */
180 
readString()181     public String readString()
182         throws RefreshException {
183 
184         return (String) readNext();
185     }
186 
readChar()187     public char readChar()
188         throws RefreshException {
189 
190         return ((Character) readNext()).charValue();
191     }
192 
readBoolean()193     public boolean readBoolean()
194         throws RefreshException {
195 
196         return ((Boolean) readNext()).booleanValue();
197     }
198 
readByte()199     public byte readByte()
200         throws RefreshException {
201 
202         return ((Byte) readNext()).byteValue();
203     }
204 
readShort()205     public short readShort()
206         throws RefreshException {
207 
208         return ((Short) readNext()).shortValue();
209     }
210 
readInt()211     public int readInt()
212         throws RefreshException {
213 
214         return ((Integer) readNext()).intValue();
215     }
216 
readLong()217     public long readLong()
218         throws RefreshException {
219 
220         return ((Long) readNext()).longValue();
221     }
222 
readSortedFloat()223     public float readSortedFloat()
224         throws RefreshException {
225 
226         return ((Float) readNext()).floatValue();
227     }
228 
readSortedDouble()229     public double readSortedDouble()
230         throws RefreshException {
231 
232         return ((Double) readNext()).doubleValue();
233     }
234 
readSortedBigDecimal()235     public BigDecimal readSortedBigDecimal()
236         throws RefreshException {
237 
238         return (BigDecimal) readNext();
239     }
240 
readBigInteger()241     public BigInteger readBigInteger()
242         throws RefreshException {
243 
244         return (BigInteger) readNext();
245     }
246 }
247