/* * Minha.pt: middleware testing platform. * Copyright (c) 2011-2014, Universidade do Minho. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package pt.minha.api.sim; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.TimeUnit; import pt.minha.api.Entry; import pt.minha.api.Process; import pt.minha.models.global.EntryHandler; import pt.minha.models.global.ResultHolder; class EntryImpl<T> extends MilestoneImpl implements Entry<T> { private T proxy; private EntryHandler target; private ResultHolder last; private long time; private boolean async, relative; private ProcessImpl proc; @SuppressWarnings("unchecked") EntryImpl(ProcessImpl process, Class<T> intf, String impl) throws ClassNotFoundException, IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { this.proc = process; this.proxy = (T) Proxy.newProxyInstance(proc.loader, new Class<?>[]{ intf }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { proc.host.world.acquire(!async); // Queue invocation ResultHolder result = new ResultHolder(method); target.invoke(time, relative, method, args, result); if (async) { if (last != null) last.setIgnored(); last = result; proc.host.world.release(false); return result.getFakeResult(); } proc.host.world.runSimulation(0); proc.host.world.release(true); if (result.isComplete()) return result.getResult(); else { result.getFakeResult(); throw new SimulationDeadlockException(); } } }); this.target = proc.impl.createEntry(impl); } @Override public Entry<T> asap() { return afterNanos(0l); } @Override public Entry<T> after(long timeout, TimeUnit unit) { return afterNanos(unit.toNanos(timeout)); } @Override public Entry<T> afterNanos(long nanosTimeout) { this.relative = true; this.time = nanosTimeout; return this; } @Override public Entry<T> at(long schedule, TimeUnit unit) { return atNanos(unit.toNanos(schedule)); } @Override public Entry<T> atNanos(long nanosSchedule) { this.relative = false; this.time = nanosSchedule; return this; } @Override public T queue() { this.async = true; return proxy; } @Override public T call() { this.async = false; return proxy; } @Override public Object getResult() throws Throwable { ResultHolder r = last; last = null; return r.getResult(); } @Override public Process getProcess() { return proc; } @Override void setWaited() { last.setSync(); } @Override public boolean isComplete() { return last.isComplete(); } @Override public boolean isPending() { return last != null; } }