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     */
022    package org.granite.tide.data;
023    
024    import java.io.Serializable;
025    import java.util.Map;
026    import java.util.Map.Entry;
027    
028    import javax.jms.Connection;
029    import javax.jms.JMSException;
030    import javax.jms.MessageProducer;
031    import javax.jms.ObjectMessage;
032    import javax.jms.Session;
033    import javax.jms.Topic;
034    import javax.jms.TopicConnectionFactory;
035    import javax.naming.InitialContext;
036    import javax.naming.NamingException;
037    import javax.servlet.http.HttpSession;
038    
039    import org.granite.context.GraniteContext;
040    import org.granite.gravity.adapters.JMSClient;
041    import org.granite.logging.Logger;
042    import 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     */
052    public 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    }