001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: Mutations.java,v 1.12.2.2 2008/01/07 15:14:19 cwl Exp $
007: */
008:
009: package com.sleepycat.persist.evolve;
010:
011: import java.io.Serializable;
012: import java.util.Collection;
013: import java.util.HashMap;
014: import java.util.Map;
015:
016: import com.sleepycat.persist.EntityStore;
017: import com.sleepycat.persist.StoreConfig;
018:
019: /**
020: * A collection of mutations for configuring class evolution.
021: *
022: * <p>Mutations are configured when a store is opened via {@link
023: * StoreConfig#setMutations StoreConfig.setMutations}. For example:</p>
024: *
025: * <pre class="code">
026: * Mutations mutations = new Mutations();
027: * // Add mutations...
028: * StoreConfig config = new StoreConfig();
029: * config.setMutations(mutations);
030: * EntityStore store = new EntityStore(env, "myStore", config);</pre>
031: *
032: * <p>Mutations cause data conversion to occur lazily as instances are read
033: * from the store. The {@link EntityStore#evolve EntityStore.evolve} method
034: * may also be used to perform eager conversion.</p>
035: *
036: * <p>Not all incompatible class changes can be handled via mutations. For
037: * example, complex refactoring may require a transformation that manipulates
038: * multiple entity instances at once. Such changes are not possible with
039: * mutations but can made by performing a <a
040: * href="package-summary.html#storeConversion">store conversion</a>.</p>
041: *
042: * @see com.sleepycat.persist.evolve Class Evolution
043: * @author Mark Hayes
044: */
045: public class Mutations implements Serializable {
046:
047: private static final long serialVersionUID = -1744401530444812916L;
048:
049: private Map<Mutation, Renamer> renamers;
050: private Map<Mutation, Deleter> deleters;
051: private Map<Mutation, Converter> converters;
052:
053: /**
054: * Creates an empty set of mutations.
055: */
056: public Mutations() {
057: renamers = new HashMap<Mutation, Renamer>();
058: deleters = new HashMap<Mutation, Deleter>();
059: converters = new HashMap<Mutation, Converter>();
060: }
061:
062: /**
063: * Returns true if no mutations are present.
064: */
065: public boolean isEmpty() {
066: return renamers.isEmpty() && deleters.isEmpty()
067: && converters.isEmpty();
068: }
069:
070: /**
071: * Adds a renamer mutation.
072: */
073: public void addRenamer(Renamer renamer) {
074: renamers.put(new Key(renamer), renamer);
075: }
076:
077: /**
078: * Returns the renamer mutation for the given class, version and field, or
079: * null if none exists. A null field name should be specified to get a
080: * class renamer.
081: */
082: public Renamer getRenamer(String className, int classVersion,
083: String fieldName) {
084: return renamers
085: .get(new Key(className, classVersion, fieldName));
086: }
087:
088: /**
089: * Returns an unmodifiable collection of all renamer mutations.
090: */
091: public Collection<Renamer> getRenamers() {
092: return renamers.values();
093: }
094:
095: /**
096: * Adds a deleter mutation.
097: */
098: public void addDeleter(Deleter deleter) {
099: deleters.put(new Key(deleter), deleter);
100: }
101:
102: /**
103: * Returns the deleter mutation for the given class, version and field, or
104: * null if none exists. A null field name should be specified to get a
105: * class deleter.
106: */
107: public Deleter getDeleter(String className, int classVersion,
108: String fieldName) {
109: return deleters
110: .get(new Key(className, classVersion, fieldName));
111: }
112:
113: /**
114: * Returns an unmodifiable collection of all deleter mutations.
115: */
116: public Collection<Deleter> getDeleters() {
117: return deleters.values();
118: }
119:
120: /**
121: * Adds a converter mutation.
122: */
123: public void addConverter(Converter converter) {
124: converters.put(new Key(converter), converter);
125: }
126:
127: /**
128: * Returns the converter mutation for the given class, version and field,
129: * or null if none exists. A null field name should be specified to get a
130: * class converter.
131: */
132: public Converter getConverter(String className, int classVersion,
133: String fieldName) {
134: return converters.get(new Key(className, classVersion,
135: fieldName));
136: }
137:
138: /**
139: * Returns an unmodifiable collection of all converter mutations.
140: */
141: public Collection<Converter> getConverters() {
142: return converters.values();
143: }
144:
145: private static class Key extends Mutation {
146:
147: Key(String className, int classVersion, String fieldName) {
148: super (className, classVersion, fieldName);
149: }
150:
151: Key(Mutation mutation) {
152: super (mutation.getClassName(), mutation.getClassVersion(),
153: mutation.getFieldName());
154: }
155: }
156:
157: /**
158: * Returns true if this collection has the same set of mutations as the
159: * given collection and all mutations are equal.
160: */
161: @Override
162: public boolean equals(Object other) {
163: if (other instanceof Mutations) {
164: Mutations o = (Mutations) other;
165: return renamers.equals(o.renamers)
166: && deleters.equals(o.deleters)
167: && converters.equals(o.converters);
168: } else {
169: return false;
170: }
171: }
172:
173: @Override
174: public int hashCode() {
175: return renamers.hashCode() + deleters.hashCode()
176: + converters.hashCode();
177: }
178:
179: @Override
180: public String toString() {
181: StringBuffer buf = new StringBuffer();
182: if (renamers.size() > 0) {
183: buf.append(renamers.values());
184: }
185: if (deleters.size() > 0) {
186: buf.append(deleters.values());
187: }
188: if (converters.size() > 0) {
189: buf.append(converters.values());
190: }
191: if (buf.length() > 0) {
192: return buf.toString();
193: } else {
194: return "[Empty Mutations]";
195: }
196: }
197: }
|