/*
* $Id$
*
* Copyright 2008 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.services.blitz.fire;
import java.lang.reflect.Method;
import omero.ApiUsageException;
import omero.InternalException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import IceStorm.AlreadySubscribed;
import IceStorm.BadQoS;
import IceStorm.NoSuchTopic;
/**
* Local dispatcher to {@link IceStorm.TopicManager}
*
* @author Josh Moore, josh at glencoesoftware.com
* @since December 2008
*/
public interface TopicManager extends ApplicationListener {
/**
* Enforces <em>no</em> security constraints. For the moment, that is the
* responsibility of application code. WILL CHANGE>
*/
public void register(String topicName, Ice.ObjectPrx prx, boolean strict)
throws omero.ServerError;
public void unregister(String topicName, Ice.ObjectPrx prx)
throws omero.ServerError;
public final static class TopicMessage extends ApplicationEvent {
private final String topic;
private final Ice.ObjectPrxHelperBase base;
private final String method;
private final Object[] args;
public TopicMessage(Object source, String topic,
Ice.ObjectPrxHelperBase base, String method, Object... args) {
super(source);
this.topic = topic;
this.base = base;
this.method = method;
this.args = args;
}
}
public final static class Impl implements TopicManager {
private final static Logger log = LoggerFactory.getLogger(Impl.class);
private final Ice.Communicator communicator;
public Impl(Ice.Communicator communicator) {
this.communicator = communicator;
}
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof TopicMessage) {
TopicMessage msg = (TopicMessage) event;
try {
IceStorm.TopicManagerPrx topicManager = managerOrNull();
if (topicManager == null) {
log.warn("No topic manager");
return; // EARLY EXIT
}
Ice.ObjectPrx obj = publisherOrNull(msg.topic);
msg.base.__copyFrom(obj);
Method m = null;
for (Method check : msg.base.getClass().getMethods()) {
if (check.getName().equals(msg.method)) {
if (check.getParameterTypes().length == msg.args.length) {
if (m != null) {
String err = String
.format(
"More than one method named "
+ "\"%s\" with %s arguments",
msg.method, msg.args);
log.error(err);
} else {
m = check;
}
}
}
}
if (m == null) {
log.error(String.format("No method named \"%s\" "
+ "with %s arguments", msg.method, msg.args));
} else {
m.invoke(msg.base, msg.args);
}
} catch (Ice.NoEndpointException nee) {
// Most likely caused during testing.
log.debug("Ice.NoEndpointException");
} catch (Exception e) {
log.error("Error publishing to topic:" + msg.topic, e);
}
}
}
public void register(String topicName, Ice.ObjectPrx prx, boolean strict)
throws omero.ServerError {
String id = prx.ice_id();
id = id.replaceFirst("::", "");
id = id.replace("::", ".");
id = id + "PrxHelper";
Class<?> pubClass = null;
try {
pubClass = Class.forName(id);
} catch (ClassNotFoundException e) {
throw new ApiUsageException(null, null,
"Unknown type for proxy: " + prx.ice_id());
}
IceStorm.TopicPrx topic = topicOrNull(topicName);
while (topic != null) { // See 45.7.3 IceStorm Clients under HA
// IceStorm
try {
topic.subscribeAndGetPublisher(null, prx);
} catch (Ice.UnknownException ue) {
log.warn("Unknown exception on subscribeAndGetPublisher");
continue;
} catch (AlreadySubscribed e) {
if (strict) {
throw new ApiUsageException(null, null,
"Proxy already subscribed: " + prx);
}
} catch (BadQoS e) {
throw new InternalException(null, null,
"BadQos in TopicManager.subscribe");
} catch (Ice.UserException ue) {
// Actually IceStorm.InvalidSubscriber, for Ice 3.4/3.5 compatibility
log.warn("Invalid subscriber on subscribeAndGetPublisher");
continue;
}
break;
}
}
public void unregister(String topicName, Ice.ObjectPrx prx)
throws omero.ServerError {
try {
IceStorm.TopicPrx topic = topicOrNull(topicName);
if (topic != null) {
topic.unsubscribe(prx);
}
} catch (Exception e) {
log.warn(String.format("Error unregistering: %s from %s",
prx, topicName));
}
}
// Helpers
// =========================================================================
protected IceStorm.TopicManagerPrx managerOrNull() {
Ice.ObjectPrx objectPrx = communicator
.stringToProxy("IceGrid/Query");
Ice.ObjectPrx[] candidates = null;
try {
IceGrid.QueryPrx query = IceGrid.QueryPrxHelper
.checkedCast(objectPrx);
candidates = query
.findAllObjectsByType("::IceStorm::TopicManager");
} catch (Ice.CommunicatorDestroyedException cde) {
// Nothing we can do. Return null;
return null;
} catch (Ice.NoEndpointException nee) {
// Most likely caused during testing.
log.debug("Ice.NoEndpointException");
} catch (Exception e) {
log.warn("Error querying for topic manager", e);
}
IceStorm.TopicManagerPrx tm = null;
if (candidates == null || candidates.length == 0) {
log.warn("Found no topic manager");
} else if (candidates.length > 1) {
log.warn("Found wrong number of topic managers: "
+ candidates.length);
} else {
try {
tm = IceStorm.TopicManagerPrxHelper
.checkedCast(candidates[0]);
} catch (Exception e) {
log.warn("Could not cast to TopicManager", e);
}
}
return tm;
}
protected IceStorm.TopicPrx topicOrNull(String name) {
IceStorm.TopicManagerPrx topicManager = managerOrNull();
IceStorm.TopicPrx topic = null;
if (topicManager != null) {
try {
topic = topicManager.create(name);
} catch (IceStorm.TopicExists ex2) {
try {
topic = topicManager.retrieve(name);
} catch (NoSuchTopic e) {
throw new RuntimeException(
"Race condition retriving topic: " + name);
}
}
}
return topic;
}
protected Ice.ObjectPrx publisherOrNull(String name) {
IceStorm.TopicPrx topic = topicOrNull(name);
Ice.ObjectPrx pub = null;
if (topic != null) {
pub = topic.getPublisher().ice_oneway();
}
return pub;
}
}
}