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.ExchangeStatus;
026 import javax.jbi.messaging.Fault;
027 import javax.jbi.messaging.InOnly;
028 import javax.jbi.messaging.InOptionalOut;
029 import javax.jbi.messaging.InOut;
030 import javax.jbi.messaging.MessageExchange;
031 import javax.jbi.messaging.MessageExchangeFactory;
032 import javax.jbi.messaging.MessagingException;
033 import javax.jbi.messaging.NormalizedMessage;
034 import javax.jbi.messaging.RobustInOnly;
035 import javax.jbi.servicedesc.ServiceEndpoint;
036 import javax.xml.namespace.QName;
037
038 import org.w3c.dom.DocumentFragment;
039
040 import org.apache.servicemix.jbi.FaultException;
041 import org.apache.servicemix.jbi.NoOutMessageAvailableException;
042 import org.apache.servicemix.jbi.api.EndpointResolver;
043 import org.apache.servicemix.jbi.api.Message;
044 import org.apache.servicemix.jbi.container.ActivationSpec;
045 import org.apache.servicemix.jbi.container.JBIContainer;
046 import org.apache.servicemix.jbi.messaging.DefaultMarshaler;
047 import org.apache.servicemix.jbi.messaging.PojoMarshaler;
048 import org.apache.servicemix.jbi.resolver.EndpointFilter;
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 * A Facade around the {@link ComponentContext} to provide the {@link ServiceMixClient} API which is useful for
059 * working with JBI from inside a POJO based JBI Component which doesn't derive from {@link PojoSupport}
060 *
061 * @version $Revision: 690190 $
062 */
063 public class ServiceMixClientFacade implements ServiceMixClient {
064
065 private ComponentContext context;
066 private EndpointFilter filter = NullEndpointFilter.getInstance();
067 private PojoMarshaler marshaler = new DefaultMarshaler();
068 private MessageExchangeFactory exchangeFactory;
069
070 public ServiceMixClientFacade(ComponentContext context) {
071 this.context = context;
072 }
073
074 /**
075 * Provides the JBI container used for message dispatch.
076 */
077 public ServiceMixClientFacade(JBIContainer container) throws JBIException {
078 this(container, new ActivationSpec());
079 }
080
081 /**
082 * Provides the JBI container and the activation specification, which can be used to register this
083 * client at a specific endpoint so that default container routing rules can be configured via dependency injection
084 * and the client endpoint metadata can be configured to allow services to talk to this client.
085 */
086 public ServiceMixClientFacade(JBIContainer container, ActivationSpec activationSpec) throws JBIException {
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 context;
173 }
174
175 public DeliveryChannel getDeliveryChannel() throws MessagingException {
176 return getContext().getDeliveryChannel();
177 }
178
179 /**
180 * Provide access to the default message exchange exchangeFactory, lazily creating one.
181 */
182 public MessageExchangeFactory getExchangeFactory() throws MessagingException {
183 if (exchangeFactory == null && context != null) {
184 exchangeFactory = getDeliveryChannel().createExchangeFactory();
185 }
186 return exchangeFactory;
187 }
188
189 /**
190 * A helper method to indicate that the message exchange is complete
191 * which will set the status to {@link ExchangeStatus#DONE} and send the message
192 * on the delivery channel.
193 *
194 * @param exchange
195 * @throws MessagingException
196 */
197 public void done(MessageExchange exchange) throws MessagingException {
198 exchange.setStatus(ExchangeStatus.DONE);
199 getDeliveryChannel().send(exchange);
200 }
201
202 /**
203 * A helper method which fails and completes the given exchange with the specified fault
204 */
205 public void fail(MessageExchange exchange, Fault fault) throws MessagingException {
206 exchange.setFault(fault);
207 getDeliveryChannel().send(exchange);
208 }
209
210 /**
211 * A helper method which fails and completes the given exchange with the specified error
212 */
213 public void fail(MessageExchange exchange, Exception error) throws MessagingException {
214 if (error instanceof FaultException) {
215 FaultException faultException = (FaultException) error;
216 exchange.setFault(faultException.getFault());
217 } else {
218 exchange.setError(error);
219 }
220 getDeliveryChannel().send(exchange);
221 }
222
223 // Helper methods to make JBI a little more concise to use from a client
224 //-------------------------------------------------------------------------
225
226 public Object request(Map inMessageProperties, Object content) throws JBIException {
227 return request(null, null, inMessageProperties, content);
228 }
229
230 public void send(Map inMessageProperties, Object content) throws JBIException {
231 send(null, null, inMessageProperties, content);
232 }
233
234 public boolean sendSync(Map inMessageProperties, Object content) throws JBIException {
235 return sendSync(null, null, inMessageProperties, content);
236 }
237
238 public void send(EndpointResolver resolver, Map exchangeProperties, Map inMessageProperties, Object content) throws JBIException {
239 InOnly exchange = createInOnlyExchange(resolver);
240 populateMessage(exchange, exchangeProperties, inMessageProperties, content);
241 send(exchange);
242 }
243
244 public boolean sendSync(EndpointResolver resolver, Map exchangeProperties,
245 Map inMessageProperties, Object content) throws JBIException {
246 InOnly exchange = createInOnlyExchange(resolver);
247 populateMessage(exchange, exchangeProperties, inMessageProperties, content);
248 return sendSync(exchange);
249 }
250
251 public Object request(EndpointResolver resolver, Map exchangeProperties, Map inMessageProperties, Object content) throws JBIException {
252 InOut exchange = createInOutExchange(resolver);
253 populateMessage(exchange, exchangeProperties, inMessageProperties, content);
254 boolean answer = sendSync(exchange);
255 if (!answer) {
256 throw new JBIException("Exchange aborted");
257 }
258 Exception error = exchange.getError();
259 if (error != null) {
260 throw new JBIException(error);
261 }
262 if (exchange.getFault() != null) {
263 done(exchange);
264 throw FaultException.newInstance(exchange);
265 }
266
267
268 NormalizedMessage outMessage = exchange.getOutMessage();
269 if (outMessage == null) {
270 throw new NoOutMessageAvailableException(exchange);
271 }
272 Object result = getMarshaler().unmarshal(exchange, outMessage);
273 done(exchange);
274 return result;
275 }
276
277 public ServiceEndpoint resolveEndpointReference(String uri) {
278 DocumentFragment epr = URIResolver.createWSAEPR(uri);
279 return getContext().resolveEndpointReference(epr);
280 }
281
282 public EndpointResolver createResolverForService(QName service) {
283 return new ServiceNameEndpointResolver(service);
284 }
285
286 public EndpointResolver createResolverInterface(QName interfaceName) {
287 return new InterfaceNameEndpointResolver(interfaceName);
288 }
289
290 public EndpointResolver createResolverForExternalService(QName service) {
291 return new ExternalServiceNameEndpointResolver(service);
292 }
293
294 public EndpointResolver createResolverForExternalInterface(QName interfaceName) {
295 return new ExternalInterfaceNameEndpointResolver(interfaceName);
296 }
297
298 public EndpointResolver createResolverForExternalInterface(QName service, String endpoint) {
299 return new ServiceAndEndpointNameResolver(service, endpoint);
300 }
301
302 public void close() throws JBIException {
303 }
304
305
306 // Properties
307 //-------------------------------------------------------------------------
308 public EndpointFilter getFilter() {
309 return filter;
310 }
311
312 /**
313 * Sets the filter used to exclude possible endpoints based on their capabilities
314 *
315 * @param filter
316 */
317 public void setFilter(EndpointFilter filter) {
318 this.filter = filter;
319 }
320
321 public PojoMarshaler getMarshaler() {
322 return marshaler;
323 }
324
325 /**
326 * Sets the marshaler used to convert objects which are not already JAXP {@link Source} instances
327 * into the normalized message content.
328 *
329 * @param marshaler
330 */
331 public void setMarshaler(PojoMarshaler marshaler) {
332 this.marshaler = marshaler;
333 }
334
335 // Implementation methods
336 //-------------------------------------------------------------------------
337
338 protected void configureEndpoint(MessageExchange exchange, EndpointResolver resolver) throws JBIException {
339 if (resolver != null) {
340 exchange.setEndpoint(resolver.resolveEndpoint(getContext(), exchange, filter));
341 }
342 }
343
344 protected void populateMessage(MessageExchange exchange, Map exchangeProperties,
345 Map inMessageProperties, Object content) throws MessagingException {
346 NormalizedMessage in = exchange.getMessage("in");
347 populateExchangeProperties(exchange, exchangeProperties);
348 populateMessageProperties(in, inMessageProperties);
349 getMarshaler().marshal(exchange, in, content);
350 }
351
352 protected void populateExchangeProperties(MessageExchange exchange, Map properties) {
353 if (properties != null) {
354 for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
355 Map.Entry entry = (Map.Entry) iter.next();
356 exchange.setProperty((String) entry.getKey(), entry.getValue());
357 }
358 }
359 }
360
361 protected void populateMessageProperties(NormalizedMessage message, Map properties) {
362 if (properties != null) {
363 for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
364 Map.Entry entry = (Map.Entry) iter.next();
365 message.setProperty((String) entry.getKey(), entry.getValue());
366 }
367 }
368 }
369 }