1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002,2008 Oracle. All rights reserved. 5 * 6 * $Id: Mutations.java,v 1.1 2008/02/07 17:12:27 mark Exp $ 7 */ 8 9package com.sleepycat.persist.evolve; 10 11import java.io.Serializable; 12import java.util.Collection; 13import java.util.HashMap; 14import java.util.Map; 15 16import com.sleepycat.persist.EntityStore; 17import com.sleepycat.persist.StoreConfig; 18 19/** 20 * A collection of mutations for configuring class evolution. 21 * 22 * <p>Mutations are configured when a store is opened via {@link 23 * StoreConfig#setMutations StoreConfig.setMutations}. For example:</p> 24 * 25 * <pre class="code"> 26 * Mutations mutations = new Mutations(); 27 * // Add mutations... 28 * StoreConfig config = new StoreConfig(); 29 * config.setMutations(mutations); 30 * EntityStore store = new EntityStore(env, "myStore", config);</pre> 31 * 32 * <p>Mutations cause data conversion to occur lazily as instances are read 33 * from the store. The {@link EntityStore#evolve EntityStore.evolve} method 34 * may also be used to perform eager conversion.</p> 35 * 36 * <p>Not all incompatible class changes can be handled via mutations. For 37 * example, complex refactoring may require a transformation that manipulates 38 * multiple entity instances at once. Such changes are not possible with 39 * mutations but can made by performing a <a 40 * href="package-summary.html#storeConversion">store conversion</a>.</p> 41 * 42 * @see com.sleepycat.persist.evolve Class Evolution 43 * @author Mark Hayes 44 */ 45public class Mutations implements Serializable { 46 47 private static final long serialVersionUID = -1744401530444812916L; 48 49 private Map<Mutation,Renamer> renamers; 50 private Map<Mutation,Deleter> deleters; 51 private Map<Mutation,Converter> converters; 52 53 /** 54 * Creates an empty set of mutations. 55 */ 56 public Mutations() { 57 renamers = new HashMap<Mutation,Renamer>(); 58 deleters = new HashMap<Mutation,Deleter>(); 59 converters = new HashMap<Mutation,Converter>(); 60 } 61 62 /** 63 * Returns true if no mutations are present. 64 */ 65 public boolean isEmpty() { 66 return renamers.isEmpty() && 67 deleters.isEmpty() && 68 converters.isEmpty(); 69 } 70 71 /** 72 * Adds a renamer mutation. 73 */ 74 public void addRenamer(Renamer renamer) { 75 renamers.put(new Key(renamer), renamer); 76 } 77 78 /** 79 * Returns the renamer mutation for the given class, version and field, or 80 * null if none exists. A null field name should be specified to get a 81 * class renamer. 82 */ 83 public Renamer getRenamer(String className, 84 int classVersion, 85 String fieldName) { 86 return renamers.get(new Key(className, classVersion, fieldName)); 87 } 88 89 /** 90 * Returns an unmodifiable collection of all renamer mutations. 91 */ 92 public Collection<Renamer> getRenamers() { 93 return renamers.values(); 94 } 95 96 /** 97 * Adds a deleter mutation. 98 */ 99 public void addDeleter(Deleter deleter) { 100 deleters.put(new Key(deleter), deleter); 101 } 102 103 /** 104 * Returns the deleter mutation for the given class, version and field, or 105 * null if none exists. A null field name should be specified to get a 106 * class deleter. 107 */ 108 public Deleter getDeleter(String className, 109 int classVersion, 110 String fieldName) { 111 return deleters.get(new Key(className, classVersion, fieldName)); 112 } 113 114 /** 115 * Returns an unmodifiable collection of all deleter mutations. 116 */ 117 public Collection<Deleter> getDeleters() { 118 return deleters.values(); 119 } 120 121 /** 122 * Adds a converter mutation. 123 */ 124 public void addConverter(Converter converter) { 125 converters.put(new Key(converter), converter); 126 } 127 128 /** 129 * Returns the converter mutation for the given class, version and field, 130 * or null if none exists. A null field name should be specified to get a 131 * class converter. 132 */ 133 public Converter getConverter(String className, 134 int classVersion, 135 String fieldName) { 136 return converters.get(new Key(className, classVersion, fieldName)); 137 } 138 139 /** 140 * Returns an unmodifiable collection of all converter mutations. 141 */ 142 public Collection<Converter> getConverters() { 143 return converters.values(); 144 } 145 146 private static class Key extends Mutation { 147 148 Key(String className, int classVersion, String fieldName) { 149 super(className, classVersion, fieldName); 150 } 151 152 Key(Mutation mutation) { 153 super(mutation.getClassName(), 154 mutation.getClassVersion(), 155 mutation.getFieldName()); 156 } 157 } 158 159 /** 160 * Returns true if this collection has the same set of mutations as the 161 * given collection and all mutations are equal. 162 */ 163 @Override 164 public boolean equals(Object other) { 165 if (other instanceof Mutations) { 166 Mutations o = (Mutations) other; 167 return renamers.equals(o.renamers) && 168 deleters.equals(o.deleters) && 169 converters.equals(o.converters); 170 } else { 171 return false; 172 } 173 } 174 175 @Override 176 public int hashCode() { 177 return renamers.hashCode() + 178 deleters.hashCode() + 179 converters.hashCode(); 180 } 181 182 @Override 183 public String toString() { 184 StringBuffer buf = new StringBuffer(); 185 if (renamers.size() > 0) { 186 buf.append(renamers.values()); 187 } 188 if (deleters.size() > 0) { 189 buf.append(deleters.values()); 190 } 191 if (converters.size() > 0) { 192 buf.append(converters.values()); 193 } 194 if (buf.length() > 0) { 195 return buf.toString(); 196 } else { 197 return "[Empty Mutations]"; 198 } 199 } 200} 201