package org.marketcetera.util.ws.wrappers; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import org.apache.commons.lang.ObjectUtils; import org.marketcetera.util.log.SLF4JLoggerProxy; import org.marketcetera.util.misc.ClassVersion; /** * A remote exception. It wraps any {@link Throwable} in a manner that * enables its marshalling using JAXB in the context of web service * faults, or for use by Java serialization in other contexts; this is * done by serializing the throwable and marshalling it using a {@link * SerWrapper}. On the server side, this class sets the wrapped * throwable as its cause. This also happens on the client side, * provided the client runs in a JVM which is able to deserialize the * throwable (because it has the right resources and classes available * in its classpath). Otherwise, the cause is an instance of {@link * RemoteProxyException}, which encapsulates the throwable's most * important information, as conveyed via a {@link RemoteProperties} * instance. * * <p>Equality and hash code generation rely only on a temporary * {@link RemoteProperties} instance created for comparison purposes * from the receiver's cause; notably, the class of the cause is * ignored.</p> * * @author tlerios@marketcetera.com * @since 1.0.0 * @version $Id: RemoteException.java 16841 2014-02-20 19:59:04Z colin $ */ /* $License$ */ @ClassVersion("$Id: RemoteException.java 16841 2014-02-20 19:59:04Z colin $") public class RemoteException extends Exception implements Externalizable { // CLASS DATA. private static final long serialVersionUID=1L; // INSTANCE DATA. private RemoteProperties mProperties; // CONSTRUCTORS. /** * Creates a new exception that wraps the given throwable. * * @param t The throwable, which may be null. */ public RemoteException (Throwable t) { this(); if (t==null) { return; } setProperties(new RemoteProperties(t)); SLF4JLoggerProxy.warn(this, t); } /** * Creates a new exception. This empty constructor is intended for * use by JAXB and Java serialization. */ public RemoteException() { super(Messages.REMOTE_EXCEPTION.getText()); } // INSTANCE METHODS. /** * Set the receiver's properties to the given ones. This method * can only be called once with a non-null argument because a side * effect is that it sets the receiver's cause based on its * non-null argument. * * @param properties The properties, which may be null. */ public void setProperties (RemoteProperties properties) { mProperties=properties; if (properties==null) { return; } initCause(getProperties().getThrowable()); } /** * Returns the receiver's properties. * * @return The properties, which may be null. */ public RemoteProperties getProperties() { return mProperties; } // Externalizable. @Override public void writeExternal (ObjectOutput out) throws IOException { out.writeObject(getProperties()); } @Override public void readExternal (ObjectInput in) throws IOException, ClassNotFoundException { setProperties((RemoteProperties)in.readObject()); } // Exception. @Override public int hashCode() { if (getCause()==null) { return 0; } return ObjectUtils.hashCode(new RemoteProperties(getCause())); } @Override public boolean equals (Object other) { if (this==other) { return true; } if ((other==null) || !getClass().equals(other.getClass())) { return false; } RemoteException o=(RemoteException)other; if (getCause()==null) { if (o.getCause()==null) { return true; } return false; } else if (o.getCause()==null) { return false; } return ObjectUtils.equals(new RemoteProperties(getCause()), new RemoteProperties(o.getCause())); } }