/*
* Copyright 2012 Nodeable Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.streamreduce.queue;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sqs.AmazonSQSClient;
import com.streamreduce.util.JSONUtils;
import com.streamreduce.util.PropertiesOverrideLoader;
import com.streamreduce.util.SqsQueueNameFormatter;
import net.sf.json.JSONObject;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.camel.component.ActiveMQComponent;
import org.apache.activemq.pool.PooledConnectionFactory;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.util.jndi.JndiContext;
import org.apache.log4j.Logger;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
public final class CamelFacade {
private CamelFacade() {
}
static private final Logger LOGGER = Logger.getLogger(CamelFacade.class);
static private ProducerTemplate producerTemplate;
static private String brokerType;
private static void startCamelContextAndSetProducerTemplate() {
try {
Properties messageBrokerProperties = PropertiesOverrideLoader.loadProperties("messagebroker.properties");
final String eventsToInsightsQueueName = messageBrokerProperties.getProperty("eventMapsToInsightsQueueName");
final String environment = messageBrokerProperties.getProperty("broker.environment.prefix");
brokerType = messageBrokerProperties.getProperty("broker.type"); //sendInsightMessage uses brokerType
//work around for https://issues.apache.org/jira/browse/CAMEL-5453
//Register a SQSClient in the context with credentials already supplied.
final SQSClientAndEndPointPair sqsClientAndEndPointPair =
setupSqsEndpointAndClient(eventsToInsightsQueueName,environment);
JndiContext jndiContext = new JndiContext();
jndiContext.bind("amazonSQSClient", sqsClientAndEndPointPair.amazonSQSClient);
CamelContext camelContext = new DefaultCamelContext(jndiContext);
final String amqEndpoint = setupAmqComponentAndEndpoint(camelContext, messageBrokerProperties,
eventsToInsightsQueueName);
final String fileEndpoint = setupFileComponent(eventsToInsightsQueueName); //For local dev
camelContext.addRoutes(new RouteBuilder() {
@Override
public void configure() throws Exception {
if ("amq" .equals(brokerType)) {
from("direct:sendEventToAmq").to(amqEndpoint);
}
if ("sqs" .equals(brokerType)) {
from("direct:sendEventToSqs").to(sqsClientAndEndPointPair.endpoint);
}
if ("file" .equals(brokerType)) {
from("direct:sendEventToTempDir").to(fileEndpoint);
}
}
});
camelContext.start();
producerTemplate = camelContext.createProducerTemplate();
LOGGER.info("Camel (Insight Message Producer) started successfully");
} catch (Exception e) {
LOGGER.error("Error starting the Camel context: " + e.getMessage(), e);
throw new RuntimeException(e);
}
}
private static String setupFileComponent(String eventsToInsightsQueueName) {
String tmpDirPath = System.getProperty( "user.home" ) + "/.nodeable/" + eventsToInsightsQueueName;
File tmpDir = new File(tmpDirPath);
tmpDir.mkdir();
return "file://" + tmpDirPath + "?tempPrefix=tmp.";
}
private static SQSClientAndEndPointPair setupSqsEndpointAndClient(String queueName, String environment) throws UnsupportedEncodingException {
Properties cloudProperties = PropertiesOverrideLoader.loadProperties("cloud.properties");
String accessKeyId = cloudProperties.getProperty("nodeable.aws.accessKeyId");
String secretKey = cloudProperties.getProperty("nodeable.aws.secretKey");
long messageRetentionPeriod = TimeUnit.DAYS.toSeconds(14);
String actualQueueName = SqsQueueNameFormatter.formatSqsQueueName(queueName,environment);
AWSCredentials awsCredentials = new BasicAWSCredentials(accessKeyId,secretKey);
AmazonSQSClient sqsClient = new AmazonSQSClient(awsCredentials);
String endpoint = String.format("aws-sqs://" + actualQueueName + "?amazonSQSClient=#amazonSQSClient&" +
"messageRetentionPeriod=%d",messageRetentionPeriod);
return new SQSClientAndEndPointPair(sqsClient,endpoint);
}
private static String setupAmqComponentAndEndpoint(CamelContext camelContext, Properties messageBrokerProperties, String eventsToInsightsQueueName) {
String brokerUrl = messageBrokerProperties.getProperty("activemq.broker.url");
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(brokerUrl);
PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(activeMQConnectionFactory);
pooledConnectionFactory.setMaxConnections(8);
pooledConnectionFactory.setMaximumActive(500);
pooledConnectionFactory.setIdleTimeout(0); //No timeout for connections in the pool
ActiveMQComponent activeMQComponent = ActiveMQComponent.activeMQComponent();
activeMQComponent.setUsePooledConnection(true);
activeMQComponent.setConnectionFactory(pooledConnectionFactory);
camelContext.addComponent("amq", activeMQComponent);
return "amq:queue:" + eventsToInsightsQueueName + "?jmsMessageType=Text";
}
public static void sendInsightMessage(Map<String, Object> eventMap) {
if (producerTemplate == null) {
startCamelContextAndSetProducerTemplate();
}
JSONObject jsonObject = JSONObject.fromObject(JSONUtils.sanitizeMapForJson(eventMap));
if ("sqs".equals(brokerType)) {
producerTemplate.sendBody("direct:sendEventToSqs",jsonObject.toString());
LOGGER.debug("Insight message sent to SQS: " + jsonObject);
} else if ("amq".equals(brokerType)) {
producerTemplate.sendBody("direct:sendEventToAmq", jsonObject.toString());
LOGGER.debug("Insight message sent to AMQ: " + jsonObject);
} else if ("file".equals(brokerType)) {
producerTemplate.sendBody("direct:sendEventToTempDir", jsonObject.toString());
LOGGER.debug("Insight message sent to Temp Directory: " + eventMap);
} else {
throw new RuntimeException("Unable to write event to queue. brokerType was \"" + brokerType +
"\" was not one of \"sqs\", \"amq\", or \"file\"");
}
}
private static class SQSClientAndEndPointPair {
final AmazonSQSClient amazonSQSClient;
final String endpoint;
SQSClientAndEndPointPair(AmazonSQSClient amazonSQSClient, String endpoint) {
this.amazonSQSClient = amazonSQSClient;
this.endpoint = endpoint;
}
}
public static void main(String[] args) {
sendInsightMessage(new HashMap<String,Object>());
}
}