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