/* * Copyright 2009 Glencoe Software, Inc. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.services.blitz.impl; import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import ome.services.blitz.fire.TopicManager; import ome.services.blitz.util.ResultHolder; import ome.system.EventContext; import ome.system.Principal; import omero.ServerError; import omero.constants.categories.PROCESSORCALLBACK; import omero.constants.topics.PROCESSORACCEPTS; import omero.grid.ProcessorCallbackPrx; import omero.grid.ProcessorCallbackPrxHelper; import omero.grid.ProcessorPrx; import omero.grid.ProcessorPrxHelper; import omero.grid._ProcessorCallbackOperations; import omero.grid._ProcessorCallbackTie; import omero.model.Job; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import Ice.Current; /** * Callback used to lookup active processors via IceStorm. */ public class ProcessorCallbackI extends AbstractAmdServant implements _ProcessorCallbackOperations { private final static Logger log = LoggerFactory.getLogger(ProcessorCallbackI.class); private final Job job; private final ServiceFactoryI sf; private final ResultHolder<ProcessorPrx> holder; private final AtomicInteger responses = new AtomicInteger(0); /** * Simplified constructor used to see if any usermode processor is active * for either the current group or the current user. Currently uses a * hard-coded value of 5 seconds wait time. For more control, pass in a * {@link ResultHolder} instance. */ public ProcessorCallbackI(ServiceFactoryI sf) { this(sf, new ResultHolder<ProcessorPrx>(5 * 1000), null); } /** * Primary constructor. Asks processors if they will accept the given job * for the current user and the current group. * * @param sf * Cannot be null. * @param holder * Cannot be null. * @param job * Can be null. */ public ProcessorCallbackI(ServiceFactoryI sf, ResultHolder<ProcessorPrx> holder, Job job) { super(null, null); this.sf = sf; this.job = job; this.holder = holder; } /** * Return the number of times this instance has been called in a thread * safe manner. * @return See above. */ public int getResponses() { return responses.get(); } /** * Generates a UUID-based {@link Ice.Identity} with the category of * {@link PROCESSORCALLBACK#value} and then calls * {@link #activateAndWait(Current, Ice.Identity)}. * @return See above. */ public ProcessorPrx activateAndWait(Ice.Current current) throws ServerError { Ice.Identity acceptId = new Ice.Identity(); acceptId.name = UUID.randomUUID().toString(); acceptId.category = PROCESSORCALLBACK.value; return activateAndWait(current, acceptId); } /** * Primary method which adds this instance to IceStorm, waits for a response * from any active processor services, and finally unregister itself before * returning the first processor instance which responded. * @param current * @param acceptId * @return See above. * @throws ServerError */ public ProcessorPrx activateAndWait(Ice.Current current, Ice.Identity acceptId) throws ServerError { Ice.ObjectPrx prx = sf.registerServant(acceptId, new _ProcessorCallbackTie(this)); try { prx = sf.adapter.createDirectProxy(acceptId); ProcessorCallbackPrx cbPrx = ProcessorCallbackPrxHelper .uncheckedCast(prx); EventContext ec = sf.getEventContext(current); TopicManager.TopicMessage msg = new TopicManager.TopicMessage(this, PROCESSORACCEPTS.value, new ProcessorPrxHelper(), "willAccept", new omero.model.ExperimenterI(ec .getCurrentUserId(), false), new omero.model.ExperimenterGroupI(ec .getCurrentGroupId(), false), this.job, cbPrx); sf.topicManager.onApplicationEvent(msg); return holder.get(); } finally { sf.unregisterServant(acceptId); } } /** * Callback method called by the remote processor instance. * See ticket 8266 for reasons this method should not be used. */ @Deprecated public void isAccepted(boolean accepted, String sessionUuid, String procConn, Current __current) { isProxyAccepted(accepted, sessionUuid, ProcessorPrxHelper.checkedCast( sf.adapter.getCommunicator().stringToProxy(procConn)), __current); } /** * Callback method called by the remote processor instance. */ public void isProxyAccepted(boolean accepted, String sessionUuid, ProcessorPrx procProxy, Current __current) { responses.incrementAndGet(); Exception exc = null; String reason = "because false returned"; if (accepted) { String procLog = sf.adapter.getCommunicator().proxyToString(procProxy); log.debug(String.format( "Processor with session %s returned %s accepted", sessionUuid, procLog, accepted)); try { EventContext procEc = sf.sessionManager .getEventContext(new Principal(sessionUuid)); EventContext ec = sf.getEventContext(__current); if (procEc.isCurrentUserAdmin() || procEc.getCurrentUserId().equals( ec.getCurrentUserId())) { this.holder.set(ProcessorPrxHelper.checkedCast(procProxy)); return; // EARLY EXIT } else { reason = "since disallowed"; } } catch (Ice.ObjectNotExistException onee) { exc = onee; reason = "due to ObjectNotExistException: " + procLog; } catch (Exception e) { exc = e; reason = "due to exception: " + e.getMessage(); } } String msg = String.format("Processor with session %s rejected %s", sessionUuid, reason); if (exc != null) { log.warn(msg, exc); } else { log.debug(msg); } this.holder.set(null); } /** * Callback method which should not be called for this instance. */ public void responseRunning(List<Long> jobIds, Current __current) { log.error("responseRunning should not have been called"); } }