Orbjson 0.0.1

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.
data/lib/orbjson.rb ADDED
@@ -0,0 +1,250 @@
1
+ require 'rubygems'
2
+ require 'logger'
3
+ require 'json/objects'
4
+ require 'json/lexer'
5
+ require 'yaml'
6
+ require 'needle'
7
+ require 'webrick'
8
+
9
+ class CGI
10
+ def raw_post
11
+ self.params.keys[0]
12
+ end
13
+ end
14
+
15
+ include WEBrick
16
+
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
+
35
+
36
+ module Orbjson
37
+
38
+ $roy_logger = Logger.new( "Orbjson.log" )
39
+ $roy_logger.level = Logger::DEBUG
40
+
41
+ Version = "0.1.1"
42
+ LibPath = File.dirname(__FILE__)
43
+
44
+ class System
45
+ @@registry = Needle::Registry.new()
46
+
47
+ def self.get_object( klass, *args )
48
+ return @@registry[ klass.intern ]
49
+ end
50
+
51
+ def self.put_object( klass, instance )
52
+ @@registry.register( klass ) { instance }
53
+ # @@cache[ klass ] = instance
54
+ end
55
+
56
+ def self.registered_classses
57
+ @@registry.keys.map{ |k| k.to_s.capitalize }
58
+ end
59
+
60
+ def listMethods
61
+ System.list_methods
62
+ end
63
+
64
+ def self.list_methods
65
+ mlist = []
66
+
67
+ System.registered_classses.each do |cls|
68
+ name = cls.to_s.downcase
69
+ begin
70
+ klass = eval(cls )
71
+ ( klass.public_instance_methods -
72
+ Object.methods ).sort.each { |m|
73
+ mlist << "#{name}.#{m}"
74
+ }
75
+ rescue Exception
76
+ STDERR.puts( "System#list_methods error #{$!}" )
77
+ $roy_logger.error( "System#list_methods error #{$!}" )
78
+ end
79
+ end
80
+ mlist
81
+ end
82
+
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
87
+ def self.init( cfg, flush = true )
88
+
89
+ @@registry = Needle::Registry.new() if flush
90
+ STDERR.puts( "cfg starts as #{cfg}")
91
+ case cfg.class.to_s
92
+ when 'String'
93
+ if cfg =~ /^file:\/\//
94
+ cfg.gsub!( /^file:\/\//, '' )
95
+ STDERR.puts( "cfg is now #{cfg}")
96
+ config_hash = YAML::load( File.open( cfg ) )
97
+ else
98
+ STDERR.puts( "cfg is #{cfg}")
99
+ config_hash = YAML::load( cfg )
100
+ end
101
+ when 'Hash'
102
+ config_hash = cfg
103
+ else
104
+ raise "init was given unusable configuration data [ #{cfg.class}]: #{$!}"
105
+ end
106
+
107
+ config_hash.each do |src_file, class_list|
108
+ require src_file
109
+ class_list.each do |klass|
110
+ @@registry.register( klass ) { new_from_name( klass ) }
111
+ end
112
+ end
113
+
114
+ @@registry.register( :System ) { System.new }
115
+ @@registry.register( :system ) { System.new }
116
+ $roy_logger.debug( "Regist now has \n" + @@registry.keys.inspect )
117
+ end
118
+ end
119
+
120
+ module Common
121
+ def format_repsonse( result, error, id )
122
+ id.class == String ? quote = '"' : quote = ''
123
+ '{ "result" : ' + result.to_json + ', "error":"' +
124
+ error.to_s + '", "id": ' + quote + id.to_s +
125
+ quote + ' }'
126
+ end
127
+
128
+ def process( json )
129
+ json = "#{json}"
130
+ null=nil;
131
+ jsonobj = {}.from_json( JSON::Lexer.new(json ) )
132
+ klass, method = jsonobj[ 'method'].split( '.' )
133
+ $roy_logger.debug( "klass, method = #{klass}, #{method}" )
134
+ receiver = System.get_object( klass.capitalize )
135
+ begin
136
+ if ( jsonobj[ 'params'] && jsonobj[ 'params'] != 'nil' )
137
+ $roy_logger.debug( __LINE__ )
138
+ if jsonobj[ 'params'].size < 1
139
+ $roy_logger.debug( __LINE__ )
140
+ result = receiver.send( method )
141
+ else
142
+ $roy_logger.debug( __LINE__ )
143
+ result = receiver.send( method , *jsonobj[ 'params'] )
144
+ end
145
+ else
146
+ $roy_logger.debug( __LINE__ )
147
+ result = receiver.send( method )
148
+ end
149
+ error = null
150
+ rescue
151
+ result = null
152
+ error = $!.to_s
153
+ $roy_logger.error( "#{_LINE__}: #{$!}" )
154
+ end
155
+ format_repsonse( result, error, jsonobj['id'] || 'default' )
156
+ end
157
+ end
158
+
159
+
160
+ # Manages json-rpc requests sent as a post to a WEBrick servlet.
161
+ # Mount a path to WEBrick_JSON_RPC, and you should be set
162
+ class WEBrick_JSON_RPC < HTTPServlet::AbstractServlet
163
+
164
+ include Common
165
+
166
+ def process_request( req, res, json )
167
+ res.body = process( json )
168
+ res['Content-Type'] = "text/javascript"
169
+ end
170
+
171
+ # Delegates the call to process_request
172
+ def do_GET( request, response )
173
+ process_request( request, response, request.query_string )
174
+ end
175
+
176
+ # Delegates the call to process_request
177
+ def do_POST( request, response )
178
+ process_request( request, response, request.body )
179
+ end
180
+
181
+
182
+ end
183
+
184
+
185
+ # Manages json-rpc requests sent as a raw post to a CGI application.
186
+ class CGI_JSON_RPC
187
+
188
+ include Common
189
+
190
+ def initialize( cfg )
191
+ System.init( cfg )
192
+ end
193
+
194
+ def process_request( )
195
+ cgi = CGI.new
196
+ json = cgi.raw_post
197
+ process( json )
198
+ end
199
+
200
+ end
201
+ end
202
+
203
+ #
204
+ #
205
+ # TODO See specs at http://www.json-rpc.org/specs.xhtml
206
+ # 1.3 notification
207
+ # A notification is a special request which does not have a response.
208
+ # The notification is a single object serialized using JSON.
209
+ # It has the same properties as the request object with one exception.
210
+ #
211
+ # * id
212
+ # Muste be null.
213
+ #
214
+ # 2.2 JSON-RPC over HTTP
215
+ # With some limitations HTTP can be used for communicating to a service.
216
+ # A client may send one or more requests to a service.
217
+ # The requests must be sent as an HTTP POST containing all serialized request objects.
218
+ # The reply must contain the serialized response objects for all requests.
219
+ # Notifications may be sent by the client or the service.
220
+ #
221
+ # A non valid request must result in closing the connection.
222
+ # A non valid responses must raise an exception for all unanswered requests on the client.
223
+ # Closing a connection must raise an exception for all unanswered requests on the client.
224
+ #
225
+ # 3. JSON Class hinting?
226
+ # There are only simple data types defined in JSON.
227
+ # To overcome this problem in a JSON compatible way a special property for objects is introduced.
228
+ # {"jsonclass":["constructor", [param1, ], "prop1": ...}
229
+ # The object is then instanciated using the constructor passing the parameters.
230
+ # Once constructed the properties will be applied.
231
+
232
+
233
+ # Copyright (C) 2005 James Britt & Neurogami LLC
234
+ # Big thanks to Florian Franks for his ruby-json lib, and Jamis Buck for
235
+ # Needle
236
+ #
237
+ # This program is free software; you can redistribute it and/or
238
+ # modify it under the terms of the GNU General Public License,
239
+ # version 2, as published by the Free Software Foundation.
240
+ #
241
+ # This program is distributed in the hope that it will be
242
+ # useful, but WITHOUT ANY WARRANTY; without even the implied
243
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
244
+ # PURPOSE. See the GNU General Public License for more details.
245
+ #
246
+ # You should have received a copy of the GNU General Public
247
+ # License along with this program; if not, write to the Free
248
+ # Software Foundation, Inc., 59 Temple Place, Suite 330,
249
+ # Boston, MA 02111-1307 USA.
250
+
@@ -0,0 +1,60 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+
4
+ require 'cgi'
5
+ require 'rubygems'
6
+ require "orbjson"
7
+ require 'logger'
8
+
9
+ include Orbjson
10
+
11
+
12
+ $logger = Logger.new( "orbjson_cgi.log" )
13
+
14
+ # Change this to ERROR or something when your code does
15
+ # all it should, and does it right:
16
+ $logger.level = Logger::DEBUG
17
+
18
+
19
+ $logger.debug( "Have a request!" )
20
+
21
+ # You can configure the Orbjsn services list in a few ways.
22
+ # Well, three, really:
23
+ # 1. Pass in a path to a local YAML file; the path must begin with
24
+ # 'file://'
25
+ # For example: cfg = 'file://config.yaml'
26
+ # json_rpc = CGI_JSON_RPC.new( cfg )
27
+ #
28
+ # 2. Pass in some YAML:
29
+ # cfg = 'services/sample:
30
+ # - Details'
31
+ # json_rpc = CGI_JSON_RPC.new( cfg )
32
+ #
33
+ # 3. Pass in some an atual Hash objectL:
34
+ # cfg = { 'services/sample' => ['Details'] }
35
+ # json_rpc = CGI_JSON_RPC.new( cfg )
36
+ #
37
+ # The hash (however you express it) consists of 'require' paths mapped
38
+ # to arrays of classes to instantiate.
39
+
40
+
41
+ # Change this to suit your actual situation:
42
+ cfg = 'services/sample:
43
+ - Details'
44
+ json_rpc = CGI_JSON_RPC.new( cfg )
45
+
46
+ print "content-type: text/javascript\n\n"
47
+ res = json_rpc.process_request
48
+ $logger.debug( "Have a response:\n#{res}" )
49
+ # Logging may make an already slow CGI app go
50
+ # even slower, so consider dropping this suf when things are good.
51
+
52
+ print res
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
@@ -0,0 +1,187 @@
1
+ /*
2
+ * JSON-RPC JavaScript client
3
+ *
4
+ * $Id: jsonrpc.js,v 1.1.1.1 2005/02/28 03:06:28 jamesgbritt Exp $
5
+ *
6
+ * Copyright (c) 2003-2004 Jan-Klaas Kollhof
7
+ * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd
8
+ *
9
+ * This code is based on Jan-Klaas' JavaScript o lait library (jsolait).
10
+ *
11
+ * This library is free software; you can redistribute it and/or
12
+ * modify it under the terms of the GNU Lesser General Public (LGPL)
13
+ * License as published by the Free Software Foundation; either
14
+ * version 2.1 of the License, or (at your option) any later version.
15
+ *
16
+ * This library is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
+ * Lesser General Public License for more details: http://www.gnu.org/
20
+ *
21
+ */
22
+
23
+ // TODO: Add async
24
+ // TODO: Add HTTP auth (user, password)
25
+
26
+ Object.prototype.toJSON = function Object_toJSON() {
27
+ var v = [];
28
+ for(attr in this) {
29
+ if(this[attr] == null) v.push("\"" + attr + "\": null");
30
+ else if(typeof this[attr] == "function"); // skip
31
+ else v.push("\"" + attr + "\": " + this[attr].toJSON());
32
+ }
33
+ return "{" + v.join(", ") + "}";
34
+ }
35
+
36
+ String.prototype.toJSON = function String_toJSON() {
37
+ return "\"" + this.replace(/([\"\\])/g, "\\$1") + "\"";
38
+ }
39
+
40
+ Number.prototype.toJSON = function Number_toJSON() {
41
+ return this.toString();
42
+ }
43
+
44
+ Boolean.prototype.toJSON = function Boolean_toJSON() {
45
+ return this.toString();
46
+ }
47
+
48
+ Date.prototype.toJSON = function Date_toJSON() {
49
+ this.valueOf().toString();
50
+ }
51
+
52
+ Array.prototype.toJSON = function Array_toJSON() {
53
+ var v = [];
54
+ for(var i=0; i<this.length; i++) {
55
+ if(this[i] == null) v.push("null");
56
+ else v.push(this[i].toJSON());
57
+ }
58
+ return "[" + v.join(", ") + "]";
59
+ }
60
+
61
+ JSONRpcClient = function JSONRpcClient_ctor(serverURL, objectID) {
62
+ this.serverURL = serverURL;
63
+ this.objectID = objectID;
64
+
65
+ // Lazy initialization of the XMLHttpRequest singleton
66
+ if(!JSONRpcClient.http)
67
+ JSONRpcClient.http = JSONRpcClient.getHTTPRequest();
68
+
69
+ // Add standard methods
70
+ this.addMethods(["system.listMethods"]);
71
+
72
+ // Query the methods on the server and add them to this object
73
+ var m = this.sendRequest("system.listMethods", []);
74
+ this.addMethods(m);
75
+ }
76
+
77
+ JSONRpcClient.Exception = function JSONRpcClient_Exception_ctor(code, msg) {
78
+ this.code = code;
79
+ this.msg = msg;
80
+ }
81
+
82
+ JSONRpcClient.Exception.prototype.toString =
83
+ function JSONRpcClient_Exception_toString(code, msg) {
84
+ return "JSONRpcClientException: " + this.msg;
85
+ }
86
+
87
+ JSONRpcClient.Method =
88
+ function JSONRpcClient_Method_ctor(client, methodName) {
89
+ var fn=function() {
90
+ var args = [];
91
+ for(var i=0;i<arguments.length;i++) {
92
+ args.push(arguments[i]);
93
+ }
94
+ return fn.client.sendRequest.call(fn.client, fn.methodName, args);
95
+ }
96
+ fn.client = client;
97
+ fn.methodName = methodName;
98
+ return fn;
99
+ }
100
+
101
+ JSONRpcClient.prototype.addMethods =
102
+ function JSONRpcClient_addMethods(methodNames) {
103
+ for(var i=0; i<methodNames.length; i++) {
104
+ var obj = this;
105
+ var names = methodNames[i].split(".");
106
+ for(var n=0; n<names.length-1; n++){
107
+ var name = names[n];
108
+ if(obj[name]){
109
+ obj = obj[name];
110
+ }
111
+ else {
112
+ obj[name] = new Object();
113
+ obj = obj[name];
114
+ }
115
+ }
116
+ var name = names[names.length-1];
117
+ if(!obj[name]){
118
+ var method = new JSONRpcClient.Method(this, methodNames[i]);
119
+ obj[name] = method;
120
+ }
121
+ }
122
+ }
123
+
124
+ JSONRpcClient.prototype.sendRequest =
125
+ function JSONRpcClient_sendRequest(methodName, args) {
126
+ // Make request object
127
+ var obj = {"method" : methodName, "params" : args};
128
+ if (this.objectID) obj.objectID = this.objectID;
129
+
130
+ // Marshall the request object to a JSON string
131
+ var req_data = obj.toJSON();
132
+
133
+ // Send the request
134
+ JSONRpcClient.http.open("POST", this.serverURL, false); // no async
135
+ // setRequestHeader is missing in Opera 8 Beta
136
+ try {
137
+ JSONRpcClient.http.setRequestHeader("Content-type", "text/plain");
138
+ }
139
+ catch(e) {}
140
+ JSONRpcClient.http.send(req_data);
141
+
142
+ // Unmarshall the response
143
+ // DEBUG
144
+ try {
145
+ eval("var obj = " + JSONRpcClient.http.responseText);
146
+ }
147
+ catch(e) {
148
+ alert( e )
149
+ alert( JSONRpcClient.http.responseText )
150
+ obj.err = e.toString()
151
+ }
152
+ if( obj.error) {
153
+ alert( JSONRpcClient.http.responseText )
154
+ throw new JSONRpcClient.Exception(obj.error.code, obj.error.msg);
155
+ }
156
+ var res = obj.result;
157
+
158
+ // Handle CallableProxy
159
+ if(res && res.objectID && res.JSONRPCType == "CallableReference")
160
+ return new JSONRpcClient(this.serverURL, res.objectID);
161
+
162
+ return res;
163
+ }
164
+
165
+ JSONRpcClient.getHTTPRequest = function JSONRpcClient_getHTTPRequest() {
166
+ try { // to get the mozilla httprequest object
167
+ return new XMLHttpRequest();
168
+ }
169
+ catch(e) {}
170
+
171
+ try { // to get MS HTTP request object
172
+ return new ActiveXObject("Msxml2.XMLHTTP.4.0");
173
+ }
174
+ catch(e) {}
175
+
176
+ try { // to get MS HTTP request object
177
+ return new ActiveXObject("Msxml2.XMLHTTP");
178
+ }
179
+ catch(e) {}
180
+
181
+ try {// to get the old MS HTTP request object
182
+ return new ActiveXObject("microsoft.XMLHTTP");
183
+ }
184
+ catch(e) {}
185
+
186
+ throw new JSONRpcClient.Exception(0, "Can't create XMLHttpRequest object");
187
+ }
@@ -0,0 +1,2 @@
1
+ services/sample:
2
+ - Details
@@ -0,0 +1,57 @@
1
+ #!/usr/local/bin/ruby
2
+ require 'webrick'
3
+
4
+ require "orbjson"
5
+ include WEBrick
6
+
7
+
8
+ Socket.do_not_reverse_lookup = true
9
+
10
+ $logger = Logger.new( "orbjson.log" )
11
+ $logger.level = Logger::DEBUG
12
+
13
+ s = HTTPServer.new( :Port => 2222,
14
+ :DocumentRoot => File.dirname( __FILE__ ) )
15
+
16
+ s.mount("/json-rpc", Orbjson::WEBrick_JSON_RPC )
17
+
18
+
19
+ # These mounts are a ahandy way to to kill a WEBrick instance via URL,
20
+ # useful mostly during debugging. Probably less useful when you've deployed
21
+ # the applicaton. Consider removing these before going live.
22
+ s.mount_proc( "/exit" ){|req, res| s.shutdown; exit; }
23
+ s.mount_proc( "/quit" ){|req, res| s.shutdown; exit; }
24
+
25
+
26
+ # You can configure the Orbjsn services list in a few ways.
27
+ # Well, three, really:
28
+ # 1. Pass in a path to a local YAML file; the path must begin with
29
+ # 'file://'
30
+ # For example: cfg = 'file://config.yaml'
31
+ # Orbjson::System.init( cfg )
32
+ #
33
+ # 2. Pass in some YAML:
34
+ # cfg = 'services/sample:
35
+ # - Details'
36
+ # Orbjson::System.init( cfg )
37
+ #
38
+ # 3. Pass in some an atual Hash objectL:
39
+ # cfg = { 'services/sample' => ['Details'] }
40
+ # Orbjson::System.init( cfg )
41
+ #
42
+ # The hash (however you express it) consists of 'require' paths mapped
43
+ # to arrays of classes to instantiate.
44
+
45
+
46
+ # Change this to suit your actual situation: If you use a configuration file,
47
+ # # mkae sure you have the correct name, path, and contents.
48
+ # This example expects to find the file config.yml in the same dir
49
+ # as server.rb
50
+ cfg = "file://config.yml"
51
+ Orbjson::System.init( cfg )
52
+
53
+
54
+ trap( "INT" ){ s.shutdown }
55
+ trap( 1 ){ s.shutdown }
56
+ s.start
57
+
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.6
3
+ specification_version: 1
4
+ name: Orbjson
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2005-02-27
8
+ summary: Lib for creating JSON-RPC server applications.
9
+ require_paths:
10
+ - lib
11
+ email: jamesgb@neurogami.com
12
+ homepage: http://orbjson.rubyforge.org
13
+ rubyforge_project: orbjson
14
+ description:
15
+ autorequire: orbjson
16
+ default_executable: orbjson
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 1.8.2
25
+ version:
26
+ platform: ruby
27
+ authors:
28
+ - James Britt
29
+ files:
30
+ - README
31
+ - docs/todo.txt
32
+ - bin/orbjson
33
+ - lib/orbjson.rb
34
+ - lib/skeleton
35
+ - lib/skeleton/cgi
36
+ - lib/skeleton/script
37
+ - lib/skeleton/webrick
38
+ - lib/skeleton/cgi/json-rpc.rb
39
+ - lib/skeleton/script/jsonrpc.js
40
+ - lib/skeleton/webrick/config.yml
41
+ - lib/skeleton/webrick/server.rb
42
+ - examples/cgi
43
+ - examples/webrick
44
+ - examples/cgi/Orbjson.log
45
+ - examples/cgi/httpd.conf
46
+ - examples/cgi/index.html
47
+ - examples/cgi/json-rpc.rb
48
+ - examples/cgi/orbjson_cgi.log
49
+ - examples/cgi/yellow_crossfade_01.gif
50
+ - examples/cgi/script
51
+ - examples/cgi/services
52
+ - examples/cgi/script/jsonrpc.js
53
+ - examples/cgi/services/sample.rb
54
+ - examples/webrick/config.yml
55
+ - examples/webrick/index.html
56
+ - examples/webrick/server.rb
57
+ - examples/webrick/yellow_crossfade_01.gif
58
+ - examples/webrick/script
59
+ - examples/webrick/services
60
+ - examples/webrick/script/jsonrpc.js
61
+ - examples/webrick/services/sample.rb
62
+ - dep/handy
63
+ - dep/required
64
+ - dep/handy/script
65
+ - dep/handy/script/jsonrpc.js
66
+ - dep/required/ruby-json
67
+ - dep/required/ruby-json/ruby-json-1.1.1.gem
68
+ test_files: []
69
+ rdoc_options: []
70
+ extra_rdoc_files: []
71
+ executables:
72
+ - orbjson
73
+ extensions: []
74
+ requirements: []
75
+ dependencies:
76
+ - !ruby/object:Gem::Dependency
77
+ name: needle
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Version::Requirement
80
+ requirements:
81
+ -
82
+ - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 1.2.0
85
+ version:
86
+ - !ruby/object:Gem::Dependency
87
+ name: ruby-json
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Version::Requirement
90
+ requirements:
91
+ -
92
+ - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "1.1"
95
+ version: