001 /* 002 * Copyright 2011 Christian Kumpe http://kumpe.de/christian/java 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package de.kumpe.hadooptimizer; 017 018 import java.io.ByteArrayInputStream; 019 import java.io.ByteArrayOutputStream; 020 import java.io.IOException; 021 import java.io.ObjectInputStream; 022 import java.io.ObjectOutputStream; 023 import java.io.Serializable; 024 025 import org.apache.commons.math.random.RandomGenerator; 026 import org.apache.commons.math.random.Well44497b; 027 028 /** 029 * The base class of all {@link Optimizer} configurations. 030 * <p> 031 * Subclasses have to override {@link #clone()} to cast the result to themself 032 * and {@link #validate()} to validate them. 033 * 034 * @param <I> 035 * the individuals' type 036 * 037 * @author <a href="http://kumpe.de/christian/java">Christian Kumpe</a> 038 */ 039 public abstract class OptimizerConfiguration<I> implements Serializable, 040 Cloneable { 041 private static final long serialVersionUID = 1L; 042 043 private final static class DefaultRandomGeneratorFactory implements 044 RandomGeneratorFactory { 045 private static final long serialVersionUID = 1L; 046 047 @Override 048 public RandomGenerator createRandomGenerator(final long seed) { 049 return new Well44497b(seed); 050 } 051 052 @Override 053 public int hashCode() { 054 return 0; 055 } 056 057 @Override 058 public boolean equals(final Object obj) { 059 if (null == obj) { 060 return false; 061 } 062 return getClass() == obj.getClass(); 063 } 064 } 065 066 private PopulationReader<I> populationReader; 067 private PopulationWriter<I> populationWriter; 068 private RandomGeneratorFactory randomGeneratorFactory = new DefaultRandomGeneratorFactory(); 069 070 /** 071 * Returns a shallow copy of this configuration. This will not clone the 072 * configuration's components. 073 * <p> 074 * Subclasses should override this method to cast the result to themself. 075 * 076 * @return the shallow copy of this configuration 077 */ 078 @Override 079 @SuppressWarnings("unchecked") 080 public OptimizerConfiguration<I> clone() { 081 try { 082 return (OptimizerConfiguration<I>) super.clone(); 083 } catch (final CloneNotSupportedException e) { 084 throw new AssertionError(); // Can't happen 085 } 086 } 087 088 /** 089 * @return the deep copy of the specified configuration 090 */ 091 public static <I, T extends OptimizerConfiguration<I>> T deepClone( 092 final T original) { 093 try { 094 // serialize 095 final ByteArrayOutputStream bos = new ByteArrayOutputStream(); 096 final ObjectOutputStream oos = new ObjectOutputStream(bos); 097 oos.writeObject(original); 098 oos.close(); 099 100 // deserialize 101 final ByteArrayInputStream bis = new ByteArrayInputStream( 102 bos.toByteArray()); 103 final ObjectInputStream ois = new ObjectInputStream(bis); 104 @SuppressWarnings("unchecked") 105 final T clone = (T) ois.readObject(); 106 ois.close(); 107 108 return clone; 109 } catch (final IOException e) { 110 throw new RuntimeException(e); 111 } catch (final ClassNotFoundException e) { 112 throw new RuntimeException(e); 113 } 114 } 115 116 /** 117 * Validates the configuration for completeness and correctness. 118 * <p> 119 * Subclasses have to override this method, then first call this method from 120 * the superclass and then do their own additional validation. 121 * <p> 122 * Verifies that a {@link #setPopulationReader(PopulationReader) 123 * populationReader} and {@link #setPopulationWriter(PopulationWriter) 124 * populationWriter} has been set. 125 * 126 * @throws IllegalStateException 127 * if this configuration is not valid 128 */ 129 public void validate() { 130 if (null == populationReader) { 131 throw new IllegalStateException( 132 "A PopulatioReader has to be set in the configuration."); 133 } 134 if (null == populationWriter) { 135 throw new IllegalStateException( 136 "A PopulationWriter has to be set in the configuration."); 137 } 138 } 139 140 /** 141 * Will inject the given {@link RandomGenerator} instance into all contained 142 * components which are implementing {@link NeedsRandomGenerator}. 143 * <p> 144 * Subclasses must override this method, if they contain additional 145 * components. Then first call this method from the superclass and then call 146 * {@link #injectRandomGenerator(Object, RandomGenerator)} for their 147 * additional components. 148 * <p> 149 * Calls {@link #injectRandomGenerator(Object, RandomGenerator)} on the 150 * given {@link #setPopulationReader(PopulationReader) populationReader} and 151 * {@link #setPopulationWriter(PopulationWriter) populationWriter}. 152 * 153 * @param randomGenerator 154 * the {@link RandomGenerator} instance to inject 155 */ 156 public void injectRandomGenerator(final RandomGenerator randomGenerator) { 157 injectRandomGenerator(populationReader, randomGenerator); 158 injectRandomGenerator(populationWriter, randomGenerator); 159 } 160 161 /** 162 * Inject the given {@link RandomGenerator} object into the passed 163 * {@code instance}, if {@code instance} is implementing 164 * {@link NeedsRandomGenerator}. 165 * 166 * @param instance 167 * the instance for injecting the {@code randomGenerator}, if 168 * needed 169 * @param randomGenerator 170 * the {@link RandomGenerator} object to inject 171 */ 172 protected final void injectRandomGenerator(final Object instance, 173 final RandomGenerator randomGenerator) { 174 if (instance instanceof NeedsRandomGenerator) { 175 ((NeedsRandomGenerator) instance) 176 .setRandomGenerator(randomGenerator); 177 } 178 } 179 180 /** 181 * @return the configured {@link PopulationReader}; <code>null</code> if 182 * none has been set 183 */ 184 public final PopulationReader<I> getPopulationReader() { 185 return populationReader; 186 } 187 188 /** 189 * @param populationReader 190 * the {@link PopulationReader} for this configuration 191 * 192 * @throws NullPointerException 193 * if {@code populationReader} is <code>null</code> 194 */ 195 public final void setPopulationReader( 196 final PopulationReader<I> populationReader) { 197 if (null == populationReader) { 198 throw new NullPointerException("populationReader may not be null."); 199 } 200 201 this.populationReader = populationReader; 202 } 203 204 /** 205 * @return the configured {@link PopulationWriter}; <code>null</code> if 206 * none has been set 207 */ 208 public final PopulationWriter<I> getPopulationWriter() { 209 return populationWriter; 210 } 211 212 /** 213 * @param populationWriter 214 * the {@link PopulationWriter} for this configuration 215 * 216 * @throws NullPointerException 217 * if {@code populationWriter} is <code>null</code> 218 */ 219 public final void setPopulationWriter( 220 final PopulationWriter<I> populationWriter) { 221 if (null == populationWriter) { 222 throw new NullPointerException("populationWriter may not be null."); 223 } 224 225 this.populationWriter = populationWriter; 226 } 227 228 /** 229 * @return the configured {@link RandomGeneratorFactory}; per default this 230 * returns a factory which creates instances of {@link Well44497b} 231 */ 232 public RandomGeneratorFactory getRandomGeneratorFactory() { 233 assert null != randomGeneratorFactory; 234 235 return randomGeneratorFactory; 236 } 237 238 /** 239 * @param randomGeneratorFactory 240 * the {@link RandomGeneratorFactory} for this configuration 241 * 242 * @throws NullPointerException 243 * if {@code randomGeneratorFactory} is <code>null</code> 244 */ 245 public void setRandomGeneratorFactory( 246 final RandomGeneratorFactory randomGeneratorFactory) { 247 if (null == randomGeneratorFactory) { 248 throw new NullPointerException( 249 "randomGeneratorFactory may not be null."); 250 } 251 252 this.randomGeneratorFactory = randomGeneratorFactory; 253 } 254 255 @Override 256 public int hashCode() { 257 assert null != randomGeneratorFactory; 258 259 final int prime = 31; 260 int result = 1; 261 result = prime * result 262 + (populationReader == null ? 0 : populationReader.hashCode()); 263 result = prime * result 264 + (populationWriter == null ? 0 : populationWriter.hashCode()); 265 result = prime * result + randomGeneratorFactory.hashCode(); 266 return result; 267 } 268 269 @Override 270 public boolean equals(final Object obj) { 271 assert null != randomGeneratorFactory; 272 273 if (this == obj) { 274 return true; 275 } 276 if (obj == null) { 277 return false; 278 } 279 if (!(obj instanceof OptimizerConfiguration)) { 280 return false; 281 } 282 final OptimizerConfiguration<?> other = (OptimizerConfiguration<?>) obj; 283 if (populationReader == null) { 284 if (other.populationReader != null) { 285 return false; 286 } 287 } else if (!populationReader.equals(other.populationReader)) { 288 return false; 289 } 290 if (populationWriter == null) { 291 if (other.populationWriter != null) { 292 return false; 293 } 294 } else if (!populationWriter.equals(other.populationWriter)) { 295 return false; 296 } 297 return randomGeneratorFactory.equals(other.randomGeneratorFactory); 298 } 299 }