caterpillar 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,4 @@
1
1
  # encoding: utf-8
2
-
3
-
4
2
  #--
5
3
  # (c) Copyright 2008 Mikael Lammentausta
6
4
  # See the file LICENSES.txt included with the distribution for
@@ -10,8 +8,8 @@
10
8
  module Caterpillar
11
9
  # Portlet configuration. The config file 'config/portlets.rb' should be installed in your Rails application. See the comments in the configuration file for more specific information about each option.
12
10
  class Config
13
- FILE = File.join('config','portlets.rb')
14
- JRUBY_HOME = nil # override in the config file if necessary
11
+ FILE = File.join('config','portlets.rb') unless defined? Caterpillar::Config::FILE
12
+ JRUBY_HOME = nil unless defined? Caterpillar::Config::JRUBY_HOME # override in the config file if necessary
15
13
 
16
14
  # Are all named routes used, or only the ones specifically defined in the config FILE?
17
15
  attr_accessor :include_all_named_routes
@@ -19,16 +17,20 @@ module Caterpillar
19
17
  attr_accessor :category
20
18
 
21
19
  attr_accessor :edit_mode
22
-
23
- attr_accessor :instanceable
24
20
 
21
+ attr_accessor :preferences_route
22
+
23
+ attr_accessor :instanceable
24
+
25
+ attr_accessor :public_render_parameters
26
+
25
27
  attr_accessor :host
26
28
 
27
29
  attr_accessor :servlet
28
30
 
29
31
  attr_accessor :instances
30
32
 
31
- attr_reader :rails_root
33
+ attr_accessor :rails_root
32
34
 
33
35
  attr_accessor :_container
34
36
 
@@ -41,30 +43,34 @@ module Caterpillar
41
43
  attr_accessor :logger
42
44
 
43
45
  # Sets sane defaults that are overridden in the config file.
44
- def initialize
46
+ def initialize(detect_configuration_file = true)
45
47
  # RAILS_ROOT is at least defined in Caterpillar initialization
46
- @rails_root = File.expand_path(RAILS_ROOT)
48
+ if defined? RAILS_ROOT
49
+ @rails_root = File.expand_path(RAILS_ROOT)
50
+ end
51
+
47
52
  @servlet = nil
48
53
  @category = nil
49
54
  @instances = []
50
55
  @javascripts = []
51
- @include_all_named_routes = true
52
-
53
- rails_conf = File.join(@rails_root,'config','environment.rb')
54
- unless File.exists?(rails_conf)
55
- STDERR.puts 'Rails configuration file could not be found'
56
- @rails_root = nil
57
- else
58
- @servlet = File.basename(@rails_root)
59
- @category = @servlet
60
-
61
- @warbler_conf = File.join(@rails_root,'config','warble.rb')
62
- unless File.exists?(@warbler_conf)
63
- #STDERR.puts 'Warbler configuration file could not be found'
64
- end
65
- end
66
56
 
67
- #@logger = (defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : Logger.new)
57
+ @include_all_named_routes = false
58
+
59
+ if @rails_root
60
+ rails_conf = File.join(@rails_root,'config','environment.rb')
61
+ unless File.exists?(rails_conf)
62
+ #STDERR.puts 'Rails configuration file could not be found'
63
+ @rails_root = nil
64
+ else
65
+ @servlet = File.basename(@rails_root)
66
+ @category = @servlet
67
+
68
+ @warbler_conf = File.join(@rails_root,'config','warble.rb')
69
+ unless File.exists?(@warbler_conf)
70
+ #STDERR.puts 'Warbler configuration file could not be found'
71
+ end
72
+ end
73
+ end
68
74
 
69
75
  yield self if block_given?
70
76
  end
@@ -73,7 +79,8 @@ module Caterpillar
73
79
  #
74
80
  # Possible values: Caterpillar::Liferay (default using Tomcat)
75
81
  def container
76
- self._container || Caterpillar::Liferay.new
82
+ return self._container if self._container
83
+ self._container = Caterpillar::Liferay.new
77
84
  end
78
85
 
79
86
  # Accepts the configuration option, and instantates the container class.
@@ -1,13 +1,13 @@
1
1
  # encoding: utf-8
2
-
3
-
4
2
  #--
