/* * Copyright 2014 Cel Skeggs * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE 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 CCRE 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 CCRE. If not, see <http://www.gnu.org/licenses/>. */ package ccre.cluck.rpc; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import ccre.log.Logger; import ccre.time.Time; import ccre.verifier.SetupPhase; /** * A simple implementation of RemoteProcedure that takes care of returning * results for the implementation. * * This is not suitable for blocking invocations! * * Also in this class is a method that will invoke a procedure with specified * arguments and return the data from it, to match the simplicity of a * SimpleProcedure. * * @author skeggsc */ public abstract class SimpleProcedure implements RemoteProcedure { /** * The result returned when a SimpleProcedure call times out. */ public static final Object TIMED_OUT = null; /** * Invoke the specified RemoteProcedure with the specified byte array and * return the result, or null (TIMED_OUT) if the request times out. * * @param rp The procedure to invoke. * @param in The input to pass it. * @param timeout The maximum number of milliseconds to wait. (Note: zero * means don't wait for a result, not wait indefinitely.) * @return The output from the procedure, or null if the request times out. * @throws java.lang.InterruptedException If the current thread is * interrupted while waiting for a response. * @see #TIMED_OUT */ @SetupPhase public static byte[] invoke(RemoteProcedure rp, byte[] in, int timeout) throws InterruptedException { final boolean[] b = new boolean[1]; final Object invk = new Object(); ByteArrayOutputStream out = new ByteArrayOutputStream() { @Override public void close() { synchronized (invk) { b[0] = true; invk.notifyAll(); } } }; rp.invoke(in, out); if (!b[0]) { synchronized (invk) { long endAt = Time.currentTimeMillis() + timeout; while (!b[0]) { long now = Time.currentTimeMillis(); if (now >= endAt) { break; } Time.wait(invk, endAt - now); } } if (!b[0]) { return (byte[]) TIMED_OUT; } } return out.toByteArray(); } @Override public final void invoke(byte[] in, OutputStream out) { try { out.write(invoke(in)); out.close(); } catch (IOException ex) { Logger.warning("IO Exception during response from SimpleProcedure!", ex); } } /** * Implement this to implement a non-blocking procedure, that reads in data * from the argument and returns data to give to the sender. * * @param in The inputs to the procedure. * @return The results from the procedure. */ @SetupPhase protected abstract byte[] invoke(byte[] in); }