/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.falcon.messaging; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.falcon.messaging.EntityInstanceMessage.ARG; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.JMSException; import javax.jms.Session; import javax.jms.Topic; import java.lang.reflect.InvocationTargetException; import java.util.List; /** * Message producer used in the workflow to send a message to the queue/topic. */ public class MessageProducer extends Configured implements Tool { private Connection connection; private static final Logger LOG = LoggerFactory.getLogger(MessageProducer.class); private static final long DEFAULT_TTL = 3 * 24 * 60 * 60 * 1000; /** * @param entityInstanceMessage - Accepts a Message to be send to JMS topic, creates a new * Topic based on topic name if it does not exist or else * existing topic with the same name is used to send the message. * @throws JMSException */ protected void sendMessage(EntityInstanceMessage entityInstanceMessage) throws JMSException { Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Topic entityTopic = session.createTopic(entityInstanceMessage .getTopicName()); javax.jms.MessageProducer producer = session .createProducer(entityTopic); producer.setDeliveryMode(DeliveryMode.PERSISTENT); long messageTTL = DEFAULT_TTL; try { long messageTTLinMins = Long.parseLong(entityInstanceMessage .getBrokerTTL()); messageTTL = messageTTLinMins * 60 * 1000; } catch (NumberFormatException e) { LOG.error("Error in parsing broker.ttl, setting TTL to: {} milli-seconds", DEFAULT_TTL); } producer.setTimeToLive(messageTTL); producer.send(new EntityInstanceMessageCreator(entityInstanceMessage) .createMessage(session)); } public static void main(String[] args) throws Exception { ToolRunner.run(new MessageProducer(), args); } private void createAndStartConnection(String implementation, String userName, String password, String url) throws JMSException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Class<ConnectionFactory> clazz = (Class<ConnectionFactory>) MessageProducer.class .getClassLoader().loadClass(implementation); ConnectionFactory connectionFactory = clazz.getConstructor( String.class, String.class, String.class).newInstance(userName, password, url); connection = connectionFactory.createConnection(); connection.start(); } private static CommandLine getCommand(String[] arguments) throws ParseException { Options options = new Options(); addOption(options, new Option(ARG.brokerImplClass.getArgName(), true, "message broker Implementation class")); addOption(options, new Option(ARG.brokerTTL.getArgName(), true, "message time-to-live")); addOption(options, new Option(ARG.brokerUrl.getArgName(), true, "message broker url")); addOption(options, new Option(ARG.entityName.getArgName(), true, "name of the entity")); addOption(options, new Option(ARG.entityType.getArgName(), true, "type of the entity")); addOption(options, new Option(ARG.feedInstancePaths.getArgName(), true, "feed instance paths")); addOption(options, new Option(ARG.feedNames.getArgName(), true, "feed names")); addOption(options, new Option(ARG.logFile.getArgName(), true, "log file path")); addOption(options, new Option(ARG.nominalTime.getArgName(), true, "instance time")); addOption(options, new Option(ARG.operation.getArgName(), true, "operation like generate, delete, archive")); addOption(options, new Option(ARG.runId.getArgName(), true, "current run-id of the instance")); addOption(options, new Option(ARG.status.getArgName(), true, "status of workflow instance")); addOption(options, new Option(ARG.timeStamp.getArgName(), true, "current timestamp")); addOption(options, new Option(ARG.topicName.getArgName(), true, "name of the topic to be used to send message")); addOption(options, new Option(ARG.workflowId.getArgName(), true, "workflow id")); addOption(options, new Option(ARG.cluster.getArgName(), true, "cluster name")); addOption(options, new Option(ARG.workflowUser.getArgName(), true, "workflow user id"), false); addOption(options, new Option(ARG.logDir.getArgName(), true, "log dir where job logs are copied"), false); return new GnuParser().parse(options, arguments); } private static void addOption(Options options, Option opt) { addOption(options, opt, true); } private static void addOption(Options options, Option opt, boolean isRequired) { opt.setRequired(isRequired); options.addOption(opt); } @Override public int run(String[] args) throws Exception { CommandLine cmd; try { cmd = getCommand(args); } catch (ParseException e) { throw new Exception("Unable to parse arguments: ", e); } List<EntityInstanceMessage> entityInstanceMessage = EntityInstanceMessage .getMessages(cmd); if (entityInstanceMessage == null || entityInstanceMessage.isEmpty()) { LOG.warn("No operation on output feed"); return 0; } try { createAndStartConnection(cmd.getOptionValue(ARG.brokerImplClass.name()), "", "", cmd.getOptionValue(ARG.brokerUrl.name())); for (EntityInstanceMessage message : entityInstanceMessage) { LOG.info("Sending message: {}", message.getKeyValueMap()); sendMessage(message); } } finally { try { if (connection != null) { connection.close(); } } catch (JMSException e) { LOG.error("Error in closing connection", e); } } return 0; } }