package org.marketcetera.util.ws.wrappers; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Serializable; import javax.xml.bind.annotation.XmlTransient; import org.marketcetera.util.misc.ClassVersion; /** * A dual-form wrapper for marshalling a data value via JAXB or * regular Java serialization. One of the two forms is a raw one, * namely the standard class used to represent that value in Java; the * other is a type that can be marshalled via JAXB or Java * serialization. The raw form is null if and only if the marshalled * one is null. * * <p>It is essential to note that the wrapper always maintains this * invariant: the raw and marshalled forms represent the same object * at all times. A consequence of this invariant is that the wrapper * should not be considered an alternate storage container for objects * server-side: if an object cannot be converted to its marshalled * form (e.g. Java serialization fails for {@link SerWrapper}), then * the wrapper will refuse to store that object and will set both the * raw and marshalled forms to null. The wrapper will still get * created and remote these null values to the client, but, on the * server-side, the wrapper will not have retained the raw form.</p> * * <p>The <code>M</code> type parameter should implement {@link * Serializable}, and subclasses of this class need to have a public * empty constructor if this wrapper (or its subclasses) is to be used * for Java Serialization. The former constraint is not enforced by * the class because, if this wrapper is only used for JAXB * marshalling, <code>M</code> need not implement {@link Serializable} * (and the empty constructor's visibility can be more limited).</p> * * @author tlerios@marketcetera.com * @since 1.0.0 * @version $Id: DualWrapper.java 16154 2012-07-14 16:34:05Z colin $ */ /* $License$ */ @ClassVersion("$Id: DualWrapper.java 16154 2012-07-14 16:34:05Z colin $") public abstract class DualWrapper<R,M> extends BaseWrapper<R> implements Externalizable { // CLASS DATA. private static final long serialVersionUID=1L; // INSTANCE DATA. private M mMarshalled; // CONSTRUCTORS. /** * Creates a new wrapper with the given value, in its raw form. It * also sets the internal marshalled form to match. * * @param raw The value in raw form, which may be null. */ public DualWrapper (R raw) { setRaw(raw); } /** * Creates a new wrapper. This empty constructor is intended for * use by JAXB and Java serialization. */ protected DualWrapper() {} // Externalizable. @Override public void writeExternal (ObjectOutput out) throws IOException { out.writeObject(getMarshalled()); } @SuppressWarnings("unchecked") @Override public void readExternal (ObjectInput in) throws IOException, ClassNotFoundException { setMarshalled((M)in.readObject()); } // INSTANCE METHODS. /** * Sets the receiver's data to the given value, in its raw * form. It does not set the internal marshalled form to match. * * @param raw The value in raw form, which may be null. */ protected void setRawOnly (R raw) { setValue(raw); } /** * Sets the receiver's data to the given value, in its raw * form. It also sets the internal marshalled form to match. * * @param raw The value in raw form, which may be null. If the * given value is invalid, it will be replaced by null. */ public void setRaw (R raw) { setRawOnly(raw); if (getRaw()==null) { setMarshalledOnly(null); } else { toMarshalled(); if (getMarshalled()==null) { setRawOnly(null); } } } /** * Returns the receiver's data, in its raw form. * * @return The data, which may be null. */ @XmlTransient public R getRaw() { return getValue(); } /** * Sets the receiver's data to the given value, in its marshalled * form. It does not set the internal raw form to match. * * @param marshalled The value in marshalled form, which may be * null. */ protected void setMarshalledOnly (M marshalled) { mMarshalled=marshalled; } /** * Sets the receiver's data to the given value, in its marshalled * form. It also sets the internal raw form to match. * * @param marshalled The value in marshalled form, which may be * null. If the given value is invalid, it will be replaced by * null. */ public void setMarshalled (M marshalled) { setMarshalledOnly(marshalled); if (getMarshalled()==null) { setRawOnly(null); } else { toRaw(); if (getRaw()==null) { setMarshalledOnly(null); } } } /** * Returns the receiver's data, in its marshalled form. * * @return The data, which may be null. */ public M getMarshalled() { return mMarshalled; } /** * Sets the raw form of the receiver's value so that it * corresponds to its marshalled form. The subclass implementation * can assume that the latter form is non-null. The subclass may * modify both the former and latter forms (for example, if the * latter form is invalid). Only {@link #setRawOnly(Object)} and * {@link #setMarshalledOnly(Object)} should be used in * setting either form, to prevent infinite recursion. The raw * form is null if and only if the marshalled one is null; the * caller of this method will enforce this invariant, so the * subclass implementation can set just the raw form to null. */ protected abstract void toRaw(); /** * Sets the marshalled form of the receiver's value so that it * corresponds to its raw form. The subclass implementation can * assume that the latter form is non-null. The subclass may * modify both the former and latter forms (for example, if the * latter form is invalid). Only {@link #setRawOnly(Object)} and * {@link #setMarshalledOnly(Object)} should be used in setting * either form, to prevent infinite recursion. The raw form is * null if and only if the marshalled one is null; the caller of * this method will enforce this invariant, so the subclass * implementation can set just the marshalled form to null. */ protected abstract void toMarshalled(); }