You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ode.apache.org by mr...@apache.org on 2008/11/27 03:02:45 UTC

svn commit: r721070 - in /ode/sandbox/simpel/src: main/antlr/org/apache/ode/simpel/antlr/ main/java/org/apache/ode/ main/java/org/apache/ode/rest/ main/java/org/apache/ode/simpel/omodel/ test/java/org/apache/ode/simpel/

Author: mriou
Date: Wed Nov 26 18:02:44 2008
New Revision: 721070

URL: http://svn.apache.org/viewvc?rev=721070&view=rev
Log:
Generation of RESTful onEvents is improving.

Added:
    ode/sandbox/simpel/src/main/java/org/apache/ode/Descriptor.java
Modified:
    ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g
    ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g
    ode/sandbox/simpel/src/main/java/org/apache/ode/rest/EngineWebResource.java
    ode/sandbox/simpel/src/main/java/org/apache/ode/rest/ProcessWebResource.java
    ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/omodel/OBuilder.java
    ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/RestfulSimPELTest.java

Modified: ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g
URL: http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g?rev=721070&r1=721069&r2=721070&view=diff
==============================================================================
--- ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g (original)
+++ ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g Wed Nov 26 18:02:44 2008
@@ -156,7 +156,7 @@
 receive_base
 	    :	'receive' '(' p=ID (',' o=ID (',' correlation)? )? ')' -> ^($p $o? correlation?);
 
-reply	:	'reply' '(' ID (',' ID ',' ID)? ')' -> ^(REPLY ID (ID ID)?);
+reply	:	'reply' '(' ID (',' ID (',' ID)?)? ')' -> ^(REPLY ID (ID ID?)?);
 
 assign	:	path_expr '=' rvalue -> ^(ASSIGN path_expr rvalue);
 rvalue

Modified: ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g
URL: http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g?rev=721070&r1=721069&r2=721070&view=diff
==============================================================================
--- ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g (original)
+++ ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g Wed Nov 26 18:02:44 2008
@@ -172,10 +172,11 @@
 catch_ex:	^(CATCH ^(NS ID ID?) param_block);
 
 scope_ex
-scope BPELScope;
+scope BPELScope Parent;
 	:	^(SCOPE {
-            OBuilder.StructuredActivity<OScope> oscope = builder.build(OScope.class, $BPELScope[-1]::oscope, $Parent::activity);
+            OBuilder.StructuredActivity<OScope> oscope = builder.build(OScope.class, $BPELScope[-1]::oscope, $Parent[-1]::activity);
             $BPELScope::oscope = oscope.getOActivity();
+            $Parent::activity = oscope;
         }
 	    ID? body scope_stmt*);
 scope_stmt
@@ -184,27 +185,30 @@
 onevent	:	^(ONEVENT ID ID param_block);
 onalarm	:	^(ONALARM expr body);
 onquery
-scope ReceiveBlock;
+scope ReceiveBlock Parent;
     :	^(ONQUERY ID {
             OBuilder.StructuredActivity<OEventHandler.OEvent> on = builder
-                .build(OEventHandler.OEvent.class, $BPELScope::oscope, $Parent::activity, deepText($ID), "GET");
-            $ReceiveBlock::activity = on.getOActivity();
+                .build(OEventHandler.OEvent.class, $BPELScope::oscope, $Parent[-1]::activity, deepText($ID), "GET");
+            $ReceiveBlock::activity = (OComm) on.getOActivity();
+            $Parent::activity = on;
         }
         body);
 onrec
-scope ReceiveBlock;
+scope ReceiveBlock Parent;
     :	^(ONRECEIVE ID {
             OBuilder.StructuredActivity<OEventHandler.OEvent> on = builder
-                .build(OEventHandler.OEvent.class, $BPELScope::oscope, $Parent::activity, deepText($ID), "POST");
-            $ReceiveBlock::activity = on.getOActivity();
+                .build(OEventHandler.OEvent.class, $BPELScope::oscope, $Parent[-1]::activity, deepText($ID), "POST");
+            $ReceiveBlock::activity = (OComm) on.getOActivity();
+            $Parent::activity = on;
         }
         body);
 onupd
