seamless 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/bin/seamless +36 -0
  2. data/lib/seamless.rb +70 -0
  3. data/lib/seamless/active_record_extension.rb +11 -0
  4. data/lib/seamless/dispatcher.rb +45 -0
  5. data/lib/seamless/message_broker.rb +12 -0
  6. data/lib/seamless/message_broker_controller.rb +11 -0
  7. data/lib/seamless/messagebroker/inmemory_message_broker.rb +45 -0
  8. data/lib/seamless/migration.rb +8 -0
  9. data/lib/seamless/model.rb +94 -0
  10. data/lib/seamless/service.rb +186 -0
  11. data/seamless/seamless_generator.rb +181 -0
  12. data/seamless/templates/README +24 -0
  13. data/seamless/templates/admin.html +166 -0
  14. data/seamless/templates/application.rb +7 -0
  15. data/seamless/templates/css/global.css +333 -0
  16. data/seamless/templates/css/seamless-admin.css +281 -0
  17. data/seamless/templates/css/seamless.css +632 -0
  18. data/seamless/templates/environment.rb +65 -0
  19. data/seamless/templates/generate +25 -0
  20. data/seamless/templates/images/arch.png +0 -0
  21. data/seamless/templates/images/arrow_undo.png +0 -0
  22. data/seamless/templates/images/cell_phone.png +0 -0
  23. data/seamless/templates/images/confirm.png +0 -0
  24. data/seamless/templates/images/deny.png +0 -0
  25. data/seamless/templates/images/dialog_close.gif +0 -0
  26. data/seamless/templates/images/dialog_close_hover.gif +0 -0
  27. data/seamless/templates/images/email.png +0 -0
  28. data/seamless/templates/images/exclamation.png +0 -0
  29. data/seamless/templates/images/indicator.gif +0 -0
  30. data/seamless/templates/images/indicator2.gif +0 -0
  31. data/seamless/templates/images/seamless.gif +0 -0
  32. data/seamless/templates/images/shadow.gif +0 -0
  33. data/seamless/templates/images/shadowAlpha.png +0 -0
  34. data/seamless/templates/images/small_star.png +0 -0
  35. data/seamless/templates/images/table_add.png +0 -0
  36. data/seamless/templates/images/table_delete.png +0 -0
  37. data/seamless/templates/images/table_edit.png +0 -0
  38. data/seamless/templates/images/table_go.png +0 -0
  39. data/seamless/templates/images/table_refresh.png +0 -0
  40. data/seamless/templates/images/tag.png +0 -0
  41. data/seamless/templates/images/warning.png +0 -0
  42. data/seamless/templates/images/wizard.gif +0 -0
  43. data/seamless/templates/images/work_phone.png +0 -0
  44. data/seamless/templates/index.html +171 -0
  45. data/seamless/templates/js/seamless-admin.js +255 -0
  46. data/seamless/templates/js/seamless.js +2755 -0
  47. data/seamless/templates/message_broker.rb +6 -0
  48. data/seamless/templates/message_broker_helper.rb +2 -0
  49. data/seamless/templates/robots.txt +2 -0
  50. data/seamless/templates/routes.rb +18 -0
  51. data/seamless/templates/seamless.xml +5 -0
  52. data/seamless/templates/server +4 -0
  53. data/seamless/templates/test_service.rb +13 -0
  54. data/service/USAGE +21 -0
  55. data/service/service_generator.rb +59 -0
  56. data/service/templates/service.rb +14 -0
  57. metadata +122 -0
