001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: EnumFormat.java,v 1.18.2.4 2008/01/07 15:14:19 cwl Exp $
007: */
008:
009: package com.sleepycat.persist.impl;
010:
011: import java.lang.reflect.Array;
012: import java.util.Arrays;
013: import java.util.HashSet;
014: import java.util.IdentityHashMap;
015: import java.util.List;
016: import java.util.Map;
017: import java.util.Set;
018:
019: import com.sleepycat.persist.raw.RawObject;
020:
021: /**
022: * Format for all enum types.
023: *
024: * In this class we resort to using reflection to allocate arrays of enums.
025: * If there is a need for it, reflection could be avoided in the future by
026: * generating code as new array formats are encountered.
027: *
028: * @author Mark Hayes
029: */
030: public class EnumFormat extends Format {
031:
032: private static final long serialVersionUID = 1069833955604373538L;
033:
034: private String[] names;
035: private transient Object[] values;
036:
037: EnumFormat(Class type) {
038: super (type);
039: values = type.getEnumConstants();
040: names = new String[values.length];
041: for (int i = 0; i < names.length; i += 1) {
042: names[i] = ((Enum) values[i]).name();
043: }
044: }
045:
046: @Override
047: public boolean isEnum() {
048: return true;
049: }
050:
051: @Override
052: public List<String> getEnumConstants() {
053: return Arrays.asList(names);
054: }
055:
056: @Override
057: void collectRelatedFormats(Catalog catalog,
058: Map<String, Format> newFormats) {
059: }
060:
061: @Override
062: void initialize(Catalog catalog, int initVersion) {
063: if (values == null) {
064: Class cls = getType();
065: if (cls != null) {
066: values = new Object[names.length];
067: for (int i = 0; i < names.length; i += 1) {
068: values[i] = Enum.valueOf(cls, names[i]);
069: }
070: }
071: }
072: }
073:
074: @Override
075: Object newArray(int len) {
076: return Array.newInstance(getType(), len);
077: }
078:
079: @Override
080: public Object newInstance(EntityInput input, boolean rawAccess) {
081: int index = input.readEnumConstant(names);
082: if (rawAccess) {
083: return new RawObject(this , names[index]);
084: } else {
085: return values[index];
086: }
087: }
088:
089: @Override
090: public Object readObject(Object o, EntityInput input,
091: boolean rawAccess) {
092: /* newInstance reads the value -- do nothing here. */
093: return o;
094: }
095:
096: @Override
097: void writeObject(Object o, EntityOutput output, boolean rawAccess) {
098: if (rawAccess) {
099: String name = ((RawObject) o).getEnum();
100: for (int i = 0; i < names.length; i += 1) {
101: if (names[i].equals(name)) {
102: output.writeEnumConstant(names, i);
103: return;
104: }
105: }
106: } else {
107: for (int i = 0; i < values.length; i += 1) {
108: if (o == values[i]) {
109: output.writeEnumConstant(names, i);
110: return;
111: }
112: }
113: }
114: throw new IllegalStateException("Bad enum: " + o);
115: }
116:
117: @Override
118: Object convertRawObject(Catalog catalog, boolean rawAccess,
119: RawObject rawObject, IdentityHashMap converted) {
120: String name = rawObject.getEnum();
121: for (int i = 0; i < names.length; i += 1) {
122: if (names[i].equals(name)) {
123: Object o = values[i];
124: converted.put(rawObject, o);
125: return o;
126: }
127: }
128: throw new IllegalArgumentException(
129: "Enum constant is not defined: " + name);
130: }
131:
132: @Override
133: void skipContents(RecordInput input) {
134: input.skipFast(input.getPackedIntByteLength());
135: }
136:
137: @Override
138: boolean evolve(Format newFormatParam, Evolver evolver) {
139: if (!(newFormatParam instanceof EnumFormat)) {
140: evolver
141: .addEvolveError(this , newFormatParam,
142: "Incompatible enum type changed detected",
143: "An enum class may not be changed to a non-enum type");
144: /* For future:
145: evolver.addMissingMutation
146: (this, newFormatParam,
147: "Converter is required when an enum class is changed to " +
148: "a non-enum type");
149: */
150: return false;
151: }
152: EnumFormat newFormat = (EnumFormat) newFormatParam;
153: if (Arrays.equals(names, newFormat.names)) {
154: evolver.useOldFormat(this , newFormat);
155: return true;
156: } else {
157: Set<String> oldNames = new HashSet<String>(Arrays
158: .asList(names));
159: List<String> newNames = Arrays.asList(newFormat.names);
160: if (newNames.containsAll(oldNames)) {
161: evolver.useEvolvedFormat(this , newFormat, newFormat);
162: return true;
163: } else {
164: oldNames.removeAll(newNames);
165: evolver.addEvolveError(this , newFormat,
166: "Incompatible enum type changed detected",
167: "Enum values may not be removed: " + oldNames);
168: /* For future:
169: evolver.addMissingMutation
170: (this, newFormatParam,
171: "Converter is required when a value is removed from an " +
172: "enum: " + oldNames);
173: */
174: return false;
175: }
176: }
177: }
178: }
|