5
- # (c) Copyright 2008,2009 Mikael Lammentausta
3
+ # (c) Copyright 2008-2010 Mikael Lammentausta
6
4
  #
7
5
  # See the file MIT-LICENSE included with the distribution for
8
6
  # software license details.
9
7
  #++
10
8
 
9
+ require "rexml/document"
10
+
11
11
  module Caterpillar # :nodoc:
12
12
 
13
13
  # Creates liferay-portlet XML and liferay-display XML.
@@ -62,7 +62,7 @@ module Caterpillar # :nodoc:
62
62
  # Liferay version is given as a String, eg. '5.2.2'.
63
63
  # Defaults to +Lportal::Schema.version+.
64
64
  def initialize(version=nil)
65
- @version = version
65
+ @version = version || '5.2.3'
66
66
  @root = '/usr/local/liferay-portal-5.2.3/tomcat-6.0.18' # as described in setup guide, when unpacked to /usr/local
67
67
  @server = 'Tomcat'
68
68
  @deploy_dir = nil
@@ -79,70 +79,39 @@ module Caterpillar # :nodoc:
79
79
  # It can also be defined from the configuration file:
80
80
  # portlet.container.deploy_dir = '/opt/myDeployDir'
81
81
  def deploy_dir
82
- return @deploy_dir unless @deploy_dir.nil?
82
+ return @deploy_dir if @deploy_dir # user configuration
83
83
 
84
- raise 'Configure container root folder' unless self.root
85
84
  case @server
86
-
87
85
  when 'Tomcat'
88
- root_dir = 'ROOT'
89
- @deploy_dir = File.join(self.root,'webapps')
86
+ raise 'Configure container root directory' unless @root
87
+ return File.join(@root,'webapps')
90
88
 
91
89
  when 'JBoss/Tomcat'
92
- # detect server name if not configured
93
- @server_dir ||= Dir.new(
94
- File.join(self.root,'server')).entries.first
95
- @deploy_dir = File.join(self.root,'server',@server_dir,'deploy')
90
+ raise "Please configure deploy directory for JBoss."
96
91
 
97
92
  end
98
-
99
- unless File.exists?(@deploy_dir)
100
- raise 'Portal deployment directory does not exist: %s' % @deploy_dir
101
- end
102
-
103
- return @deploy_dir
104
93
  end
105
94
 
106
- # The location of Liferay's WEB-INF folder for XML analyzation.
107
- # This is relative to installation directory (self.root)
95
+ # The location of Liferay's WEB-INF folder,
96
+ # relative to installation directory (@root).
97
+ # This is where the XML files are housed.
108
98
  def WEB_INF
109
- raise 'Configure container root folder' unless self.root
99
+ raise 'Configure container root directory' unless @root
110
100
  case @server
111
101
 
112
102
  when 'Tomcat'
113
- root_dir = 'ROOT'
114
- return web_inf_dir(root_dir)
103
+ return File.join(@root, %w{webapps ROOT WEB-INF})
115
104
 
116
105
  when 'JBoss/Tomcat'
117
- # detect lportal dir (ROOT.war or lportal.war)
118
- root_dir =
119
- if File.exists?(File.join(self.deploy_dir,'ROOT.war'))
120
- 'ROOT.war'
121
- elsif File.exists?(File.join(self.deploy_dir,'lportal.war'))
122
- 'lportal.war'
123
- end
124
- unless root_dir
125
- STDERR.puts 'There seems to be a problem detecting the proper install paths.'
126
- STDERR.puts 'Please file a bug on Caterpillar.'
127
- raise 'Portal root directory not found at %s' % self.deploy_dir
106
+ # user should configure server_dir !!
107
+ unless @server_dir
108
+ raise 'Please configure server_dir for JBoss/Tomcat'
128
109
  end
129
-
130
- return web_inf_dir(root_dir)
110
+ return File.join(@root, @server_dir, 'WEB-INF')
131
111
 
132
112
  end
133
113
  end
134
114
 
135
- # The rule by which the WEB-INF is constructed regardless of the server.
136
- def web_inf_dir(root_dir)
137
- # The @deploy_dir variable does not need checking,
138
- # as the method deploy_dir() does that.
139
- #if deploy_dir_defined?
140
-
141
- #self.deploy_dir(),
142
- # Xml files need to be in WEB-INF and not, for example, /opt/liferay/deploy
143
- return File.join(File.join(self.root,'webapps'), root_dir,'WEB-INF')
144
- end
145
-
146
115
  # Reads Liferay portlet descriptor XML files and parses them with Hpricot.
