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.client;
018    
019    import java.util.Iterator;
020    import java.util.Map;
021    
022    import javax.jbi.JBIException;
023    import javax.jbi.component.ComponentContext;
024    import javax.jbi.messaging.DeliveryChannel;
025    import javax.jbi.messaging.Fault;
026    import javax.jbi.messaging.InOnly;
027    import javax.jbi.messaging.InOptionalOut;
028    import javax.jbi.messaging.InOut;
029    import javax.jbi.messaging.MessageExchange;
030    import javax.jbi.messaging.MessageExchangeFactory;
031    import javax.jbi.messaging.MessagingException;
032    import javax.jbi.messaging.NormalizedMessage;
033    import javax.jbi.messaging.RobustInOnly;
034    import javax.jbi.servicedesc.ServiceEndpoint;
035    import javax.xml.namespace.QName;
036    
037    import org.w3c.dom.DocumentFragment;
038    
039    import org.apache.servicemix.components.util.ComponentSupport;
040    import org.apache.servicemix.jbi.FaultException;
041    import org.apache.servicemix.jbi.NoOutMessageAvailableException;
042    import org.apache.servicemix.jbi.api.Message;
043    import org.apache.servicemix.jbi.container.ActivationSpec;
044    import org.apache.servicemix.jbi.container.JBIContainer;
045    import org.apache.servicemix.jbi.messaging.DefaultMarshaler;
046    import org.apache.servicemix.jbi.messaging.PojoMarshaler;
047    import org.apache.servicemix.jbi.resolver.EndpointFilter;
048    import org.apache.servicemix.jbi.resolver.EndpointResolver;
049    import org.apache.servicemix.jbi.resolver.ExternalInterfaceNameEndpointResolver;
050    import org.apache.servicemix.jbi.resolver.ExternalServiceNameEndpointResolver;
051    import org.apache.servicemix.jbi.resolver.InterfaceNameEndpointResolver;
052    import org.apache.servicemix.jbi.resolver.NullEndpointFilter;
053    import org.apache.servicemix.jbi.resolver.ServiceAndEndpointNameResolver;
054    import org.apache.servicemix.jbi.resolver.ServiceNameEndpointResolver;
055    import org.apache.servicemix.jbi.resolver.URIResolver;
056    
057    /**
058     * The default implementation of the {@link ServiceMixClient} API.
059     *
060     * @version $Revision: 690848 $
061     */
062    public class DefaultServiceMixClient extends ComponentSupport implements ServiceMixClient {
063    
064        private EndpointFilter filter = NullEndpointFilter.getInstance();
065        private PojoMarshaler marshaler = new DefaultMarshaler();
066        private JBIContainer container;
067        private ActivationSpec activationSpec;
068    
069        protected DefaultServiceMixClient() {
070        }
071        
072        /**
073         * Provides the JBI container used for message dispatch.
074         */
075        public DefaultServiceMixClient(JBIContainer container) throws JBIException {
076            this(container, new ActivationSpec());
077        }
078    
079        /**
080         * Provides the JBI container and the activation specification, which can be used to register this
081         * client at a specific endpoint so that default container routing rules can be configured via dependency injection
082         * and the client endpoint metadata can be configured to allow services to talk to this client.
083         */
084        public DefaultServiceMixClient(JBIContainer container, ActivationSpec activationSpec) throws JBIException {
085            this.container = container;
086            this.activationSpec = activationSpec;
087            activationSpec.setComponent(this);
088            container.activateComponent(activationSpec);
089        }
090    
091        public InOnly createInOnlyExchange() throws MessagingException {
092            InOnly exchange = getExchangeFactory().createInOnlyExchange();
093            NormalizedMessage in = exchange.createMessage();
094            exchange.setInMessage(in);
095            return exchange;
096        }
097    
098        public InOnly createInOnlyExchange(EndpointResolver resolver) throws JBIException {
099            InOnly exchange = createInOnlyExchange();
100            configureEndpoint(exchange, resolver);
101            return exchange;
102        }
103    
104        public InOut createInOutExchange() throws MessagingException {
105            InOut exchange = getExchangeFactory().createInOutExchange();
106            NormalizedMessage in = exchange.createMessage();
107            exchange.setInMessage(in);
108            return exchange;
109        }
110    
111        public InOut createInOutExchange(EndpointResolver resolver) throws JBIException {
112            InOut exchange = createInOutExchange();
113            configureEndpoint(exchange, resolver);
114            return exchange;
115        }
116    
117        public InOptionalOut createInOptionalOutExchange() throws MessagingException {
118            InOptionalOut exchange = getExchangeFactory().createInOptionalOutExchange();
119            NormalizedMessage in = exchange.createMessage();
120            exchange.setInMessage(in);
121            return exchange;
122        }
123    
124        public InOptionalOut createInOptionalOutExchange(EndpointResolver resolver) throws JBIException {
125            InOptionalOut exchange = createInOptionalOutExchange();
126            configureEndpoint(exchange, resolver);
127            return exchange;
128        }
129    
130        public RobustInOnly createRobustInOnlyExchange() throws MessagingException {
131            RobustInOnly exchange = getExchangeFactory().createRobustInOnlyExchange();
132            NormalizedMessage in = exchange.createMessage();
133            exchange.setInMessage(in);
134            return exchange;
135        }
136    
137        public RobustInOnly createRobustInOnlyExchange(EndpointResolver resolver) throws JBIException {
138            RobustInOnly exchange = getExchangeFactory().createRobustInOnlyExchange();
139            configureEndpoint(exchange, resolver);
140            return exchange;
141        }
142    
143        public Destination createDestination(String uri) throws MessagingException {
144            return new DefaultDestination(this, uri);
145        }
146        
147        public void send(MessageExchange exchange) throws MessagingException {
148            getDeliveryChannel().send(exchange);
149        }
150        
151        public void send(Message message) throws MessagingException {
152            send(message.getExchange());
153        }
154    
155        public boolean sendSync(MessageExchange exchange) throws MessagingException {
156            return getDeliveryChannel().sendSync(exchange);
157        }
158    
159        public boolean sendSync(MessageExchange exchange, long timeout) throws MessagingException {
160            return getDeliveryChannel().sendSync(exchange, timeout);
161        }
162    
163        public MessageExchange receive() throws MessagingException {
164            return getDeliveryChannel().accept();
165        }
166    
167        public MessageExchange receive(long timeout) throws MessagingException {
168            return getDeliveryChannel().accept(timeout);
169        }
170    
171        public ComponentContext getContext() {
172            return super.getContext();
173        }
174    
175        public DeliveryChannel getDeliveryChannel() throws MessagingException {
176            return super.getDeliveryChannel();
177        }
178    
179        public MessageExchangeFactory getExchangeFactory() throws MessagingException {
180            return super.getExchangeFactory();
181        }
182    
183        public void done(MessageExchange exchange) throws MessagingException {
184            super.done(exchange);
185        }
186    
187        public void fail(MessageExchange exchange, Fault fault) throws MessagingException {
188            super.fail(exchange, fault);
189        }
190    
191        public void fail(MessageExchange exchange, Exception error) throws MessagingException {
192            super.fail(exchange, error);
193        }
194    
195        // Helper methods to make JBI a little more concise to use from a client
196        //-------------------------------------------------------------------------
197        public Object request(Map inMessageProperties, Object content) throws JBIException {
198            return request(null, null, inMessageProperties, content);
199        }
200    
201        public void send(Map inMessageProperties, Object content) throws JBIException {
202            send(null, null, inMessageProperties, content);
203        }
204    
205        public boolean sendSync(Map inMessageProperties, Object content) throws JBIException {
206            return sendSync(null, null, inMessageProperties, content);
207        }
208    
209        public void send(EndpointResolver resolver, Map exchangeProperties, Map inMessageProperties, Object content) throws JBIException {
210            InOnly exchange = createInOnlyExchange(resolver);
211            populateMessage(exchange, exchangeProperties, inMessageProperties, content);
212            send(exchange);
213        }
214    
215        public boolean sendSync(EndpointResolver resolver, Map exchangeProperties, 
216                                Map inMessageProperties, Object content) throws JBIException {
217            InOnly exchange = createInOnlyExchange(resolver);
218            populateMessage(exchange, exchangeProperties, inMessageProperties, content);
219            return sendSync(exchange);
220        }
221    
222        public Object request(EndpointResolver resolver, Map exchangeProperties, Map inMessageProperties, Object content) throws JBIException {
223            InOut exchange = createInOutExchange(resolver);
224            populateMessage(exchange, exchangeProperties, inMessageProperties, content);
225            boolean answer = sendSync(exchange);
226            if (!answer) {
227                throw new JBIException("Exchange aborted");
228            }
229            Exception error = exchange.getError();
230            if (error != null) {
231                throw new JBIException(error);
232            }
233            if (exchange.getFault() != null) {
234                done(exchange);
235                throw FaultException.newInstance(exchange);
236            }
237    
238    
239            NormalizedMessage outMessage = exchange.getOutMessage();
240            if (outMessage == null) {
241                throw new NoOutMessageAvailableException(exchange);
242            }
243            Object result = getMarshaler().unmarshal(exchange, outMessage);
244            done(exchange);
245            return result;
246        }
247    
248        /**
249         * Resolves a WS-Addressing endpoint reference String into a JBI {@link ServiceEndpoint}
250         * reference so that message exchanges can be directed to an endpoint
251         */
252        public ServiceEndpoint resolveEndpointReference(String uri) {
253            DocumentFragment epr = URIResolver.createWSAEPR(uri);
254            return getContext().resolveEndpointReference(epr);
255        }
256    
257        public EndpointResolver createResolverForService(QName service) {
258            return new ServiceNameEndpointResolver(service);
259        }
260    
261        public EndpointResolver createResolverInterface(QName interfaceName) {
262            return new InterfaceNameEndpointResolver(interfaceName);
263        }
264    
265        public EndpointResolver createResolverForExternalService(QName service) {
266            return new ExternalServiceNameEndpointResolver(service);
267        }
268    
269        public EndpointResolver createResolverForExternalInterface(QName interfaceName) {
270            return new ExternalInterfaceNameEndpointResolver(interfaceName);
271        }
272    
273        public EndpointResolver createResolverForExternalInterface(QName service, String endpoint) {
274            return new ServiceAndEndpointNameResolver(service, endpoint);
275        }
276        
277        public void close() throws JBIException {
278            if (container != null) {
279                container.deactivateComponent(activationSpec.getComponentName());
280            }
281        }
282    
283    
284        // Properties
285        //-------------------------------------------------------------------------
286        public EndpointFilter getFilter() {
287            return filter;
288        }
289    
290        /**
291         * Sets the filter used to exclude possible endpoints based on their capabilities
292         *
293         * @param filter
294         */
295        public void setFilter(EndpointFilter filter) {
296            this.filter = filter;
297        }
298    
299        public PojoMarshaler getMarshaler() {
300            return marshaler;
301        }
302    
303        /**
304         * Sets the marshaler used to convert objects which are not already JAXP {@link Source} instances
305         * into the normalized message content.
306         *
307         * @param marshaler
308         */
309        public void setMarshaler(PojoMarshaler marshaler) {
310            this.marshaler = marshaler;
311        }
312    
313    
314        // Implementation methods
315        //-------------------------------------------------------------------------
316    
317        protected void configureEndpoint(MessageExchange exchange, EndpointResolver resolver) throws JBIException {
318            if (resolver != null) {
319                exchange.setEndpoint(resolver.resolveEndpoint(getContext(), exchange, filter));
320            }
321        }
322    
323        protected void populateMessage(MessageExchange exchange, Map exchangeProperties, 
324                                       Map inMessageProperties, Object content) throws MessagingException {
325            NormalizedMessage in = exchange.getMessage("in");
326            populateExchangeProperties(exchange, exchangeProperties);
327            populateMessageProperties(in, inMessageProperties);
328            getMarshaler().marshal(exchange, in, content);
329        }
330    
331        protected void populateExchangeProperties(MessageExchange exchange, Map properties) {
332            if (properties != null) {
333                for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
334                    Map.Entry entry = (Map.Entry) iter.next();
335                    exchange.setProperty((String) entry.getKey(), entry.getValue());
336                }
337            }
338        }
339    
340        protected void populateMessageProperties(NormalizedMessage message, Map properties) {
341            if (properties != null) {
342                for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
343                    Map.Entry entry = (Map.Entry) iter.next();
344                    message.setProperty((String) entry.getKey(), entry.getValue());
345                }
346            }
347        }
348    
349        public void send(org.apache.servicemix.client.Message message) throws MessagingException {
350            send(message.getExchange());
351        }
352    
353        public InOnly createInOnlyExchange(org.apache.servicemix.jbi.api.EndpointResolver resolver)
354            throws JBIException {
355            InOnly exchange = createInOnlyExchange();
356            configureEndpoint(exchange, resolver);
357            return exchange;
358        }
359    
360        public InOptionalOut createInOptionalOutExchange(org.apache.servicemix.jbi.api.EndpointResolver resolver)
361            throws JBIException {
362            InOptionalOut exchange = createInOptionalOutExchange();
363            configureEndpoint(exchange, resolver);
364            return exchange;
365        }
366    
367        public InOut createInOutExchange(org.apache.servicemix.jbi.api.EndpointResolver resolver) throws JBIException {
368            InOut exchange = createInOutExchange();
369            configureEndpoint(exchange, resolver);
370            return exchange;
371        }
372    
373        public RobustInOnly createRobustInOnlyExchange(org.apache.servicemix.jbi.api.EndpointResolver resolver)
374            throws JBIException {
375            RobustInOnly exchange = getExchangeFactory().createRobustInOnlyExchange();
376            configureEndpoint(exchange, resolver);
377            return exchange;
378        }
379    
380        public Object request(org.apache.servicemix.jbi.api.EndpointResolver resolver, Map exchangeProperties, 
381                              Map inMessageProperties, Object content) throws JBIException {
382            InOut exchange = createInOutExchange(resolver);
383            populateMessage(exchange, exchangeProperties, inMessageProperties, content);
384            boolean answer = sendSync(exchange);
385            if (!answer) {
386                throw new JBIException("Exchange aborted");
387            }
388            Exception error = exchange.getError();
389            if (error != null) {
390                throw new JBIException(error);
391            }
392            if (exchange.getFault() != null) {
393                done(exchange);
394                throw FaultException.newInstance(exchange);
395            }
396    
397    
398            NormalizedMessage outMessage = exchange.getOutMessage();
399            if (outMessage == null) {
400                throw new NoOutMessageAvailableException(exchange);
401            }
402            Object result = getMarshaler().unmarshal(exchange, outMessage);
403            done(exchange);
404            return result;
405        }
406    
407        public void send(org.apache.servicemix.jbi.api.EndpointResolver resolver, Map exchangeProperties, 
408                         Map inMessageProperties, Object content) throws JBIException {
409            InOnly exchange = createInOnlyExchange(resolver);
410            populateMessage(exchange, exchangeProperties, inMessageProperties, content);
411            send(exchange);        
412        }
413    
414        public boolean sendSync(org.apache.servicemix.jbi.api.EndpointResolver resolver, 
415                                Map exchangeProperties, Map inMessageProperties,
416                                Object content) throws JBIException {
417            InOnly exchange = createInOnlyExchange(resolver);
418            populateMessage(exchange, exchangeProperties, inMessageProperties, content);
419            return sendSync(exchange);
420        }
421        
422        protected void configureEndpoint(MessageExchange exchange, 
423            org.apache.servicemix.jbi.api.EndpointResolver resolver) throws JBIException {
424            if (resolver != null) {
425                exchange.setEndpoint(resolver.resolveEndpoint(getContext(), exchange, filter));
426            }
427        }
428    }