# # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This task creates a JBI package based on the component/bootstrap specification. # It extends ZipTask, and all its over lovely options. # # The easiest way to use this task is through the Project#package method. For example: # package(:jbi).tap do |jbi| # jbi.component :type=>:service_engine=>"MyEngine", :description=>self.comment # jbi.component :class_name=>"com.example.MyComponent", :delegation=>:self, :libs=>libs # jbi.bootstrap :class_name=>"com.example.MyBootstrap", :delegation=>:parent, :libs=>libs # end class JBITask < Buildr::ZipTask # Specifies the name of a jbi.xml file to use, or a Proc/Method returning # the contents of jbi.xml. Leave empty if you want to use #component and # bootstrap instead. attr_accessor :jbi_xml # Component specification. class Component # Component name. attr_accessor :name # Component type, e.g. :service_engine. attr_accessor :type # Description of component. attr_accessor :description # Delegation method. Default is :parent. attr_accessor :delegation # Component class name. attr_accessor :class_name # Array of libraries used by component. attr_accessor :libs def initialize() @libs = [] end end # Bootstrap specification. class Bootstrap # Delegation method. Default is :parent. attr_accessor :delegation # Bootstrap class name. attr_accessor :class_name # Array of libraries used for bootstrapping. attr_accessor :libs def initialize() @libs = [] end end def initialize(*args) super prepare { path("lib").include((component.libs + bootstrap.libs).flatten.uniq) } enhance do case jbi_xml when String path("META-INF").include jbi_xml.path, :as=>"jbi.xml" when nil, true # Tempfiles gets deleted on garbage collection, so we're going to hold on to it # through instance variable not closure variable. Tempfile.open("MANIFEST.MF") { |@jbi_xml_tmp| @jbi_xml_tmp.write descriptor } path("META-INF").include @jbi_xml_tmp.path, :as=>"jbi.xml" when Proc, Method Tempfile.open("MANIFEST.MF") { |@jbi_xml_tmp| @jbi_xml_tmp.write jbi_xml.call.to_s } path("META-INF").include @jbi_xml_tmp.path, :as=>"jbi.xml" end end end def []=(key, value) case key.to_sym when :name, :description, :type self.component.send "#{name}=", value when :component, :bootstrap self.send key, value else super key, value end value end # Returns the component specification for this JBI package. # You can call accessor methods to configure the component # specification, you can also pass a hash of settings, for example: # jbi.component :type=>:service_engine, :name=>"MyEngine" def component(args = nil) (@component ||= Component.new).tap do |component| args.each { |k, v| component.send "#{k}=", v } if args end end # Returns the bootstrap specification for this JBI package. # You can call accessor methods to configure the bootstrap # specification, you can also pass a hash of settings, for example: # jbi.bootstrap :class_name=>"com.example.jbi.MyBootstrap", :libs=>libs def bootstrap(args = nil) (@bootstrap ||= Bootstrap.new).tap do |bootstrap| args.each { |k, v| bootstrap.send "#{k}=", v } if args end end # Create a JBI descriptor (jbi.xml) from the component/bootstrap specification. def descriptor() delegation = lambda { |key| "#{key || :parent}-first" } path_elements = lambda do |xml, libs| libs.each { |lib| xml.tag! "path-element", "lib/#{lib.to_s.pathmap('%f')}" } end xml = Builder::XmlMarkup.new(:indent=>2) xml.instruct! xml.jbi :xmlns=>"http://java.sun.com/xml/ns/jbi", :version=>"1.0" do xml.component :type=>component.type.to_s.sub("_", "-"), "component-class-loader-delegation"=>delegation[component.delegation], "bootstrap-class-loader-delegation"=>delegation[bootstrap.delegation] do xml.identification do xml.name component.name xml.description component.description end xml.tag!("component-class-name", component.class_name) xml.tag!("component-class-path") { path_elements[xml, component.libs] } xml.tag!("bootstrap-class-name", bootstrap.class_name) xml.tag!("bootstrap-class-path") { path_elements[xml, bootstrap.libs] } end end end end class Project def package_as_jbi(file_name, options) # The file name extension is zip, not jbi. And we also need to reset # the type on the artifact specification. # The file type is ZIP, not JBI, so update the file name/spec accordingly. options[:type] = :zip file_name = path_to(:target, Artifact.hash_to_file_name(options)) JBITask.define_task(file_name) unless Rake::Task.task_defined?(file_name) file(file_name) end end