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 #add, #<<, #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