Object rep = super.send(data);
if (rep instanceof RemoteLibraryException) {
RemoteLibraryException remoteEx = (RemoteLibraryException) rep;
- IOException cause = remoteEx.getCause();
- if (cause == null) {
- cause = new IOException("IOException");
- }
-
- throw cause;
+ throw remoteEx.unwrapException();
}
return rep;
/**
* Stop the server.
+ *
+ * @throws IOException
+ * in case of I/O error (including bad key)
*/
public void exit() throws IOException {
connectRemoteAction(new RemoteAction() {
public class RemoteLibraryException extends IOException {
private static final long serialVersionUID = 1L;
+ private boolean wrapped;
+
+ @SuppressWarnings("unused")
private RemoteLibraryException() {
// for serialization purposes
}
* Wrap an {@link IOException} to allow it to pass across the network.
*
* @param cause
- * the excption to wrap
+ * the exception to wrap
+ * @param remote
+ * this exception is used to send the contained
+ * {@link IOException} to the other end of the network
+ */
+ public RemoteLibraryException(IOException cause, boolean remote) {
+ this(null, cause, remote);
+ }
+
+ /**
+ * Wrap an {@link IOException} to allow it to pass across the network.
+ *
+ * @param message
+ * the error message
+ * @param wrapped
+ * this exception is used to send the contained
+ * {@link IOException} to the other end of the network
*/
- public RemoteLibraryException(IOException cause) {
- super(cause);
+ public RemoteLibraryException(String message, boolean wrapped) {
+ this(message, null, wrapped);
}
- @Override
- public synchronized IOException getCause() {
- return (IOException) super.getCause();
+ /**
+ * Wrap an {@link IOException} to allow it to pass across the network.
+ *
+ * @param message
+ * the error message
+ * @param cause
+ * the exception to wrap
+ * @param wrapped
+ * this exception is used to send the contained
+ * {@link IOException} to the other end of the network
+ */
+ public RemoteLibraryException(String message, IOException cause,
+ boolean wrapped) {
+ super(message, cause);
+ this.wrapped = wrapped;
+ }
+
+ /**
+ * Return the actual exception we should return to the client code. It can
+ * be:
+ * <ul>
+ * <li>the <tt>cause</tt> if {@link RemoteLibraryException#isWrapped()} is
+ * TRUE</li>
+ * <li><tt>this</tt> if {@link RemoteLibraryException#isWrapped()} is FALSE
+ * (</li>
+ * <li><tt>this</tt> if the <tt>cause</tt> is NULL (so we never return NULL)
+ * </li>
+ * </ul>
+ * It is never NULL.
+ *
+ * @return the unwrapped exception or <tt>this</tt>, never NULL
+ */
+ public synchronized IOException unwrapException() {
+ Throwable ex = super.getCause();
+ if (!isWrapped() || !(ex instanceof IOException)) {
+ ex = this;
+ }
+
+ return (IOException) ex;
+ }
+
+ /**
+ * This exception is used to send the contained {@link IOException} to the
+ * other end of the network.
+ * <p>
+ * In other words, do not use <tt>this</tt> exception in client code when it
+ * has reached the other end of the network, but use its cause instead (see
+ * {@link RemoteLibraryException#unwrapException()}).
+ *
+ * @return TRUE if it is
+ */
+ public boolean isWrapped() {
+ return wrapped;
}
}
import java.io.IOException;
import java.net.URL;
-import java.rmi.AccessException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
try {
rep = doRequest(action, command, args, rw, whitelist);
} catch (IOException e) {
- rep = new RemoteLibraryException(e);
+ rep = new RemoteLibraryException(e, true);
}
commands.put(id, command);
}
} else if ("SAVE_STORY".equals(command)) {
if (!rw) {
- throw new AccessException("Read-Only remote library: "
- + args[0]);
+ throw new RemoteLibraryException("Read-Only remote library: "
+ + args[0], false);
}
List<Object> list = new ArrayList<Object>();
return story.getMeta().getLuid();
} else if ("IMPORT".equals(command)) {
if (!rw) {
- throw new AccessException("Read-Only remote library: "
- + args[0]);
+ throw new RemoteLibraryException("Read-Only remote library: "
+ + args[0], false);
}
Progress pg = createPgForwarder(action);
return story.getMeta().getLuid();
} else if ("DELETE_STORY".equals(command)) {
if (!rw) {
- throw new AccessException("Read-Only remote library: "
- + args[0]);
+ throw new RemoteLibraryException("Read-Only remote library: "
+ + args[0], false);
}
Instance.getLibrary().delete((String) args[0]);
}
} else if ("SET_COVER".equals(command)) {
if (!rw) {
- throw new AccessException("Read-Only remote library: "
- + args[0] + ", " + args[1]);
+ throw new RemoteLibraryException("Read-Only remote library: "
+ + args[0] + ", " + args[1], false);
}
if ("SOURCE".equals(args[0])) {
}
} else if ("CHANGE_STA".equals(command)) {
if (!rw) {
- throw new AccessException("Read-Only remote library: "
- + args[0] + ", " + args[1]);
+ throw new RemoteLibraryException("Read-Only remote library: "
+ + args[0] + ", " + args[1], false);
}
Progress pg = createPgForwarder(action);
forcePgDoneSent(pg);
} else if ("EXIT".equals(command)) {
if (!rw) {
- throw new AccessException(
- "Read-Only remote library: EXIT");
+ throw new RemoteLibraryException(
+ "Read-Only remote library: EXIT", false);
}
stop(0, false);