/** * Copyright (C) 2012-2013 Selventa, Inc. * * This file is part of the OpenBEL Framework. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The OpenBEL Framework is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>. * * Additional Terms under LGPL v3: * * This license does not authorize you and you are prohibited from using the * name, trademarks, service marks, logos or similar indicia of Selventa, Inc., * or, in the discretion of other licensors or authors of the program, the * name, trademarks, service marks, logos or similar indicia of such authors or * licensors, in any marketing or advertising materials relating to your * distribution of the program or any covered product. This restriction does * not waive or limit your obligation to keep intact all copyright notices set * forth in the program as delivered to you. * * If you distribute the program in whole or in part, or any modified version * of the program, and you assume contractual liability to the recipient with * respect to the program or modified version, then you will indemnify the * authors and licensors of the program for any liabilities that these * contractual assumptions directly impose on those licensors and authors. */ package org.openbel.framework.common.external; import static java.lang.System.err; import static org.openbel.framework.common.BELUtilities.nulls; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OptionalDataException; /** * This class provides a skeletal implementation of the * {@link CachingExternalizable} interface to minize the effort needed to * externalize a type. * * @since 1.3 */ public abstract class ExternalType implements CachingExternalizable { /** * Reads a {@link String} from the input. * * @param in Non-null {@link ObjectInput} * @return {@link String} * @throws IOException Thrown if an I/O error occurred * @throws ClassNotFoundException Thrown if the class of the object being * read cannot be found */ public static String readString(final ObjectInput in) throws IOException, ClassNotFoundException { try { Object o = in.readObject(); return (String) o; } catch (OptionalDataException e) { StringBuilder bldr = new StringBuilder(); if (e.length == 0) { bldr.append("(attempted to read past end of object data)"); } else { bldr.append("(attempted to read object data when "); bldr.append(e.length); bldr.append(" byte(s) of primitive data is present)"); } err.println(bldr); e.printStackTrace(); throw e; } } /** * Writes the {@link Integer} to the output. * <p> * This method and its equivalent {@link #readInteger(ObjectInput) * read-variant} store {@code i} in a more efficient way than serializing * the {@link Integer} class. * </p> * * @param out Non-null {@link ObjectOutput} * @param i {@link Integer}; may be null * @throws IOException Thrown if an I/O error occurred * @see #readInteger(ObjectInput) */ public static void writeInteger(final ObjectOutput out, final Integer i) throws IOException { if (i == null) { out.writeByte(0); return; } out.writeByte(1); out.writeInt(i); } /** * Writes the potentially null object to output. If {@code o} is null, one * byte is written to the output to indicate that. Otherwise, the written * size is the serialized object size plus an additional byte to indicate * non-null. * <p> * This method doesn't differ in functionality with * {@link ObjectOutput#writeObject(Object)}, including its support for * nulls. It exists as an analogue to the other methods here and as a point * for documenting how nulls are handled. * </p> * * @param out Non-null {@link ObjectOutput} * @param o Object being written * @throws IOException Thrown if an I/O error occurs */ public static void writeObject(final ObjectOutput out, final Object o) throws IOException { if (o == null) { out.writeByte(0); return; } out.writeByte(1); out.writeObject(o); } /** * Reads the potentially null object from input. * <p> * This method doesn't differ in functionality with * {@link ObjectInput#readObject()}, including its support for nulls. It * exists as an analogue to the other methods here and as a point for * documenting how nulls are handled. * </p> * * @param in Non-null {@link ObjectInput} * @return {@link Object} * @throws IOException Thrown if an I/O error occurs * @throws ClassNotFoundException Thrown if the class of the object being * read cannot be found */ public static Object readObject(final ObjectInput in) throws IOException, ClassNotFoundException { byte obyte = in.readByte(); if (obyte == 0) { return null; } return in.readObject(); } /** * Writes the {@link Long} to the output. * <p> * This method and its equivalent {@link #readLong(ObjectInput) * read-variant} store {@code l} in a more efficient way than serializing * the {@link Long} class. * </p> * * @param out Non-null {@link ObjectOutput} * @param l {@link Long}; may be null * @throws IOException Thrown if an I/O error occurred * @see #readLong(ObjectInput) */ public static void writeLong(final ObjectOutput out, final Long l) throws IOException { if (l == null) { out.writeByte(0); return; } out.writeByte(1); out.writeLong(l); } /** * {@inheritDoc} */ @Override public final void writeExternal(ObjectOutput out) throws IOException { _to(out); } /** * {@inheritDoc} */ @Override public final void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { _from(in); } /** * Reads an {@link Integer} from the input. * <p> * This method and its equivalent * {@link #writeInteger(ObjectOutput, Integer) write-variant} store * {@code i} in a more efficient way than serializing the {@link Integer} * class. * </p> * * @param in Non-null {@link ObjectInput} * @return {@link Integer} * @throws IOException Thrown if an I/O error occurred */ public static Integer readInteger(final ObjectInput in) throws IOException { byte b = in.readByte(); if (b == 0) return null; return in.readInt(); } /** * Reads a {@link Long} from the input. * <p> * This method and its equivalent {@link #writeLong(ObjectOutput, Long) * write-variant} store {@code l} in a more efficient way than serializing * the {@link Long} class. * </p> * * @param in Non-null {@link ObjectInput} * @return {@link Long} * @throws IOException Thrown if an I/O error occurred */ public static Long readLong(final ObjectInput in) throws IOException { byte b = in.readByte(); if (b == 0) return null; return in.readLong(); } /** * {@inheritDoc} */ @Override public final void from(File f) throws IOException, ClassNotFoundException { if (nulls(f)) throw new NullPointerException(); FileInputStream fis = null; try { fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis); from(ois); } finally { if (fis != null) fis.close(); } } /** * {@inheritDoc} */ @Override public final void from(File f, ReadCache cache) throws IOException, ClassNotFoundException { if (cache == null) { from(f); return; } if (nulls(f)) throw new NullPointerException(); FileInputStream fis = null; try { fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis); from(ois, cache); } finally { if (fis != null) fis.close(); } } /** * {@inheritDoc} */ @Override public final void from(ObjectInput in) throws IOException, ClassNotFoundException { if (nulls(in)) throw new NullPointerException(); // delegate to the equivalent internal method _from(in); } /** * {@inheritDoc} */ @Override public final void from(ObjectInput in, ReadCache cache) throws IOException, ClassNotFoundException { if (cache == null) { from(in); return; } if (nulls(in)) throw new NullPointerException(); // delegate to the equivalent internal method _from(in, cache); } /** * {@inheritDoc} */ @Override public final void from(String path) throws IOException, ClassNotFoundException { if (nulls(path)) throw new NullPointerException(); from(new File(path)); } /** * {@inheritDoc} */ @Override public final void from(String path, ReadCache cache) throws IOException, ClassNotFoundException { if (cache == null) { from(path); return; } if (nulls(path)) throw new NullPointerException(); FileInputStream fis = null; try { fis = new FileInputStream(new File(path)); ObjectInputStream ois = new ObjectInputStream(fis); from(ois, cache); return; } finally { if (fis != null) fis.close(); } } /** * {@inheritDoc} */ @Override public final void to(File f) throws IOException { if (f == null) throw new NullPointerException(); FileOutputStream fos = null; try { fos = new FileOutputStream(f); ObjectOutputStream oos = new ObjectOutputStream(fos); to(oos); } finally { if (fos != null) fos.close(); } } /** * {@inheritDoc} */ @Override public final void to(File f, WriteCache cache) throws IOException { if (cache == null) { to(f); return; } if (f == null) throw new NullPointerException(); // delegate to the equivalent internal method to(f, cache); } /** * {@inheritDoc} */ @Override public final void to(ObjectOutput out) throws IOException { if (out == null) throw new NullPointerException(); // delegate to the equivalent internal method _to(out); } /** * {@inheritDoc} */ @Override public final void to(ObjectOutput out, WriteCache cache) throws IOException { if (cache == null) { to(out); return; } if (out == null) throw new NullPointerException(); // delegate to the equivalent internal method _to(out, cache); } /** * {@inheritDoc} */ @Override public final void to(String path) throws IOException { if (path == null) throw new NullPointerException(); to(new File(path)); } /** * {@inheritDoc} */ @Override public final void to(String path, WriteCache cache) throws IOException { if (cache == null) { to(path); return; } if (path == null) throw new NullPointerException(); FileOutputStream fos = null; try { fos = new FileOutputStream(new File(path)); ObjectOutputStream oos = new ObjectOutputStream(fos); to(oos, cache); } finally { if (fos != null) fos.close(); } } /** * Reads itself from the input. * * @param in Non-null {@link ObjectInput} * @throws IOException XXX WUTM * @throws ClassNotFoundException XXX WUTM */ protected abstract void _from(ObjectInput in) throws IOException, ClassNotFoundException; /** * Reads itself from the input. The supplied cache is an ancillary structure * allowing the implementing type to reference a cached copy of an object by * its hash value. * <p> * The use of the cache is not required. However the use or disuse of the * cache should be symmetric according to both * {@link #_from(ObjectInput, ReadCache)} and * {@link #_to(ObjectOutput, WriteCache)}. Put differently, the cache use * should be identical in both methods. * </p> * * @param in Non-null {@link ObjectInput} * @param cache Non-null Object {@link ReadCache} * @throws IOException XXX WUTM * @throws ClassNotFoundException XXX WUTM */ protected abstract void _from(ObjectInput in, ReadCache cache) throws IOException, ClassNotFoundException; /** * Writes this to the output. * * @param out {@link ObjectOutput} * @throws IOException XXX WUTM */ protected abstract void _to(ObjectOutput out) throws IOException; /** * Writes this to the output. The supplied cache is an ancillary structure * allowing the implementing type to reference a cached copy of an object by * its hash value. * <p> * The use of the cache is not required. However the use or disuse of the * cache should be symmetric according to both * {@link #to(Object, ObjectOutput, WriteCache)} and * {@link #from(ObjectInput, ReadCache)}. Put differently, the cache use * should be identical in both methods. * </p> * * @param out Non-null {@link ObjectOutput} * @param cache Non-null Object {@link WriteCache} * @throws IOException XXX WUTM */ protected abstract void _to(ObjectOutput out, WriteCache cache) throws IOException; }