You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@synapse.apache.org by as...@apache.org on 2007/10/20 03:01:05 UTC

svn commit: r586651 - in /webservices/synapse/trunk/java/modules: core/src/main/java/org/apache/synapse/ core/src/main/java/org/apache/synapse/core/axis2/ core/src/main/java/org/apache/synapse/endpoints/ core/src/main/java/org/apache/synapse/mediators/...

Author: asankha
Date: Fri Oct 19 18:01:03 2007
New Revision: 586651

URL: http://svn.apache.org/viewvc?rev=586651&view=rev
Log:
enhancements to fix initialization of startups
improve logging for startups and endpoints when failures are encountered
enhance VFS transport to support binary and text content as native files of those types

Modified:
    webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/ServerManager.java
    webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2MessageContext.java
    webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java
    webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/SynapseInitializationModule.java
    webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/endpoints/IndirectEndpoint.java
    webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/MediatorWorker.java
    webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartz.java
    webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartzJob.java
    webservices/synapse/trunk/java/modules/transports/src/main/java/org/apache/synapse/transport/vfs/VFSTransportSender.java

Modified: webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/ServerManager.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/ServerManager.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/ServerManager.java (original)
+++ webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/ServerManager.java Fri Oct 19 18:01:03 2007
@@ -111,7 +111,7 @@
                 throw new SynapseException(message + "Synapse Environment");
             }
 
-            ((SynapseConfiguration) synCfg.getValue()).init((SynapseEnvironment) synEnv.getValue());
+            //((SynapseConfiguration) synCfg.getValue()).init((SynapseEnvironment) synEnv.getValue());
 
             System.out.println("[SynapseServer] Ready");
 

Modified: webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2MessageContext.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2MessageContext.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2MessageContext.java (original)
+++ webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2MessageContext.java Fri Oct 19 18:01:03 2007
@@ -354,7 +354,9 @@
                 serviceLog = LogFactory.getLog(SynapseConstants.SERVICE_LOGGER_PREFIX + serviceName);
                 return serviceLog;
             } else {
-                serviceLog = LogFactory.getLog(Axis2MessageContext.class);
+                serviceLog = LogFactory.getLog(
+                    SynapseConstants.SERVICE_LOGGER_PREFIX.substring(0,
+                    SynapseConstants.SERVICE_LOGGER_PREFIX.length()-1));
                 return serviceLog;
             }
         }

Modified: webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java (original)
+++ webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java Fri Oct 19 18:01:03 2007
@@ -157,7 +157,7 @@
 
     public void injectAsync(final MessageContext synCtx, SequenceMediator seq) {
         if (log.isDebugEnabled()) {
-            log.debug("Injecting MessageContext for asynchronous mediation using the "
+            log.debug("Injecting MessageContext for asynchronous mediation using the : "
                 + (seq.getName() == null? "Anonymous" : seq.getName()) + " Sequence");
         }
         synCtx.setEnvironment(this);

Modified: webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/SynapseInitializationModule.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/SynapseInitializationModule.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/SynapseInitializationModule.java (original)
+++ webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/core/axis2/SynapseInitializationModule.java Fri Oct 19 18:01:03 2007
@@ -163,6 +163,7 @@
             log.fatal(msg, e);
             throw new SynapseException(msg, e);
         }
+        synapseConfiguration.init(synEnv);
         
         return synapseConfiguration;
     }

Modified: webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/endpoints/IndirectEndpoint.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/endpoints/IndirectEndpoint.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/endpoints/IndirectEndpoint.java (original)
+++ webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/endpoints/IndirectEndpoint.java Fri Oct 19 18:01:03 2007
@@ -22,6 +22,8 @@
 import org.apache.synapse.MessageContext;
 import org.apache.synapse.SynapseException;
 import org.apache.synapse.FaultHandler;
