From ac8bb2ddecac09d60760ef83319b627548d0fd77 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Thu, 1 Jul 2010 06:04:35 +0000 Subject: Minimal support for implementation.widget, using simplified (and generic) JSONRPC and ATOMPub Javascript proxies. Minor changes to the server runtime to serve reference requests from widgets. Adjust and simplified samples using the widget support. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@959521 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/kernel/string.hpp | 14 + sca-cpp/trunk/modules/http/httpd-conf | 1 + sca-cpp/trunk/modules/json/json-test.cpp | 4 +- sca-cpp/trunk/modules/server/Makefile.am | 2 +- .../trunk/modules/server/htdocs/js/tuscany-ref.js | 553 +++++++++++++++++ sca-cpp/trunk/modules/server/mod-eval.hpp | 18 +- sca-cpp/trunk/modules/server/mod-wiring.cpp | 2 +- sca-cpp/trunk/modules/server/server-conf | 4 + sca-cpp/trunk/modules/wsgi/scdl.py | 73 ++- sca-cpp/trunk/samples/store-cpp/Makefile.am | 2 +- sca-cpp/trunk/samples/store-cpp/fruits-catalog.cpp | 15 +- sca-cpp/trunk/samples/store-cpp/htdocs/store.html | 15 +- sca-cpp/trunk/samples/store-cpp/htdocs/store.js | 661 --------------------- sca-cpp/trunk/samples/store-cpp/shopping-cart.cpp | 9 - sca-cpp/trunk/samples/store-cpp/store.composite | 10 + sca-cpp/trunk/samples/store-gae/Makefile.am | 11 +- .../samples/store-gae/domain-single.composite | 2 +- sca-cpp/trunk/samples/store-gae/domain.composite | 2 +- sca-cpp/trunk/samples/store-gae/fruits-catalog.py | 6 +- sca-cpp/trunk/samples/store-gae/htdocs/store.html | 15 +- sca-cpp/trunk/samples/store-gae/htdocs/store.js | 661 --------------------- sca-cpp/trunk/samples/store-gae/shopping-cart.py | 3 - sca-cpp/trunk/samples/store-gae/store.py | 6 +- sca-cpp/trunk/samples/store-java/Makefile.am | 2 +- sca-cpp/trunk/samples/store-java/htdocs/store.html | 15 +- sca-cpp/trunk/samples/store-java/htdocs/store.js | 661 --------------------- sca-cpp/trunk/samples/store-java/store.composite | 10 + .../store-java/store/FruitsCatalogImpl.java | 9 +- .../samples/store-java/store/ShoppingCartImpl.java | 7 - sca-cpp/trunk/samples/store-nosql/Makefile.am | 2 +- .../trunk/samples/store-nosql/fruits-catalog.scm | 5 +- .../trunk/samples/store-nosql/htdocs/store.html | 15 +- sca-cpp/trunk/samples/store-nosql/htdocs/store.js | 661 --------------------- .../trunk/samples/store-nosql/shopping-cart.scm | 2 - sca-cpp/trunk/samples/store-nosql/store.composite | 2 +- sca-cpp/trunk/samples/store-nosql/store.scm | 5 +- sca-cpp/trunk/samples/store-python/Makefile.am | 2 +- .../trunk/samples/store-python/fruits-catalog.py | 6 +- .../trunk/samples/store-python/htdocs/store.html | 15 +- sca-cpp/trunk/samples/store-python/htdocs/store.js | 661 --------------------- .../trunk/samples/store-python/shopping-cart.py | 3 - sca-cpp/trunk/samples/store-python/store.py | 6 +- sca-cpp/trunk/samples/store-scheme/Makefile.am | 2 +- .../trunk/samples/store-scheme/fruits-catalog.scm | 5 +- .../trunk/samples/store-scheme/htdocs/store.html | 15 +- sca-cpp/trunk/samples/store-scheme/htdocs/store.js | 661 --------------------- sca-cpp/trunk/samples/store-scheme/script-test.scm | 4 +- .../trunk/samples/store-scheme/shopping-cart.scm | 2 - sca-cpp/trunk/samples/store-scheme/store.composite | 2 +- sca-cpp/trunk/samples/store-scheme/store.scm | 5 +- sca-cpp/trunk/samples/store-sql/Makefile.am | 2 +- sca-cpp/trunk/samples/store-sql/fruits-catalog.scm | 5 +- sca-cpp/trunk/samples/store-sql/htdocs/store.html | 15 +- sca-cpp/trunk/samples/store-sql/htdocs/store.js | 661 --------------------- sca-cpp/trunk/samples/store-sql/shopping-cart.scm | 2 - sca-cpp/trunk/samples/store-sql/store.composite | 2 +- sca-cpp/trunk/samples/store-sql/store.scm | 5 +- .../xsd/tuscany-sca-1.1-implementation-widget.xsd | 43 ++ sca-cpp/trunk/xsd/tuscany-sca-1.1.xsd | 2 +- 59 files changed, 810 insertions(+), 4801 deletions(-) create mode 100644 sca-cpp/trunk/modules/server/htdocs/js/tuscany-ref.js delete mode 100644 sca-cpp/trunk/samples/store-cpp/htdocs/store.js delete mode 100644 sca-cpp/trunk/samples/store-gae/htdocs/store.js delete mode 100644 sca-cpp/trunk/samples/store-java/htdocs/store.js delete mode 100644 sca-cpp/trunk/samples/store-nosql/htdocs/store.js delete mode 100644 sca-cpp/trunk/samples/store-python/htdocs/store.js delete mode 100644 sca-cpp/trunk/samples/store-scheme/htdocs/store.js delete mode 100644 sca-cpp/trunk/samples/store-sql/htdocs/store.js create mode 100644 sca-cpp/trunk/xsd/tuscany-sca-1.1-implementation-widget.xsd (limited to 'sca-cpp/trunk') diff --git a/sca-cpp/trunk/kernel/string.hpp b/sca-cpp/trunk/kernel/string.hpp index 931417e430..1daec2aac7 100644 --- a/sca-cpp/trunk/kernel/string.hpp +++ b/sca-cpp/trunk/kernel/string.hpp @@ -241,6 +241,9 @@ const int find(const string& s1, const char* s2) { return find(s1, s2, 0); } +/** + * Return true if string s1 contains s2. + */ const bool contains(const string& s1, const char* s2) { return find(s1, s2) != length(s1); } @@ -252,6 +255,17 @@ const int find_first_of(const string& s1, const string& s2) { return strcspn(c_str(s1), c_str(s2)); } +/** + * Find the first occurence of a character in a string. + */ +const int find(const string& s, const char c) { + const char* cs = c_str(s); + const char* f = strchr(cs, c); + if (f == NULL) + return length(s); + return f - cs; +} + /** * Find the last occurence of a character in a string. */ diff --git a/sca-cpp/trunk/modules/http/httpd-conf b/sca-cpp/trunk/modules/http/httpd-conf index 45941fc163..35c6c78254 100755 --- a/sca-cpp/trunk/modules/http/httpd-conf +++ b/sca-cpp/trunk/modules/http/httpd-conf @@ -38,6 +38,7 @@ ServerName $host PidFile $root/logs/httpd.pid # Minimal set of modules +LoadModule alias_module ${modules_prefix}/modules/mod_alias.so LoadModule authn_file_module ${modules_prefix}/modules/mod_authn_file.so LoadModule authn_default_module ${modules_prefix}/modules/mod_authn_default.so LoadModule authz_host_module ${modules_prefix}/modules/mod_authz_host.so diff --git a/sca-cpp/trunk/modules/json/json-test.cpp b/sca-cpp/trunk/modules/json/json-test.cpp index b74f068710..707a785968 100644 --- a/sca-cpp/trunk/modules/json/json-test.cpp +++ b/sca-cpp/trunk/modules/json/json-test.cpp @@ -93,11 +93,11 @@ bool testJSON() { bool testJSONRPC() { JSONContext cx; { - const string lm("{\"id\": 1, \"method\": \"system.listMethods\", \"params\": []}"); + const string lm("{\"id\": 1, \"method\": \"test\", \"params\": []}"); const list e = content(readJSON(mklist(lm), cx)); const list v = elementsToValues(e); assert(assoc("id", v) == mklist("id", 1)); - assert(assoc("method", v) == mklist("method", string("system.listMethods"))); + assert(assoc("method", v) == mklist("method", string("test"))); assert(assoc("params", v) == mklist("params", list())); } { diff --git a/sca-cpp/trunk/modules/server/Makefile.am b/sca-cpp/trunk/modules/server/Makefile.am index 30c89da85d..4c3e5531f0 100644 --- a/sca-cpp/trunk/modules/server/Makefile.am +++ b/sca-cpp/trunk/modules/server/Makefile.am @@ -23,7 +23,7 @@ incldir = $(prefix)/include/modules/server dist_mod_SCRIPTS = cpp-conf scheme-conf server-conf moddir = $(prefix)/modules/server -EXTRA_DIST = domain-test.composite client-test.scm server-test.scm htdocs/*.xml htdocs/*.txt htdocs/*.html +EXTRA_DIST = domain-test.composite client-test.scm server-test.scm htdocs/*.xml htdocs/*.txt htdocs/*.html htdocs/js/*.js mod_LTLIBRARIES = libmod_tuscany_eval.la libmod_tuscany_wiring.la noinst_DATA = libmod_tuscany_eval.so libmod_tuscany_wiring.so diff --git a/sca-cpp/trunk/modules/server/htdocs/js/tuscany-ref.js b/sca-cpp/trunk/modules/server/htdocs/js/tuscany-ref.js new file mode 100644 index 0000000000..fd09a3efc7 --- /dev/null +++ b/sca-cpp/trunk/modules/server/htdocs/js/tuscany-ref.js @@ -0,0 +1,553 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * The JSON-RPC client code is based on Jan-Klaas' JavaScript + * o lait library (jsolait). + * + * $Id: jsonrpc.js,v 1.36.2.3 2006/03/08 15:09:37 mclark Exp $ + * + * Copyright (c) 2003-2004 Jan-Klaas Kollhof + * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"). + */ + +/** + * Escape a character. + */ +function escapeJSONChar(c) { + if(c == "\"" || c == "\\") return "\\" + c; + else if (c == "\b") return "\\b"; + else if (c == "\f") return "\\f"; + else if (c == "\n") return "\\n"; + else if (c == "\r") return "\\r"; + else if (c == "\t") return "\\t"; + var hex = c.charCodeAt(0).toString(16); + if(hex.length == 1) return "\\u000" + hex; + else if(hex.length == 2) return "\\u00" + hex; + else if(hex.length == 3) return "\\u0" + hex; + else return "\\u" + hex; +} + +/** + * Encode a string into JSON format. + */ +function escapeJSONString(s) { + /* The following should suffice but Safari's regex is broken + (doesn't support callback substitutions) + return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, + escapeJSONChar) + "\""; + */ + + /* Rather inefficient way to do it */ + var parts = s.split(""); + for(var i = 0; i < parts.length; i++) { + var c = parts[i]; + if(c == '"' || + c == '\\' || + c.charCodeAt(0) < 32 || + c.charCodeAt(0) >= 128) + parts[i] = escapeJSONChar(parts[i]); + } + return "\"" + parts.join("") + "\""; +} + +/** + * Marshall objects to JSON format. + */ +function toJSON(o) { + if(o == null) { + return "null"; + } else if(o.constructor == String) { + return escapeJSONString(o); + } else if(o.constructor == Number) { + return o.toString(); + } else if(o.constructor == Boolean) { + return o.toString(); + } else if(o.constructor == Date) { + return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; + } else if(o.constructor == Array) { + var v = []; + for(var i = 0; i < o.length; i++) v.push(toJSON(o[i])); + return "[" + v.join(", ") + "]"; + } else { + var v = []; + for(attr in o) { + if(o[attr] == null) v.push("\"" + attr + "\": null"); + else if(typeof o[attr] == "function"); /* skip */ + else v.push(escapeJSONString(attr) + ": " + toJSON(o[attr])); + } + return "{" + v.join(", ") + "}"; + } +} + +/** + * HTTPBindingClient.Exception + */ +HTTPBindingClient.Exception = function(code, message, javaStack) { + this.code = code; + var name; + if(javaStack) { + this.javaStack = javaStack; + var m = javaStack.match(/^([^:]*)/); + if(m) name = m[0]; + } + if(name) this.name = name; + else this.name = "HTTPBindingClientException"; + this.message = message; +}; + +HTTPBindingClient.Exception.CODE_REMOTE_EXCEPTION = 490; +HTTPBindingClient.Exception.CODE_ERR_CLIENT = 550; +HTTPBindingClient.Exception.CODE_ERR_PARSE = 590; +HTTPBindingClient.Exception.CODE_ERR_NOMETHOD = 591; +HTTPBindingClient.Exception.CODE_ERR_UNMARSHALL = 592; +HTTPBindingClient.Exception.CODE_ERR_MARSHALL = 593; + +HTTPBindingClient.Exception.prototype = new Error(); +HTTPBindingClient.Exception.prototype.toString = function(code, msg) +{ + return this.name + ": " + this.message; +}; + +/** + * Default top level exception handler + */ +HTTPBindingClient.default_ex_handler = function(e) { alert(e); }; + + +/** + * Client settable variables + */ +HTTPBindingClient.toplevel_ex_handler = HTTPBindingClient.default_ex_handler; +HTTPBindingClient.profile_async = false; +HTTPBindingClient.max_req_active = 1; +HTTPBindingClient.requestId = 1; + + +/** + * HTTPBindingClient implementation + */ +HTTPBindingClient.prototype._createApplyMethod = function() { + var fn = function() { + var args = []; + var callback = null; + var methodName = arguments[0]; + for(var i = 1; i < arguments.length; i++) args.push(arguments[i]); + + if(typeof args[args.length - 1] == "function") callback = args.pop(); + + var req = fn.client._makeRequest.call(fn.client, methodName, args, callback); + if(callback == null) { + return fn.client._sendRequest.call(fn.client, req); + } else { + HTTPBindingClient.async_requests.push(req); + HTTPBindingClient.kick_async(); + return req.requestId; + } + }; + fn.client = this; + return fn; +}; + +HTTPBindingClient._getCharsetFromHeaders = function(http) { + try { + var contentType = http.getResponseHeader("Content-type"); + var parts = contentType.split(/\s*;\s*/); + for(var i = 0; i < parts.length; i++) { + if(parts[i].substring(0, 8) == "charset=") + return parts[i].substring(8, parts[i].length); + } + } catch (e) {} + return "UTF-8"; +}; + +/** + * Async queue globals + */ +HTTPBindingClient.async_requests = []; +HTTPBindingClient.async_inflight = {}; +HTTPBindingClient.async_responses = []; +HTTPBindingClient.async_timeout = null; +HTTPBindingClient.num_req_active = 0; + +HTTPBindingClient._async_handler = function() { + HTTPBindingClient.async_timeout = null; + + while(HTTPBindingClient.async_responses.length > 0) { + var res = HTTPBindingClient.async_responses.shift(); + if(res.canceled) continue; + if(res.profile) res.profile.dispatch = new Date(); + try { + res.cb(res.result, res.ex, res.profile); + } catch(e) { + HTTPBindingClient.toplevel_ex_handler(e); + } + } + + while(HTTPBindingClient.async_requests.length > 0 && HTTPBindingClient.num_req_active < HTTPBindingClient.max_req_active) { + var req = HTTPBindingClient.async_requests.shift(); + if(req.canceled) continue; + req.client._sendRequest.call(req.client, req); + } +}; + +HTTPBindingClient.kick_async = function() { + if(HTTPBindingClient.async_timeout == null) + HTTPBindingClient.async_timeout = setTimeout(HTTPBindingClient._async_handler, 0); +}; + +HTTPBindingClient.cancelRequest = function(requestId) { + /* If it is in flight then mark it as canceled in the inflight map + and the XMLHttpRequest callback will discard the reply. */ + if(HTTPBindingClient.async_inflight[requestId]) { + HTTPBindingClient.async_inflight[requestId].canceled = true; + return true; + } + + /* If its not in flight yet then we can just mark it as canceled in + the the request queue and it will get discarded before being sent. */ + for(var i in HTTPBindingClient.async_requests) { + if(HTTPBindingClient.async_requests[i].requestId == requestId) { + HTTPBindingClient.async_requests[i].canceled = true; + return true; + } + } + + /* It may have returned from the network and be waiting for its callback + to be dispatched, so mark it as canceled in the response queue + and the response will get discarded before calling the callback. */ + for(var i in HTTPBindingClient.async_responses) { + if(HTTPBindingClient.async_responses[i].requestId == requestId) { + HTTPBindingClient.async_responses[i].canceled = true; + return true; + } + } + + return false; +}; + +HTTPBindingClient.prototype._makeRequest = function(methodName, args, cb) { + var req = {}; + req.client = this; + req.requestId = HTTPBindingClient.requestId++; + + var obj = {}; + obj.id = req.requestId; + if (this.objectID) + obj.method = ".obj#" + this.objectID + "." + methodName; + else + obj.method = methodName; + obj.params = args; + + if (cb) req.cb = cb; + if (HTTPBindingClient.profile_async) + req.profile = { "submit": new Date() }; + req.data = toJSON(obj); + + return req; +}; + +HTTPBindingClient.prototype._sendRequest = function(req) { + if(req.profile) req.profile.start = new Date(); + + /* Get free http object from the pool */ + var http = HTTPBindingClient.poolGetHTTPRequest(); + HTTPBindingClient.num_req_active++; + + /* Send the request */ + http.open("POST", this.uri, (req.cb != null)); + + /* setRequestHeader is missing in Opera 8 Beta */ + try { + http.setRequestHeader("Content-type", "text/plain"); + } catch(e) {} + + /* Construct call back if we have one */ + if(req.cb) { + var self = this; + http.onreadystatechange = function() { + if(http.readyState == 4) { + http.onreadystatechange = function () {}; + var res = { "cb": req.cb, "result": null, "ex": null}; + if (req.profile) { + res.profile = req.profile; + res.profile.end = new Date(); + } + try { res.result = self._handleResponse(http); } + catch(e) { res.ex = e; } + if(!HTTPBindingClient.async_inflight[req.requestId].canceled) + HTTPBindingClient.async_responses.push(res); + delete HTTPBindingClient.async_inflight[req.requestId]; + HTTPBindingClient.kick_async(); + } + }; + } else { + http.onreadystatechange = function() {}; + } + + HTTPBindingClient.async_inflight[req.requestId] = req; + + try { + http.send(req.data); + } catch(e) { + HTTPBindingClient.poolReturnHTTPRequest(http); + HTTPBindingClient.num_req_active--; + throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed"); + } + + if(!req.cb) return this._handleResponse(http); +}; + +HTTPBindingClient.prototype._handleResponse = function(http) { + /* Get the charset */ + if(!this.charset) { + this.charset = HTTPBindingClient._getCharsetFromHeaders(http); + } + + /* Get request results */ + var status, statusText, data; + try { + status = http.status; + statusText = http.statusText; + data = http.responseText; + } catch(e) { + HTTPBindingClient.poolReturnHTTPRequest(http); + HTTPBindingClient.num_req_active--; + HTTPBindingClient.kick_async(); + throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed"); + } + + /* Return http object to the pool; */ + HTTPBindingClient.poolReturnHTTPRequest(http); + HTTPBindingClient.num_req_active--; + + /* Unmarshall the response */ + if(status != 200) { + throw new HTTPBindingClient.Exception(status, statusText); + } + var obj; + try { + eval("obj = " + data); + } catch(e) { + throw new HTTPBindingClient.Exception(550, "error parsing result"); + } + if(obj.error) + throw new HTTPBindingClient.Exception(obj.error.code, obj.error.msg, obj.error.trace); + var res = obj.result; + + /* Handle CallableProxy */ + if(res && res.objectID && res.JSONRPCType == "CallableReference") + return new HTTPBindingClient(this.uri, res.objectID); + + return res; +}; + + +/** + * XMLHttpRequest wrapper code + */ +HTTPBindingClient.http_spare = []; +HTTPBindingClient.http_max_spare = 8; + +HTTPBindingClient.poolGetHTTPRequest = function() { + if(HTTPBindingClient.http_spare.length > 0) { + return HTTPBindingClient.http_spare.pop(); + } + return HTTPBindingClient.getHTTPRequest(); +}; + +HTTPBindingClient.poolReturnHTTPRequest = function(http) { + if(HTTPBindingClient.http_spare.length >= HTTPBindingClient.http_max_spare) + delete http; + else + HTTPBindingClient.http_spare.push(http); +}; + +HTTPBindingClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0", + "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", + "MSXML2.XMLHTTP", + "Microsoft.XMLHTTP" ]; + +HTTPBindingClient.getHTTPRequest = function() { + /* Mozilla XMLHttpRequest */ + try { + HTTPBindingClient.httpObjectName = "XMLHttpRequest"; + return new XMLHttpRequest(); + } catch(e) {} + + /* Microsoft MSXML ActiveX */ + for (var i=0; i < HTTPBindingClient.msxmlNames.length; i++) { + try { + HTTPBindingClient.httpObjectName = HTTPBindingClient.msxmlNames[i]; + return new ActiveXObject(HTTPBindingClient.msxmlNames[i]); + } catch (e) {} + } + + /* None found */ + HTTPBindingClient.httpObjectName = null; + throw new HTTPBindingClient.Exception(0, "Can't create XMLHttpRequest object"); +}; + + +HTTPBindingClient.prototype.get = function(id, responseFunction) { + var xhr = this.createXMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + var strDocument = xhr.responseText; + var xmlDocument = xhr.responseXML; + if(!xmlDocument || xmlDocument.childNodes.length==0){ + xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml"); + } + if (responseFunction != null) responseFunction(xmlDocument); + } else { + alert("get - Error getting data from the server"); + } + } + } + xhr.open("GET", this.uri + '/' + id, true); + xhr.send(null); +} + +HTTPBindingClient.prototype.post = function (entry, responseFunction) { + var xhr = this.createXMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 201) { + var strDocument = xhr.responseText; + var xmlDocument = xhr.responseXML; + if(!xmlDocument || xmlDocument.childNodes.length==0){ + xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml"); + } + if (responseFunction != null) responseFunction(xmlDocument); + } else { + alert("post - Error getting data from the server"); + } + } + } + xhr.open("POST", this.uri, true); + xhr.setRequestHeader("Content-Type", "application/atom+xml"); + xhr.send(entry); +} + +HTTPBindingClient.prototype.put = function (id, entry, responseFunction) { + var xhr = this.createXMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + var strDocument = xhr.responseText; + var xmlDocument = xhr.responseXML; + if(!xmlDocument || xmlDocument.childNodes.length==0){ + xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml"); + } + if (responseFunction != null) responseFunction(xmlDocument); + } else { + alert("put - Error getting data from the server"); + } + } + } + xhr.open("PUT", this.uri + '/' + id, true); + xhr.setRequestHeader("Content-Type", "application/atom+xml"); + xhr.send(entry); +} + +HTTPBindingClient.prototype.del = function (id, responseFunction) { + var xhr = this.createXMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + if (responseFunction != null) responseFunction(); + } else { + alert("delete - Error getting data from the server"); + } + } + } + xhr.open("DELETE", this.uri + '/' + id, true); + xhr.send(null); +} + +HTTPBindingClient.prototype.createXMLHttpRequest = function () { + /* Mozilla XMLHttpRequest */ + try { return new XMLHttpRequest(); } catch(e) {} + + /* Microsoft MSXML ActiveX */ + for (var i = 0; i < HTTPBindingClient.msxmlNames.length; i++) { + try { return new ActiveXObject(HTTPBindingClient.msxmlNames[i]); } catch (e) {} + } + alert("XML http request not supported"); + return null; +} + +/** + * Create Tuscany namespace. + */ +var tuscany; +if (!tuscany) + tuscany = {}; +if (!tuscany.sca) + tuscany.sca = {}; + +/** + * Configure component name + */ +tuscany.sca.componentName = "Default"; + +tuscany.sca.Component = function(name) { + tuscany.sca.componentName = name; + return name +} + +/** + * Construct an HTTPBindingClient. + */ +function HTTPBindingClient(cname, uri, objectID) { + this.uri = "/references/" + cname + "/" + uri; + this.objectID = objectID; + this.apply = this._createApplyMethod(); + + if (typeof DOMParser == "undefined") { + DOMParser = function () {} + + DOMParser.prototype.parseFromString = function (str, contentType) { + if (typeof ActiveXObject != "undefined") { + var d = new ActiveXObject("MSXML.DomDocument"); + d.loadXML(str); + return d; + } else if (typeof XMLHttpRequest != "undefined") { + var req = new XMLHttpRequest; + req.open("GET", "data:" + (contentType || "application/xml") + + ";charset=utf-8," + encodeURIComponent(str), false); + if (req.overrideMimeType) { + req.overrideMimeType(contentType); + } + req.send(null); + return req.responseXML; + } + } + } +}; + +/** + * Construct a reference proxy + */ +tuscany.sca.Reference = function(name) { + return new HTTPBindingClient(tuscany.sca.componentName, name); +} + diff --git a/sca-cpp/trunk/modules/server/mod-eval.hpp b/sca-cpp/trunk/modules/server/mod-eval.hpp index e46d8ba78a..14e5f40e9b 100644 --- a/sca-cpp/trunk/modules/server/mod-eval.hpp +++ b/sca-cpp/trunk/modules/server/mod-eval.hpp @@ -358,6 +358,22 @@ const list propProxies(const list& props) { /** * Evaluate a component and convert it to an applicable lambda function. */ +struct implementationFailure { + const value reason; + implementationFailure(const value& r) : reason(r) { + } + + // Default implementation representing an implementation that + // couldn't be evaluated. Report the evaluation error on all + // subsequent calls expect start/stop. + const value operator()(unused const list& params) const { + const value func = car(params); + if (func == "start" || func == "stop") + return mklist(lambda&)>()); + return mklist(value(), reason); + } +}; + const value evalComponent(ServerConf& sc, server_rec& server, const value& comp) { extern const failable&)> > evalImplementation(const string& cpath, const value& impl, const list& px, const lambda&)>& lifecycle); @@ -380,7 +396,7 @@ const value evalComponent(ServerConf& sc, server_rec& server, const value& comp) // Evaluate the component implementation and convert it to an applicable lambda function const failable&)> > cimpl(evalImplementation(sc.contributionPath, impl, append(rpx, ppx), sc.lifecycle)); if (!hasContent(cimpl)) - return reason(cimpl); + return lambda&)>(implementationFailure(reason(cimpl))); return content(cimpl); } diff --git a/sca-cpp/trunk/modules/server/mod-wiring.cpp b/sca-cpp/trunk/modules/server/mod-wiring.cpp index 296181acfa..7f41a7e03d 100644 --- a/sca-cpp/trunk/modules/server/mod-wiring.cpp +++ b/sca-cpp/trunk/modules/server/mod-wiring.cpp @@ -107,7 +107,7 @@ int translateReference(request_rec *r) { } // Route to a relative target URI using a local internal redirect - r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/components/") + target)); + r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/components/") + substr(target, 0, find(target, '/')))); r->handler = "mod_tuscany_wiring"; return OK; } diff --git a/sca-cpp/trunk/modules/server/server-conf b/sca-cpp/trunk/modules/server/server-conf index ed5ead4cf5..c430d53de2 100755 --- a/sca-cpp/trunk/modules/server/server-conf +++ b/sca-cpp/trunk/modules/server/server-conf @@ -23,6 +23,7 @@ root=`readlink -f $1` host=`cat $root/conf/httpd.conf | grep ServerName | awk '{ print $2 }'` port=`cat $root/conf/httpd.conf | grep Listen | tail -1 | awk '{ print $2 }'` + ssl=`cat $root/conf/httpd.conf | grep "SSLEngine" | awk '{ print $2 }'` if [ "$ssl" = "on" ]; then protocol="https" @@ -44,4 +45,7 @@ cat >>$root/conf/httpd.conf <> stderr, "evalComponent", comp.impl, comp.svcs, comp.refs, comp.props + comp.proxies = tuple(map(lambda r: evalReference(r, comps), comp.refs)) + tuple(map(lambda p: evalProperty(p), comp.props)) return comp diff --git a/sca-cpp/trunk/samples/store-cpp/Makefile.am b/sca-cpp/trunk/samples/store-cpp/Makefile.am index 2323896010..05c8d33808 100644 --- a/sca-cpp/trunk/samples/store-cpp/Makefile.am +++ b/sca-cpp/trunk/samples/store-cpp/Makefile.am @@ -19,7 +19,7 @@ dist_sample_SCRIPTS = start stop ssl-start sampledir = $(prefix)/samples/store-cpp -nobase_dist_sample_DATA = currency-converter.cpp fruits-catalog.cpp shopping-cart.cpp store.composite htdocs/.htaccess htdocs/*.html htdocs/*.js +nobase_dist_sample_DATA = currency-converter.cpp fruits-catalog.cpp shopping-cart.cpp store.composite htdocs/.htaccess htdocs/*.html sample_LTLIBRARIES = libcurrency-converter.la libfruits-catalog.la libshopping-cart.la diff --git a/sca-cpp/trunk/samples/store-cpp/fruits-catalog.cpp b/sca-cpp/trunk/samples/store-cpp/fruits-catalog.cpp index 20f2bd35f7..a6c1056080 100644 --- a/sca-cpp/trunk/samples/store-cpp/fruits-catalog.cpp +++ b/sca-cpp/trunk/samples/store-cpp/fruits-catalog.cpp @@ -50,7 +50,7 @@ const list mkfruit(const string& name, const string& code, const string& mklist("javaClass", string("services.Item")) + mklist("name", name) + mklist("currencyCode", code) + mklist("currencySymbol", symbol) + mklist("price", price); } -const failable get(const lambda&)> converter, const lambda&)> currencyCode) { +const failable getcatalog(const lambda&)> converter, const lambda&)> currencyCode) { const string currency(currencyCode(list())); const string symbol(converter(mklist("symbol", currency))); const lambda conv(convert(converter, currency)); @@ -61,13 +61,6 @@ const failable get(const lambda&)> converter, con mkfruit("Pear", currency, symbol, conv(1.55))); } -/** - * TODO remove this JSON-RPC specific function. - */ -const failable listMethods(unused const lambda&)> converter, unused const lambda&)> currencyCode) { - return value(mklist(string("Service.get"))); -} - } } @@ -75,10 +68,8 @@ extern "C" { const tuscany::value apply(const tuscany::list& params) { const tuscany::value func(car(params)); - if (func == "get") - return tuscany::store::get(cadr(params), caddr(params)); - if (func == "listMethods") - return tuscany::store::listMethods(cadr(params), caddr(params)); + if (func == "getcatalog") + return tuscany::store::getcatalog(cadr(params), caddr(params)); return tuscany::mkfailure(); } diff --git a/sca-cpp/trunk/samples/store-cpp/htdocs/store.html b/sca-cpp/trunk/samples/store-cpp/htdocs/store.html index 21eabca7a7..4e2ee6795a 100644 --- a/sca-cpp/trunk/samples/store-cpp/htdocs/store.html +++ b/sca-cpp/trunk/samples/store-cpp/htdocs/store.html @@ -20,10 +20,12 @@ Store - + + + + + + +