Orbjson 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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