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