class Buildr::Packaging::Java::EarTask
Extend the JarTask
to create an EAR file.
The following component types are supported by the EARTask:
-
:war – A J2EE Web
Application
-
:ejb – An Enterprise
Java
Bean -
:jar – A J2EE
Application
Client. -
:lib – An ear scoped shared library (for things like logging,
spring, etc) common to the ear components
The EarTask
uses the “Mechanism 2: Bundled Optional Classes” as described on [2]. All specified libraries are added to the EAR archive and the Class-Path manifiest entry is modified for each EAR component. Special care is taken with WebApplications, as they can contain libraries on their WEB-INF/lib directory, libraries already included in a war file are not referenced by the Class-Path entry of the war in order to avoid class collisions
EarTask
supports all the same options as JarTask
, in additon to these two options:
-
:display_name – The displayname to for this ear on application.xml
-
:map – A
Hash
used to map component type to paths within the EAR.By default each component type is mapped to a directory with the same name, for example, EJBs are stored in the /ejb path. To customize: package(:ear).map[:war] = 'web-applications' package(:ear).map[:lib] = nil # store shared libraries on root of archive
EAR components are added by means of the EarTask#add
, EarTask#<<
, EarTask#push
methods Component type is determined from the artifact's type.
package(:ear) << project('coolWebService').package(:war)
The << method is just an alias for push, with the later you can add multiple components at the same time. For example..
package(:ear).push 'org.springframework:spring:jar:2.6', projects('reflectUtils', 'springUtils'), project('coolerWebService').package(:war)
The add method takes a single component with an optional hash. You can use it to override some component attributes.
You can override the component type for a particular artifact. The following example shows how you can tell the EarTask
to treat a JAR file as an EJB:
# will add an ejb entry for the-cool-ejb-2.5.jar in application.xml package(:ear).add 'org.coolguys:the-cool-ejb:jar:2.5', :type=>:ejb # A better syntax for this is: package(:ear).add :ejb=>'org.coolguys:the-cool-ejb:jar:2.5'
By default, every JAR package is assumed to be a library component, so you need to specify the type when including an EJB (:ejb) or Application
Client JAR (:jar).
For WebApplications (:war)s, you can customize the context-root that appears in application.xml. The following example also specifies a different directory inside the EAR where to store the webapp.
package(:ear).add project(:remoteService).package(:war), :path=>'web-services', :context_root=>'/Some/URL/Path'
Constants
- SUPPORTED_TYPES
Attributes
The description entry for application.xml
Map from component type to path inside the EAR.
The display-name entry for application.xml
Security roles entry for application.xml
Public Class Methods
# File lib/buildr/java/packaging.rb, line 395 def initialize(*args) super @dirs = Hash.new { |h, k| k.to_s } @libs, @components, @security_roles = [], [], [] prepare do @components.each do |component| path(component[:path]).include(component[:clone] || component[:artifact]) end path('META-INF').include(descriptor) end end
Public Instance Methods
Add an artifact to this EAR.
# File lib/buildr/java/packaging.rb, line 408 def add(*args) options = Hash === args.last ? args.pop.clone : {} args.flatten! args.map! do |pkg| case pkg when Project pkg.packages.select { |pp| JarTask === pp && SUPPORTED_TYPES.include?(pp.type) } when Rake::FileTask pkg # add the explicitly provided file when Hash Buildr.artifact(pkg) when String begin Buildr.artifact(pkg) rescue # not an artifact spec, it must me a filename file(pkg) end else raise "Invalid EAR component #{pkg.class}: #{pkg}" end end args.flatten! args.compact! if args.empty? raise ":type must not be specified for type=>component argument style" if options.key?(:type) raise ":as must not be specified for type=>component argument style" if options.key?(:as) comps = {} options.delete_if { |k, v| comps[k] = v if SUPPORTED_TYPES.include?(k) } raise "You must specify at least one valid component to add" if comps.empty? comps.each { |k, v| add(v, {:as => k}.merge(options)) } else args.each do |artifact| type = options[:as] || options[:type] unless type type = artifact.respond_to?(:type) ? artifact.type : artifact.to_s.pathmap('%x').to_sym type = :lib if type == :jar end raise "Unknown EAR component type: #{type}. Perhaps you may explicity tell what component type to use." unless SUPPORTED_TYPES.include?(type) component = options.merge(:artifact => artifact, :type => type, :id=>artifact.respond_to?(:to_spec) ? artifact.id : artifact.to_s.pathmap('%n'), :path=>options[:path] || dirs[type].to_s) component[:clone] = component_clone(component) unless :lib == type # update_classpath(component) unless :lib == type || Artifact === artifact @components << component end end self end
Protected Instance Methods
# File lib/buildr/java/packaging.rb, line 480 def associate(project) @project = project end
# File lib/buildr/java/packaging.rb, line 463 def component_clone(component) file(path_to(component[:path], component[:artifact].to_s.pathmap('%f')) => component[:artifact]) do |task| mkpath task.to_s.pathmap('%d') cp component[:artifact].to_s, task.to_s Manifest.update_manifest(task) do |manifest| class_path = manifest.main['Class-Path'].to_s.split included_libs = class_path.map { |fn| fn.pathmap('%f') } Zip::File.foreach(task.to_s) do |entry| included_libs << entry.name.pathmap('%f') if entry.file? && entry.name =~ /^WEB-INF\/lib\/[^\/]+$/ end # Include all other libraries in the classpath. class_path += libs_classpath(component).reject { |path| included_libs.include?(File.basename(path)) } manifest.main['Class-Path'] = class_path.join(' ') end end end
# File lib/buildr/java/packaging.rb, line 489 def update_classpath(component) package = file(component[:artifact].to_s) package.manifest = (package.manifest || {}).dup # avoid mofifying parent projects manifest package.prepare do header = case package.manifest when Hash then package.manifest when Array then package.manifest.first end if header # Determine which libraries are already included. class_path = header['Class-Path'].to_s.split included_libs = class_path.map { |fn| File.basename(fn) } included_libs += package.path('WEB-INF/lib').sources.map { |fn| File.basename(fn) } # Include all other libraries in the classpath. class_path += libs_classpath(component).reject { |path| included_libs.include?(File.basename(path)) } header['Class-Path'] = class_path.join(' ') end end end
Private Instance Methods
return a FileTask to build the ear application.xml file
# File lib/buildr/java/packaging.rb, line 562 def descriptor return @descriptor if @descriptor descriptor_path = path_to('META-INF/application.xml') @descriptor = file(descriptor_path) do |task| trace "Creating EAR Descriptor: #{task.to_s}" mkpath File.dirname(task.name) File.open(task.name, 'w') { |file| file.print task.xml } end class << @descriptor attr_accessor :ear def xml @xml ||= ear.send :descriptor_xml end def needed? super || xml != File.read(self.to_s) rescue true end end @descriptor.ear = self @descriptor end
# File lib/buildr/java/packaging.rb, line 522 def descriptor_xml buffer = "" xml = Builder::XmlMarkup.new(:target=>buffer, :indent => 2) xml.declare! :DOCTYPE, :application, :PUBLIC, '-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN', 'http://java.sun.com/j2ee/dtds/application_1_2.dtd' xml.application do xml.tag! 'display-name', display_name desc = self.description || @project.comment xml.tag! 'description', desc if desc @components.each do |comp| basename = comp[:artifact].to_s.pathmap('%f') uri = comp[:path].empty? ? basename : File.join(comp[:path], basename) case comp[:type] when :war xml.module :id=>comp[:id] do xml.web do xml.tag! 'web-uri', uri xml.tag! 'context-root', File.join('', (comp[:context_root] || comp[:id])) unless comp[:context_root] == false end end when :ejb xml.module :id=>comp[:id] do xml.ejb uri end when :jar xml.jar uri end end @security_roles.each do |role| xml.tag! 'security-role', :id=>role[:id] do xml.description role[:description] xml.tag! 'role-name', role[:name] end end end buffer end
Classpath of all packages included as libraries (type :lib).
# File lib/buildr/java/packaging.rb, line 512 def libs_classpath(component) from = component[:path] @classpath = @components.select { |comp| comp[:type] == :lib }. map do |lib| basename = lib[:artifact].to_s.pathmap('%f') full_path = lib[:path].empty? ? basename : File.join(lib[:path], basename) Util.relative_path(full_path, from) end end