/* * $Id$ * * Copyright 2008 Glencoe Software, Inc. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt * */ package ome.services.throttling; import java.lang.reflect.Method; import ome.system.OmeroContext; import omero.InternalException; import omero.util.IceMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Simple base task which contains logic for routing calls reflectively to * ice_response and ice_exception of any AMD callback. * * @since Beta4 */ public abstract class Task { private final static Logger log = LoggerFactory.getLogger(Task.class); protected final Object cb; protected final boolean isVoid; protected final Ice.Current current; protected final Method response; protected final Method exception; public Task(Object callback, Ice.Current current, boolean isVoid) { this.current = current; this.isVoid = isVoid; this.cb = callback; if (callback != null) { response = getMethod(callback, "ice_response"); exception = getMethod(callback, "ice_exception"); } else { response = null; exception = null; } } public abstract void run(OmeroContext ctx); /** * Calls the response method */ protected void response(Object rv, OmeroContext ctx) { try { if (isVoid) { response.invoke(cb); } else { response.invoke(cb, rv); } } catch (Exception e) { InternalException ie = new InternalException(); IceMapper.fillServerError(ie, e); ie.message = "Failed to invoke: " + this.toString(); log.error(ie.message, e); exception(ie, ctx); } } protected void exception(Throwable ex, OmeroContext ctx) { try { if (!(ex instanceof Exception)) { log.error("Throwable thrown!", ex); } IceMapper mapper = new IceMapper(); ex = mapper.handleException(ex, ctx); exception.invoke(cb, ex); } catch (Exception e2) { String msg = "Failed to invoke exception()"; log.error(msg, e2); throw new RuntimeException("Failed to invoke exception()", e2); } } // Helpers // ========================================================================= Method getMethod(Object o, String methodName) { Class c = getPublicInterface(o.getClass()); Method[] methods = c.getMethods(); Method rv = null; for (int i = 0; i < methods.length; i++) { Method m = methods[i]; if (methodName.equals(m.getName())) { if (rv != null) { throw new RuntimeException(methodName + " exists twice!"); } else { rv = m; } } } return rv; } /** * The Ice AMD-implementations are package-private and so cannot be executed * on. Instead, we have to find the public interface and use its methods. */ private Class getPublicInterface(Class c) { if (!c.getName().startsWith("AMD_")) { while (!c.equals(Object.class)) { Class[] ifaces = c.getInterfaces(); for (Class c2 : ifaces) { if (c2.getSimpleName().startsWith("AMD_")) { return c2; } } // Ok. We didn't find anything so recurse into the superclass c = c.getSuperclass(); } throw new RuntimeException("No public AMD_ interface found."); } else { return c; } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(super.toString()); sb.append(" ("); sb.append(cb); sb.append(" )"); return sb.toString(); } }