001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.component.jms;
018    
019    import javax.jms.Connection;
020    
021    import org.apache.camel.FailedToCreateConsumerException;
022    import org.apache.camel.Processor;
023    import org.apache.camel.SuspendableService;
024    import org.apache.camel.impl.DefaultConsumer;
025    import org.springframework.jms.listener.AbstractMessageListenerContainer;
026    import org.springframework.jms.support.JmsUtils;
027    
028    /**
029     * A {@link org.apache.camel.Consumer} which uses Spring's {@link AbstractMessageListenerContainer} implementations to consume JMS messages
030     *
031     * @version $Revision: 16521 $
032     */
033    public class JmsConsumer extends DefaultConsumer implements SuspendableService {
034        private AbstractMessageListenerContainer listenerContainer;
035        private EndpointMessageListener messageListener;
036        private boolean initialized;
037        private boolean suspended;
038    
039        public JmsConsumer(JmsEndpoint endpoint, Processor processor, AbstractMessageListenerContainer listenerContainer) {
040            super(endpoint, processor);
041            this.listenerContainer = listenerContainer;
042            this.listenerContainer.setMessageListener(getEndpointMessageListener());
043        }
044    
045        public JmsEndpoint getEndpoint() {
046            return (JmsEndpoint) super.getEndpoint();
047        }
048    
049        public AbstractMessageListenerContainer getListenerContainer() {
050            if (listenerContainer == null) {
051                createMessageListenerContainer();
052            }
053            return listenerContainer;
054        }
055    
056        public EndpointMessageListener getEndpointMessageListener() {
057            if (messageListener == null) {
058                createMessageListener(getEndpoint(), getProcessor());
059            }
060            return messageListener;
061        }
062    
063        protected void createMessageListener(JmsEndpoint endpoint, Processor processor) {
064            messageListener = new EndpointMessageListener(endpoint, processor);
065            messageListener.setBinding(endpoint.getBinding());
066        }
067    
068        protected void createMessageListenerContainer() {
069            listenerContainer = getEndpoint().createMessageListenerContainer();
070            getEndpoint().configureListenerContainer(listenerContainer);
071            listenerContainer.setMessageListener(getEndpointMessageListener());
072        }
073    
074        /**
075         * Starts the JMS listener container
076         * <p/>
077         * Can be used to start this consumer later if it was configured to not auto startup.
078         */
079        public void startListenerContainer() {
080            listenerContainer.start();
081        }
082    
083        /**
084         * Pre tests the connection before starting the listening.
085         * <p/>
086         * In case of connection failure the exception is thrown which prevents Camel from starting.
087         *
088         * @throws FailedToCreateConsumerException is thrown if testing the connection failed
089         */
090        protected void testConnectionOnStartup() throws FailedToCreateConsumerException {
091            try {
092                if (log.isDebugEnabled()) {
093                    log.debug("Testing JMS Connection on startup for destination: " + getDestinationName());
094                }
095                Connection con = listenerContainer.getConnectionFactory().createConnection();
096                JmsUtils.closeConnection(con);
097    
098                log.info("Successfully tested JMS Connection on startup for destination: " + getDestinationName());
099            } catch (Exception e) {
100                String msg = "Cannot get JMS Connection on startup for destination " + getDestinationName();
101                throw new FailedToCreateConsumerException(getEndpoint(), msg, e);
102            }
103        }
104    
105        @Override
106        protected void doStart() throws Exception {
107            super.doStart();
108    
109            // create listener container
110            if (listenerContainer == null) {
111                createMessageListenerContainer();
112            }
113    
114            listenerContainer.afterPropertiesSet();
115    
116            // only start listener if auto start is enabled or we are explicit invoking start later
117            if (initialized || getEndpoint().isAutoStartup()) {
118                // should we pre test connections before starting?
119                if (getEndpoint().isTestConnectionOnStartup()) {
120                    testConnectionOnStartup();
121                }
122                startListenerContainer();
123            }
124    
125            // mark as initialized for the first time
126            initialized = true;
127        }
128    
129        @Override
130        protected void doStop() throws Exception {
131            listenerContainer.stop();
132            listenerContainer.destroy();
133    
134            // null container and listener so they are fully re created if this consumer is restarted
135            // then we will use updated configuration from jms endpoint that may have been managed using JMX
136            listenerContainer = null;
137            messageListener = null;
138            super.doStop();
139        }
140    
141        public void suspend() {
142            if (listenerContainer != null) {
143                listenerContainer.stop();
144                suspended = true;
145            }
146        }
147    
148        public void resume() {
149            if (listenerContainer != null) {
150                startListenerContainer();
151                suspended = false;
152            }
153        }
154    
155        public boolean isSuspended() {
156            return suspended;
157        }
158    
159        private String getDestinationName() {
160            if (listenerContainer.getDestination() != null) {
161                return listenerContainer.getDestination().toString();
162            } else {
163                return listenerContainer.getDestinationName();
164            }
165        }
166    
167    
168    }