/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package fedora.server.messaging; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.naming.Context; import javax.jms.Session; import org.apache.log4j.Logger; import fedora.common.Constants; import fedora.server.DatastoreConfig; import fedora.server.Module; import fedora.server.Server; import fedora.server.errors.MessagingException; import fedora.server.errors.ModuleInitializationException; import fedora.server.errors.ModuleShutdownException; import fedora.server.messaging.JMSManager.DestinationType; import fedora.server.utilities.ServerUtility; /** * Fedora's <code>Messaging</code> as a configurable module. * * @author Edwin Shin * @version $Id$ */ public class MessagingModule extends Module implements Messaging { /** Logger for this class. */ private static Logger LOG = Logger.getLogger(MessagingModule.class.getName()); private Messaging msg; private JMSManager jmsMgr; private static final String ACTIVEMQ_PREFIX = "org.apache.activemq.default.directory.prefix"; public MessagingModule(Map<String, String> moduleParameters, Server server, String role) throws ModuleInitializationException { super(moduleParameters, server, role); } public void initModule() throws ModuleInitializationException { if (!enabled()) { LOG.info("Messaging Module is disabled."); return; } // Sets the location of the activemq-data directory // Property is ignored if the messaging provider is not ActiveMQ if (System.getProperty(ACTIVEMQ_PREFIX) == null) { System.setProperty(ACTIVEMQ_PREFIX, new File(Constants.FEDORA_HOME, "data").getPath() + File.separator); } Properties jndiProps = getJNDISettings(); try { jmsMgr = new JMSManager(jndiProps); } catch (Exception e) { throw new ModuleInitializationException(e.getMessage(), getRole()); } try { String fedoraBaseUrl = ServerUtility.getBaseURL("http"); msg = new MessagingImpl(fedoraBaseUrl, createDestinations(), jmsMgr); } catch (Exception e) { throw new ModuleInitializationException("Error connecting to JMS ", getRole(), e); } } public void postInitModule() throws ModuleInitializationException { } public void shutdownModule() throws ModuleShutdownException { if(enabled()) { try { close(); } catch (MessagingException e) { throw new ModuleShutdownException(e.getMessage(), getRole(), e); } } } public void send(String destName, FedoraMessage message) throws MessagingException { msg.send(destName, message); } public void send(FedoraMethod method) throws MessagingException { msg.send(method); } private Properties getJNDISettings() { String contextFactory = getParameter(Context.INITIAL_CONTEXT_FACTORY); String providerURL = getParameter(Context.PROVIDER_URL); String connectionFactory = getParameter(JMSManager.CONNECTION_FACTORY_NAME); if (providerURL == null || providerURL.length() == 0) { providerURL = "vm:(broker:(tcp://localhost:61616))"; if (LOG.isDebugEnabled()) { LOG.debug("Using default provider url: " + providerURL); } } if (connectionFactory == null || connectionFactory.length() == 0) { connectionFactory = "ConnectionFactory"; if (LOG.isDebugEnabled()) { LOG.debug("Using default connection factory name: " + connectionFactory); } } if (contextFactory == null || contextFactory.length() == 0) { contextFactory = "org.apache.activemq.jndi.ActiveMQInitialContextFactory"; if (LOG.isDebugEnabled()) { LOG.debug("Using default initial context factory: " + contextFactory); } } else if (contextFactory.equalsIgnoreCase("container")) { // assume jndi information is provided via the container return null; } Properties props = new Properties(); props.setProperty(Context.INITIAL_CONTEXT_FACTORY, contextFactory); props.setProperty(Context.PROVIDER_URL, providerURL); props .setProperty(JMSManager.CONNECTION_FACTORY_NAME, connectionFactory); return props; } /** * @return a <code>Map</code>ping of message type to destinations * @throws ModuleInitializationException */ private Map<String, List<String>> createDestinations() throws ModuleInitializationException { Map<String, List<String>> mdMap = new HashMap<String, List<String>>(); for (MessageType type : MessageType.values()) { mdMap.put(type.toString(), new ArrayList<String>()); } Iterator<String> parameters = parameterNames(); String param; while (parameters.hasNext()) { param = parameters.next(); if (param.startsWith("datastore")) { DatastoreConfig dsConfig = getDatastore(param); String[] msgTypes = dsConfig.getParameter("messageTypes").split(" "); for (String msgType : msgTypes) { if (!mdMap.containsKey(msgType)) { throw new ModuleInitializationException(msgType + " is not a supported MessageType.", getRole()); } } String destName = dsConfig.getParameter("name"); String type = dsConfig.getParameter("type"); boolean transacted = Boolean.parseBoolean(dsConfig .getParameter("transacted")); String ackMode = dsConfig.getParameter("ackMode"); DestinationType destType = DestinationType.Topic; if (type.equalsIgnoreCase("queue")) { destType = DestinationType.Queue; } int destAckMode = Session.AUTO_ACKNOWLEDGE; if (ackMode != null && ackMode.length() > 0) { try { destAckMode = Integer.parseInt(ackMode); } catch (NumberFormatException e) { throw new ModuleInitializationException("ackMode must be a number", getRole()); } } try { if (LOG.isDebugEnabled()) { LOG.debug(String .format("createDestination(%s, %s, %s, %s)", destName, destType, transacted, destAckMode)); } jmsMgr.createDestination(destName, destType, transacted, destAckMode); } catch (Exception e) { throw new ModuleInitializationException(e.getMessage(), getRole()); } for (String msgType : msgTypes) { mdMap.get(msgType).add(destName); } } } return mdMap; } private DatastoreConfig getDatastore(String name) throws ModuleInitializationException { String value = getParameter(name); if (value == null || value.length() == 0) { throw new ModuleInitializationException(name + " parameter " + "is required", getRole()); } DatastoreConfig dsConfig = getServer().getDatastoreConfig(value); if (dsConfig == null) { throw new ModuleInitializationException(value + " datastore " + "configuration is missing.", getRole()); } return dsConfig; } // Check to see if messaging is enabled private boolean enabled() { String enabled = getParameter("enabled"); return (enabled != null && enabled.equalsIgnoreCase("true")); } public void close() throws MessagingException { if (msg != null) { msg.close(); msg = null; } } }