diff --git a/.idea/dictionaries/cgfrost.xml b/.idea/dictionaries/cgfrost.xml
new file mode 100644
index 0000000000..bed05d0733
--- /dev/null
+++ b/.idea/dictionaries/cgfrost.xml
@@ -0,0 +1,7 @@
+
+
+
+ cafebabe
+
+
+
\ No newline at end of file
diff --git a/config/open_jdk_jre.yml b/config/open_jdk_jre.yml
index 2a4feb2af6..2044fd5fda 100644
--- a/config/open_jdk_jre.yml
+++ b/config/open_jdk_jre.yml
@@ -14,16 +14,21 @@
# limitations under the License.
# Configuration for JRE repositories keyed by vendor
-# To go back to Java 7, permgen should be used instead of metaspace. Please see the documentation for more detail.
+# Pre Java 1.8, permgen was used instead of metaspace, the buildpack will consume the configuration as appropriate.
+# Please see the documentation for more detail.
---
repository_root: "{default.repository.root}/openjdk/{platform}/{architecture}"
-version: 1.8.0_+
+version:
+ detect_compiled: enabled
+ 8: 1.8.0_+
+ 7: 1.7.0_+
+ 6: 1.6.0_+
memory_sizes:
metaspace: 64m..
- # permgen: 64m..
+ permgen: 64m..
memory_heuristics:
heap: 75
metaspace: 10
- # permgen: 10
+ permgen: 10
stack: 5
native: 10
diff --git a/config/oracle_jre.yml b/config/oracle_jre.yml
index cdb6226dc2..6ffe8bf3b8 100644
--- a/config/oracle_jre.yml
+++ b/config/oracle_jre.yml
@@ -14,19 +14,24 @@
# limitations under the License.
# Configuration for JRE repositories keyed by vendor
-# Pre Java 1.8, permgen was used instead of metaspace. Please see the documentation for more detail.
+# Pre Java 1.8, permgen was used instead of metaspace, the buildpack will consume the configuration as appropriate.
+# Please see the documentation for more detail.
---
# You must specify a the repository root of an Oracle JRE repository. Please see the documentation for more detail.
# e.g. repository_root: "http://example.com/oracle-jre/{platform}/{architecture}"
repository_root: ""
-version: 1.8.0_+
+version:
+ detect_compiled: enabled
+ 8: 1.8.0_+
+ 7: 1.7.0_+
+ 6: 1.6.0_+
memory_sizes:
metaspace: 64m..
-# permgen: 64m..
+ permgen: 64m..
memory_heuristics:
heap: 75
metaspace: 10
-# permgen: 10
+ permgen: 10
stack: 5
native: 10
diff --git a/java-buildpack.iml b/java-buildpack.iml
index a0bcb4d298..85fb2c22ac 100644
--- a/java-buildpack.iml
+++ b/java-buildpack.iml
@@ -271,7 +271,7 @@
-
+
@@ -281,13 +281,13 @@
-
+
-
+
diff --git a/lib/java_buildpack/jre/open_jdk_like.rb b/lib/java_buildpack/jre/open_jdk_like.rb
index 4b665c02b6..6592151c92 100644
--- a/lib/java_buildpack/jre/open_jdk_like.rb
+++ b/lib/java_buildpack/jre/open_jdk_like.rb
@@ -15,6 +15,8 @@
# limitations under the License.
require 'fileutils'
+require 'zip'
+require 'find'
require 'java_buildpack/component/versioned_dependency_component'
require 'java_buildpack/jre'
require 'java_buildpack/jre/memory/openjdk_memory_heuristic_factory'
@@ -39,8 +41,12 @@ def initialize(context)
# (see JavaBuildpack::Component::BaseComponent#detect)
def detect
+ version = required_java_version
+ version_specific_configuration = { KEY_REPOSITORY_ROOT => @configuration[KEY_REPOSITORY_ROOT],
+ KEY_VERSION => version }
+
@version, @uri = JavaBuildpack::Repository::ConfiguredItem.find_item(@component_name,
- @configuration)
+ version_specific_configuration)
@droplet.java_home.version = @version
super
end
@@ -65,15 +71,90 @@ def release
KEY_MEMORY_SIZES = 'memory_sizes'.freeze
- private_constant :KEY_MEMORY_HEURISTICS, :KEY_MEMORY_SIZES
+ KEY_DETECT_COMPILED_VERSION = 'detect_compiled'.freeze
+
+ KEY_JAVA_EIGHT_VERSION = 8.freeze
+
+ KEY_JAVA_SEVEN_VERSION = 7.freeze
+
+ KEY_JAVA_SIX_VERSION = 6.freeze
+
+ KEY_REPOSITORY_ROOT = 'repository_root'.freeze
+
+ KEY_VERSION = 'version'.freeze
+
+ CAFEBABE = 'cafebabe'.freeze
+
+ private_constant :KEY_MEMORY_HEURISTICS, :KEY_MEMORY_SIZES, :KEY_DETECT_COMPILED_VERSION,
+ :KEY_JAVA_SEVEN_VERSION, :KEY_JAVA_SIX_VERSION, :KEY_VERSION, :CAFEBABE
def killjava
@droplet.sandbox + 'bin/killjava.sh'
end
+ def java_6?(version_code)
+ version_code == 32
+ end
+
+ def java_7?(version_code)
+ version_code == 33
+ end
+
+ def java_6_or_java_7?(version_code)
+ java_6?(version_code) || java_7?(version_code)
+ end
+
+ def required_java_version
+ version_configuration = @configuration[KEY_VERSION]
+ detected_version = resolved_version_code version_configuration
+
+ if java_6? detected_version
+ version = version_configuration[KEY_JAVA_SIX_VERSION]
+ elsif java_7? detected_version
+ version = version_configuration[KEY_JAVA_SEVEN_VERSION]
+ else
+ version = version_configuration[KEY_JAVA_EIGHT_VERSION]
+ end
+ version
+ end
+
+ def resolved_version_code(configuration)
+ configuration[KEY_DETECT_COMPILED_VERSION] == 'enabled' ? detect_compiled_version(@application.root) : 34
+ end
+
+ # If no valid files are found with 'cafebabe' and an expected version code then
+ # the code '34' for Java 8 will be returned.
+ def detect_compiled_version(application_root)
+ result = 0
+ Find.find(application_root.to_path) do |sub_entry|
+ result = check_file(sub_entry, result) if sub_entry.end_with? '.class' unless FileTest.directory?(sub_entry)
+ end
+ result == 0 ? 34 : result
+ end
+
+ def check_file(entry, result)
+ bits = File.open(entry).read.unpack('H*')[0]
+ logger = JavaBuildpack::Logging::LoggerFactory.instance.get_logger OpenJDKLike
+ logger.debug "Scanning '#{entry}', first 8 bits are '#{bits[0, 8]}' and the version code is '#{bits[14, 2]}'."
+ result = [result, Integer(bits[14, 2])].max if bits[0, 8] == CAFEBABE
+ result
+ end
+
def memory
- sizes = @configuration[KEY_MEMORY_SIZES] || {}
- heuristics = @configuration[KEY_MEMORY_HEURISTICS] || {}
+ sizes = @configuration[KEY_MEMORY_SIZES] ? @configuration[KEY_MEMORY_SIZES].clone : {}
+ heuristics = @configuration[KEY_MEMORY_HEURISTICS] ? @configuration[KEY_MEMORY_HEURISTICS].clone : {}
+
+ version_configuration = @configuration[KEY_VERSION]
+ detected_version = resolved_version_code version_configuration
+
+ if java_6_or_java_7? detected_version
+ heuristics.delete 'metaspace'
+ sizes.delete 'metaspace'
+ else
+ heuristics.delete 'permgen'
+ sizes.delete 'permgen'
+ end
+
OpenJDKMemoryHeuristicFactory.create_memory_heuristic(sizes, heuristics, @version).resolve
end
diff --git a/spec/fixtures/jre_java6_application/META-INF/MANIFEST.MF b/spec/fixtures/jre_java6_application/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..58630c02ef
--- /dev/null
+++ b/spec/fixtures/jre_java6_application/META-INF/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/spec/fixtures/jre_java6_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationConfiguration.class b/spec/fixtures/jre_java6_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationConfiguration.class
new file mode 100644
index 0000000000..70c48311b4
Binary files /dev/null and b/spec/fixtures/jre_java6_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationConfiguration.class differ
diff --git a/spec/fixtures/jre_java6_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationInitializer.class b/spec/fixtures/jre_java6_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationInitializer.class
new file mode 100644
index 0000000000..e9f0ceccd7
Binary files /dev/null and b/spec/fixtures/jre_java6_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationInitializer.class differ
diff --git a/spec/fixtures/jre_java7_application/META-INF/MANIFEST.MF b/spec/fixtures/jre_java7_application/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..58630c02ef
--- /dev/null
+++ b/spec/fixtures/jre_java7_application/META-INF/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
diff --git a/spec/fixtures/jre_java7_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationConfiguration.class b/spec/fixtures/jre_java7_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationConfiguration.class
new file mode 100644
index 0000000000..41847273ee
Binary files /dev/null and b/spec/fixtures/jre_java7_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationConfiguration.class differ
diff --git a/spec/fixtures/jre_java7_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationInitializer.class b/spec/fixtures/jre_java7_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationInitializer.class
new file mode 100644
index 0000000000..84967a6d3d
Binary files /dev/null and b/spec/fixtures/jre_java7_application/WEB-INF/classes/com/gopivotal/cloudfoundry/test/ApplicationInitializer.class differ
diff --git a/spec/java_buildpack/jre/open_jdk_jre_spec.rb b/spec/java_buildpack/jre/open_jdk_jre_spec.rb
index 62208cbefc..f15f2048da 100644
--- a/spec/java_buildpack/jre/open_jdk_jre_spec.rb
+++ b/spec/java_buildpack/jre/open_jdk_jre_spec.rb
@@ -27,6 +27,20 @@
let(:memory_heuristic) { double('MemoryHeuristic', resolve: %w(opt-1 opt-2)) }
+ let(:configuration) do
+ { 'version' => { 'detect_compile' => 'disabled',
+ 8 => '1.8.0_+',
+ 7 => '1.7.0_+',
+ 6 => '1.6.0_+' },
+ 'memory_sizes' => { 'metaspace' => '64m..',
+ 'permgen' => '64m..' },
+ 'memory_heuristics' => { 'heap' => '75',
+ 'metaspace' => '10',
+ 'permgen' => '10',
+ 'stack' => '5',
+ 'native' => '10' } }
+ end
+
before do
allow(JavaBuildpack::Jre::WeightBalancingMemoryHeuristic).to receive(:new).and_return(memory_heuristic)
end
@@ -81,4 +95,81 @@
expect(java_opts).to include('-Djava.io.tmpdir=$TMPDIR')
end
+ context do
+
+ let(:configuration) { super().merge 'version' => { 'detect_compile' => 'enabled' } }
+
+ context do
+
+ before do
+ allow_any_instance_of(described_class).to receive(:java_6?).and_return(true)
+ end
+
+ it 'detects with id of openjdk_jre- for a java 6 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java6_application' do
+
+ expect(component.detect).to eq("open-jdk-jre=#{version}")
+ end
+
+ it 'adds memory options to java_opts for a java 6 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java6_application' do
+
+ component.detect
+ component.release
+
+ expect(java_opts).to include('opt-1')
+ expect(java_opts).to include('opt-2')
+ end
+
+ end
+
+ context do
+
+ before do
+ allow_any_instance_of(described_class).to receive(:java_7?).and_return(true)
+ end
+
+ it 'detects with id of openjdk_jre- for a java 7 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java7_application' do
+
+ expect(component.detect).to eq("open-jdk-jre=#{version}")
+ end
+
+ end
+
+ context do
+
+ let(:component) { StubOpenJdkJRE.new context }
+
+ before do
+ allow_any_instance_of(StubOpenJdkJRE).to receive(:supports?).and_return(true)
+ end
+
+ it 'detects the correct version for a java 7 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java7_application' do
+
+ expect(component.detect_compiled_version Pathname.new('spec/fixtures/jre_java7_application')).to eq(33)
+ end
+
+ it 'detects the correct version for a java 6 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java6_application' do
+
+ expect(component.detect_compiled_version Pathname.new('spec/fixtures/jre_java6_application')).to eq(32)
+ end
+
+ class StubOpenJdkJRE < JavaBuildpack::Jre::OpenJdkJRE
+
+ public :detect_compiled_version
+
+ end
+
+ end
+
+ end
+
end
diff --git a/spec/java_buildpack/jre/oracle_jre_spec.rb b/spec/java_buildpack/jre/oracle_jre_spec.rb
index efec872043..534d8b8d9f 100644
--- a/spec/java_buildpack/jre/oracle_jre_spec.rb
+++ b/spec/java_buildpack/jre/oracle_jre_spec.rb
@@ -27,6 +27,20 @@
let(:memory_heuristic) { double('MemoryHeuristic', resolve: %w(opt-1 opt-2)) }
+ let(:configuration) do
+ { 'version' => { 'detect_compile' => 'disabled',
+ 8 => '1.8.0_+',
+ 7 => '1.7.0_+',
+ 6 => '1.6.0_+' },
+ 'memory_sizes' => { 'metaspace' => '64m..',
+ 'permgen' => '64m..' },
+ 'memory_heuristics' => { 'heap' => '75',
+ 'metaspace' => '10',
+ 'permgen' => '10',
+ 'stack' => '5',
+ 'native' => '10' } }
+ end
+
before do
allow(JavaBuildpack::Jre::WeightBalancingMemoryHeuristic).to receive(:new).and_return(memory_heuristic)
end
@@ -81,4 +95,81 @@
expect(java_opts).to include('-Djava.io.tmpdir=$TMPDIR')
end
+ context do
+
+ let(:configuration) { super().merge 'version' => { 'detect_compile' => 'enabled' } }
+
+ context do
+
+ before do
+ allow_any_instance_of(described_class).to receive(:java_6?).and_return(true)
+ end
+
+ it 'detects with id of oracle_jre- for a java 6 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java6_application' do
+
+ expect(component.detect).to eq("oracle-jre=#{version}")
+ end
+
+ it 'adds memory options to java_opts for a java 6 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java6_application' do
+
+ component.detect
+ component.release
+
+ expect(java_opts).to include('opt-1')
+ expect(java_opts).to include('opt-2')
+ end
+
+ end
+
+ context do
+
+ before do
+ allow_any_instance_of(described_class).to receive(:java_7?).and_return(true)
+ end
+
+ it 'detects with id of oracle_jre- for a java 7 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java7_application' do
+
+ expect(component.detect).to eq("oracle-jre=#{version}")
+ end
+
+ end
+
+ context do
+
+ let(:component) { StubOracleJRE.new context }
+
+ before do
+ allow_any_instance_of(StubOracleJRE).to receive(:supports?).and_return(true)
+ end
+
+ it 'detects the correct version for a java 7 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java7_application' do
+
+ expect(component.detect_compiled_version Pathname.new('spec/fixtures/jre_java7_application')).to eq(33)
+ end
+
+ it 'detects the correct version for a java 6 app',
+ cache_fixture: 'stub-java.tar.gz',
+ app_fixture: 'jre_java6_application' do
+
+ expect(component.detect_compiled_version Pathname.new('spec/fixtures/jre_java6_application')).to eq(32)
+ end
+
+ class StubOracleJRE < JavaBuildpack::Jre::OracleJRE
+
+ public :detect_compiled_version
+
+ end
+
+ end
+
+ end
+
end