IO.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.9.0).
003  * Copyright (c) 2007-2017 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019  */
020 package org.jenetics.util;
021 
022 import static org.jenetics.internal.util.JAXBContextCache.context;
023 import static org.jenetics.internal.util.jaxb.adapterFor;
024 import static org.jenetics.internal.util.jaxb.marshal;
025 
026 import java.io.File;
027 import java.io.FileInputStream;
028 import java.io.FileOutputStream;
029 import java.io.IOException;
030 import java.io.InputStream;
031 import java.io.ObjectInputStream;
032 import java.io.ObjectOutputStream;
033 import java.io.OutputStream;
034 import java.nio.file.Path;
035 import java.util.Arrays;
036 
037 import javax.xml.bind.Marshaller;
038 import javax.xml.bind.Unmarshaller;
039 import javax.xml.bind.annotation.adapters.XmlAdapter;
040 
041 import org.jenetics.internal.util.JAXBContextCache;
042 import org.jenetics.internal.util.require;
043 
044 /**
045  * Class for object serialization. The following example shows how to write and
046  * reload a given population.
047  *
048  <pre>{@code
049  * // Creating result population.
050  * EvolutionResult<DoubleGene, Double> result = stream
051  *     .collect(toBestEvolutionResult());
052  *
053  * // Writing the population to disk.
054  * final File file = new File("population.xml");
055  * IO.jaxb.write(result.getPopulation(), file);
056  *
057  * // Reading the population from disk.
058  * Population<DoubleGene, Double> population =
059  *     (Population<DoubleGene, Double>)IO.jaxb.read(file);
060  * EvolutionStream<DoubleGene, Double> stream = Engine
061  *     .build(ff, gtf)
062  *     .stream(population, 1);
063  * }</pre>
064  *
065  * The {@code jaxb} marshalling also allows to read and write own classes. For
066  * this you have to register your {@code @XmlType}d class first.
067  <pre>{@code
068  * // The user defined 'JAXB' model class.
069  * \@XmlRootElement(name = "data-class")
070  * \@XmlType(name = "DataClass")
071  * \@XmlAccessorType(XmlAccessType.FIELD)
072  * public static final class DataClass {
073  *     \@XmlAttribute public String name;
074  *     \@XmlValue public String value;
075  * }
076  *
077  * // Register the 'JAXB' model class.
078  * IO.JAXB.register(DataClass.class);
079  * final DataClass data = ...;
080  * IO.jaxb.write(data, "data.xml");
081  * }</pre>
082  *
083  * It is safe to call {@code IO.JAXB.register(DataClass.class)} more than once.
084  *
085  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
086  @since 1.0
087  @version 3.5
088  */
089 public abstract class IO {
090 
091     protected IO() {
092     }
093 
094     /**
095      * Helper class for <em>JAXB</em> class registering/de-registering.
096      *
097      <pre>{@code
098      * // The user defined 'JAXB' model class.
099      * \@XmlRootElement(name = "data-class")
100      * \@XmlType(name = "DataClass")
101      * \@XmlAccessorType(XmlAccessType.FIELD)
102      * public static final class DataClass {
103      *     \@XmlAttribute public String name;
104      *     \@XmlValue public String value;
105      * }
106      *
107      * // Register the 'JAXB' model class.
108      * IO.JAXB.register(DataClass.class);
109      * final DataClass data = ...;
110      * IO.jaxb.write(data, "data.xml");
111      * }</pre>
112      *
113      * It is safe to call {@code IO.JAXB.register(DataClass.class)} more than
114      * once.
115      *
116      @deprecated Since the {@code javax.xml.bind} is marked as deprecated for
117      *             removal in Java 9, the JAXB marshalling will be removed as
118      *             well. Use the {@code org.jenetics.xml} module when writing
119      *             and reading Jenetics data-objects as XML.
120      *
121      @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
122      @since 3.5
123      @version 3.5
124      */
125     @Deprecated
126     public static final class JAXB {
127         private JAXB() {require.noInstance();}
128 
129         /**
130          * Registers the given <em>JAXB</em> model classes. This allows to use
131          * the {@code IO.jaxb} class with own <em>JAXB</em> marshallings.
132          <p>
133          <em>It is safe to call this method more than once for a given class.
134          * The class is registered only once.</em>
135          *
136          @param classes the <em>JAXB</em> model classes to register
137          @throws NullPointerException if one of the classes is {@code null}
138          */
139         public static void register(final Class<?>... classes) {
140             Arrays.asList(classes).forEach(JAXBContextCache::add);
141         }
142 
143         /**
144          * De-registers the given <em>JAXB</em> model classes.
145          *
146          @param classes the <em>JAXB</em> model classes to register
147          @throws NullPointerException if one of the classes is {@code null}
148          */
149         public static void deregister(final Class<?>... classes) {
150             Arrays.asList(classes).forEach(JAXBContextCache::remove);
151         }
152 
153         /**
154          * Check is the given class is already registered.
155          *
156          @param cls the class to check
157          @return {@code true} if the given class is already registered,
158          *         {@code false} otherwise.
159          */
160         public static boolean contains(final Class<?> cls) {
161             return JAXBContextCache.contains(cls);
162         }
163     }
164 
165     /**
166      * JAXB for <i>XML</i> serialization.
167      *
168      @deprecated Since the {@code javax.xml.bind} is marked as deprecated for
169      *             removal in Java 9, the JAXB marshalling will be removed as
170      *             well. Use the {@code org.jenetics.xml} module when writing
171      *             and reading Jenetics data-objects as XML.
172      */
173     @Deprecated
174     public static final IO jaxb = new IO() {
175 
176         @Override
177         public void write(final Object object, final OutputStream out)
178             throws IOException
179         {
180             try {
181                 final Marshaller marshaller = context().createMarshaller();
182                 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
183                 marshaller.marshal(marshal(object), out);
184             catch (Exception e) {
185                 throw new IOException(e);
186             }
187         }
188 
189         @Override
190         public <T> T read(final Class<T> type, final InputStream in)
191             throws IOException
192         {
193             try {
194                 final Unmarshaller unmarshaller = context().createUnmarshaller();
195 
196                 //final XMLInputFactory factory = XMLInputFactory.newInstance();
197                 //final XMLStreamReader reader = factory.createXMLStreamReader(in);
198                 //try {
199                     final Object object = unmarshaller.unmarshal(in);
200                     final XmlAdapter<Object, Object> adapter = adapterFor(object);
201                     if (adapter != null) {
202                         return type.cast(adapter.unmarshal(object));
203                     else {
204                         return type.cast(object);
205                     }
206                 //} finally {
207                 //    reader.close();
208                 //}
209             catch (Exception e) {
210                 throw new IOException(e);
211             }
212         }
213     };
214 
215     /**
216      * IO implementation for "native" <i>Java</i> serialization.
217      */
218     public static final IO object = new IO() {
219 
220         @Override
221         public void write(final Object object, final OutputStream out)
222             throws IOException
223         {
224             final ObjectOutputStream oout = new ObjectOutputStream(out);
225             oout.writeObject(object);
226             out.flush();
227         }
228 
229         @Override
230         public <T> T read(final Class<T> type, final InputStream in)
231             throws IOException
232         {
233             final ObjectInputStream oin = new ObjectInputStream(in);
234             try {
235                 return type.cast(oin.readObject());
236             catch (ClassNotFoundException | ClassCastException e) {
237                 throw new IOException(e);
238             }
239         }
240     };
241 
242 
243     /**
244      * Write the (serializable) object to the given path.
245      *
246      @param object the object to serialize.
247      @param path the path to write the object to.
248      @throws NullPointerException if one of the arguments is {@code null}.
249      @throws IOException if the object could not be serialized.
250      */
251     public void write(final Object object, final String path)
252         throws IOException
253     {
254         write(object, new File(path));
255     }
256 
257     /**
258      * Write the (serializable) object to the given path.
259      *
260      @param object the object to serialize.
261      @param path the path to write the object to.
262      @throws NullPointerException if one of the arguments is {@code null}.
263      @throws IOException if the object could not be serialized.
264      */
265     public void write(final Object object, final Path path)
266         throws IOException
267     {
268         write(object, path.toFile());
269     }
270 
271     /**
272      * Write the (serializable) object to the given file.
273      *
274      @param object the object to serialize.
275      @param file the file to write the object to.
276      @throws NullPointerException if one of the arguments is {@code null}.
277      @throws IOException if the object could not be serialized.
278      */
279     public void write(final Object object, final File file)
280         throws IOException
281     {
282         try (final FileOutputStream out = new FileOutputStream(file)) {
283             write(object, out);
284         }
285     }
286 
287     /**
288      * Write the (serializable) object to the given output stream.
289      *
290      @param object the object to serialize.
291      @param out the output stream to write the object to.
292      @throws NullPointerException if one of the arguments is {@code null}.
293      @throws IOException if the object could not be serialized.
294      */
295     public abstract void write(final Object object, final OutputStream out)
296         throws IOException;
297 
298     /**
299      * Reads an object from the given file.
300      *
301      @param <T> the type of the read object
302      @param path the path to read from.
303      @param type the type of the read object.
304      @return the de-serialized object.
305      @throws NullPointerException if the input stream {@code in} is {@code null}.
306      @throws IOException if the object could not be read.
307      */
308     public <T> T read(final Class<T> type, final String path)
309         throws IOException
310     {
311         try (final FileInputStream in = new FileInputStream(new File(path))) {
312             return read(type, in);
313         }
314     }
315 
316     /**
317      * Reads an object from the given file.
318      *
319      @param path the path to read from.
320      @return the de-serialized object.
321      @throws NullPointerException if the input stream {@code in} is {@code null}.
322      @throws IOException if the object could not be read.
323      */
324     public Object read(final String paththrows IOException {
325         return read(Object.class, path);
326     }
327 
328     /**
329      * Reads an object from the given file.
330      *
331      @param <T> the type of the read object
332      @param path the path to read from.
333      @param type the type of the read object.
334      @return the de-serialized object.
335      @throws NullPointerException if the input stream {@code in} is {@code null}.
336      @throws IOException if the object could not be read.
337      */
338     public <T> T read(final Class<T> type, final Path path)
339         throws IOException
340     {
341         try (final FileInputStream in = new FileInputStream(path.toFile())) {
342             return read(type, in);
343         }
344     }
345 
346     /**
347      * Reads an object from the given file.
348      *
349      @param path the path to read from.
350      @return the de-serialized object.
351      @throws NullPointerException if the input stream {@code in} is {@code null}.
352      @throws IOException if the object could not be read.
353      */
354     public Object read(final Path paththrows IOException {
355         return read(Object.class, path);
356     }
357 
358     /**
359      * Reads an object from the given file.
360      *
361      @param <T> the type of the read object
362      @param file the file to read from.
363      @param type the type of the read object.
364      @return the de-serialized object.
365      @throws NullPointerException if the input stream {@code in} is {@code null}.
366      @throws IOException if the object could not be read.
367      */
368     public <T> T read(final Class<T> type, final File file)
369         throws IOException
370     {
371         try (final FileInputStream in = new FileInputStream(file)) {
372             return read(type, in);
373         }
374     }
375 
376     /**
377      * Reads an object from the given file.
378      *
379      @param file the file to read from.
380      @return the de-serialized object.
381      @throws NullPointerException if the input stream {@code in} is {@code null}.
382      @throws IOException if the object could not be read.
383      */
384     public Object read(final File filethrows IOException {
385         return read(Object.class, file);
386     }
387 
388     /**
389      * Reads an object from the given input stream.
390      *
391      @param <T> the type of the read object
392      @param in the input stream to read from.
393      @param type the type of the read object.
394      @return the de-serialized object.
395      @throws NullPointerException if the input stream {@code in} is {@code null}.
396      @throws IOException if the object could not be read.
397      */
398     public abstract <T> T read(final Class<T> type, final InputStream in)
399         throws IOException;
400 
401     /**
402      * Reads an object from the given input stream.
403      *
404      @param in the input stream to read from.
405      @return the de-serialized object.
406      @throws NullPointerException if the input stream {@code in} is {@code null}.
407      @throws IOException if the object could not be read.
408      */
409     public Object read(final InputStream inthrows IOException {
410         return read(Object.class, in);
411     }
412 }