1 /*
2 * $Id: AbstractMessageRequester.java 23247 2011-10-24 17:16:56Z mike.schilling $
3 * --------------------------------------------------------------------------------------
4 * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
5 *
6 * The software in this package is published under the terms of the CPAL v1.0
7 * license, a copy of which has been included with this distribution in the
8 * LICENSE.txt file.
9 */
10
11 package org.mule.transport;
12
13 import org.mule.DefaultMuleMessage;
14 import org.mule.api.MuleException;
15 import org.mule.api.MuleMessage;
16 import org.mule.api.config.MuleProperties;
17 import org.mule.api.context.WorkManager;
18 import org.mule.api.endpoint.InboundEndpoint;
19 import org.mule.api.lifecycle.InitialisationException;
20 import org.mule.api.transformer.Transformer;
21 import org.mule.api.transport.MessageRequester;
22 import org.mule.api.transport.PropertyScope;
23 import org.mule.api.transport.ReceiveException;
24 import org.mule.context.notification.EndpointMessageNotification;
25
26 import java.util.List;
27
28 /**
29 * The Message Requester is used to explicitly request messages from a message channel or
30 * resource rather than subscribing to inbound events or polling for messages.
31 * This is often used programatically but will not be used for inbound endpoints
32 * configured on services.
33 */
34 public abstract class AbstractMessageRequester extends AbstractTransportMessageHandler implements MessageRequester
35 {
36 private List<Transformer> defaultInboundTransformers;
37
38 public AbstractMessageRequester(InboundEndpoint endpoint)
39 {
40 super(endpoint);
41 }
42
43 @Override
44 protected ConnectableLifecycleManager createLifecycleManager()
45 {
46 return new ConnectableLifecycleManager<MessageRequester>(getRequesterName(), this);
47 }
48
49 /**
50 * Method used to perform any initialisation work. If a fatal error occurs during
51 * initialisation an <code>InitialisationException</code> should be thrown,
52 * causing the Mule instance to shutdown. If the error is recoverable, say by
53 * retrying to connect, a <code>RecoverableException</code> should be thrown.
54 * There is no guarantee that by throwing a Recoverable exception that the Mule
55 * instance will not shut down.
56 *
57 * @throws org.mule.api.lifecycle.InitialisationException if a fatal error occurs
58 * causing the Mule instance to shutdown
59 * @throws org.mule.api.lifecycle.RecoverableException if an error occurs that
60 * can be recovered from
61 */
62 @Override
63 public final void initialise() throws InitialisationException
64 {
65 defaultInboundTransformers = connector.getDefaultInboundTransformers(endpoint);
66 super.initialise();
67 }
68
69 protected String getRequesterName()
70 {
71 return getConnector().getName() + ".requester." + System.identityHashCode(this);
72 }
73
74 /**
75 * Make a specific request to the underlying transport
76 *
77 * @param timeout the maximum time the operation should block before returning.
78 * The call should return immediately if there is data available. If
79 * no data becomes available before the timeout elapses, null will be
80 * returned
81 * @return the result of the request wrapped in a MuleMessage object. Null will be
82 * returned if no data was available
83 * @throws Exception if the call to the underlying protocol causes an exception
84 */
85 public final MuleMessage request(long timeout) throws Exception
86 {
87 try
88 {
89 EndpointMessageNotification beginNotification = null;
90 if (connector.isEnableMessageEvents())
91 {
92 MuleMessage dummyMessage = new DefaultMuleMessage(NullPayload.getInstance(), connector.getMuleContext());
93 beginNotification = new EndpointMessageNotification(dummyMessage, endpoint, null, EndpointMessageNotification.MESSAGE_REQUEST_BEGIN);
94 }
95 // Make sure we are connected
96 connect();
97 MuleMessage result = null;
98 result = doRequest(timeout);
99 if (result != null)
100 {
101 String rootId = result.getInboundProperty(MuleProperties.MULE_ROOT_MESSAGE_ID_PROPERTY);
102 if (rootId != null)
103 {
104 result.setMessageRootId(rootId);
105 result.removeProperty(MuleProperties.MULE_ROOT_MESSAGE_ID_PROPERTY, PropertyScope.INBOUND);
106 }
107 if (beginNotification != null)
108 {
109 result.propagateRootId(beginNotification.getSource());
110 }
111 if (!endpoint.isDisableTransportTransformer())
112 {
113 applyInboundTransformers(result);
114 }
115 if (beginNotification != null)
116 {
117 connector.fireNotification(beginNotification);
118 connector.fireNotification(new EndpointMessageNotification(result, endpoint, null,
119 EndpointMessageNotification.MESSAGE_REQUEST_END));
120 }
121 }
122 return result;
123 }
124 catch (ReceiveException e)
125 {
126 disposeAndLogException();
127 throw e;
128 }
129 catch (Exception e)
130 {
131 disposeAndLogException();
132 throw new ReceiveException(endpoint, timeout, e);
133 }
134 }
135
136 protected void applyInboundTransformers(MuleMessage message) throws MuleException
137 {
138 message.applyTransformers(null, defaultInboundTransformers);
139 }
140
141 @Override
142 protected WorkManager getWorkManager() throws MuleException
143 {
144 return connector.getRequesterWorkManager();
145 }
146
147 public InboundEndpoint getEndpoint()
148 {
149 return (InboundEndpoint) super.getEndpoint();
150 }
151
152 /**
153 * Make a specific request to the underlying transport
154 *
155 * @param timeout the maximum time the operation should block before returning.
156 * The call should return immediately if there is data available. If
157 * no data becomes available before the timeout elapses, null will be
158 * returned
159 * @return the result of the request wrapped in a MuleMessage object. Null will be
160 * returned if no data was avaialable
161 * @throws Exception if the call to the underlying protocal cuases an exception
162 */
163 protected abstract MuleMessage doRequest(long timeout) throws Exception;
164
165 }