147
116
  def analyze(type=:native)
148
117
  require 'hpricot'
@@ -209,94 +178,78 @@ module Caterpillar # :nodoc:
209
178
 
210
179
  # liferay-portlet XML
211
180
  def portletapp_xml(portlets)
212
- doctype = 'liferay-portlet-app'
213
- xml = xml_header(doctype)
214
- portlets.each do |p|
215
- xml << portletapp_template(p)
181
+ doc = REXML::Document.new
182
+ doc << REXML::XMLDecl.new('1.0', 'utf-8')
183
+ doc << REXML::DocType.new('liferay-portlet-app',
184
+ 'PUBLIC '+\
185
+ '"-//Liferay//DTD Portlet Application %s//EN" ' % (self.dtd_version) +\
186
+ '"http://www.liferay.com/dtd/liferay-portlet-app_%s.dtd"' % self.dtd_version.gsub('.','_')
187
+ )
188
+ app = REXML::Element.new('liferay-portlet-app', doc)
189
+
190
+ portlets.each do |portlet|
191
+ # <portlet>
192
+ app.elements << self.portlet_element(portlet)
193
+ # <role-mapper>s
194
+ roles.each {|role| app.elements << role}
216
195
  end
217
- xml << roles
218
- xml << portlet_xml_footer(doctype)
196
+
197
+ xml = ''
198
+ #doc.write(xml, -1) # no indentation, tag and text should be on same line
199
+ doc.write(xml, 4) # without identation is very dificult to reconfigure those files in production
200
+ return xml.gsub('\'', '"') # fix rexml attribute single quotes to double quotes
219
201
  end
220
202
 
221
203
  # liferay-display XML
222
204
  def display_xml(portlets)
223
- xml = self.xml_header('display')
224
-
225
- categories = []
226
- # process Rails portlets
227
- Util.categorize(portlets).each_pair do |category,portlets|
228
- categories << category
229
- xml << self.display_template(category,portlets)
230
- end
231
-
232
- # include other native Liferay portlets and categories
233
- if self.WEB_INF
234
- require 'hpricot'
235
-
236
- filename = self.WEB_INF+'/liferay-display.xml'
237
- f=File.open(filename,'r')
238
- doc = Hpricot.XML(f.read)
239
- f.close
240
- (doc/"display/category").each do |el|
241
- unless categories.include?(el.attributes['name'])
242
- xml << ' ' + el.to_original_html + "\n"
243
- end
205
+ liferay_display_file = File.join(self.WEB_INF,'liferay-display.xml')
206
+
207
+ doc = REXML::Document.new File.new(liferay_display_file)
208
+ display = doc.root
209
+
210
+ # include portlets
211
+ Util.categorize(portlets).each_pair do |category_name, portlets|
212
+ category = nil
213
+ display.each_element {|e| if e.attributes['name'] == category_name.to_s then category = e; break end}
214
+
215
+ unless category
216
+ category = REXML::Element.new('category', display)
217
+ category.attributes['name'] = category_name.to_s
244
218
  end
219
+
220
+ portlets.each do |portlet|
221
+ if category.has_elements?
222
+ # unless he holds does not add again
223
+ category.each_element do |e|
224
+ unless e.attributes['id'] == portlet[:name]
225
+ category.add_element 'portlet', {'id' => portlet[:name]}
226
+ break
227
+ end
228
+ end
229
+ else
230
+ category.add_element 'portlet', {'id' => portlet[:name]}
231
+ end
232
+ end
233
+
245
234
  end
246
235
 
247
- xml << self.portlet_xml_footer('display')
248
- return xml
236
+ xml = ''
237
+ #doc.write(xml, -1) # no indentation, tag and text should be on same line
238
+ doc.write(xml, 4) # without identation is very dificult to reconfigure those files in production
239
+ return xml.gsub('\'', '"') # fix rexml attribute single quotes to double quotes
249
240
  end
250
241
 
251
242
  protected
252
243
 