+import org.apache.synapse.SynapseConstants;
+import org.apache.synapse.endpoints.utils.EndpointDefinition;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -34,6 +36,7 @@
  */
 public class IndirectEndpoint implements Endpoint {
 
+    private static final Log trace = LogFactory.getLog(SynapseConstants.TRACE_LOGGER);
     private static final Log log = LogFactory.getLog(IndirectEndpoint.class);
 
     private String name = null;
@@ -56,13 +59,19 @@
 
         if (endpoint.isActive(synMessageContext)) {
             endpoint.send(synMessageContext);
-        } else {
 
+        } else {
             // if this is a child of some other endpoint, inform parent about the failure.
             // if not, inform to the next fault handler.
             if (parentEndpoint != null) {
+                auditWarn("Endpoint : " + endpoint.getName() + " is currently inactive" +
+                    " - invoking parent endpoint", synMessageContext);
                 parentEndpoint.onChildEndpointFail(this, synMessageContext);
+
             } else {
+                auditWarn("Endpoint : " + endpoint.getName() + " is currently inactive" +
+                    " - invoking fault handler / assuming failure", synMessageContext);
+
                 Object o = synMessageContext.getFaultStack().pop();
                 if (o != null) {
                     ((FaultHandler) o).handleFault(synMessageContext);
@@ -143,4 +152,34 @@
         log.error(msg);
         throw new SynapseException(msg);
     }
+
+    protected void auditWarn(String msg, MessageContext msgContext) {
+        log.warn(msg);
+        if (msgContext.getServiceLog() != null) {
+            msgContext.getServiceLog().warn(msg);
+        }
+        if (shouldTrace(msgContext)) {
+            trace.warn(msg);
+        }
+    }
+
+    public boolean shouldTrace(MessageContext synCtx){
+        Endpoint endpoint = synCtx.getEndpoint(key);
+        EndpointDefinition endptDefn = null;
+        if (endpoint instanceof AddressEndpoint) {
+            AddressEndpoint addEndpt = (AddressEndpoint) endpoint;
+            endptDefn = addEndpt.getEndpoint();
+        } else if (endpoint instanceof WSDLEndpoint) {
+            WSDLEndpoint wsdlEndpt = (WSDLEndpoint) endpoint;
+            endptDefn = wsdlEndpt.getEndpoint();
+        }
+
+        if (endptDefn != null) {
+            return (endptDefn.getTraceState() == SynapseConstants.TRACING_ON) ||
+                   (endptDefn.getTraceState() == SynapseConstants.TRACING_UNSET &&
+                        synCtx.getTracingState() == SynapseConstants.TRACING_ON);
+        }
+        return false;
+    }
+
 }

Modified: webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/MediatorWorker.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/MediatorWorker.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/MediatorWorker.java (original)
+++ webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/mediators/MediatorWorker.java Fri Oct 19 18:01:03 2007
@@ -19,8 +19,10 @@
 
 package org.apache.synapse.mediators;
 
-import org.apache.synapse.Mediator;
-import org.apache.synapse.MessageContext;
+import org.apache.synapse.*;
+import org.apache.synapse.core.axis2.Axis2MessageContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
 /**
  * This class will be used as the executer for the injectAsync method for the
@@ -28,6 +30,9 @@
  */
 public class MediatorWorker implements Runnable {
 
+    private static final Log log = LogFactory.getLog(MediatorWorker.class);
+    private static final Log trace = LogFactory.getLog(SynapseConstants.TRACE_LOGGER);
+
     /** Mediator to be executed */
     private Mediator seq = null;
 
@@ -61,6 +66,49 @@
      * Synapse MessageContext using the specified Sequence Mediator
      */
     public void run() {
-        seq.mediate(synCtx);
+        try {
+            seq.mediate(synCtx);
+            ((Axis2MessageContext)synCtx).getAxis2MessageContext().getEnvelope().discard();
+
+        } catch (SynapseException syne) {
+            if (!synCtx.getFaultStack().isEmpty()) {
+                warn(false, "Executing fault handler due to exception encountered", synCtx);
+                ((FaultHandler) synCtx.getFaultStack().pop()).handleFault(synCtx, syne);
+
+            } else {
+                warn(false, "Exception encountered but no fault handler found - " +
+                    "message dropped", synCtx);
+            }
+
+        } catch (Exception e) {
+            String msg = "Unexpected error executing task";
+            log.error(msg, e);
+            if (synCtx.getServiceLog() != null) {
+                synCtx.getServiceLog().error(msg, e);
+            }
+            if (!synCtx.getFaultStack().isEmpty()) {
+                warn(false, "Executing fault handler due to exception encountered", synCtx);
+                ((FaultHandler) synCtx.getFaultStack().pop()).handleFault(synCtx, e);
+
+            } else {
+                warn(false, "Exception encountered but no fault handler found - " +
+                    "message dropped", synCtx);
+            }
+        }
+        synCtx = null;
+        seq = null;
+    }
+
+    private void warn(boolean traceOn, String msg, MessageContext msgContext) {
+        if (traceOn) {
+            trace.warn(msg);
+        }
+        if (log.isDebugEnabled()) {
+            log.warn(msg);
+        }
+        if (msgContext.getServiceLog() != null) {
+            msgContext.getServiceLog().warn(msg);
+        }
     }
+
 }

Modified: webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartz.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartz.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartz.java (original)
+++ webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartz.java Fri Oct 19 18:01:03 2007
@@ -55,15 +55,10 @@
     private static final int THREADPOOLSIZE = 5;
 
     private String cron;
-
     private int repeatCount = -1;
-
     private long repeatInterval;
-
     private String className;
-
     private Scheduler sch;
-
     Set xmlProperties = new HashSet();
 
     public QName getTagQName() {
@@ -75,10 +70,10 @@
             try {
                 sch.shutdown();
             } catch (SchedulerException e) {
-                throw new SynapseException(e);
+                log.warn("Error shutting down scheduler", e);
+                throw new SynapseException("Error shutting down scheduler", e);
             }
         }
-
     }
 
     public void init(SynapseEnvironment synapseEnvironment) {
@@ -86,6 +81,7 @@
         try {
             DirectSchedulerFactory.getInstance().createVolatileScheduler(THREADPOOLSIZE);
             sch = DirectSchedulerFactory.getInstance().getScheduler();
+
             Trigger trigger = null;
             if (cron == null) {
                 if (repeatCount >= 0) {
@@ -93,16 +89,19 @@
                 } else {
                     trigger = TriggerUtils.makeImmediateTrigger(-1, repeatInterval);
                 }
+
             } else {
                 CronTrigger cronTrig = new CronTrigger();
                 cronTrig.setCronExpression(cron);
                 trigger = cronTrig;
             }
+
             // give the trigger a random name
             trigger.setName("Trigger" + String.valueOf((new Random()).nextLong()));
             trigger.setGroup("synapse.simple.quartz");
             trigger.setVolatility(true);
             JobDetail jobDetail = new JobDetail();
+
             // Give the job a name
             jobDetail.setName(name);
             jobDetail.setGroup("synapse.simple.quartz");
@@ -112,12 +111,14 @@
             jdm.put(SimpleQuartzJob.CLASSNAME, className);
             jdm.put(SimpleQuartzJob.PROPERTIES, xmlProperties);
             jobDetail.setJobDataMap(jdm);
+
             sch.scheduleJob(jobDetail, trigger);
             sch.start();
             log.info("Scheduled job " + jobDetail.getFullName() + " for class " + className);
 
         } catch (Exception e) {
-            throw new SynapseException("Problem with startup of Scheduler ", e);
+            log.fatal("Error starting up Scheduler", e);
+            throw new SynapseException("Error starting up Scheduler", e);
         }
 
     }

Modified: webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartzJob.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartzJob.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartzJob.java (original)
+++ webservices/synapse/trunk/java/modules/core/src/main/java/org/apache/synapse/startup/quartz/SimpleQuartzJob.java Fri Oct 19 18:01:03 2007
@@ -7,6 +7,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.synapse.ManagedLifecycle;
+import org.apache.synapse.startup.Task;
 import org.apache.synapse.config.xml.PropertyHelper;
 import org.apache.synapse.core.SynapseEnvironment;
 import org.quartz.Job;
@@ -15,36 +16,51 @@
 import org.quartz.JobExecutionException;
 
 public class SimpleQuartzJob implements Job {
-	public static final String SYNAPSEENVIRONMENT= "SynapseEnvironment", CLASSNAME="ClassName", PROPERTIES = "Properties";
-	private static final Log log = LogFactory.getLog(SimpleQuartzJob.class);
-	public void execute(JobExecutionContext ctx) throws JobExecutionException {
-		log.debug("executing task "+ctx.getJobDetail().getFullName());
-		JobDataMap jdm = ctx.getMergedJobDataMap();
-		String jobClassName = (String)jdm.get(CLASSNAME);
-		if (jobClassName==null) {
-			throw new JobExecutionException("No "+CLASSNAME+" in JobDetails");
-		}
-		org.apache.synapse.startup.Task task =null;
-		try {
-			task = (org.apache.synapse.startup.Task)getClass().getClassLoader().loadClass(jobClassName).newInstance();
-		} catch (Exception e) {
-			throw new JobExecutionException("Cannot instantiate task "+jobClassName, e);
-		}
-		Set properties = (Set)jdm.get(PROPERTIES);
-		Iterator it = properties.iterator();
-		while (it.hasNext()) {
-			OMElement prop = (OMElement)it.next();
-			log.debug("found Property"+prop.toString());
-			PropertyHelper.setStaticProperty(prop, task);
-		}
-		SynapseEnvironment se = (SynapseEnvironment)jdm.get("SynapseEnvironment");
-		if (task instanceof ManagedLifecycle) {
-			if (se!=null) {
-				((ManagedLifecycle) task).init(se);
-			}
-		}
-		task.execute();
-		
-	}
+    public static final String SYNAPSEENVIRONMENT = "SynapseEnvironment",
+        CLASSNAME = "ClassName", PROPERTIES = "Properties";
+    private static final Log log = LogFactory.getLog(SimpleQuartzJob.class);
+
+    public void execute(JobExecutionContext ctx) throws JobExecutionException {
+
+        log.debug("Executing task : " + ctx.getJobDetail().getFullName());
+        JobDataMap jdm = ctx.getMergedJobDataMap();
+        String jobClassName = (String) jdm.get(CLASSNAME);
+        if (jobClassName == null) {
+            handleException("No " + CLASSNAME + " in JobDetails");
+        }
+
+        Task task = null;
+        try {
+            task = (Task) getClass().getClassLoader().loadClass(jobClassName).newInstance();
+        } catch (Exception e) {
+            handleException("Cannot instantiate task : " + jobClassName, e);
+        }
+
+        Set properties = (Set) jdm.get(PROPERTIES);
+        Iterator it = properties.iterator();
+        while (it.hasNext()) {
+            OMElement prop = (OMElement) it.next();
+            log.debug("Found Property : " + prop.toString());
+            PropertyHelper.setStaticProperty(prop, task);
+        }
+
+        SynapseEnvironment se = (SynapseEnvironment) jdm.get("SynapseEnvironment");
+        if (task instanceof ManagedLifecycle) {
+            if (se != null) {
+                ((ManagedLifecycle) task).init(se);
+            }
+        }
+        task.execute();
+    }
+
+    private void handleException(String msg) throws JobExecutionException {
+        log.error(msg);
+        throw new JobExecutionException(msg);
+    }
+
+    private void handleException(String msg, Exception e) throws JobExecutionException {
+        log.error(msg, e);
+        throw new JobExecutionException(msg, e);
+    }
 
 }

Modified: webservices/synapse/trunk/java/modules/transports/src/main/java/org/apache/synapse/transport/vfs/VFSTransportSender.java
URL: http://svn.apache.org/viewvc/webservices/synapse/trunk/java/modules/transports/src/main/java/org/apache/synapse/transport/vfs/VFSTransportSender.java?rev=586651&r1=586650&r2=586651&view=diff
==============================================================================
--- webservices/synapse/trunk/java/modules/transports/src/main/java/org/apache/synapse/transport/vfs/VFSTransportSender.java (original)
+++ webservices/synapse/trunk/java/modules/transports/src/main/java/org/apache/synapse/transport/vfs/VFSTransportSender.java Fri Oct 19 18:01:03 2007
@@ -21,6 +21,7 @@
 import org.apache.synapse.transport.base.AbstractTransportSender;
 import org.apache.synapse.transport.base.BaseUtils;
 import org.apache.synapse.transport.base.BaseTransportException;
+import org.apache.synapse.transport.base.BaseConstants;
 import org.apache.axis2.transport.OutTransportInfo;
 import org.apache.axis2.transport.MessageFormatter;
 import org.apache.axis2.transport.TransportUtils;
@@ -31,8 +32,14 @@
 import org.apache.commons.vfs.*;
 import org.apache.commons.logging.LogFactory;
 import org.apache.axiom.om.OMOutputFormat;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMNode;
+import org.apache.axiom.om.OMText;
 
+import javax.activation.DataHandler;
 import java.io.OutputStream;
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
 
 public class VFSTransportSender extends AbstractTransportSender {
 
@@ -118,6 +125,62 @@
 
     private void populateResponseFile(FileObject responseFile, MessageContext msgContext) throws AxisFault {
 
+        // check the first element of the SOAP body, do we have content wrapped using the
+        // default wrapper elements for binary (BaseConstants.DEFAULT_BINARY_WRAPPER) or
+        // text (BaseConstants.DEFAULT_TEXT_WRAPPER) ? If so, do not create SOAP messages
+        // within the files but just get the payload in its native format
+
+        OMElement firstChild = msgContext.getEnvelope().getBody().getFirstElement();
+        if (firstChild != null) {
+            if (BaseConstants.DEFAULT_BINARY_WRAPPER.equals(firstChild.getQName())) {
+                try {
+                    OutputStream os = responseFile.getContent().getOutputStream();
+                    OMNode omNode = firstChild.getFirstOMChild();
+                    if (omNode != null && omNode instanceof OMText) {
+                        Object dh = ((OMText) omNode).getDataHandler();
+                        if (dh != null && dh instanceof DataHandler) {
+                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                            try {
+                                ((DataHandler) dh).writeTo(baos);
+                            } catch (IOException e) {
+                                handleException("Error serializing binary content of element : " +
+                                    BaseConstants.DEFAULT_BINARY_WRAPPER, e);
+                            }
+                            os.write(baos.toByteArray());
+                        }
+                    }
+                } catch (FileSystemException e) {
+                    handleException("Error getting an output stream to file : " +
+                        responseFile.getName().getBaseName(), e);
+                } catch (IOException e) {
+                    handleException("Error getting binary content of message", e);
+                }
+
+            } else if (BaseConstants.DEFAULT_TEXT_WRAPPER.equals(firstChild.getQName())) {
+                try {
+                    OutputStream os = responseFile.getContent().getOutputStream();
+                    os.write(firstChild.getText().getBytes());
+                } catch (FileSystemException e) {
+                    handleException("Error getting an output stream to file : " +
+                        responseFile.getName().getBaseName(), e);
+                } catch (IOException e) {
+                    handleException("Error getting text content of message as bytes", e);
+                }
+            } else {
+                populateSOAPFile(responseFile, msgContext);
+            }
+        } else {
+            populateSOAPFile(responseFile, msgContext);
+        }
+    }
+
+    /**
+     * Populate file with a SOAP formatted message
+     * @param responseFile the response file created
+     * @param msgContext the message context that holds the message to be written
+     * @throws AxisFault on error
+     */
+    private void populateSOAPFile(FileObject responseFile, MessageContext msgContext) throws AxisFault {
         OMOutputFormat format = BaseUtils.getOMOutputFormat(msgContext);
         MessageFormatter messageFormatter = null;
         try {



---------------------------------------------------------------------
To unsubscribe, e-mail: synapse-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: synapse-dev-help@ws.apache.org