001/*
002  GRANITE DATA SERVICES
003  Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004
005  This file is part of Granite Data Services.
006
007  Granite Data Services is free software; you can redistribute it and/or modify
008  it under the terms of the GNU Library General Public License as published by
009  the Free Software Foundation; either version 2 of the License, or (at your
010  option) any later version.
011
012  Granite Data Services is distributed in the hope that it will be useful, but
013  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015  for more details.
016
017  You should have received a copy of the GNU Library General Public License
018  along with this library; if not, see <http://www.gnu.org/licenses/>.
019*/
020
021package org.granite.tide.data;
022
023import java.io.Serializable;
024import java.util.Map;
025import java.util.Map.Entry;
026
027import javax.jms.Connection;
028import javax.jms.JMSException;
029import javax.jms.MessageProducer;
030import javax.jms.ObjectMessage;
031import javax.jms.Session;
032import javax.jms.Topic;
033import javax.jms.TopicConnectionFactory;
034import javax.naming.InitialContext;
035import javax.naming.NamingException;
036import javax.servlet.http.HttpSession;
037
038import org.granite.context.GraniteContext;
039import org.granite.gravity.adapters.JMSClient;
040import org.granite.logging.Logger;
041import org.granite.messaging.webapp.ServletGraniteContext;
042
043/**
044 *  Implementation for data update dispatchers using JMS to dispatch updates.
045 * 
046 *  @see DataDispatcher
047 *  @see DataContext
048 * 
049 *  @author William Drai
050 */
051public class JMSDataDispatcher extends AbstractDataDispatcher {
052    
053    private static final Logger log = Logger.getLogger(JMSDataDispatcher.class);
054
055    
056    private boolean transacted = false;
057    private TopicConnectionFactory connectionFactory = null;
058    private Topic topic;
059    private JMSClient jmsClient = null;
060    
061    
062        public JMSDataDispatcher(String topicName, boolean transacted, Class<? extends DataTopicParams> dataTopicParamsClass) {
063                super(topicName, dataTopicParamsClass);
064                
065                this.transacted = transacted;
066                
067                GraniteContext graniteContext = GraniteContext.getCurrentInstance();
068                if (graniteContext instanceof ServletGraniteContext) {
069                        HttpSession session = ((ServletGraniteContext)graniteContext).getSession(false);
070                        if (session == null) {
071                                log.debug("Gravity not found or HTTP session not found, data dispatch disabled");
072                                return;
073                        }
074                        sessionId = session.getId();
075                        
076                        jmsClient = (JMSClient)((ServletGraniteContext)graniteContext).getSessionMap().get(JMSClient.JMSCLIENT_KEY_PREFIX + topicName);
077                }
078                else {
079                        // Server initiated dispatcher
080                        this.sessionId = SERVER_DISPATCHER_GDS_SESSION_ID;
081                        
082                        try {
083                                InitialContext ic = new InitialContext();
084                                this.connectionFactory = (TopicConnectionFactory)ic.lookup("java:comp/env/tide/ConnectionFactory");
085                                this.topic = (Topic)ic.lookup("java:comp/env/tide/topic/" + topicName);
086                        }
087                        catch (NamingException e) {
088                                log.warn(e, "Could not retrieve ConnectionFactory and Topic in JNDI for topic %s", topicName);
089                                return;
090                        }
091                }
092                
093                enabled = true;
094        }
095        
096        
097        @Override
098        protected void changeDataSelector(String dataSelector) {
099                if (jmsClient != null) {
100                        try {
101                                jmsClient.subscribe(dataSelector, topicName, TIDE_DATA_SUBTOPIC);                       
102                                log.debug("JMS Topic %s data selector changed: %s", topicName, dataSelector);
103                        }
104                        catch (Exception e) {
105                                log.error(e, "Could not change JMS Topic %s data selector: %s", topicName);
106                        }
107                }
108        }
109        
110        @Override
111        public void publishUpdate(Map<String, String> params, Object body) {
112                if (jmsClient != null) {
113                        try {
114                                jmsClient.send(params, body, 0L);
115                        }
116                        catch (Exception e) {
117                                log.error("Could not dispatch data update on topic %s using internal JMS client, message %s", topicName, body.toString());
118                        }
119                }
120                else if (enabled) {
121                        try {
122                                Connection jmsConnection = connectionFactory.createConnection();
123                                Session jmsSession = jmsConnection.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
124                                MessageProducer jmsProducer = jmsSession.createProducer(topic);
125                                ObjectMessage jmsMessage = jmsSession.createObjectMessage((Serializable)body);
126                                for (Entry<String, String> hh : params.entrySet())
127                                        jmsMessage.setStringProperty(hh.getKey(), hh.getValue());
128                        
129                                jmsProducer.send(jmsMessage);
130                                log.debug("Data message dispatched on JMS topic %s", topicName);
131                        }
132                        catch (JMSException e) {
133                                log.error("Could not dispatch data update on topic %s, message %s", topicName, body.toString());
134                        }
135                }
136        }
137}