001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.synapse.endpoints;
021:
022: import org.apache.axiom.om.OMElement;
023: import org.apache.axis2.clustering.ClusterManager;
024: import org.apache.axis2.context.ConfigurationContext;
025: import org.apache.commons.logging.Log;
026: import org.apache.commons.logging.LogFactory;
027: import org.apache.synapse.FaultHandler;
028: import org.apache.synapse.MessageContext;
029: import org.apache.synapse.SynapseConstants;
030: import org.apache.synapse.core.axis2.Axis2MessageContext;
031: import org.apache.synapse.endpoints.utils.EndpointDefinition;
032: import org.apache.synapse.statistics.impl.EndPointStatisticsStack;
033:
034: import java.util.Stack;
035:
036: /**
037: * WSDLEndpoint represents the endpoints built using a wsdl document. It stores the details about
038: * the endpoint in a EndpointDefinition object. Once the WSDLEndpoint object is constructed, it should
039: * not access the wsdl document at runtime to obtain endpoint information. If it is necessary to
040: * create an endpoint using a dynamic wsdl, store the endpoint configuration in the registry and
041: * create a dynamic wsdl endpoint using that registry key.
042: * <p/>
043: * TODO: This should allow various policies to be applied on fine grained level (e.g. operations).
044: */
045: public class WSDLEndpoint extends FaultHandler implements Endpoint {
046:
047: private static final Log log = LogFactory
048: .getLog(AddressEndpoint.class);
049: private static final Log trace = LogFactory
050: .getLog(SynapseConstants.TRACE_LOGGER);
051:
052: private String name = null;
053: private String wsdlURI;
054: private OMElement wsdlDoc;
055: private String serviceName;
056: private String portName;
057:
058: /**
059: * Leaf level endpoints will be suspended for the specified time by this variable, after a
060: * failure. If this is not explicitly set, it is set to -1, which causes endpoints to suspended forever.
061: */
062: private long suspendOnFailDuration = -1;
063:
064: private Endpoint parentEndpoint = null;
065: private EndpointDefinition endpoint = null;
066:
067: /**
068: * The endpoint context , place holder for keep any runtime states related to the endpoint
069: */
070: private final EndpointContext endpointContext = new EndpointContext();
071:
072: /**
073: * Sends the message through this endpoint. This method just handles statistics related functions
074: * and gives the message to the Synapse environment to send. It does not add any endpoint
075: * specific details to the message context. These details are added only to the cloned message
076: * context by the Axis2FlexibleMepClient. So that we can reuse the original message context for
077: * resending through different endpoints.
078: *
079: * @param synCtx MessageContext sent by client to Synapse
080: */
081: public void send(MessageContext synCtx) {
082:
083: boolean traceOn = isTraceOn(synCtx);
084: boolean traceOrDebugOn = isTraceOrDebugOn(traceOn);
085:
086: if (traceOrDebugOn) {
087: traceOrDebug(traceOn, "Start : WSDL Endpoint");
088:
089: if (traceOn && trace.isTraceEnabled()) {
090: trace.trace("Message : " + synCtx.getEnvelope());
091: }
092: }
093:
094: String eprAddress = null;
095: if (endpoint.getAddress() != null) {
096:
097: eprAddress = endpoint.getAddress();
098:
099: boolean isClusteringEnable = false;
100: // get Axis2 MessageContext and ConfigurationContext
101: org.apache.axis2.context.MessageContext axisMC = ((Axis2MessageContext) synCtx)
102: .getAxis2MessageContext();
103: ConfigurationContext cc = axisMC.getConfigurationContext();
104:
105: //The check for clustering environment
106:
107: ClusterManager clusterManager = cc.getAxisConfiguration()
108: .getClusterManager();
109: if (clusterManager != null
110: && clusterManager.getContextManager() != null) {
111: isClusteringEnable = true;
112: }
113:
114: String endPointName = this .getName();
115: if (endPointName == null) {
116:
117: if (traceOrDebugOn && isClusteringEnable) {
118: log
119: .warn("In a clustering environment , the endpoint name should be specified"
120: + "even for anonymous endpoints. Otherwise , the clustering would not be "
121: + "functioned correctly if there are more than one anonymous endpoints. ");
122: }
123: endPointName = SynapseConstants.ANONYMOUS_ENDPOINT;
124: }
125:
126: if (isClusteringEnable) {
127: // if this is a cluster environment , then set configuration context
128: // to endpoint context
129: if (endpointContext.getConfigurationContext() == null) {
130: endpointContext.setConfigurationContext(cc);
131: endpointContext.setContextID(endPointName);
132: }
133: }
134:
135: // Setting Required property to collect the End Point statistics
136: boolean statisticsEnable = (SynapseConstants.STATISTICS_ON == endpoint
137: .getStatisticsState());
138:
139: if (statisticsEnable) {
140: EndPointStatisticsStack endPointStatisticsStack = null;
141: Object statisticsStackObj = synCtx
142: .getProperty(org.apache.synapse.SynapseConstants.ENDPOINT_STATS);
143: if (statisticsStackObj == null) {
144: endPointStatisticsStack = new EndPointStatisticsStack();
145: synCtx
146: .setProperty(
147: org.apache.synapse.SynapseConstants.ENDPOINT_STATS,
148: endPointStatisticsStack);
149: } else if (statisticsStackObj instanceof EndPointStatisticsStack) {
150: endPointStatisticsStack = (EndPointStatisticsStack) statisticsStackObj;
151: }
152: if (endPointStatisticsStack != null) {
153: boolean isFault = synCtx.getEnvelope().getBody()
154: .hasFault();
155: endPointStatisticsStack.put(endPointName, System
156: .currentTimeMillis(), !synCtx.isResponse(),
157: statisticsEnable, isFault);
158: }
159: }
160: if (traceOrDebugOn) {
161: traceOrDebug(traceOn,
162: "Sending message to WSDL endpoint : "
163: + endPointName
164: + " resolves to address = "
165: + eprAddress);
166: traceOrDebug(traceOn, "SOAPAction: "
167: + (synCtx.getSoapAction() != null ? synCtx
168: .getSoapAction() : "null"));
169: traceOrDebug(traceOn, "WSA-Action: "
170: + (synCtx.getWSAAction() != null ? synCtx
171: .getWSAAction() : "null"));
172:
173: if (traceOn && trace.isTraceEnabled()) {
174: trace.trace("Envelope : \n" + synCtx.getEnvelope());
175: }
176: }
177:
178: // register this as the immediate fault handler for this message.
179: synCtx.pushFaultHandler(this );
180:
181: // add this as the last endpoint to process this message. it is used by statistics code.
182: synCtx.setProperty(SynapseConstants.PROCESSED_ENDPOINT,
183: this );
184:
185: synCtx.getEnvironment().send(endpoint, synCtx);
186: }
187: }
188:
189: public void onFault(MessageContext synCtx) {
190: // perform retries here
191:
192: // if this endpoint has actually failed, inform the parent.
193: setActive(false, synCtx);
194:
195: if (parentEndpoint != null) {
196: parentEndpoint.onChildEndpointFail(this , synCtx);
197: } else {
198: Stack faultStack = synCtx.getFaultStack();
199: if (!faultStack.isEmpty()) {
200: ((FaultHandler) faultStack.pop()).handleFault(synCtx);
201: }
202: }
203: }
204:
205: public void onChildEndpointFail(Endpoint endpoint,
206: MessageContext synMessageContext) {
207: // WSDLEndpoint does not contain any child endpoints. So this method will never be called.
208: }
209:
210: public String getName() {
211: return name;
212: }
213:
214: public void setName(String name) {
215: this .name = name.trim();
216: }
217:
218: public long getSuspendOnFailDuration() {
219: return suspendOnFailDuration;
220: }
221:
222: public void setSuspendOnFailDuration(long suspendOnFailDuration) {
223: this .suspendOnFailDuration = suspendOnFailDuration;
224: }
225:
226: public String getWsdlURI() {
227: return wsdlURI;
228: }
229:
230: public void setWsdlURI(String wsdlURI) {
231: this .wsdlURI = wsdlURI;
232: }
233:
234: public OMElement getWsdlDoc() {
235: return wsdlDoc;
236: }
237:
238: public void setWsdlDoc(OMElement wsdlDoc) {
239: this .wsdlDoc = wsdlDoc;
240: }
241:
242: public String getServiceName() {
243: return serviceName;
244: }
245:
246: public void setServiceName(String serviceName) {
247: this .serviceName = serviceName;
248: }
249:
250: public String getPortName() {
251: return portName;
252: }
253:
254: public void setPortName(String portName) {
255: this .portName = portName;
256: }
257:
258: /**
259: * Checks if the endpoint is active (failed or not). If endpoint is in failed state and
260: * suspendOnFailDuration has elapsed, it will be set to active.
261: *
262: * @param synMessageContext MessageContext of the current message. This is not used here.
263: * @return true if endpoint is active. false otherwise.
264: */
265: public boolean isActive(MessageContext synMessageContext) {
266: boolean active = endpointContext.isActive();
267: if (!active) {
268: long recoverOn = endpointContext.getRecoverOn();
269: if (System.currentTimeMillis() > recoverOn) {
270: endpointContext.setActive(true);
271: }
272: }
273: return active;
274: }
275:
276: /**
277: * Sets if endpoint active or not. if endpoint is set as failed (active = false), the recover on
278: * time is calculated so that it will be activated after the recover on time.
279: *
280: * @param active true if active. false otherwise.
281: * @param synMessageContext MessageContext of the current message. This is not used here.
282: */
283: public void setActive(boolean active,
284: MessageContext synMessageContext) {
285:
286: if (!active) {
287: if (suspendOnFailDuration != -1) {
288: // Calculating a new value by adding suspendOnFailDuration to current time.
289: // as the endpoint is set as failed
290: endpointContext.setRecoverOn(System.currentTimeMillis()
291: + suspendOnFailDuration);
292: } else {
293: endpointContext.setRecoverOn(Long.MAX_VALUE);
294: }
295: }
296:
297: endpointContext.setActive(true);
298: }
299:
300: public void setParentEndpoint(Endpoint parentEndpoint) {
301: this .parentEndpoint = parentEndpoint;
302: }
303:
304: public EndpointDefinition getEndpoint() {
305: return endpoint;
306: }
307:
308: public void setEndpoint(EndpointDefinition endpoint) {
309: this .endpoint = endpoint;
310: }
311:
312: /**
313: * Should this mediator perform tracing? True if its explicitly asked to
314: * trace, or its parent has been asked to trace and it does not reject it
315: *
316: * @param msgCtx the current message
317: * @return true if tracing should be performed
318: */
319: protected boolean isTraceOn(MessageContext msgCtx) {
320: return (endpoint.getTraceState() == SynapseConstants.TRACING_ON)
321: || (endpoint.getTraceState() == SynapseConstants.TRACING_UNSET && msgCtx
322: .getTracingState() == SynapseConstants.TRACING_ON);
323: }
324:
325: /**
326: * Is tracing or debug logging on?
327: *
328: * @param isTraceOn is tracing known to be on?
329: * @return true, if either tracing or debug logging is on
330: */
331: protected boolean isTraceOrDebugOn(boolean isTraceOn) {
332: return isTraceOn || log.isDebugEnabled();
333: }
334:
335: /**
336: * Perform Trace and Debug logging of a message @INFO (trace) and DEBUG (log)
337: *
338: * @param traceOn is runtime trace on for this message?
339: * @param msg the message to log/trace
340: */
341: protected void traceOrDebug(boolean traceOn, String msg) {
342: if (traceOn) {
343: trace.info(msg);
344: }
345: if (log.isDebugEnabled()) {
346: log.debug(msg);
347: }
348: }
349: }
|