@@ -0,0 +1,65 @@
1
+ # Be sure to restart your web server when you modify this file.
2
+
3
+ # Uncomment below to force Rails into production mode when
4
+ # you don't control web/app server and can't set it the proper way
5
+ # ENV['RAILS_ENV'] ||= 'production'
6
+
7
+ # Specifies gem version of Rails to use when vendor/rails is not present
8
+ <%= '# ' if freeze %>RAILS_GEM_VERSION = '<%= Rails::VERSION::STRING %>' unless defined? RAILS_GEM_VERSION
9
+
10
+ # Bootstrap the Rails environment, frameworks, and default configuration
11
+ require File.join(File.dirname(__FILE__), 'boot')
12
+
13
+ Rails::Initializer.run do |config|
14
+ # Settings in config/environments/* take precedence over those specified here
15
+
16
+ # Skip frameworks you're not going to use (only works if using vendor/rails)
17
+ # config.frameworks -= [ :action_web_service, :action_mailer ]
18
+
19
+ # Only load the plugins named here, by default all plugins in vendor/plugins are loaded
20
+ # config.plugins = %W( exception_notification ssl_requirement )
21
+
22
+ # NOTE: this is required to load seam(less) services so make sure
23
+ # you don't remove services dir
24
+ #
25
+ # Add additional load paths for your own custom dirs
26
+ config.load_paths += %W( #{RAILS_ROOT}/app/services )
27
+
28
+ # Force all environments to use the same logger level
29
+ # (by default production uses :info, the others :debug)
30
+ # config.log_level = :debug
31
+
32
+ # Use the database for sessions instead of the file system
33
+ # (create the session table with 'rake db:sessions:create')
34
+ # config.action_controller.session_store = :active_record_store
35
+
36
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
37
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
38
+ # like if you have constraints or database-specific column types
39
+ # config.active_record.schema_format = :sql
40
+
41
+ # Activate observers that should always be running
42
+ # config.active_record.observers = :cacher, :garbage_collector
43
+
44
+ # Make Active Record use UTC-base instead of local time
45
+ # config.active_record.default_timezone = :utc
46
+
47
+ # See Rails::Configuration for more options
48
+ end
49
+
50
+ # Add new inflection rules using the following format
51
+ # (all these examples are active by default):
52
+ # Inflector.inflections do |inflect|
53
+ # inflect.plural /^(ox)$/i, '\1en'
54
+ # inflect.singular /^(ox)en/i, '\1'
55
+ # inflect.irregular 'person', 'people'
56
+ # inflect.uncountable %w( fish sheep )
57
+ # end
58
+
59
+ # Add new mime types for use in respond_to blocks:
60
+ # Mime::Type.register "text/richtext", :rtf
61
+ # Mime::Type.register "application/x-mobile", :mobile
62
+
63
+ require 'seamless'
64
+
65
+ # Include your application configuration below
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../config/boot'
3
+
4
+ if ARGV[0] =~ /((svc)|Service)/i
5
+ require 'rubygems'
6
+ gem 'rails'
7
+
8
+ # find the path to RAILS
9
+ rails_gem = Gem.cache.search('rails').last
10
+ RAILS = rails_gem.full_gem_path
11
+
12
+ # find the path to SEAMLESS
13
+ seamless_gem = Gem.cache.search('seamless').last
14
+ SEAMLESS = seamless_gem.full_gem_path
15
+
16
+ require RAILS + '/lib/rails_generator'
17
+ require 'rails_generator/scripts/generate'
18
+
19
+ path = SEAMLESS
20
+ Rails::Generator::Base.sources << Rails::Generator::PathSource.new('', path)
21
+
22
+ Rails::Generator::Scripts::Generate.new.run(ARGV, {:generator => 'service', :source_root => path, :source => path})
23
+ else
24
+ require 'commands/generate'
25
+ end
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,171 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:seamless="http://www.hakano.org/seamless">
3
+ <head>
4
+ <title>MySeam(less) Starter Application</title>
5
+ <meta http-equiv="Content-Type" content="UTF-8" />
6
+
7
+ <link rel="stylesheet" href="css/global.css" type="text/css" media="all" />
8
+ <link rel="stylesheet" href="css/seamless.css" type="text/css" media="all" />
9
+
10
+ <script src="js/seamless.js" type="text/javascript" />
11
+
12
+ <style>
13
+ body
14
+ {
15
+ color:#444;
16
+ }
17
+ #logo
18
+ {
19
+ float:right;
20
+ margin-left:10px;
21
+ margin-right:10px;
22
+ }
23
+ #form
24
+ {
25
+ margin:30px;
26
+ }
27
+ h2
28
+ {
29
+ font-weight:bold;
30
+ font-size:32px;
31
+ margin-bottom:15px;
32
+ }
33
+ textarea
34
+ {
35
+ width:100%;
36
+ height:100px;
37
+ margin-top:10px;
38
+ margin-bottom:10px;
39
+ border:1px solid #aaa;
40
+ font-size: 18px;
41
+ padding:3px;
42
+ }
43
+ textarea:focus
44
+ {
45
+ background-color:#ffffcc;
46
+ }
47
+ input#messagetype
48
+ {
49
+ margin-left:6px;
50
+ width:698px;
51
+ border:1px solid #aaa;
52
+ font-size: 18px;
53
+ padding:3px;
54
+ }
55
+ input#messagetype:focus
56
+ {
57
+ background-color:#ffffcc;
58
+ }
59
+ #messagebox
60
+ {
61
+ position:absolute;
62
+ top:380px;
63
+ left:350px;
64
+ width:350px;
65
+ padding:10px;
66
+ color:#3c78b5;
67
+ font-weight:bold;
68
+ }
69
+ form
70
+ {
71
+ margin-bottom:50px;
72
+ }
73
+ #trace
74
+ {
75
+ margin-top:5px;
76
+ width:100%;
77
+ font-family: courier;
78
+ font-size: 14px;
79
+ }
80
+ #banner
81
+ {
82
+ background-color:#850001;
83
+ border-bottom:1px solid #000;
84
+ height:60px;
85
+ }
86
+ #header
87
+ {
88
+ background-color:#444;
89
+ height:10px;
90
+ }
91
+ #intro
92
+ {
93
+ margin-top:20px;
94
+ margin-bottom:20px;
95
+ font-family: Georgia, sans-serif;
96
+ font-size: 18px;
97
+ }
98
+ #footer
99
+ {
100
+ margin-top:50px;
101
+ font-family: Georgia, sans-serif;
102
+ font-size: 15px;
103
+ }
104
+ </style>
105
+
106
+ <body>
107
+ <div id="header"></div>
108
+
109
+ <div id="banner">
110
+ <img id="logo" src="images/seamless.gif" alt="seamless"/>
111
+ </div>
112
+
113
+ <div id="form">
114
+ <h2 class="primary_light_color">Welcome to the Seam(less) Application Starter Project</h2>
115
+
116
+ <div id="intro">
117
+ This is a simple "starter" project called <strong>myseamless</strong>. The goal of this project is to
118
+ give you a simple application structure to start your Seam(less) application development. It contains
119
+ everything you need to make your application - <span class="highlight">seamless</span>.
120
+ </div>
121
+
122
+ <form>
123
+ <div>Type in a message to test server messaging connectivity: <input id="messagetype" fieldset="myform" type="text" validator="required" value="remote:seamless.test.message.request"/></div>
124
+ <div><textarea name="message" id="messageargs"></textarea></div>
125
+ <div>
126
+ <input type="button" fieldset="myform" onClickMessage="local:send.test.message" activators="messagetype" value="Send Message"/>
127
+ </div>
128
+ </form>
129
+
130
+ <div style="display:none;" class="infoBox" id="messagebox" onBindMessageEffect="remote:seamless.test.message" onBindMessageEffectType="Appear"
131
+ onBindMessageEffect1="remote:seamless.test.message" onBindMessageEffect1Type="Fade" onBindMessageEffect1Delay="3000">
132
+ <img src="images/confirm.png" alt="*"/><span>&nbsp;&nbsp;</span><span onBindMessage="remote:seamless.test.message" onBindMessageProperty="message"></span>
133
+ </div>
134
+
135
+ <div>
136
+ <strong>Message Trace Log</strong>
137
+ <textarea id="trace" readonly="true" onBindMessage="~.*" onBindMessageAppend="true" onBindMessageExpr="return '[' + hakano.util.DateTime.get12HourTime() + '] ' + this.direction+':' + this.type + ' => ' + this.data.toJSONString()+'\n'"></textarea>
138
+ </div>
139
+
140
+ <div id="footer">
141
+ For more information, documentation and demos, please visit <a href="http://www.hakano.org">http://www.hakano.org</a>. <br/>
142
+ To discuss Seam(less), please <a href="http://groups.google.com/group/seamless-web?hl=en">visit our discussion group</a> or email <a href="mailto:seamless@hakano.org">seamless@hakano.org</a>.<br/>
143
+ Seam(less) is a product of <a href="http://www.hakano.com">Hakano</a> and Copyright &copy; 2006-2007 by Hakano, Inc. All Rights Reserved.
144
+ </div>
145
+
146
+ <seamless:script onBindMessage="local:send.test.message">
147
+ try
148
+ {
149
+ var type = $("messagetype").value;
150
+ var args = $('messageargs');
151
+ var value = args.value;
152
+ var message = {};
153
+ if (value.charAt(0)=='{')
154
+ {
155
+ message = eval('('+value+')');
156
+ }
157
+ else
158
+ {
159
+ message = {message:value};
160
+ }
161
+ hakano.util.MessageBroker.queue({type: type, data: message});
162
+ }
163
+ catch (e)
164
+ {
165
+ alert (e.stack);
166
+ }
167
+ </seamless:script>
168
+
169
+ </div>
170
+ </body>
171
+ </html>
@@ -0,0 +1,255 @@
1
+ var selectedRow = null;
2
+ var columns = null;
3
+ var primaryKeyColumn = 'id';
4
+ var rowData = null;
5
+
6
+ function deleteRow(data)
7
+ {
8
+ var table = $('table');
9
+ var tableName = table[table.selectedIndex].value;
10
+ hakano.util.MessageBroker.queue({type:'remote:seamless.'+tableName+'.delete.request',data:{id:getPrimaryKey(data)}});
11
+ selectedRow = null;
12
+ hakano.util.MessageBroker.queue({type:'local:search.table.nonselected',data:{}});
13
+ }
14
+
15
+ function updateFromDelete(data)
16
+ {
17
+ var id = data['id'];
18
+ $$('#search_results_table td.primarykey').each(function(td)
19
+ {
20
+ var value = td.innerHTML;
21
+ if (value == id)
22
+ {
23
+ var parent = td.parentNode;
24
+ Effect.Fade(parent,
25
+ {
26
+ afterFinish: function()
27
+ {
28
+ var p = parent.parentNode;
29
+ p.removeChild(parent);
30
+ $('search_count').innerHTML = parseInt($('search_count').innerHTML) - 1;
31
+ $('search_total').innerHTML = parseInt($('search_total').innerHTML) - 1;
32
+ }
33
+ });
34
+ throw $break;
35
+ }
36
+ });
37
+ }
38
+
39
+ function getPrimaryKey()
40
+ {
41
+ var idx = selectedRow.getAttribute('idx');
42
+ var datarow = rowData[parseInt(idx)];
43
+ return datarow[primaryKeyColumn||'id'] || '';
44
+ }
45
+
46
+ function loadModels (data)
47
+ {
48
+ var models = data['models'];
49
+ if (models.length > 0)
50
+ {
51
+ $('table_name').innerHTML = models[0].name;
52
+ loadTableAssembly(models[0].model);
53
+ }
54
+ }
55
+
56
+ function loadTableAssembly (tableName)
57
+ {
58
+ var request = 'remote:seamless.'+tableName+'.assembly.request';
59
+ hakano.util.MessageBroker.queue({type:request,data:{}});
60
+ }
61
+
62
+ function loadColumns (data)
63
+ {
64
+ columns = data['columns'];
65
+ refreshData();
66
+ }
67
+
68
+ function refreshData()
69
+ {
70
+ var table = $('table');
71
+ var tableName = table[table.selectedIndex].value;
72
+ hakano.util.MessageBroker.queue({type:'remote:seamless.'+tableName+'.list.request',data:{limit:10}});
73
+ }
74
+
75
+ function displayRecord(edit)
76
+ {
77
+ var html = '';
78
+ var table = $('table');
79
+ var tableName = table[table.selectedIndex].value;
80
+
81
+ if (edit)
82
+ {
83
+ var req = 'remote:seamless.' + tableName + '.update.request';
84
+ var resp = 'remote:seamless.' + tableName + '.update.response';
85
+ html+='<form onBindMessageDisable="'+req+'" onBindMessageEnable="'+resp+'">';
86
+ html+='<div style="display:none" class="editSuccess" onBindMessageEffect="'+resp+'" onBindMessageEffectCond="this.data.success" onBindMessageEffectType="Fade" onBindMessageEffectDelay="5000" onBindMessageShow="'+resp+'" onBindMessageShowCond="this.data.success"><img src="images/confirm.png"/> Record saved</div>';
87
+ html+='<div style="display:none" class="editFailed" onBindMessageHide="'+req+'" onBindMessageShow="'+resp+'" onBindMessageShowCond="!this.data.success"><img src="images/deny.png"/> <span onBindMessage="'+resp+'" onBindMessageCond="!this.data.success" onBindMessageProperty="message"/> </div>';
88
+ }
89
+
90
+ html += "<table class='record'>";
91
+ var idx = selectedRow.getAttribute('idx');
92
+ var datarow = rowData[parseInt(idx)];
93
+
94
+ var activators = (edit ? [] : null);
95
+
96
+ for (var c=0,len=columns.length;c<len;c++)
97
+ {
98
+ var name = columns[c].name;
99
+ if (edit)
100
+ {
101
+ switch (name)
102
+ {
103
+ case 'created_at':
104
+ case 'updated_at':
105
+ continue;
106
+ }
107
+ }
108
+ html+='<tr>';
109
+ if (!columns[c].primary)
110
+ {
111
+ html+='<td class="label '+(edit?'edit':'display')+'">'+name+'</td>';
112
+ }
113
+ else
114
+ {
115
+ html+='<td colspan="2"><input type="hidden" name="' + name + '" value="'+datarow[name]+'" fieldset="edit"/></td>';
116
+ continue;
117
+ }
118
+
119
+ var value = datarow[name];
120
+ if (!value || value == 'null') value = '';
121
+
122
+ if (edit)
123
+ {
124
+ html+='<td class="value edit">';
125
+
126
+ var type = 'text';
127
+ if (columns[c].type == 'boolean')
128
+ {
129
+ type = 'checkbox';
130
+ }
131
+
132
+ html+='<input fieldset="edit" type="' + type + '" name="' + name + '" id="' + name + '" value="'+value+'" ';
133
+ if (type=='checkbox' && (value=='true' || value==true))
134
+ {
135
+ html+='checked="true" ';
136
+ }
137
+ if (!columns[c].nullable)
138
+ {
139
+ activators.push(name);
140
+
141
+ html+="validator='";
142
+ html+=(name == 'password') ? "password" : "required";
143
+ html+="' decorator='";
144
+ html+=(name == 'password') ? "password" : "required";
145
+ html+="' ";
146
+ }
147
+ if (columns[c].limit)
148
+ {
149
+ html+="limit='" + (columns[c].limit || 100) + "' ";
150
+ }
151
+ html+=' /></td>';
152
+ }
153
+ else
154
+ {
155
+ html+='<td class="value display">'+value+'</td>';
156
+ }
157
+ html+='</tr>\n';
158
+ }
159
+ html+='</table>';
160
+
161
+ if (edit)
162
+ {
163
+ html+="<div id='save_button'><input fieldset='edit' type='button' value='Save' ";
164
+ if (activators.length > 0)
165
+ {
166
+ html+="activators='" + activators.join(',') + "' ";
167
+ }
168
+ html+=' onClickMessage="remote:seamless.' + tableName+'.update.request" ';
169
+ html+="/></div>";
170
+
171
+ html+="</form>";
172
+ }
173
+
174
+ $('search_results_table_container').innerHTML = html;
175
+ Seamless.wire($('search_results_table_container'),window,false,true);
176
+ }
177
+
178
+ function restoreTable ()
179
+ {
180
+ if (rowData)
181
+ {
182
+ loadTable({rows:rowData});
183
+ }
184
+ }
185
+ function loadTable (data)
186
+ {
187
+ try
188
+ {
189
+ var rows = data['rows'];
190
+ if (!rows) return;
191
+ var html = "<table id='search_results_table'>";
192
+ rowData = rows;
193
+ html+='<thead><tr>';
194
+ for (var c=0,len=columns.length;c<len;c++)
195
+ {
196
+ if (c < 6)
197
+ {
198
+ html+='<th>' + columns[c].name+ '</th>';
199
+ }
200
+ else
201
+ {
202
+ break;
203
+ }
204
+ }
205
+ html+='</tr></thead><tbody>';
206
+ for (var c=0,len=rows.length;c<len;c++)
207
+ {
208
+ html+='<tr idx="'+c+'">';
209
+ columns.each(function(col,idx)
210
+ {
211
+ var className = columns[idx].primary ? 'primarykey' : '';
212
+ html+='<td class="' + className + ' ' + ((c%2==0) ? 'even':'odd') + '">' + ( rows[c][col.name] || '') + '</td>';
213
+ if (idx >= 5) throw $break;
214
+ });
215
+ html+='</tr>';
216
+ }
217
+ html+='</tbody></table>';
218
+ $('search_results_table_container').innerHTML = html;
219
+
220
+ selectedRow = null;
221
+
222
+ $$('#search_results_table tr').each(function(cell)
223
+ {
224
+ cell.onclick = function(e)
225
+ {
226
+ var idx = cell.getAttribute('idx');
227
+ var datarow = rows[parseInt(idx)];
228
+ if (selectedRow)
229
+ {
230
+ $A(selectedRow.childNodes).each(function(n)
231
+ {
232
+ Element.removeClassName(n,'selected');
233
+ });
234
+ hakano.util.MessageBroker.queue({type:'local:search.table.unselected',data:{datarow:datarow}});
235
+ }
236
+ if (selectedRow == cell)
237
+ {
238
+ hakano.util.MessageBroker.queue({type:'local:search.table.nonselected',data:{}});
239
+ selectedRow = null;
240
+ return;
241
+ }
242
+ selectedRow = cell;
243
+ $A(selectedRow.childNodes).each(function(n)
244
+ {
245
+ Element.addClassName(n,'selected');
246
+ });
247
+ hakano.util.MessageBroker.queue({type:'local:search.table.selected',data:{datarow:datarow}});
248
+ };
249
+ });
250
+ }
251
+ catch(e)
252
+ {
253
+ alert(e);
254
+ }
255
+ }