|
| 1 | +# Cloud Foundry Java Buildpack |
| 2 | +# Copyright 2017 the original author or authors. |
| 3 | +# |
| 4 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +# you may not use this file except in compliance with the License. |
| 6 | +# You may obtain a copy of the License at |
| 7 | +# |
| 8 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +# |
| 10 | +# Unless required by applicable law or agreed to in writing, software |
| 11 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +# See the License for the specific language governing permissions and |
| 14 | +# limitations under the License. |
| 15 | + |
| 16 | +require 'digest' |
| 17 | +require 'fileutils' |
| 18 | +require 'java_buildpack/component/versioned_dependency_component' |
| 19 | +require 'java_buildpack/jre' |
| 20 | +require 'java_buildpack/util/tokenized_version' |
| 21 | + |
| 22 | +module JavaBuildpack |
| 23 | + module Jre |
| 24 | + |
| 25 | + # Encapsulates the detect, compile, and release functionality for selecting a JRE. |
| 26 | + class IbmJreInitializer < JavaBuildpack::Component::VersionedDependencyComponent |
| 27 | + |
| 28 | + # Creates an instance |
| 29 | + # |
| 30 | + # @param [Hash] context a collection of utilities used the component |
| 31 | + def initialize(context) |
| 32 | + @application = context[:application] |
| 33 | + @component_name = context[:component_name] |
| 34 | + @configuration = context[:configuration] |
| 35 | + @droplet = context[:droplet] |
| 36 | + |
| 37 | + @droplet.java_home.root = @droplet.sandbox + 'jre/' |
| 38 | + end |
| 39 | + |
| 40 | + # (see JavaBuildpack::Component::BaseComponent#detect) |
| 41 | + def detect |
| 42 | + @version, @uri = JavaBuildpack::Repository::ConfiguredItem.find_item(@component_name, |
| 43 | + @configuration) |
| 44 | + @droplet.java_home.version = @version |
| 45 | + super |
| 46 | + end |
| 47 | + |
| 48 | + # (see JavaBuildpack::Component::BaseComponent#compile) |
| 49 | + def compile |
| 50 | + download(@version, @uri, @component_name) do |file| |
| 51 | + with_timing "Installing #{@component_name} to #{@droplet.sandbox.relative_path_from(@droplet.root)}" do |
| 52 | + install_bin(@droplet.sandbox, file) |
| 53 | + end |
| 54 | + end |
| 55 | + @droplet.copy_resources |
| 56 | + end |
| 57 | + |
| 58 | + # (see JavaBuildpack::Component::BaseComponent#release) |
| 59 | + def release |
| 60 | + @droplet |
| 61 | + .java_opts |
| 62 | + .add_system_property('java.io.tmpdir', '$TMPDIR') |
| 63 | + @droplet.java_opts << '-Xtune:virtualized' |
| 64 | + @droplet.java_opts.concat mem_opts |
| 65 | + @droplet.java_opts << '-Xshareclasses:none' |
| 66 | + end |
| 67 | + |
| 68 | + private |
| 69 | + |
| 70 | + # constant HEAP_RATIO is the ratio of memory assigned to the heap |
| 71 | + # as against the container total and is set using -Xmx. |
| 72 | + HEAP_RATIO = 0.75 |
| 73 | + |
| 74 | + KILO = 1024 |
| 75 | + |
| 76 | + private_constant :HEAP_RATIO, :KILO |
| 77 | + |
| 78 | + # Installs the Downloaded InstallAnywhere (tm) BIN file to the target directory |
| 79 | + # |
| 80 | + # @param [String] target_directory, Where the java needs to be installed |
| 81 | + # @param [File] file, InstallAnywhere (tm) BIN file |
| 82 | + # @return [Void] |
| 83 | + def install_bin(target_directory, file) |
| 84 | + FileUtils.mkdir_p target_directory |
| 85 | + response_file = Tempfile.new('response.properties') |
| 86 | + response_file.puts('INSTALLER_UI=silent') |
| 87 | + response_file.puts('LICENSE_ACCEPTED=TRUE') |
| 88 | + response_file.puts("USER_INSTALL_DIR=#{target_directory}") |
| 89 | + response_file.close |
| 90 | + |
| 91 | + File.chmod(0o755, file.path) unless File.executable?(file.path) |
| 92 | + shell "#{file.path} -i silent -f #{response_file.path} 2>&1" |
| 93 | + end |
| 94 | + |
| 95 | + # Returns the max heap size ('-Xmx') value |
| 96 | + def mem_opts |
| 97 | + mopts = [] |
| 98 | + total_memory = memory_limit_finder |
| 99 | + if total_memory.nil? |
| 100 | + # if no memory option has been set by cloudfoundry, we just assume defaults |
| 101 | + else |
| 102 | + calculated_heap_ratio = heap_ratio_verification(heap_ratio) |
| 103 | + heap_size = heap_size_calculator(total_memory, calculated_heap_ratio) |
| 104 | + mopts.push "-Xmx#{heap_size}" |
| 105 | + end |
| 106 | + mopts |
| 107 | + end |
| 108 | + |
| 109 | + # Returns the heap_ratio attribute in config file (if specified) or the HEAP_RATIO constant value |
| 110 | + def heap_ratio |
| 111 | + @configuration['heap_ratio'] || HEAP_RATIO |
| 112 | + end |
| 113 | + |
| 114 | + # Returns the container total memory limit in bytes |
| 115 | + def memory_limit_finder |
| 116 | + memory_limit = ENV['MEMORY_LIMIT'] |
| 117 | + return nil unless memory_limit |
| 118 | + memory_limit_size = memory_size_bytes(memory_limit) |
| 119 | + raise "Invalid negative $MEMORY_LIMIT #{memory_limit}" if memory_limit_size < 0 |
| 120 | + memory_limit_size |
| 121 | + end |
| 122 | + |
| 123 | + # Returns the no. of bytes for a given string of minified size representation |
| 124 | + # |
| 125 | + # @param [String] size, A minified memory representation string |
| 126 | + # @return [Integer] bytes, value of size in bytes |
| 127 | + def memory_size_bytes(size) |
| 128 | + if size == '0' |
| 129 | + bytes = 0 |
| 130 | + else |
| 131 | + raise "Invalid memory size '#{size}'" if !size || size.length < 2 |
| 132 | + unit = size[-1] |
| 133 | + value = size[0..-2] |
| 134 | + raise "Invalid memory size '#{size}'" unless check_is_integer? value |
| 135 | + value = size.to_i |
| 136 | + # store the bytes |
| 137 | + bytes = calculate_bytes(unit, value) |
| 138 | + end |
| 139 | + bytes |
| 140 | + end |
| 141 | + |
| 142 | + # Returns the no. of bytes for a given memory size unit |
| 143 | + # |
| 144 | + # @param [String] unit, Represents a Memory Size Unit |
| 145 | + # @param [Integer] value |
| 146 | + # @return [Integer] bytes, value of size in bytes |
| 147 | + def calculate_bytes(unit, value) |
| 148 | + if %w[b B].include?(unit) |
| 149 | + bytes = value |
| 150 | + elsif %w[k K].include?(unit) |
| 151 | + bytes = KILO * value |
| 152 | + elsif %w[m M].include?(unit) |
| 153 | + bytes = KILO * KILO * value |
| 154 | + elsif %w[g G].include?(unit) |
| 155 | + bytes = KILO * KILO * KILO * value |
| 156 | + else |
| 157 | + raise "Invalid unit '#{unit}' in memory size" |
| 158 | + end |
| 159 | + bytes |
| 160 | + end |
| 161 | + |
| 162 | + # Checks whether the given value is an Integer |
| 163 | + # |
| 164 | + # @param [String] v, value as a string |
| 165 | + def check_is_integer?(v) |
| 166 | + v = Float(v) |
| 167 | + v && v.floor == v |
| 168 | + end |
| 169 | + |
| 170 | + # Calculates the Heap size as per the Heap ratio |
| 171 | + # |
| 172 | + # @param [Integer] membytes, total memory in bytes |
| 173 | + # @param [Numeric] heapratio, Desired/Default Heap Ratio |
| 174 | + def heap_size_calculator(membytes, heapratio) |
| 175 | + memory_size_minified(membytes * heapratio) |
| 176 | + end |
| 177 | + |
| 178 | + # Calculates the Memory Size in a Minified String Representation |
| 179 | + # |
| 180 | + # @param [Numeric] membytes, calculated heap size |
| 181 | + def memory_size_minified(membytes) |
| 182 | + giga = membytes / 2**(10 * 3) |
| 183 | + mega = membytes / 2**(10 * 2) |
| 184 | + kilo = (membytes / 2**(10 * 1)).round |
| 185 | + if check_is_integer?(giga) |
| 186 | + minified_size_calculator(giga, 'G') |
| 187 | + elsif check_is_integer?(mega) |
| 188 | + minified_size_calculator(mega, 'M') |
| 189 | + elsif check_is_integer?(kilo) |
| 190 | + minified_size_calculator(kilo, 'K') |
| 191 | + end |
| 192 | + end |
| 193 | + |
| 194 | + # Returns the minified memory string |
| 195 | + # |
| 196 | + # @param [Integer] order, calculated memory value |
| 197 | + # @param [String] char, calculated memory unit |
| 198 | + # @return [String] minified memory string |
| 199 | + def minified_size_calculator(order, char) |
| 200 | + order.to_i.to_s + char |
| 201 | + end |
| 202 | + |
| 203 | + # Verifies whether heap ratio is valid |
| 204 | + def heap_ratio_verification(ratio) |
| 205 | + raise 'Invalid heap ratio' unless ratio.is_a? Numeric |
| 206 | + raise 'heap ratio cannot be greater than 100%' unless ratio <= 1 |
| 207 | + ratio |
| 208 | + end |
| 209 | + |
| 210 | + end |
| 211 | + |
| 212 | + end |
| 213 | +end |
0 commit comments