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 }