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.servicemix.components.util;
018    
019    import javax.jbi.JBIException;
020    import javax.jbi.component.ComponentContext;
021    import javax.jbi.component.ComponentLifeCycle;
022    import javax.jbi.messaging.DeliveryChannel;
023    import javax.jbi.messaging.ExchangeStatus;
024    import javax.jbi.messaging.Fault;
025    import javax.jbi.messaging.InOnly;
026    import javax.jbi.messaging.InOptionalOut;
027    import javax.jbi.messaging.InOut;
028    import javax.jbi.messaging.MessageExchange;
029    import javax.jbi.messaging.MessageExchangeFactory;
030    import javax.jbi.messaging.MessagingException;
031    import javax.jbi.messaging.NormalizedMessage;
032    import javax.jbi.servicedesc.ServiceEndpoint;
033    import javax.management.ObjectName;
034    import javax.xml.namespace.QName;
035    
036    import org.apache.commons.logging.Log;
037    import org.apache.commons.logging.LogFactory;
038    import org.apache.servicemix.jbi.FaultException;
039    import org.apache.servicemix.jbi.NotInitialisedYetException;
040    import org.apache.servicemix.jbi.management.BaseLifeCycle;
041    
042    /**
043     * A useful base class for a POJO based JBI component which contains most of the basic plumbing
044     *
045     * @version $Revision: 2153 $
046     */
047    public abstract class PojoSupport extends BaseLifeCycle implements ComponentLifeCycle {
048    
049        protected Log logger = LogFactory.getLog(getClass());
050        
051        private ComponentContext context;
052        private ObjectName extensionMBeanName;
053        private QName service;
054        private String endpoint;
055        private MessageExchangeFactory exchangeFactory;
056        private String description = "POJO Component";
057        private ServiceEndpoint serviceEndpoint;
058        private DeliveryChannel channel;
059        
060        protected PojoSupport() {
061        }
062    
063        protected PojoSupport(QName service, String endpoint) {
064            this.service = service;
065            this.endpoint = endpoint;
066        }
067        
068        /**
069         * Get the description
070         * @return the description
071         */
072        public String getDescription() {
073            return description;
074        }
075    
076    
077        /**
078         * Called when the Component is initialized
079         *
080         * @param cc
081         * @throws JBIException
082         */
083        public void init(ComponentContext cc) throws JBIException {
084            this.context = cc;
085            this.channel = this.context.getDeliveryChannel();
086            init();
087            if (service != null && endpoint != null) {
088                serviceEndpoint = context.activateEndpoint(service, endpoint);
089            }
090        }
091    
092        /**
093         * Shut down the item. The releases resources, preparing to uninstall
094         * 
095         * @exception javax.jbi.JBIException if the item fails to shut down.
096         */
097        public void shutDown() throws javax.jbi.JBIException {
098            if (serviceEndpoint != null) {
099                context.deactivateEndpoint(serviceEndpoint);
100            }
101            exchangeFactory = null;
102            super.shutDown();
103        }
104    
105        // Helper methods
106        //-------------------------------------------------------------------------
107    
108        /**
109         * A helper method to return the body of the message as a POJO which could be a
110         * bean or some DOMish model of the body.
111         *
112         * @param message the message on which to extract the body
113         * @return the body of the message as a POJO or DOM object
114         * @throws MessagingException
115         */
116        public Object getBody(NormalizedMessage message) throws MessagingException {
117            return MessageHelper.getBody(message);
118        }
119    
120        /**
121         * Sets the body of the message as a POJO
122         *
123         * @param message the message on which to set the body
124         * @param body    the POJO or DOMish model to set
125         * @throws MessagingException
126         */
127        public void setBody(NormalizedMessage message, Object body) throws MessagingException {
128            MessageHelper.setBody(message, body);
129        }
130    
131    
132        // Properties
133        //-------------------------------------------------------------------------
134        public ObjectName getExtensionMBeanName() {
135            return extensionMBeanName;
136        }
137    
138        public void setExtensionMBeanName(ObjectName extensionMBeanName) {
139            this.extensionMBeanName = extensionMBeanName;
140        }
141    
142        public ComponentContext getContext() {
143            return context;
144        }
145    
146        public QName getService() {
147            return service;
148        }
149    
150        public void setService(QName service) {
151            this.service = service;
152        }
153    
154        public String getEndpoint() {
155            return endpoint;
156        }
157    
158        public void setEndpoint(String endpoint) {
159            this.endpoint = endpoint;
160        }
161    
162    
163        /**
164         * Provide access to the default message exchange exchangeFactory, lazily creating one.
165         */
166        public MessageExchangeFactory getExchangeFactory() throws MessagingException {
167            if (exchangeFactory == null && context != null) {
168                exchangeFactory = getDeliveryChannel().createExchangeFactory();
169            }
170            return exchangeFactory;
171        }
172    
173        public DeliveryChannel getDeliveryChannel() throws MessagingException {
174            if (channel == null) {
175                throw new NotInitialisedYetException();
176            }
177            return channel;
178        }
179    
180        /**
181         * A helper method to allow a component to initialise prior to the endpoint being activated
182         * but after the component context has been configured.
183         *
184         * @throws JBIException
185         */
186        protected void init() throws JBIException {
187            super.init();
188        }
189    
190        /**
191         * A helper method to indicate that the message exchange is complete
192         * which will set the status to {@link ExchangeStatus#DONE} and send the message
193         * on the delivery channel.
194         *
195         * @param exchange
196         * @throws MessagingException
197         */
198        public void done(MessageExchange exchange) throws MessagingException {
199            exchange.setStatus(ExchangeStatus.DONE);
200            getDeliveryChannel().send(exchange);
201        }
202    
203        public void send(MessageExchange exchange) throws MessagingException {
204            getDeliveryChannel().send(exchange);
205        }
206        
207        public boolean sendSync(MessageExchange exchange) throws MessagingException {
208            return getDeliveryChannel().sendSync(exchange);
209        }
210    
211        public boolean sendSync(MessageExchange exchange, long timeMillis) throws MessagingException {
212            return getDeliveryChannel().sendSync(exchange, timeMillis);
213        }
214    
215        /**
216         * A helper method to indicate that the message exchange should be
217         * continued with the given response and send the message
218         * on the delivery channel.
219         *
220         * @param exchange
221         * @throws MessagingException
222         */
223        public void answer(MessageExchange exchange, NormalizedMessage answer) throws MessagingException {
224            exchange.setMessage(answer, "out");
225            getDeliveryChannel().send(exchange);
226        }
227    
228        /**
229         * A helper method which fails and completes the given exchange with the specified fault
230         */
231        public void fail(MessageExchange exchange, Fault fault) throws MessagingException {
232            if (exchange instanceof InOnly || fault == null) {
233                exchange.setError(new FaultException("Fault occured for in-only exchange", exchange, fault));
234            } else {
235                exchange.setFault(fault);
236            }
237            getDeliveryChannel().send(exchange);
238        }
239    
240        /**
241         * A helper method which fails and completes the given exchange with the specified error
242         * @throws MessagingException 
243         */
244        public void fail(MessageExchange exchange, Exception error) throws MessagingException {
245            if (exchange instanceof InOnly || !(error instanceof FaultException)) {
246                exchange.setError(error);
247            } else {
248                FaultException faultException = (FaultException) error;
249                exchange.setFault(faultException.getFault());
250            }
251            getDeliveryChannel().send(exchange);
252        }
253    
254    
255        /**
256         * A helper method which will return true if the exchange is capable of both In and Out such as InOut,
257         * InOptionalOut etc.
258         *
259         * @param exchange
260         * @return true if the exchange can handle both input and output
261         */
262        protected boolean isInAndOut(MessageExchange exchange) {
263            return exchange instanceof InOut || exchange instanceof InOptionalOut;
264        }
265    
266    }