1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 * $Id: SimpleCatalog.java,v 1.1 2008/02/07 17:12:27 mark Exp $
7 */
8
9package com.sleepycat.persist.impl;
10
11import java.util.ArrayList;
12import java.util.HashMap;
13import java.util.IdentityHashMap;
14import java.util.List;
15import java.util.Map;
16import java.util.NoSuchElementException;
17
18import com.sleepycat.persist.model.EntityModel;
19import com.sleepycat.persist.raw.RawObject;
20
21/**
22 * A static catalog containing simple types only.  Once created, this catalog
23 * is immutable.
24 *
25 * For bindings accessed by a PersistComparator during recovery, the
26 * SimpleCatalog provides formats for all simple types.  To reduce redundant
27 * format objects, the SimpleCatalog's formats are copied when creating a
28 * regular PersistCatalog.
29 *
30 * This class also contains utility methods for dealing with primitives.
31 *
32 * @author Mark Hayes
33 */
34public class SimpleCatalog implements Catalog {
35
36    private static final Map<String,Class> keywordToPrimitive;
37    static {
38        keywordToPrimitive = new HashMap<String,Class>(8);
39        keywordToPrimitive.put("boolean", Boolean.TYPE);
40        keywordToPrimitive.put("char", Character.TYPE);
41        keywordToPrimitive.put("byte", Byte.TYPE);
42        keywordToPrimitive.put("short", Short.TYPE);
43        keywordToPrimitive.put("int", Integer.TYPE);
44        keywordToPrimitive.put("long", Long.TYPE);
45        keywordToPrimitive.put("float", Float.TYPE);
46        keywordToPrimitive.put("double", Double.TYPE);
47    }
48
49    private static final Map<Class,Class> primitiveTypeToWrapper;
50    static {
51        primitiveTypeToWrapper = new HashMap<Class,Class>(8);
52        primitiveTypeToWrapper.put(Boolean.TYPE, Boolean.class);
53        primitiveTypeToWrapper.put(Character.TYPE, Character.class);
54        primitiveTypeToWrapper.put(Byte.TYPE, Byte.class);
55        primitiveTypeToWrapper.put(Short.TYPE, Short.class);
56        primitiveTypeToWrapper.put(Integer.TYPE, Integer.class);
57        primitiveTypeToWrapper.put(Long.TYPE, Long.class);
58        primitiveTypeToWrapper.put(Float.TYPE, Float.class);
59        primitiveTypeToWrapper.put(Double.TYPE, Double.class);
60    }
61
62    private static final SimpleCatalog instance = new SimpleCatalog();
63
64    static SimpleCatalog getInstance() {
65        return instance;
66    }
67
68    static boolean isSimpleType(Class type) {
69        return instance.formatMap.containsKey(type.getName());
70    }
71
72    static Class primitiveToWrapper(Class type) {
73        Class cls = primitiveTypeToWrapper.get(type);
74        if (cls == null) {
75            throw new IllegalStateException(type.getName());
76        }
77        return cls;
78    }
79
80    public static Class keyClassForName(String className) {
81        Class cls = keywordToPrimitive.get(className);
82        if (cls != null) {
83            cls = primitiveTypeToWrapper.get(cls);
84        } else {
85            try {
86                cls = EntityModel.classForName(className);
87            } catch (ClassNotFoundException e) {
88                throw new IllegalArgumentException
89                    ("Key class not found: " + className);
90            }
91        }
92        return cls;
93    }
94
95    public static String keyClassName(String className) {
96        Class cls = keywordToPrimitive.get(className);
97        if (cls != null) {
98            cls = primitiveTypeToWrapper.get(cls);
99            return cls.getName();
100        } else {
101            return className;
102        }
103    }
104
105    public static Class classForName(String className)
106        throws ClassNotFoundException {
107
108        Class cls = keywordToPrimitive.get(className);
109        if (cls == null) {
110            cls = EntityModel.classForName(className);
111        }
112        return cls;
113    }
114
115    static SimpleFormat getSimpleFormat(Class type) {
116        return instance.formatMap.get(type.getName());
117    }
118
119    static List<Format> copyFormatList() {
120        return new ArrayList<Format>(instance.formatList);
121    }
122
123    static boolean copyMissingFormats(List<Format> copyToList) {
124        boolean anyCopied = false;
125        for (int i = 0; i <= Format.ID_PREDEFINED; i += 1) {
126            Format thisFormat = instance.formatList.get(i);
127            Format otherFormat = copyToList.get(i);
128            if (thisFormat != null && otherFormat == null) {
129                copyToList.set(i, thisFormat);
130                anyCopied = true;
131            }
132        }
133        return anyCopied;
134    }
135
136    private List<SimpleFormat> formatList;
137    private Map<String,SimpleFormat> formatMap;
138
139    private SimpleCatalog() {
140
141        /*
142         * Reserve slots for all predefined IDs, so that that next ID assigned
143         * will be Format.ID_PREDEFINED plus one.
144         */
145        int initCapacity = Format.ID_PREDEFINED * 2;
146        formatList = new ArrayList<SimpleFormat>(initCapacity);
147        formatMap = new HashMap<String,SimpleFormat>(initCapacity);
148
149        for (int i = 0; i <= Format.ID_PREDEFINED; i += 1) {
150            formatList.add(null);
151        }
152
153        /* Initialize all predefined formats.  */
154        setFormat(Format.ID_BOOL,     new SimpleFormat.FBool(true));
155        setFormat(Format.ID_BOOL_W,   new SimpleFormat.FBool(false));
156        setFormat(Format.ID_BYTE,     new SimpleFormat.FByte(true));
157        setFormat(Format.ID_BYTE_W,   new SimpleFormat.FByte(false));
158        setFormat(Format.ID_SHORT,    new SimpleFormat.FShort(true));
159        setFormat(Format.ID_SHORT_W,  new SimpleFormat.FShort(false));
160        setFormat(Format.ID_INT,      new SimpleFormat.FInt(true));
161        setFormat(Format.ID_INT_W,    new SimpleFormat.FInt(false));
162        setFormat(Format.ID_LONG,     new SimpleFormat.FLong(true));
163        setFormat(Format.ID_LONG_W,   new SimpleFormat.FLong(false));
164        setFormat(Format.ID_FLOAT,    new SimpleFormat.FFloat(true));
165        setFormat(Format.ID_FLOAT_W,  new SimpleFormat.FFloat(false));
166        setFormat(Format.ID_DOUBLE,   new SimpleFormat.FDouble(true));
167        setFormat(Format.ID_DOUBLE_W, new SimpleFormat.FDouble(false));
168        setFormat(Format.ID_CHAR,     new SimpleFormat.FChar(true));
169        setFormat(Format.ID_CHAR_W,   new SimpleFormat.FChar(false));
170        setFormat(Format.ID_STRING,   new SimpleFormat.FString());
171        setFormat(Format.ID_BIGINT,   new SimpleFormat.FBigInt());
172        /*
173        setFormat(Format.ID_BIGDEC,   new SimpleFormat.FBigDec());
174        */
175        setFormat(Format.ID_DATE,     new SimpleFormat.FDate());
176
177        /* Tell primitives about their wrapper class. */
178        setWrapper(Format.ID_BOOL, Format.ID_BOOL_W);
179        setWrapper(Format.ID_BYTE, Format.ID_BYTE_W);
180        setWrapper(Format.ID_SHORT, Format.ID_SHORT_W);
181        setWrapper(Format.ID_INT, Format.ID_INT_W);
182        setWrapper(Format.ID_LONG, Format.ID_LONG_W);
183        setWrapper(Format.ID_FLOAT, Format.ID_FLOAT_W);
184        setWrapper(Format.ID_DOUBLE, Format.ID_DOUBLE_W);
185        setWrapper(Format.ID_CHAR, Format.ID_CHAR_W);
186    }
187
188    /**
189     * Sets a format for which space in the formatList has been preallocated,
190     * and makes it the current format for the class.
191     */
192    private void setFormat(int id, SimpleFormat format) {
193        format.setId(id);
194        format.initializeIfNeeded(this);
195        formatList.set(id, format);
196        formatMap.put(format.getClassName(), format);
197    }
198
199    /**
200     * Tells a primitive format about the format for its corresponding
201     * primitive wrapper class.
202     */
203    private void setWrapper(int primitiveId, int wrapperId) {
204        SimpleFormat primitiveFormat = formatList.get(primitiveId);
205        SimpleFormat wrapperFormat = formatList.get(wrapperId);
206        primitiveFormat.setWrapperFormat(wrapperFormat);
207    }
208
209    public int getInitVersion(Format format, boolean forReader) {
210        return Catalog.CURRENT_VERSION;
211    }
212
213    public Format getFormat(int formatId) {
214        Format format;
215        try {
216            format = formatList.get(formatId);
217            if (format == null) {
218                throw new IllegalStateException
219                    ("Not a simple type: " + formatId);
220            }
221            return format;
222        } catch (NoSuchElementException e) {
223            throw new IllegalStateException
224                ("Not a simple type: " + formatId);
225        }
226    }
227
228    public Format getFormat(Class cls) {
229        Format format = formatMap.get(cls.getName());
230        if (format == null) {
231            throw new IllegalArgumentException
232                ("Not a simple type: " + cls.getName());
233        }
234        return format;
235    }
236
237    public Format getFormat(String className) {
238        return formatMap.get(className);
239    }
240
241    public Format createFormat(String clsName, Map<String,Format> newFormats) {
242        throw new IllegalStateException();
243    }
244
245    public Format createFormat(Class type, Map<String,Format> newFormats) {
246        throw new IllegalStateException();
247    }
248
249    public boolean isRawAccess() {
250        return false;
251    }
252
253    public Object convertRawObject(RawObject o, IdentityHashMap converted) {
254        throw new IllegalStateException();
255    }
256}
257