seamless 1.0.0

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.
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
+ }