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.bean.support;
018    
019    import javax.annotation.Resource;
020    import javax.jbi.component.ComponentContext;
021    import javax.jbi.messaging.DeliveryChannel;
022    import javax.jbi.messaging.ExchangeStatus;
023    import javax.jbi.messaging.Fault;
024    import javax.jbi.messaging.InOnly;
025    import javax.jbi.messaging.InOptionalOut;
026    import javax.jbi.messaging.InOut;
027    import javax.jbi.messaging.MessageExchange;
028    import javax.jbi.messaging.MessageExchangeFactory;
029    import javax.jbi.messaging.MessagingException;
030    import javax.jbi.messaging.NormalizedMessage;
031    import javax.jbi.messaging.RobustInOnly;
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.JbiConstants;
039    import org.apache.servicemix.components.util.CopyTransformer;
040    import org.apache.servicemix.components.util.MessageHelper;
041    import org.apache.servicemix.components.util.MessageTransformer;
042    import org.apache.servicemix.jbi.FaultException;
043    import org.apache.servicemix.jbi.NoInMessageAvailableException;
044    
045    /**
046     * A useful base class for servicemix-bean POJOs
047     *
048     * @version $$
049     */
050    public abstract class BeanSupport {
051    
052        protected Log logger = LogFactory.getLog(getClass());
053        
054        @Resource
055        private ComponentContext context;
056        
057        @Resource
058        private DeliveryChannel channel;
059        
060        @Resource
061        private ServiceEndpoint serviceEndpoint;
062        
063        private ObjectName extensionMBeanName;
064        private MessageExchangeFactory exchangeFactory;
065        private MessageTransformer messageTransformer = CopyTransformer.getInstance();
066        
067        protected BeanSupport() {
068        }
069        
070        // Helper methods
071        //-------------------------------------------------------------------------
072    
073        /**
074         * A helper method to return the body of the message as a POJO which could be a
075         * bean or some DOMish model of the body.
076         *
077         * @param message the message on which to extract the body
078         * @return the body of the message as a POJO or DOM object
079         * @throws MessagingException
080         */
081        public Object getBody(NormalizedMessage message) throws MessagingException {
082            return MessageHelper.getBody(message);
083        }
084    
085        /**
086         * Sets the body of the message as a POJO
087         *
088         * @param message the message on which to set the body
089         * @param body    the POJO or DOMish model to set
090         * @throws MessagingException
091         */
092        public void setBody(NormalizedMessage message, Object body) throws MessagingException {
093            MessageHelper.setBody(message, body);
094        }
095    
096    
097        // Properties
098        //-------------------------------------------------------------------------
099        public ObjectName getExtensionMBeanName() {
100            return extensionMBeanName;
101        }
102    
103        public void setExtensionMBeanName(ObjectName extensionMBeanName) {
104            this.extensionMBeanName = extensionMBeanName;
105        }
106    
107        public ComponentContext getContext() {
108            return context;
109        }
110        
111        public void setContext(ComponentContext context) {
112            this.context = context;
113        }
114    
115        public ServiceEndpoint getServiceEndpoint() {
116            return serviceEndpoint;
117        }
118        
119        public void setServiceEndpoint(ServiceEndpoint serviceEndpoint) {
120            this.serviceEndpoint = serviceEndpoint;
121        }
122        
123        /**
124         * Provide access to the default message exchange exchangeFactory, lazily creating one.
125         */
126        public MessageExchangeFactory getExchangeFactory() throws MessagingException {
127            if (exchangeFactory == null && context != null) {
128                exchangeFactory = getDeliveryChannel().createExchangeFactory();
129            }
130            return exchangeFactory;
131        }
132    
133        public DeliveryChannel getDeliveryChannel() throws MessagingException {
134            if (channel == null) {
135                channel = context.getDeliveryChannel();
136            }
137            return channel;
138        }
139    
140        /**
141         * A helper method to indicate that the message exchange is complete
142         * which will set the status to {@link ExchangeStatus#DONE} and send the message
143         * on the delivery channel.
144         *
145         * @param exchange
146         * @throws MessagingException
147         */
148        public void done(MessageExchange exchange) throws MessagingException {
149            exchange.setStatus(ExchangeStatus.DONE);
150            getDeliveryChannel().send(exchange);
151        }
152    
153        public void send(MessageExchange exchange) throws MessagingException {
154            getDeliveryChannel().send(exchange);
155        }
156        
157        public boolean sendSync(MessageExchange exchange) throws MessagingException {
158            return getDeliveryChannel().sendSync(exchange);
159        }
160    
161        public boolean sendSync(MessageExchange exchange, long timeMillis) throws MessagingException {
162            return getDeliveryChannel().sendSync(exchange, timeMillis);
163        }
164    
165        /**
166         * A helper method to indicate that the message exchange should be
167         * continued with the given response and send the message
168         * on the delivery channel.
169         *
170         * @param exchange
171         * @throws MessagingException
172         */
173        public void answer(MessageExchange exchange, NormalizedMessage answer) throws MessagingException {
174            exchange.setMessage(answer, "out");
175            getDeliveryChannel().send(exchange);
176        }
177    
178        /**
179         * A helper method which fails and completes the given exchange with the specified fault
180         */
181        public void fail(MessageExchange exchange, Fault fault) throws MessagingException {
182            if (exchange instanceof InOnly || fault == null) {
183                exchange.setError(new FaultException("Fault occured for in-only exchange", exchange, fault));
184            } else {
185                exchange.setFault(fault);
186            }
187            getDeliveryChannel().send(exchange);
188        }
189    
190        /**
191         * A helper method which fails and completes the given exchange with the specified error
192         * @throws MessagingException 
193         */
194        public void fail(MessageExchange exchange, Exception error) throws MessagingException {
195            if (exchange instanceof InOnly || !(error instanceof FaultException)) {
196                exchange.setError(error);
197            } else {
198                FaultException faultException = (FaultException) error;
199                exchange.setFault(faultException.getFault());
200            }
201            getDeliveryChannel().send(exchange);
202        }
203    
204    
205        /**
206         * A helper method which will return true if the exchange is capable of both In and Out such as InOut,
207         * InOptionalOut etc.
208         *
209         * @param exchange
210         * @return true if the exchange can handle both input and output
211         */
212        protected boolean isInAndOut(MessageExchange exchange) {
213            return exchange instanceof InOut || exchange instanceof InOptionalOut;
214        }
215    
216        /**
217         * Returns the in message or throws an exception if there is no in message.
218         */
219        protected NormalizedMessage getInMessage(MessageExchange exchange) throws NoInMessageAvailableException {
220            NormalizedMessage message = exchange.getMessage("in");
221            if (message == null) {
222                throw new NoInMessageAvailableException(exchange);
223            }
224            return message;
225        }
226    
227        public MessageTransformer getMessageTransformer() {
228            return messageTransformer;
229        }
230    
231        public void setMessageTransformer(MessageTransformer transformer) {
232            this.messageTransformer = transformer;
233        }
234    
235        /**
236         * Performs an invocation where the service, operation or interface name could be specified
237         *
238         * @param exchange
239         * @param in
240         * @param service
241         * @param interfaceName
242         * @param operation
243         */
244        public void invoke(MessageExchange exchange, NormalizedMessage in, 
245                           QName service, QName interfaceName, QName operation) throws MessagingException {
246            InOnly outExchange = createInOnlyExchange(service, interfaceName, operation);
247            forwardToExchange(exchange, outExchange, in, operation);
248        }
249    
250        /**
251         * Creates a new InOnly exchange for the given service, interface and/or operation (any of which can be null).
252         */
253        public InOnly createInOnlyExchange(QName service, QName interfaceName, QName operation) throws MessagingException {
254            MessageExchangeFactory factory = null;
255            if (service != null) {
256                factory = getDeliveryChannel().createExchangeFactoryForService(service);
257            } else if (interfaceName != null) {
258                factory = getDeliveryChannel().createExchangeFactory(interfaceName);
259            } else {
260                factory = getExchangeFactory();
261            }
262            InOnly outExchange = factory.createInOnlyExchange();
263            if (service != null) {
264                outExchange.setService(service);
265            }
266            if (interfaceName != null) {
267                outExchange.setInterfaceName(interfaceName);
268            }
269            if (operation != null) {
270                outExchange.setOperation(operation);
271            }
272            return outExchange;
273        }
274    
275        public InOnly createInOnlyExchange(QName service, QName interfaceName, 
276                                           QName operation, MessageExchange beforeExchange) throws MessagingException {
277            InOnly inOnly = createInOnlyExchange(service, interfaceName, operation);
278            propagateCorrelationId(beforeExchange, inOnly);
279            return inOnly;
280        }
281    
282        /**
283         * Creates a new InOut exchange for the given service, interface and/or operation (any of which can be null).
284         */
285        public InOut createInOutExchange(QName service, QName interfaceName, QName operation) throws MessagingException {
286            MessageExchangeFactory factory = null;
287            if (service != null) {
288                factory = getDeliveryChannel().createExchangeFactoryForService(service);
289            } else if (interfaceName != null) {
290                factory = getDeliveryChannel().createExchangeFactory(interfaceName);
291            } else {
292                factory = getExchangeFactory();
293            }
294            InOut outExchange = factory.createInOutExchange();
295            if (service != null) {
296                outExchange.setService(service);
297            }
298            if (interfaceName != null) {
299                outExchange.setInterfaceName(interfaceName);
300            }
301            if (operation != null) {
302                outExchange.setOperation(operation);
303            }
304            return outExchange;
305        }
306    
307        public InOut createInOutExchange(QName service, QName interfaceName, 
308                                        QName operation, MessageExchange srcExchange) throws MessagingException {
309            InOut inOut = createInOutExchange(service, interfaceName, operation);
310            propagateCorrelationId(srcExchange, inOut);
311            return inOut;
312        }
313    
314        /**
315         * Creates an InOnly exchange and propagates the correlation id from the given exchange
316         * to the newly created exchange
317         * @param srcExchange
318         * @return InOnly
319         * @throws MessagingException
320         */
321        public InOnly createInOnlyExchange(MessageExchange srcExchange) throws MessagingException {
322            MessageExchangeFactory factory = getExchangeFactory();
323            InOnly inOnly = factory.createInOnlyExchange();
324    
325            propagateCorrelationId(srcExchange, inOnly);
326    
327            return inOnly;
328        }
329    
330        /**
331         * Creates an InOptionalOut exchange and propagates the correlation id from the given exchange
332         * to the newly created exchange
333         * @param srcExchange
334         * @return InOptionalOut
335         * @throws MessagingException
336         */
337        public InOptionalOut createInOptionalOutExchange(MessageExchange srcExchange) throws MessagingException {
338            MessageExchangeFactory factory = getExchangeFactory();
339            InOptionalOut inOptionalOut = factory.createInOptionalOutExchange();
340    
341            propagateCorrelationId(srcExchange, inOptionalOut);
342    
343            return inOptionalOut;
344        }
345    
346        /**
347         * Creates an InOut exchange and propagates the correlation id from the given exchange
348         * to the newly created exchange
349         * @param srcExchange
350         * @return InOut
351         * @throws MessagingException
352         */
353        public InOut createInOutExchange(MessageExchange srcExchange) throws MessagingException {
354            MessageExchangeFactory factory = getExchangeFactory();
355            InOut inOut = factory.createInOutExchange();
356    
357            propagateCorrelationId(srcExchange, inOut);
358    
359            return inOut;
360        }
361    
362        /**
363         * Creates an RobustInOnly exchange and propagates the correlation id from the given exchange
364         * to the newly created exchange
365         * @param srcExchange
366         * @return RobustInOnly the created exchange
367         * @throws MessagingException
368         */
369        public RobustInOnly createRobustInOnlyExchange(MessageExchange srcExchange) throws MessagingException {
370            MessageExchangeFactory factory = getExchangeFactory();
371            RobustInOnly robustInOnly = factory.createRobustInOnlyExchange();
372    
373            propagateCorrelationId(srcExchange, robustInOnly);
374    
375            return robustInOnly;
376        }
377    
378        /**
379         * Propagates the correlation id from an exchange to a newly created exchange
380         * @param source Exchange which already exists
381         * @param dest Newly created exchange which should get the correlation id
382         */
383        public void propagateCorrelationId(MessageExchange source, MessageExchange dest) {
384            if (source == null || dest == null) {
385                return;
386            }
387            String correlationId = (String) source.getProperty(JbiConstants.CORRELATION_ID);
388            if (correlationId != null) {
389                dest.setProperty(JbiConstants.CORRELATION_ID, correlationId);
390            } else {
391                dest.setProperty(JbiConstants.CORRELATION_ID, source.getExchangeId());
392            }
393        }
394    
395        protected void forwardToExchange(MessageExchange exchange, InOnly outExchange, 
396                                         NormalizedMessage in, QName operationName) throws MessagingException {
397            if (operationName != null) {
398                exchange.setOperation(operationName);
399            }
400            forwardToExchange(exchange, outExchange, in);
401        }
402    
403        protected void forwardToExchange(MessageExchange exchange, InOnly outExchange, NormalizedMessage in) throws MessagingException {
404            NormalizedMessage out = outExchange.createMessage();
405            outExchange.setInMessage(out);
406            getMessageTransformer().transform(exchange, in, out);
407            getDeliveryChannel().send(outExchange);
408        }
409        
410        protected QName getService() {
411            QName service = null;
412            if (serviceEndpoint != null) {
413                service = serviceEndpoint.getServiceName();
414            }
415            return service;
416        }
417    
418        protected String getEndpoint() {
419            String endpoint = null;
420            if (serviceEndpoint != null) {
421                endpoint = serviceEndpoint.getEndpointName();
422            }
423            return endpoint;
424        }
425    
426    }