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