-scope ReceiveBlock;
+scope ReceiveBlock Parent;
     :	^(ONUPDATE ID {
             OBuilder.StructuredActivity<OEventHandler.OEvent> on = builder
-                .build(OEventHandler.OEvent.class, $BPELScope::oscope, $Parent::activity, deepText($ID), "PUT");
-            $ReceiveBlock::activity = on.getOActivity();
+                .build(OEventHandler.OEvent.class, $BPELScope::oscope, $Parent[-1]::activity, deepText($ID), "PUT");
+            $ReceiveBlock::activity = (OComm) on.getOActivity();
+            $Parent::activity = on;
         }
         body);
 compensation
@@ -230,20 +234,25 @@
         (prb=(param_block))?;
 
 reply	
-  :	^(REPLY msg=ID (pl=ID var=ID)?) {
+  :	^(REPLY msg=ID (pl=ID (op=ID)?)?) {
       if (ReceiveBlock_stack.size() > 0)
         builder.build(OReply.class, $BPELScope::oscope, $Parent::activity,
-			      $ReceiveBlock::activity, text($msg), text($pl), text($var));
+			      $ReceiveBlock::activity, text($msg), text($pl), text($op));
       else
         builder.build(OReply.class, $BPELScope::oscope, $Parent::activity,
-			      null, text($msg), text($pl), text($var));
+			      null, text($msg), text($pl), text($op));
     };
 receive	
 scope ReceiveBlock;
 	:	^(RECEIVE ^(p=ID o=ID? correlation?) {
 	        // The receive input is the lvalue of the assignment expression in which this receive is enclosed (if it is)
-            OBuilder.StructuredActivity<OPickReceive> rec = builder.build(OPickReceive.class, $BPELScope::oscope,
-                $Parent::activity, text($p), text($o), $ExprContext::expr);
+	        OBuilder.StructuredActivity<OPickReceive> rec;
+	        if (ExprContext_stack.size() > 0)
+                rec = builder.build(OPickReceive.class, $BPELScope::oscope,
+                    $Parent::activity, text($p), text($o), $ExprContext::expr);
+            else
+                rec = builder.build(OPickReceive.class, $BPELScope::oscope,
+                    $Parent::activity, text($p), text($o), null);
 
 		    $ReceiveBlock::activity = rec.getOActivity().onMessages.get(0);
             // TODO support for multiple "correlations"

Added: ode/sandbox/simpel/src/main/java/org/apache/ode/Descriptor.java
URL: http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/java/org/apache/ode/Descriptor.java?rev=721070&view=auto
==============================================================================
--- ode/sandbox/simpel/src/main/java/org/apache/ode/Descriptor.java (added)
+++ ode/sandbox/simpel/src/main/java/org/apache/ode/Descriptor.java Wed Nov 26 18:02:44 2008
@@ -0,0 +1,41 @@
+package org.apache.ode;
+
+/**
+ * Deployment level information about a process.
+ */
+public class Descriptor {
+
+    private String address;
+    private boolean restful = true;
+
+    /**
+     * @return address of the root RESTful resource that the process implements. 
+     */
+    public String getAddress() {
+        return address;
+    }
+
+    /**
+     * For a RESTful process, sets the root resource address that the process implements.
+     * @param address ex: "/calendar"
+     */
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    /**
+     * Whether the deployed process follows the RESTful or SOAP style. Defaults to true.
+     * @return true if restful
+     */
+    public boolean isRestful() {
+        return restful;
+    }
+
+    /**
+     * Declare whether this process follows the RESTful or SOAP style. Processes are RESTful by default.
+     * @param restful
+     */
+    public void setRestful(boolean restful) {
+        this.restful = restful;
+    }
+}

Modified: ode/sandbox/simpel/src/main/java/org/apache/ode/rest/EngineWebResource.java
URL: http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/java/org/apache/ode/rest/EngineWebResource.java?rev=721070&r1=721069&r2=721070&view=diff
==============================================================================
--- ode/sandbox/simpel/src/main/java/org/apache/ode/rest/EngineWebResource.java (original)
+++ ode/sandbox/simpel/src/main/java/org/apache/ode/rest/EngineWebResource.java Wed Nov 26 18:02:44 2008
@@ -19,6 +19,7 @@
 import org.apache.ode.embed.ServerLifecycle;
 
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentHashMap;
 
 @Path("/")
 public class EngineWebResource {
@@ -27,7 +28,7 @@
     private static ServerLifecycle _serverLifecyle;
 
     //    private HashMap<String,QName> _services = new HashMap<String, QName>();
-    private static ConcurrentLinkedQueue<Resource> _engineResources;
+    private static ConcurrentHashMap<String,ResourceDesc> _engineResources;
 
     @GET @Produces("application/xhtml+xml")
     public String getXHTML() {
@@ -35,10 +36,11 @@
         res.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><html xmlns=\"http://www.w3.org/1999/xhtml\"><body>");
         res.append("<p>List of deployed processes:</p>");
         res.append("<ul>");
-        for (Resource r : _engineResources) {
-            res.append("<li><a href=\"").append(r.getUrl()).append("\">").append(r.getUrl()).append("</a>");
-            res.append("<span id=\"method\">").append(r.getMethod()).append("</span>");
-            res.append("<span id=\"content-type\">").append(r.getContentType()).append("</span>");
+        for (ResourceDesc r : _engineResources.values()) {
+            String p = "/"+r.resourcePath;
+            res.append("<li><a href=\"").append(p).append("\">").append(p).append("</a>");
+            res.append("<span id=\"method\">").append(r.methods()).append("</span>");
+            res.append("<span id=\"content-type\">").append(r.contentType).append("</span>");
             res.append("</li>");
         }
         res.append("</ul>");
@@ -51,11 +53,11 @@
         Document doc = DOMUtils.newDocument();
         Element root = doc.createElement("resources");
         doc.appendChild(root);
-        for (Resource r : _engineResources) {
+        for (ResourceDesc r : _engineResources.values()) {
             Element pelmt = doc.createElement("resource");
-            pelmt.setAttribute("method", r.getMethod());
-            pelmt.setAttribute("contentType", r.getContentType());
-            pelmt.setTextContent(r.getUrl());
+            pelmt.setAttribute("methods", r.methods());
+            pelmt.setAttribute("contentType", r.contentType);
+            pelmt.setTextContent("/"+r.resourcePath);
             root.appendChild(pelmt);
         }
         return DOMUtils.domToString(doc);
@@ -63,27 +65,35 @@
 
     @Path("{subpath}")
     public ProcessWebResource buildProcessResource(@javax.ws.rs.core.Context UriInfo subpath) {
-        for (Resource engineResource : _engineResources) {
-            // TODO This should be able to match based on a pattern
-            if (stripSlashes(subpath.getPath()).equals(stripSlashes(engineResource.getUrl()))) 
-                return new ProcessWebResource(engineResource, _serverLifecyle);
+        // TODO This should be able to match based on a pattern
+        ResourceDesc rdesc = _engineResources.get(stripSlashes(subpath.getPath()));
+        if (rdesc == null) throw new NotFoundException("Resource " + subpath.getPath() + " is unknown.");
+        else {
+            String base = subpath.getBaseUri().toString();
+            return new ProcessWebResource(rdesc, _serverLifecyle, base.substring(0, base.length()-1));
         }
-        throw new NotFoundException("Resource " + subpath.getPath() + " is unknown.");        
     }
 
-    private String stripSlashes(String sl) {
+    private static String stripSlashes(String sl) {
         int start = sl.charAt(0) == '/' ? 1 : 0;
         int end = sl.charAt(sl.length()-1) == '/' ? sl.length() - 1 : sl.length();
         return sl.substring(start, end);
     }
 
     public static void registerResource(Resource resource) {
-        _engineResources.add(resource);
+        String nonSlashed = stripSlashes(resource.getUrl());
+        ResourceDesc desc = _engineResources.get(nonSlashed);
+        if (desc == null) {
+            desc = new ResourceDesc();
+            desc.resourcePath = nonSlashed;
+            _engineResources.put(nonSlashed, desc);
+        }
+        desc.enable(resource.getMethod());
     }
 
     public static void startRestfulServer(ServerLifecycle serverLifecyle) {
         _serverLifecyle = serverLifecyle;
-        _engineResources = new ConcurrentLinkedQueue<Resource>();
+        _engineResources = new ConcurrentHashMap<String,ResourceDesc>();
         ServletHolder sh = new ServletHolder(ServletContainer.class);
 
         sh.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
@@ -110,4 +120,41 @@
             throw new RuntimeException(e);
         }
     }
+
+    public static class ResourceDesc {
+        String resourcePath;
+        String contentType;
+        boolean get;
+        boolean post;
+        boolean put;
+        boolean delete;
+
+        public Resource toResource(String method) {
+            return new Resource("/"+resourcePath, contentType, method);
+        }
+
+        public void enable(String method) {
+            if ("GET".equalsIgnoreCase(method)) get = true;
+            else if ("POST".equalsIgnoreCase(method)) post = true;
+            else if ("PUT".equalsIgnoreCase(method)) put = true;
+            else if ("DELETE".equalsIgnoreCase(method)) delete = true;
+        }
+        public String methods() {
+            StringBuffer m = new StringBuffer();
+            if (get) m.append("GET");
+            if (post) {
+                if (m.length() > 0) m.append(",");
+                m.append("POST");
+            }
+            if (put) {
+                if (m.length() > 0) m.append(",");
+                m.append("PUT");
+            }
+            if (delete) {
+                if (m.length() > 0) m.append(",");
+                m.append("DELETE");
+            }
+            return m.toString();
+        }
+    }
 }

Modified: ode/sandbox/simpel/src/main/java/org/apache/ode/rest/ProcessWebResource.java
URL: http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/java/org/apache/ode/rest/ProcessWebResource.java?rev=721070&r1=721069&r2=721070&view=diff
==============================================================================
--- ode/sandbox/simpel/src/main/java/org/apache/ode/rest/ProcessWebResource.java (original)
+++ ode/sandbox/simpel/src/main/java/org/apache/ode/rest/ProcessWebResource.java Wed Nov 26 18:02:44 2008
@@ -10,37 +10,58 @@
 import org.w3c.dom.Element;
 import org.w3c.dom.Document;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.Produces;
-import javax.ws.rs.POST;
-import javax.ws.rs.Consumes;
+import javax.ws.rs.*;
 import javax.ws.rs.core.Response;
 import javax.xml.namespace.QName;
 import java.io.IOException;
 
 public class ProcessWebResource {
 
-    private Resource _resource;
+    private EngineWebResource.ResourceDesc _resource;
     private static ServerLifecycle _serverLifecyle;
+    private String _root;
 
-    public ProcessWebResource(Resource resource, ServerLifecycle serverLifecyle) {
+    public ProcessWebResource(EngineWebResource.ResourceDesc resource, ServerLifecycle serverLifecyle, String root) {
         _resource = resource;
         _serverLifecyle = serverLifecyle;
+        _root = root;
     }
 
     @GET @Produces("application/xml")
     public Response get() {
-        if ("GET".equals(_resource.getMethod())) {
+        if (_resource.get) {
+            RESTMessageExchange mex = _serverLifecyle.getServer().createMessageExchange(
+                    _resource.toResource("GET"), new GUID().toString());
+            try {
+                mex.invokeBlocking();
+            } catch (java.util.concurrent.TimeoutException te) {
+                return Response.status(408).entity("The server timed out while processing the request.").build();
+            }
 
+            if (mex.getResponse() == null) {
+                return Response.status(204).build();
+            } else {
+                return Response.status(200)
+                        .entity(DOMUtils.domToString(DOMUtils.getFirstChildElement(DOMUtils
+                                .getFirstChildElement(mex.getResponse().getMessage()))))
+                        .type("application/xml")
+                        .header("Location", _root+mex.getResource().getUrl())
+                        .build();
+            }
         }
-        // TODO use the resource supported methods
-        return Response.status(405).header("Allow", "POST").build();
+        else return Response.status(405).header("Allow", _resource.methods()).build();
+    }
+
+    @GET @Produces("application/xml") @Path("{subpath}")
+    public Response getSub() {
+        return get();
     }
 
     @POST @Consumes("application/xml")
     public Response post(String content) {
-        if ("POST".equals(_resource.getMethod())) {
-            RESTMessageExchange mex = _serverLifecyle.getServer().createMessageExchange(_resource, new GUID().toString());
+        if (_resource.post) {
+            RESTMessageExchange mex = _serverLifecyle.getServer().createMessageExchange(
+                    _resource.toResource("POST"), new GUID().toString());
             Message request = mex.createMessage(null);
             try {
                 // TODO support for http headers and parameters as additional parts
@@ -70,13 +91,16 @@
                         .entity(DOMUtils.domToString(DOMUtils.getFirstChildElement(DOMUtils
                                 .getFirstChildElement(mex.getResponse().getMessage()))))
                         .type("application/xml")
-                        .header("Location", mex.getResource().getUrl())
+                        .header("Location", _root+mex.getResource().getUrl())
                         .build();
             }
-
         }
-        // TODO use the resource supported methods
-        return Response.status(405).header("Allow", "GET").build();
+        else return Response.status(405).header("Allow", _resource.methods()).build();
+    }
+
+    @POST @Consumes("application/xml") @Path("{subpath}")
+    public Response postSub(String content) {
+        return post(content);
     }
 
 //    @GET @Produces("application/xhtml+xml")

Modified: ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/omodel/OBuilder.java
URL: http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/omodel/OBuilder.java?rev=721070&r1=721069&r2=721070&view=diff
==============================================================================
--- ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/omodel/OBuilder.java (original)
+++ ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/omodel/OBuilder.java Wed Nov 26 18:02:44 2008
@@ -13,11 +13,8 @@
 import org.apache.ode.simpel.wsdl.SimPELPortType;
 import org.apache.ode.utils.GUID;
 import org.apache.ode.Descriptor;
-import org.w3c.dom.Node;
-import org.w3c.dom.Document;
 
 import javax.wsdl.PortType;
-import javax.wsdl.Part;
 import javax.xml.namespace.QName;
 import java.lang.reflect.Method;
 import java.util.*;
@@ -41,7 +38,7 @@
     private HashMap<String,String> namespaces = new HashMap<String,String>();
     private HashMap<String, OPartnerLink> partnerLinks = new HashMap<String,OPartnerLink>();
     private HashMap<String,OScope.Variable> variables = new HashMap<String,OScope.Variable>();
-    private HashMap<String,OResource> webResources = new HashMap<String,OResource>();
+    private HashMap<String,ResourceDesc> webResources = new HashMap<String,ResourceDesc>();
     private HashSet<String> typedVariables = new HashSet<String>();
 
     public OBuilder(Descriptor desc) {
@@ -127,7 +124,13 @@
     public StructuredActivity<OScope> buildScope(final OScope oscope, OScope parentScope) {
         return new StructuredActivity<OScope>(oscope) {
             public void run(OActivity child) {
-                oscope.activity = child;
+                if (child instanceof OEventHandler.OEvent) {
+                    if (oscope.eventHandler == null)
+                        oscope.eventHandler = new OEventHandler(_oprocess);
+                    oscope.eventHandler.onMessages.add((OEventHandler.OEvent) child);
+                } else {
+                    oscope.activity = child;
+                }
             }
         };
     }
@@ -165,10 +168,10 @@
                                            String operation, SimPELExpr expr) {
         OPickReceive.OnMessage onMessage = new OPickReceive.OnMessage(_oprocess);
         if (operation == null) {
-            onMessage.resource = webResources.get(partnerLinkOrResource);
+            onMessage.resource = copyResource(webResources.get(partnerLinkOrResource), "POST");
             if (onMessage.resource == null)
                 throw new RuntimeException("Unknown resource declared in receive: " + partnerLinkOrResource);
-            onMessage.resource.setMethod("POST");
+            _oprocess.providedResources.add(onMessage.resource);
         } else {
             onMessage.partnerLink = buildPartnerLink(oscope, partnerLinkOrResource, operation, true, true);
             onMessage.operation = onMessage.partnerLink.myRolePortType.getOperation(operation, null, null);
@@ -179,7 +182,9 @@
                 onMessage.partnerLink.addCreateInstanceOperation(onMessage.operation);
             receive.createInstanceFlag = true;
             _oprocess.firstReceive = receive;
-            if (onMessage.resource != null) onMessage.resource.setInstantiateResource(true);
+            if (onMessage.resource != null) {
+                webResources.get(partnerLinkOrResource).setInstantiating(true);
+            }
         }
 
         // Is this receive part of an assignment? In this case the input var is the lvalue.
@@ -195,15 +200,17 @@
     }
 
     public StructuredActivity buildEvent(final OEventHandler.OEvent oevent, OScope oscope, String resource, String method) {
-        oevent.resource = webResources.get(resource);
-        // TODO a single resource can have more than one method
-        oevent.resource.setMethod(method);
+        oevent.resource = copyResource(webResources.get(resource), method);
+        _oprocess.providedResources.add(oevent.resource);
+        OScope eventScope = new OScope(_oprocess, oevent);
+        oevent.activity = eventScope;
+
         return new StructuredActivity<OEventHandler.OEvent>(oevent) {
             public void run(OActivity child) {
-                oevent.activity = child;
+                ((OScope)oevent.activity).activity = child;
             }
         };
-    }    
+    }
 
     public SimpleActivity buildInvoke(OInvoke invoke, OScope oscope, String partnerLink,
                                       String operation, String incomingMsg) {
@@ -214,14 +221,6 @@
         return new SimpleActivity<OInvoke>(invoke);
     }
 
-    public SimpleActivity buildCollect(OCollect collect, OScope oscope, String resource) {
-        OResource res = webResources.get(resource);
-        if (res == null) throw new RuntimeException("Unknown resource referenced in collect: " + resource);
-
-        collect.setResource(res);
-        return new SimpleActivity<OCollect>(collect);
-    }
-
     public StructuredActivity buildSequence(final OSequence seq, OScope oscope) {
         return new StructuredActivity<OSequence>(seq) {
             public void run(OActivity child) {
@@ -256,11 +255,11 @@
     }
 
     public SimpleActivity buildReply(OReply oreply, OScope oscope, OComm ocomm,
-                                     String var, String partnerLink, String operation) {
+                                     String var, String plinkOrRes, String operation) {
         oreply.variable = resolveVariable(oscope, var, operation, false);
-        if (partnerLink == null) {
+        if (plinkOrRes == null) {
             if (ocomm == null) throw new RuntimeException("No parent receive but reply with var " + var +
-                    " has no partnerLink/operation information.");
+                    " has no plinkOrRes/operation or resource information.");
             if (ocomm.isRestful()) {
                 oreply.resource = ocomm.getResource();
             } else {
@@ -269,8 +268,15 @@
                 buildPartnerLink(oscope, oreply.partnerLink.name, oreply.operation.getName(), true, false);
             }
         } else {
-            oreply.partnerLink = buildPartnerLink(oscope, partnerLink, operation, true, false);
-            oreply.operation = oreply.partnerLink.myRolePortType.getOperation(operation, null, null);
+            if (operation == null) {
+                ResourceDesc res = webResources.get(plinkOrRes);
+                if (res == null) throw new RuntimeException("Couldn't resolve the reply using partner link " +
+                        "or resource " + plinkOrRes +". Either an operation is missing or the resource isn't recognized.");
+                oreply.resource = res.latest;
+            } else {
+                oreply.partnerLink = buildPartnerLink(oscope, plinkOrRes, operation, true, false);
+                oreply.operation = oreply.partnerLink.myRolePortType.getOperation(operation, null, null);
+            }
         }
         // Adding partner role
         return new SimpleActivity<OReply>(oreply);
@@ -341,21 +347,20 @@
     }
 
     public void addResourceDecl(OScope scope, String resourceName, SimPELExpr pathExpr, String resourceRef) {
-        OResource res = new OResource(_oprocess);
-        res.setName(resourceName);
-        res.setDeclaringScope(scope);
-        scope.resource.put(resourceName, res);
+        ResourceDesc res = new ResourceDesc();
+        res.name = resourceName;
+        res.declaringScope = scope;
 
         if (pathExpr != null) {
             pathExpr.expressionLanguage = _exprLang;
-            res.setSubpath(pathExpr);
+            res.subpath = pathExpr;
         }
 
         if (resourceRef != null) {
-            OResource reference = webResources.get(resourceRef);
+            ResourceDesc reference = webResources.get(resourceRef);
             if (reference == null) throw new RuntimeException("Unknown resource reference " + resourceRef +
                     " in the definition of resource " + resourceName);
-            res.setReference(reference);
+            res.reference = reference;
         }
 
         // Creating a variable to make the resource accessible as one
@@ -369,7 +374,6 @@
         typedVariables.add(resourceName);
 
         webResources.put(resourceName, res);
-        _oprocess.providedResources.add(res);
     }
 
     public void addCorrelationMatch(OActivity receive, List match) {
@@ -454,6 +458,7 @@
             resolved = new OScope.Variable(_oprocess, omsgType);
             resolved.name = name;
             resolved.declaringScope = oscope;
+            oscope.addLocalVariable(resolved);
             variables.put(name, resolved);
         }
 
@@ -479,9 +484,42 @@
         return ce;
     }
 
-
     protected String getBpwsNamespace() {
         return "http://ode.apache.org/simpel/1.0";
     }
 
+    private OResource copyResource(ResourceDesc res, String method) {
+        OResource newRes = res.methods.get(method);
+        if (newRes != null) return newRes;
+
+        newRes = new OResource(_oprocess);
+        newRes.setMethod(method);
+        newRes.setDeclaringScope(res.declaringScope);
+        newRes.setInstantiateResource(res.instantiating);
+        newRes.setName(res.name);
+        if (res.reference != null) newRes.setReference(copyResource(res.reference, method));
+        newRes.setSubpath(res.subpath);
+        res.declaringScope.resource.put(newRes.getName(), newRes);
+        res.methods.put(method, newRes);
+        res.latest = newRes;
+
+        return newRes;
+    }
+
+    private static class ResourceDesc {
+        String name;
+        private boolean instantiating;
+        ResourceDesc reference;
+        OExpression subpath;
+        OScope declaringScope;
+        OResource latest;
+        HashMap<String,OResource> methods = new HashMap<String,OResource>();
+
+        void setInstantiating(boolean i) {
+            instantiating = i;
+            for (OResource resource : methods.values()) {
+                resource.setInstantiateResource(i);
+            }
+        }
+    }
 }

Modified: ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/RestfulSimPELTest.java
URL: http://svn.apache.org/viewvc/ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/RestfulSimPELTest.java?rev=721070&r1=721069&r2=721070&view=diff
==============================================================================
--- ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/RestfulSimPELTest.java (original)
+++ ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/RestfulSimPELTest.java Wed Nov 26 18:02:44 2008
@@ -38,7 +38,7 @@
         String response = resp.getEntity(String.class);
         System.out.println("=> " + response);
         assertTrue(response.indexOf("Hello foo") > 0);
-        assertTrue(resp.getMetadata().get("Location").get(0).matches("/hello/[0-9]*"));
+        assertTrue(resp.getMetadata().get("Location").get(0), resp.getMetadata().get("Location").get(0).matches("/hello/[0-9]*"));
         System.out.println("loc " + resp.getMetadata().get("Location"));
         server.stop();
     }
@@ -46,6 +46,7 @@
     private static final String COUNTER =
             "process Counter {\n" +
             "   counter = receive(self); \n" +
+            "   reply(counter, self); \n" +
             "   value = resource(\"/value\"); \n" +
             "   inc = resource(\"/inc\"); \n" +
             "   dec = resource(\"/dec\"); \n" +
@@ -78,9 +79,17 @@
         Client c = Client.create(cc);
 
         WebResource wr = c.resource("http://localhost:3434/counter");
-        ClientResponse resp = wr.path("/").accept("application/xml").type("application/xml")
-                .post(ClientResponse.class, "<simpelWrapper xmlns=\"http://ode.apache.org/simpel/1.0/definition/HelloWorld\">5</simpelWrapper>");
-        String response = resp.getEntity(String.class);
+        ClientResponse createResponse = wr.path("/").accept("application/xml").type("application/xml")
+                .post(ClientResponse.class, "<simpelWrapper xmlns=\"http://ode.apache.org/simpel/1.0/definition/Counter\">5</simpelWrapper>");
+        String response = createResponse.getEntity(String.class);
+        System.out.println("=> " + response);
+        System.out.println("=> " + createResponse.getMetadata().get("Location").get(0));
+
+        String location = createResponse.getMetadata().get("Location").get(0);
+        WebResource instance = c.resource(location);
+        ClientResponse queryResponse = instance.path("/").type("application/xml").get(ClientResponse.class);
+        System.out.println("=> " + queryResponse.getStatus());
+        System.out.println("=> " + queryResponse.getEntity(String.class));
 
         server.stop();
     }