253
- # common XML header
254
- def xml_header(doctype)
255
- version = self.dtd_version(doctype)
256
- xml = '<?xml version="1.0" encoding="UTF-8"?>'
257
- xml << "\n"
258
- xml << '<!DOCTYPE %s PUBLIC' % doctype
259
- case doctype
260
-
261
- when 'liferay-portlet-app'
262
- xml << ' "-//Liferay//DTD Portlet Application %s//EN"' % version
263
- xml << ' "http://www.liferay.com/dtd/%s_%s.dtd">' % [
264
- doctype, version.gsub('.','_') ]
265
-
266
- when 'display'
267
- xml << ' "-//Liferay//DTD Display %s//EN"' % version
268
- xml << ' "http://www.liferay.com/dtd/liferay-%s_%s.dtd">' % [
269
- doctype, version.gsub('.','_') ]
270
-
271
- end
272
- xml << "\n\n"
273
- xml << '<%s>' % doctype
274
- xml << "\n"
275
- return xml
276
- end
277
-
278
- # common XML footer
279
- def portlet_xml_footer(doctype)
280
- '</%s>' % doctype
281
- end
282
-
283
- # DTD version detection based on self.version
284
- def dtd_version(type)
285
- #case type
286
- #when 'liferay-portlet-app'
287
- #when 'display'
288
- self.version[/.../] + '.0'
289
- end
290
-
291
- # liferay-portlet-ext definition
244
+ # <portlet> element for liferay-portlet-ext.xml
292
245
  #
293
246
  # http://www.liferay.com/web/guest/community/wiki/-/wiki/Main/Liferay-portlet.xml
294
247
  #
