package won.matcher.service.nodemanager.config;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedActorContext;
import akka.camel.Camel;
import akka.camel.CamelExtension;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ActiveMQSslConnectionFactory;
import org.apache.camel.FailedToCreateConsumerException;
import org.apache.camel.component.jms.JmsComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import won.cryptography.ssl.MessagingContext;
import won.matcher.service.common.spring.SpringExtension;
import won.matcher.service.nodemanager.actor.HintProducerProtocolActor;
import won.matcher.service.nodemanager.actor.NeedConsumerProtocolActor;
import won.matcher.service.nodemanager.pojo.WonNodeConnection;
import won.protocol.service.WonNodeInfo;
import won.protocol.vocabulary.WON;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
import java.util.UUID;
/**
* Factory for creating a {@link won.matcher.service.nodemanager.pojo.WonNodeConnection} with ActiveMq endpoint of a won node
* <p>
* User: hfriedrich
* Date: 18.05.2015
*/
//TODO reuse BrokerComponentFactory
public class ActiveMqWonNodeConnectionFactory {
protected static final Logger log = LoggerFactory.getLogger(ActiveMqWonNodeConnectionFactory.class);
/**
* Create a {@link won.matcher.service.nodemanager.pojo.WonNodeConnection} for active mq
*
* @param context actor context to create the message consuming actors in
* @param wonNodeInfo info about the won node (e.g. topics to subscribe)
* @return the connection
* @throws FailedToCreateConsumerException
*/
public static WonNodeConnection createWonNodeConnection(UntypedActorContext context,
WonNodeInfo wonNodeInfo, MessagingContext messagingContext) {
// read won node info
String activeMq = WON.WON_OVER_ACTIVE_MQ.toString();
String brokerUri = wonNodeInfo.getSupportedProtocolImplParamValue(
activeMq, WON.HAS_BROKER_URI.toString());
String createdTopic = wonNodeInfo.getSupportedProtocolImplParamValue(
activeMq, WON.HAS_ACTIVEMQ_MATCHER_PROTOCOL_OUT_NEED_CREATED_TOPIC_NAME.toString());
String activatedTopic = wonNodeInfo.getSupportedProtocolImplParamValue(
activeMq, WON.HAS_ACTIVEMQ_MATCHER_PROTOCOL_OUT_NEED_ACTIVATED_TOPIC_NAME.toString());
String deactivatedTopic = wonNodeInfo.getSupportedProtocolImplParamValue(
activeMq, WON.HAS_ACTIVEMQ_MATCHER_PROTOCOL_OUT_NEED_DEACTIVATED_TOPIC_NAME.toString());
String hintQueue = wonNodeInfo.getSupportedProtocolImplParamValue(
activeMq, WON.HAS_ACTIVEMQ_MATCHER_PROTOCOL_QUEUE_NAME.toString());
// create the activemq component for this won node
String uuid = UUID.randomUUID().toString();
String componentName = "activemq-" + uuid;
ActiveMQConnectionFactory connectionFactory = createConnectionFactory(brokerUri, messagingContext);
// connectionFactory.setExceptionListener( ... )
Camel camel = CamelExtension.get(context.system());
camel.context().addComponent(componentName, JmsComponent.jmsComponent(connectionFactory));
// create the actors that receive the messages (need events)
String createdComponent = componentName + ":topic:" + createdTopic + "?testConnectionOnStartup=false";
Props createdProps = SpringExtension.SpringExtProvider.get(context.system()).props(
NeedConsumerProtocolActor.class, createdComponent);
ActorRef created = context.actorOf(createdProps, "ActiveMqNeedCreatedConsumerProtocolActor-" + uuid);
log.info("Create camel component JMS listener {} for won node {}", createdComponent, wonNodeInfo.getWonNodeURI());
ActorRef activated = created;
if (!activatedTopic.equals(createdTopic)) {
String activatedComponent = componentName + ":topic:" + activatedTopic + "?testConnectionOnStartup=false";
Props activatedProps = SpringExtension.SpringExtProvider.get(context.system()).props(
NeedConsumerProtocolActor.class, activatedComponent);
activated = context.actorOf(activatedProps, "ActiveMqNeedActivatedConsumerProtocolActor-" + uuid);
log.info("Create camel component JMS listener {} for won node {}", activatedComponent, wonNodeInfo.getWonNodeURI());
}
ActorRef deactivated;
if (deactivatedTopic.equals(createdTopic)) {
deactivated = created;
} else if (deactivatedTopic.equals(activatedTopic)) {
deactivated = activated;
} else {
String deactivatedComponent = componentName + ":topic:" + deactivatedTopic + "?testConnectionOnStartup=false";
Props deactivatedProps = SpringExtension.SpringExtProvider.get(context.system()).props(
NeedConsumerProtocolActor.class, deactivatedComponent);
deactivated = context.actorOf(deactivatedProps, "ActiveMqNeedDeactivatedConsumerProtocolActor-" + uuid);
log.info("Create camel component JMS listener {} for won node {}", deactivatedComponent, wonNodeInfo.getWonNodeURI());
}
// create the actor that sends messages (hint events)
String hintComponent = componentName + ":queue:" + hintQueue;
Props hintProps = SpringExtension.SpringExtProvider.get(context.system()).props(
HintProducerProtocolActor.class, hintComponent, null);
ActorRef hintProducer = context.actorOf(hintProps, "ActiveMqHintProducerProtocolActor-" + uuid);
log.info("Create camel component JMS listener {} for won node {}", hintComponent, wonNodeInfo.getWonNodeURI());
// watch the created consumers from the context to get informed when they are terminated
context.watch(created);
context.watch(activated);
context.watch(deactivated);
context.watch(hintProducer);
// create the connection
WonNodeConnection jmsConnection = new WonNodeConnection(wonNodeInfo, created, activated, deactivated, hintProducer);
return jmsConnection;
}
private static ActiveMQConnectionFactory createConnectionFactory(final String brokerUri, final MessagingContext messagingContext) {
KeyManager keyManager = null;
TrustManager trustManager = null;
if (messagingContext != null) {
try {
keyManager = messagingContext.getClientKeyManager();
trustManager = messagingContext.getClientTrustManager();
} catch (Exception e) {
log.error("Key- or Trust- manager initialization problem", e);
}
}
// jms.prefetchPolicy parameter is added to prevent matcher-consumer death due to overflowing with messages,
// see http://activemq.apache.org/what-is-the-prefetch-limit-for.html
ActiveMQSslConnectionFactory connectionFactory = new ActiveMQSslConnectionFactory(brokerUri + "?jms.prefetchPolicy.all=50");
// for non-persistent messages setting "AlwaysSyncSend" to true makes it slow, but ensures that a producer is immediately informed
// about the memory issues on broker (is blocked or gets exception depending on <systemUsage> config)
// see more info http://activemq.apache.org/producer-flow-control.html
connectionFactory.setAlwaysSyncSend(false);
// disable timestamps by default so that ttl of messages is not checked
connectionFactory.setDisableTimeStampsByDefault(true);
if (keyManager != null && trustManager != null) {
connectionFactory.setKeyAndTrustManagers(new KeyManager[]{keyManager}, new TrustManager[]{trustManager}, null);
} else {
log.warn("key or trust manager was null, therefore do not set them in connection factory");
}
return connectionFactory;
}
}