Orbjson 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * JSON-RPC JavaScript client
3
3
  *
4
- * $Id: jsonrpc.js,v 1.1.1.1 2005/02/28 03:06:29 jamesgbritt Exp $
4
+ * $Id: jsonrpc.js,v 1.2 2005/03/15 02:29:22 jamesgbritt Exp $
5
5
  *
6
6
  * Copyright (c) 2003-2004 Jan-Klaas Kollhof
7
7
  * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd
@@ -0,0 +1,262 @@
1
+ /*
2
+ * JSON-RPC JavaScript client
3
+ *
4
+ * $Id: jsonrpc_async.js,v 1.2 2005/03/15 02:29:22 jamesgbritt Exp $
5
+ *
6
+ * Copyright (c) 2003-2004 Jan-Klaas Kollhof
7
+ * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd
8
+ * Copyright (c) 2005 James Britt, Neurogami, LLC
9
+ *
10
+ * This code is based on Michael Clark's' version of Jan-Klaas' jsonrpc.js
11
+ * file fom the JavaScript o lait library (jsolait).
12
+
13
+ * The Clark version seemed easier to use the original Module-based
14
+ * code, but did not do asyncronous requests. The current version
15
+ * is essentialy the same code, but with the async requests and callback
16
+ * hooks
17
+ *
18
+ * This library is free software; you can redistribute it and/or
19
+ * modify it under the terms of the GNU Lesser General Public (LGPL)
20
+ * License as published by the Free Software Foundation; either
21
+ * version 2.1 of the License, or (at your option) any later version.
22
+ *
23
+ * This library is distributed in the hope that it will be useful,
24
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26
+ * Lesser General Public License for more details: http://www.gnu.org/
27
+ *
28
+ */
29
+
30
+ // TODO: Add async
31
+ // TODO: Add HTTP auth (user, password)
32
+
33
+ Object.prototype.toJSON = function Object_toJSON() {
34
+ var v = [];
35
+ for(attr in this) {
36
+ if(this[attr] == null) v.push("\"" + attr + "\": null");
37
+ else if(typeof this[attr] == "function"); // skip
38
+ else v.push("\"" + attr + "\": " + this[attr].toJSON());
39
+ }
40
+ return "{" + v.join(", ") + "}";
41
+ }
42
+
43
+ String.prototype.toJSON = function String_toJSON() {
44
+ return "\"" + this.replace(/([\"\\])/g, "\\$1") + "\"";
45
+ }
46
+
47
+ Number.prototype.toJSON = function Number_toJSON() {
48
+ return this.toString();
49
+ }
50
+
51
+ Boolean.prototype.toJSON = function Boolean_toJSON() {
52
+ return this.toString();
53
+ }
54
+
55
+ Date.prototype.toJSON = function Date_toJSON() {
56
+ this.valueOf().toString();
57
+ }
58
+
59
+ Array.prototype.toJSON = function Array_toJSON() {
60
+ var v = [];
61
+ for(var i=0; i<this.length; i++) {
62
+ if(this[i] == null) v.push("null");
63
+ else v.push(this[i].toJSON());
64
+ }
65
+ return "[" + v.join(", ") + "]";
66
+ }
67
+
68
+
69
+ /*******************************************************************
70
+ ******************************************************************/
71
+ JSONRpcAsyncClient = function JSONRpcAsyncClient_ctor( serverURL, objectID ) {
72
+ this.serverURL = serverURL;
73
+ this.objectID = objectID;
74
+ if( !JSONRpcAsyncClient.http )
75
+ JSONRpcAsyncClient.http = JSONRpcAsyncClient.getHTTPRequest();
76
+ this.addAsyncMethods( ["system.listMethods"] );
77
+ var m = this.sendRequest( "system.listMethods", [] );
78
+ this.addAsyncMethods( m );
79
+
80
+ }
81
+
82
+ /*******************************************************************
83
+ ******************************************************************/
84
+ JSONRpcAsyncClient.Exception = function JSONRpcAsyncClient_Exception_ctor(code, msg) {
85
+ this.code = code;
86
+ this.msg = msg;
87
+ }
88
+
89
+ /*******************************************************************
90
+ ******************************************************************/
91
+ JSONRpcAsyncClient.Exception.prototype.toString =
92
+ function JSONRpcAsyncClient_Exception_toString(code, msg) {
93
+ return "JSONRpcAsyncClientException: " + this.msg;
94
+ }
95
+
96
+
97
+
98
+
99
+ JSONRpcAsyncClient.AsyncMethod =
100
+ function JSONRpcAsyncClient_Method_ctor( client, methodName ) {
101
+
102
+ var fn=function() {
103
+ var args = [];
104
+ var callback = arguments[0]
105
+ for(var i=1; i< arguments.length;i++) {
106
+ args.push(arguments[i]);
107
+ }
108
+ return fn.client.sendAsyncRequest.call( fn.client, fn.methodName, callback, args);
109
+ }
110
+
111
+ fn.client = client;
112
+ fn.methodName = methodName;
113
+ return fn;
114
+ }
115
+
116
+ JSONRpcAsyncClient.prototype.addAsyncMethods =
117
+ function JSONRpcAsyncClient_addAsyncMethods(methodNames) {
118
+ for(var i=0; i<methodNames.length; i++) {
119
+ var obj = this;
120
+ var names = methodNames[i].split(".");
121
+ for(var n=0; n<names.length-1; n++){
122
+ var name = names[n];
123
+ if(obj[name]){
124
+ obj = obj[name];
125
+ }
126
+ else {
127
+ obj[name] = new Object();
128
+ obj = obj[name];
129
+ }
130
+ }
131
+ var name = names[names.length-1];
132
+ if(!obj[name]){
133
+ var method = new JSONRpcAsyncClient.AsyncMethod(this, methodNames[i]);
134
+ obj[name] = method;
135
+ }
136
+ }
137
+ }
138
+
139
+
140
+ /*******************************************************************
141
+ ******************************************************************/
142
+ // Async JSON-RPC call. The tricky part may be catching the
143
+ // state change when the call is complete, and unmarshalling the
144
+ // response.
145
+ // Possibility: Have the user pass in a caqllback method; this method
146
+ // assumes it will get called with the unnarshalled response.
147
+ // When the reqadyState goes to 4, grab the JSON response, unmarshal,
148
+ // and invokve the callback
149
+
150
+ JSONRpcAsyncClient.prototype.sendAsyncRequest =
151
+ function JSONRpcAsyncClient_sendAsyncRequest( methodName, call_back, args ) {
152
+ var obj = {"method" : methodName, "params" : args };
153
+ if (this.objectID) obj.objectID = this.objectID;
154
+
155
+ var req_data = obj.toJSON();
156
+
157
+ var http = JSONRpcAsyncClient.getHTTPRequest();
158
+
159
+ http.open("POST", this.serverURL, true); // async
160
+
161
+ try {
162
+ http.setRequestHeader( "Content-type", "text/plain" );
163
+ }
164
+ catch(e) {}
165
+
166
+
167
+ http.onreadystatechange = function() {
168
+ if ( http.readyState == 4 && http.status == 200) {
169
+ try {
170
+ s = "var obj = " + http.responseText
171
+ eval( s );
172
+ }
173
+ catch( e ) {
174
+ var e_msg = "onreadystatechange Error: " + e + "\nresponseText: " + http.responseText
175
+ obj.err = e.toString()
176
+ }
177
+ if( obj.error ) {
178
+ throw new JSONRpcAsyncClient.Exception( obj.error.code, obj.error.msg );
179
+ }
180
+ return call_back( obj.result );
181
+ }
182
+ else {
183
+ window.status = "http.status '" + http.status + "' "
184
+ }
185
+ }
186
+
187
+ http.send( req_data );
188
+
189
+ }
190
+
191
+
192
+ /*******************************************************************
193
+ ******************************************************************/
194
+ JSONRpcAsyncClient.prototype.sendRequest =
195
+
196
+ function JSONRpcAsyncClient_sendRequest(methodName, args) {
197
+ // Make request object
198
+ var obj = {"method" : methodName, "params" : args};
199
+ if (this.objectID) obj.objectID = this.objectID;
200
+
201
+ // Marshall the request object to a JSON string
202
+ var req_data = obj.toJSON();
203
+
204
+ // Send the request
205
+ JSONRpcAsyncClient.http.open("POST", this.serverURL, false); // no async
206
+ // setRequestHeader is missing in Opera 8 Beta
207
+ try {
208
+ JSONRpcAsyncClient.http.setRequestHeader("Content-type", "text/plain");
209
+ }
210
+ catch(e) {}
211
+ JSONRpcAsyncClient.http.send(req_data);
212
+
213
+ // Unmarshall the response
214
+
215
+ try {
216
+ eval("var obj = " + JSONRpcAsyncClient.http.responseText);
217
+ }
218
+ catch(e) {
219
+ alert( "sendRequest error: " + e + "\nresponseText: " + JSONRpcAsyncClient.http.responseText )
220
+ obj.err = e.toString()
221
+ }
222
+ if( obj.error) {
223
+ alert( JSONRpcAsyncClient.http.responseText )
224
+ throw new JSONRpcAsyncClient.Exception(obj.error.code, obj.error.msg);
225
+ }
226
+ var res = obj.result;
227
+
228
+ // Handle CallableProxy
229
+ if(res && res.objectID && res.JSONRPCType == "CallableReference")
230
+ return new JSONRpcAsyncClient(this.serverURL, res.objectID);
231
+
232
+ return res;
233
+ }
234
+
235
+ /*******************************************************************
236
+ ******************************************************************/
237
+ JSONRpcAsyncClient.getHTTPRequest = function JSONRpcAsyncClient_getHTTPRequest() {
238
+
239
+ try { // to get the mozilla httprequest object
240
+ return new XMLHttpRequest();
241
+ }
242
+ catch(e) {}
243
+
244
+ try { // to get MS HTTP request object
245
+ return new ActiveXObject("Msxml2.XMLHTTP.4.0");
246
+ }
247
+ catch(e) {}
248
+
249
+ try { // to get MS HTTP request object
250
+ return new ActiveXObject("Msxml2.XMLHTTP");
251
+ }
252
+ catch(e) {}
253
+
254
+ try {// to get the old MS HTTP request object
255
+ return new ActiveXObject("microsoft.XMLHTTP");
256
+ }
257
+ catch(e) {}
258
+
259
+ throw new JSONRpcAsyncClient.Exception( 0, "Can't create XMLHttpRequest object");
260
+ }
261
+
262
+
@@ -1,6 +1,6 @@
1
1
  #!/usr/local/bin/ruby
2
2
  require 'webrick'
3
-
3
+ require 'rubygems'
4
4
  require "orbjson"
5
5
  include WEBrick
6
6
 
@@ -1,4 +1,5 @@
1
1
  require 'rubygems'
2
+ require 'utils'
2
3
  require 'logger'
3
4
  require 'json/objects'
4
5
  require 'json/lexer'
@@ -6,84 +7,105 @@ require 'yaml'
6
7
  require 'needle'
7
8
  require 'webrick'
8
9
 
9
- class CGI
10
- def raw_post
11
- self.params.keys[0]
12
- end
13
- end
14
10
 
15
11
  include WEBrick
16
12
 
17
- def new_from_name( classname, *args)
18
- cname = String.new( classname.untaint )
19
- obj = nil
20
- begin
21
- obj = Object.const_get( cname ).new( *args )
22
- rescue Exception
23
- begin
24
- require cname
25
- obj = Object.const_get( cname ).new( *args )
26
- rescue Exception
27
- raise "Cannot create object #{cname}: #{$!}" unless obj
28
- end
29
- end
30
- obj
31
- end
32
-
33
-
34
13
 
35
14
 
36
15
  module Orbjson
16
+
37
17
 
38
18
  $roy_logger = Logger.new( "Orbjson.log" )
39
19
  $roy_logger.level = Logger::DEBUG
40
20
 
41
- Version = "0.1.1"
21
+ Version = "0.0.4"
22
+ STDERR.puts( "Orbjson: version #{Version }")
42
23
  LibPath = File.dirname(__FILE__)
24
+
43
25
 
26
+ # The System class holds the core broker methods. It is reponsible for
27
+ # registering server-side classes, sending a list of available services
28
+ # to the client, and connecting JSON-RPC requests with registered services
29
+ #
30
+ # The System object is initialized by calling +init+ and passing in a
31
+ # mapping of files and classes implementing services.
44
32
  class System
45
33
  @@registry = Needle::Registry.new()
46
-
34
+
35
+ # Returns an object stored in the registry
47
36
  def self.get_object( klass, *args )
48
37
  return @@registry[ klass.intern ]
49
38
  end
50
39
 
40
+ # Adds an object to the registry
51
41
  def self.put_object( klass, instance )
52
42
  @@registry.register( klass ) { instance }
53
- # @@cache[ klass ] = instance
54
43
  end
55
44
 
45
+ # Returns a list of registered service classes.
56
46
  def self.registered_classses
57
- @@registry.keys.map{ |k| k.to_s.capitalize }
47
+ @@registry.keys.map{ |k|
48
+ $roy_logger.debug( "[#{__LINE__}] self.registered_classses has @@registry[k].to_s #{@@registry[k].to_s}" )
49
+ cls = @@registry[k].class.to_s
50
+ ( cls =~ /Needle::/ || cls =~ /^Hash$/ || cls =~ /^[a-z]/ ) ? nil : @@registry[k].class.to_s
51
+ }.compact
52
+
58
53
  end
59
-
54
+
55
+ # Returns a list of registerd services. Wraps a call to System.list_methods.
56
+ # The format of each listed service name is className.method
57
+ # It was added as a conveience for client code that uses the archaic
58
+ # camelCase method naming convention found in 2oth C. programming languages
60
59
  def listMethods
61
60
  System.list_methods
62
61
  end
63
62
 
63
+ # Returns a list of registerd services.
64
+ # The format of each listed service name is +className.method+
64
65
  def self.list_methods
65
66
  mlist = []
66
67
 
67
68
  System.registered_classses.each do |cls|
68
- name = cls.to_s.downcase
69
+ name = String.new( cls )
70
+ name[0] = name[0].chr.downcase
69
71
  begin
70
- klass = eval(cls )
72
+ $roy_logger.debug( "[#{__LINE__}] System#list_methods has cls #{cls}" )
73
+ klass = eval( cls )
71
74
  ( klass.public_instance_methods -
72
75
  Object.methods ).sort.each { |m|
76
+ $roy_logger.debug( "[#{__LINE__}] System#list_methods adding #{name}.#{m}" )
73
77
  mlist << "#{name}.#{m}"
74
78
  }
75
79
  rescue Exception
76
- STDERR.puts( "System#list_methods error #{$!}" )
77
- $roy_logger.error( "System#list_methods error #{$!}" )
80
+ STDERR.puts( "[#{__LINE__}] System#list_methods error #{$!}" )
81
+ $roy_logger.error( "[#{__LINE__}] System#list_methods error #{$!}" )
78
82
  end
79
83
  end
84
+ $roy_logger.debug( "[#{__LINE__}] System#list_methods returning #{mlist.inspect}" )
80
85
  mlist
81
86
  end
82
87
 
83
-
84
- # You configure the services list by passing in either a hash of file
85
- # paths mapped to class names, or a YMAL string encoding the same, or
86
- # the path to YAML file
88
+ # You can configure the Orbjson services list in a few ways, passing
89
+ # detials into the init method.
90
+ #
91
+ # Well, three, really:
92
+ # 1. Pass in a path to a local YAML file; the path must begin with
93
+ # 'file://'
94
+ # For example: cfg = 'file://config.yaml'
95
+ # System.init( cfg )
96
+ #
97
+ # 2. Pass in some YAML:
98
+ # cfg = 'services/sample:
99
+ # - Details'
100
+ # System.init( cfg )
101
+ #
102
+ # 3. Pass in some an actual Hash object:
103
+ # cfg = { 'services/sample' => ['Details'] }
104
+ # System.init( cfg )
105
+ #
106
+ # The hash (however you express it) consists of 'require' paths mapped
107
+ # to arrays of classes to instantiate.
108
+ #
87
109
  def self.init( cfg, flush = true )
88
110
 
89
111
  @@registry = Needle::Registry.new() if flush
@@ -113,11 +135,15 @@ module Orbjson
113
135
 
114
136
  @@registry.register( :System ) { System.new }
115
137
  @@registry.register( :system ) { System.new }
116
- $roy_logger.debug( "Regist now has \n" + @@registry.keys.inspect )
138
+ $roy_logger.debug( "@@registry now has \n" + @@registry.keys.inspect )
117
139
  end
118
140
  end
119
141
 
142
+ # Assorted method used by both CGI and WEBrick Orbjson classes
120
143
  module Common
144
+
145
+ # Takes the result of some method, plus the id of the originating
146
+ # JSON-RP call, and creates the JSON-RPC reponse
121
147
  def format_repsonse( result, error, id )
122
148
  id.class == String ? quote = '"' : quote = ''
123
149
  '{ "result" : ' + result.to_json + ', "error":"' +
@@ -125,6 +151,9 @@ module Orbjson
125
151
  quote + ' }'
126
152
  end
127
153
 
154
+ # Takes a JSON-RPC message, figures out what it means in Ruby,
155
+ # invokes the request method on the correspnding service, and returns
156
+ # the results
128
157
  def process( json )
129
158
  json = "#{json}"
130
159
  null=nil;
@@ -134,23 +163,18 @@ module Orbjson
134
163
  receiver = System.get_object( klass.capitalize )
135
164
  begin
136
165
  if ( jsonobj[ 'params'] && jsonobj[ 'params'] != 'nil' )
137
- $roy_logger.debug( __LINE__ )
138
166
  if jsonobj[ 'params'].size < 1
139
- $roy_logger.debug( __LINE__ )
140
167
  result = receiver.send( method )
141
168
  else
142
- $roy_logger.debug( __LINE__ )
143
169
  result = receiver.send( method , *jsonobj[ 'params'] )
144
170
  end
145
171
  else
146
- $roy_logger.debug( __LINE__ )
147
172
  result = receiver.send( method )
148
173
  end
149
174
  error = null
150
175
  rescue
151
176
  result = null
152
177
  error = $!.to_s
153
- $roy_logger.error( "#{_LINE__}: #{$!}" )
154
178
  end
155
179
  format_repsonse( result, error, jsonobj['id'] || 'default' )
156
180
  end
@@ -162,7 +186,9 @@ module Orbjson
162
186
  class WEBrick_JSON_RPC < HTTPServlet::AbstractServlet
163
187
 
164
188
  include Common
165
-
189
+
190
+ # This initiats the actual message processing. Calls into the Common
191
+ # menthod 'process'
166
192
  def process_request( req, res, json )
167
193
  res.body = process( json )
168
194
  res['Content-Type'] = "text/javascript"
@@ -187,10 +213,13 @@ module Orbjson
187
213
 
188
214
  include Common
189
215
 
216
+ # Passes the configuration off to System.init
190
217
  def initialize( cfg )
191
218
  System.init( cfg )
192
219
  end
193
-
220
+
221
+ # Takes the raw post data, grabs the JSON-RPC message, and starts
222
+ # the processing
194
223
  def process_request( )
195
224
  cgi = CGI.new
196
225
  json = cgi.raw_post