295
- # The content of element type "portlet" must match "(portlet-name,icon?,virtual-path?,struts-path?,configuration-path?,configuration-action-class?,indexer-class?,open-search-class?,scheduler-class?,portlet-url-class?,friendly-url-mapper-class?,url-encoder-class?,portlet-data-handler-class?,portlet-layout-listener-class?,poller-processor-class?,pop-message-listener-class?,social-activity-interpreter-class?,social-request-interpreter-class?,webdav-storage-token?,webdav-storage-class?,control-panel-entry-category?,control-panel-entry-weight?,control-panel-entry-class?,preferences-company-wide?,preferences-unique-per-layout?,preferences-owned-by-group?,use-default-template?,show-portlet-access-denied?,show-portlet-inactive?,action-url-redirect?,restore-current-view?,maximize-edit?,maximize-help?,pop-up-print?,layout-cacheable?,instanceable?,scopeable?,user-principal-strategy?,private-request-attributes?,private-session-attributes?,render-weight?,ajaxable?,header-portal-css*,header-portlet-css*,header-portal-javascript*,header-portlet-javascript*,footer-portal-css*,footer-portlet-css*,footer-portal-javascript*,footer-portlet-javascript*,css-class-wrapper?,facebook-integration?,add-default-resource?,system?,active?,include?)".
296
- def portletapp_template(portlet)
297
- xml = " <portlet>\n"
298
- xml << " <portlet-name>%s</portlet-name>\n" % portlet[:name]
299
- xml << " <icon>%s</icon>\n" % [
248
+ def portlet_element(portlet)
249
+ element = REXML::Element.new('portlet')
250
+
251
+ REXML::Element.new('portlet-name', element).text = portlet[:name]
252
+ REXML::Element.new('icon', element).text = [
300
253
  portlet[:host], portlet[:servlet], 'favicon.png' # .ico does not work on Firefox 3.0
301
254
  ].join('/').gsub(/([^:])\/\//,'\1/')
302
255
 
@@ -305,9 +258,8 @@ module Caterpillar # :nodoc:
305
258
  # Note that when the control panel settings are defined,
306
259
  # the portlet cannot be instanceable.
307
260
  unless @version[/5.1/]
308
- xml << " <control-panel-entry-category>#{portlet[:category]}</control-panel-entry-category>\n"
309
- xml << " <control-panel-entry-weight>420.0</control-panel-entry-weight>\n"
310
- #xml << " <control-panel-entry-class></control-panel-entry-class>\n"
261
+ REXML::Element.new('control-panel-entry-category', element).text = portlet[:category]
262
+ REXML::Element.new('control-panel-entry-weight', element).text = '420.0'
311
263
  end
312
264
 
313
265
  # Set the use-default-template value to true if the portlet uses the default template to decorate and wrap content. Setting this to false allows the developer to own and maintain the portlet's entire outputted content. The default value is true.
@@ -315,60 +267,52 @@ module Caterpillar # :nodoc:
315
267
  # The most common use of this is if you want the portlet to look different from the other portlets or if you want the portlet to not have borders around the outputted content.
316
268
  #
317
269
  # RD: This is a nice option except that if you set it, then you loose all border functionality including drag, drop, min,max,edit,conf,close These should be controlled by a separate property.
318
- xml << " <use-default-template>true</use-default-template>\n"
270
+ REXML::Element.new('use-default-template', element).text = 'true'
319
271
 
320
272
  # can there be several portlet instances on the same page?
321
- xml << " <instanceable>#{portlet[:instanceable]}</instanceable>\n"
273
+ REXML::Element.new('instanceable', element).text = portlet[:instanceable].to_s
322
274
 
323
275
  # The default value of ajaxable is true. If set to false, then this portlet can never be displayed via Ajax.
324
- xml << " <ajaxable>true</ajaxable>\n"
276
+ REXML::Element.new('ajaxable', element).text = 'true'
325
277
 
326
278
  # include javascripts?
327
279
  js_tag = (@version[/5.1/] ? 'header' : 'footer') + '-portal-javascript'
328
280
  portlet[:javascripts].each do |js|
329
- xml << " <#{js_tag}>"
330
- xml << "/#{portlet[:servlet]}/javascripts/#{js}"
331
- xml << "</#{js_tag}>\n"
281
+ REXML::Element.new(js_tag, element).text = "/#{portlet[:servlet]}/javascripts/#{js}"
332
282
  end
333
283
 
334
284
  # If the add-default-resource value is set to true, the default portlet resources and permissions are added to the page. The user can then view the portlet.
335
- xml << " <add-default-resource>true</add-default-resource>\n"
336
- xml << " <system>false</system>\n"
337
- xml << " <active>true</active>\n"
338
- xml << " <include>true</include>\n"
285
+ REXML::Element.new('add-default-resource', element).text = 'true'
286
+ REXML::Element.new('system', element).text = 'false'
287
+ REXML::Element.new('active', element).text = 'true'
288
+ REXML::Element.new('include', element).text = 'true'
339
289
 
340
- xml << " </portlet>\n\n"
290
+ return element
341
291
  end
342
292
 
343
- def display_template(category,portlets)
344
- xml = ' <category name="%s">' % category +"\n"
345
- portlets.each do |p|
346
- xml << ' <portlet id="%s" />' % p[:name] + "\n"
347
- end
348
- xml << " </category>\n\n"
293
+ # DTD version based on self.version
294
+ def dtd_version
295
+ self.version[/.../] + '.0'
349
296
  end
350
297
 
351
298
  private
352
299
 
353
300
  # XML role-mapper.
354
- # Has to be duplicated in -ext.xml
355
301
  def roles
356
- xml = " <role-mapper>\n"
357
- xml << " <role-name>administrator</role-name>\n"
358
- xml << " <role-link>Administrator</role-link>\n"
359
- xml << " </role-mapper>\n"
360
- xml << " <role-mapper>\n"
361
- xml << " <role-name>guest</role-name>\n"
362
- xml << " <role-link>Guest</role-link>\n"
363
- xml << " </role-mapper>\n"
364
- xml << " <role-mapper>\n"
365
- xml << " <role-name>power-user</role-name>\n"
366
- xml << " <role-link>Power User</role-link>\n"
367
- xml << " </role-mapper>\n"
368
- xml << " <role-mapper>\n"
369
- xml << " <role-name>user</role-name>\n"
370
- xml << " <role-link>User</role-link>\n"
371
- xml << " </role-mapper>\n"
302
+ elements = []
303
+ # name => link
304
+ {
305
+ 'administrator' => 'Administrator',
306
+ 'guest' => 'Guest',
307
+ 'power-user' => 'Power User',
308
+ 'user' => 'User'
309
+ }.each_pair do |name,link|
310
+ mapper = REXML::Element.new('role-mapper')
311
+ REXML::Element.new('role-name', mapper).text = name
312
+ REXML::Element.new('role-link', mapper).text = link
313
+ elements << mapper
314
+ end
315
+ return elements
372
316
  end
373
317
 
374
318
  public