Skip to content

Commit 4db158a

Browse files
author
Glyn Normington
committed
Support Play 2.2
Refactor Play framework to encapsulate the application-specific pieces in a "PlayApp" abstraction defined by the BasePlayApp class. This class has two subclasses: PlayAppPost22 for Play 2.2 and upwards and PlayAppPre22 for Play 2.1.x and earlier (actually no earlier than 2.0 since older versions are not supported). PlayAppPre22 is further subclassed by PlayAppPre22Dist and PlayAppPre22Staged to represent the differences between Play 2.0/2.1 dist and staged applications, respectively. PlayAppFactory isolates the using code (the Play container and some associated frameworks) from the concrete subclasses of BasePlayApp. Play version parsing and the naming requirements for the Play JAR are both tightened up. Play 2.2 support consists of: 1. Looking for a different style of start script. The start script is now present in the bin directory and named after the application. 2. Updating the classpath variable in the start script (for both dist and staged apps, which are now identical in structure in Play 2.2). 3. Supporting Play 2.2 style Java options by pre-pending '-J' to each Java option. 4. Avoiding incompatible minimum and maximum heap sizes. Play 2.2 sets -Xms to a large value by default and when this exceeds our calculated -Xmx the JVM fails to initialise. Since we do not normally specify -Xms, we set this to a low value (currently 2M since 1M is insufficient for the JVM to initialise), but note that we do this for Play 2.2 only. [#58432326]
1 parent 6548d1e commit 4db158a

45 files changed

Lines changed: 1183 additions & 370 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/container-play.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ The Play Container allows Play applications to be run.
33

44
<table>
55
<tr>
6-
<td><strong>Detection Criteria</strong></td><td>The files <tt>start</tt> and <tt>lib/play.play_*.jar</tt> (or <tt>staged/play_*.jar</tt>) exist in the application
6+
<td><strong>Detection Criteria</strong></td><td>The Play start script and the Play runtime JAR exist in the appropriate subdirectories of the application
77
directory or one of its immediate subdirectories (but not in both)</td>
88
</tr>
99
<tr>

docs/util-other.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
# Other Utiltities
22
The buildpack provides a number of other utilities that may help in implementing components.
33

4-
54
## [`JavaBuildpack::Util::GroovyUtils`][]
65
The `GroovyUtils` class provides a set of methods for finding groovy files and determing if they are of any special kind (e.g. they have a main method, they are a pogo, etc.).
76

8-
## [`JavaBuildpack::Util::PlayUtils`][]
9-
The `PlayUtils` class provides a set of methods for determing information about a Play Framework application.
10-
117
## [`JavaBuildpack::Util::Properties`][]
128
The `Properties` class provides a Ruby class that can read in a Java properties file and acts as a `Hash` with that data.
139

@@ -17,7 +13,6 @@ The `ResourceUtils` class provides an abstract around the `resources` directory
1713
## [`JavaBuildpack::Util::ServiceUtils`][]
1814
The `ServiceUtils` class provides a set of methods for finding a given service in the `VCAP_SERVICES` payload.
1915

20-
2116
[`JavaBuildpack::Util::GroovyUtils`]: ../lib/java_buildpack/util/groovy_utils.rb
2217
[`JavaBuildpack::Util::PlayUtils`]: ../lib/java_buildpack/util/play_utils.rb
2318
[`JavaBuildpack::Util::Properties`]: ../lib/java_buildpack/util/properties.rb

lib/java_buildpack/base_component.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
require 'java_buildpack'
1818
require 'java_buildpack/util/application_cache'
19+
require 'java_buildpack/util/library_utils'
1920
require 'java_buildpack/util/shell'
2021

2122
module JavaBuildpack
@@ -69,7 +70,7 @@ def compile
6970
# are expected to read the +context+ values and take them into account when creating the command.
7071
#
7172
# @return [void, String] components other than containers are not expected to return any value. Container
72-
# compoonents are expected to return the command required to run the application.
73+
# components are expected to return the command required to run the application.
7374
def release
7475
fail "Method 'release' must be defined"
7576
end
@@ -105,6 +106,13 @@ def download_jar(version, uri, jar_name, target_directory = @lib_directory, desc
105106
download(version, uri, description) { |file| shell "cp #{file.path} #{File.join(target_directory, jar_name)}" }
106107
end
107108

109+
# Returns the additional libraries.
110+
#
111+
# @param [Array<String>] the paths of JARs in the additional libraries directory
112+
def additional_libraries
113+
JavaBuildpack::Util::LibraryUtils.lib_jars @lib_directory
114+
end
115+
108116
end
109117

110118
end

lib/java_buildpack/container/container_utils.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def self.to_java_opts_s(java_opts)
3333
# Evaluates a value and if it is not +nil+ or empty, prepends it with a space. This can be used to create BASH
3434
# command lines that do not have ugly extra spacing.
3535
#
36-
# @param [String, nil] value the value to evalutate for extra spacing
36+
# @param [String, nil] value the value to evaluate for extra spacing
3737
# @return [String] an empty string if +value+ is +nil+ or empty, otherwise the value prepended with a space
3838
def self.space(value)
3939
value = value.to_s if value.respond_to?(:to_s)
@@ -47,18 +47,18 @@ def self.space(value)
4747
# @param [String] lib_directory the directory that additional libraries are placed in
4848
# @return [Array<String>] the relative paths of the JARs located in the additional libraries directory
4949
def self.libs(root_dir, lib_directory)
50-
libs = []
51-
52-
if lib_directory
53-
root_directory = Pathname.new(root_dir)
54-
55-
libs = Pathname.new(lib_directory).children
56-
.select { |file| file.extname == '.jar' }
57-
.map { |file| file.relative_path_from(root_directory) }
58-
.sort
59-
end
50+
relative_paths(root_dir, JavaBuildpack::Util::LibraryUtils.lib_jars(lib_directory))
51+
end
6052

61-
libs
53+
# Returns an +Array+ containing the relative paths of the given files. The
54+
# paths of these files are relative to the +root_dir+.
55+
#
56+
# @param [String] root_dir the directory relative to which the resultant are calculated
57+
# @param [Array<String>] libs an array of file paths
58+
# @return [Array<String>] the relative paths of the given file paths
59+
def self.relative_paths(root_dir, libs)
60+
root_directory = Pathname.new(root_dir)
61+
libs.map { |lib| lib.relative_path_from(root_directory) }
6262
end
6363

6464
end

lib/java_buildpack/container/play.rb

Lines changed: 17 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
require 'java_buildpack/container/container_utils'
2020
require 'java_buildpack/repository/configured_item'
2121
require 'java_buildpack/util/application_cache'
22-
require 'java_buildpack/util/play_utils'
22+
require 'java_buildpack/util/play_app_factory'
2323
require 'pathname'
2424

2525
module JavaBuildpack::Container
@@ -30,95 +30,46 @@ class Play < JavaBuildpack::BaseComponent
3030
def initialize(context)
3131
super('Play Framework', context)
3232

33-
@play_root = JavaBuildpack::Util::PlayUtils.root(@app_dir)
34-
@version = @play_root ? JavaBuildpack::Util::PlayUtils.version(@play_root) : nil
33+
@play_app = JavaBuildpack::Util::PlayAppFactory.create @app_dir
3534
end
3635

3736
def detect
38-
@version ? id(@version) : nil
37+
if @play_app
38+
version = @play_app.version
39+
version ? id(version) : nil
40+
else
41+
nil
42+
end
3943
end
4044

4145
def compile
42-
shell "chmod +x #{JavaBuildpack::Util::PlayUtils.start_script @play_root}"
43-
add_libs_to_classpath
44-
replace_bootstrap @play_root
46+
@play_app.set_executable
47+
@play_app.add_libs_to_classpath additional_libraries
48+
@play_app.replace_bootstrap BOOTSTRAP_CLASS_NAME
4549
end
4650

4751
def release
48-
@java_opts << "-D#{KEY_HTTP_PORT}=$PORT"
52+
java_opts = @java_opts.clone
53+
java_opts << "-D#{KEY_HTTP_PORT}=$PORT"
4954

5055
path_string = "PATH=#{File.join @java_home, 'bin'}:$PATH"
5156
java_home_string = ContainerUtils.space("JAVA_HOME=#{@java_home}")
52-
start_script_string = ContainerUtils.space(start_script_relative @play_root)
53-
java_opts_string = ContainerUtils.space(ContainerUtils.to_java_opts_s(@java_opts))
57+
start_script_string = ContainerUtils.space(@play_app.start_script_relative)
58+
java_opts_string = ContainerUtils.space(ContainerUtils.to_java_opts_s(@play_app.decorate_java_opts java_opts))
5459

5560
"#{path_string}#{java_home_string}#{start_script_string}#{java_opts_string}"
5661
end
5762

5863
private
5964

60-
KEY_HTTP_PORT = 'http.port'.freeze
61-
62-
def add_libs_to_classpath
63-
if JavaBuildpack::Util::PlayUtils.lib_play_jar @play_root
64-
add_libs_to_dist_classpath
65-
else
66-
add_libs_to_staged_classpath
67-
end
68-
end
69-
70-
def add_libs_to_staged_classpath
71-
# Staged applications add all the JARs in the staged directory to the classpath, so add symbolic links to the staged directory.
72-
# Note: for staged applications, @app_dir = @play_root
73-
link_libs_to_classpath_directory(JavaBuildpack::Util::PlayUtils.staged @play_root)
74-
end
65+
BOOTSTRAP_CLASS_NAME = 'org.cloudfoundry.reconfiguration.play.Bootstrap'.freeze
7566

76-
def link_libs_to_classpath_directory(classpath_directory)
77-
ContainerUtils.libs(@play_root, @lib_directory).each do |lib|
78-
shell "ln -nsf ../#{lib} #{classpath_directory}"
79-
end
80-
end
81-
82-
def add_libs_to_dist_classpath
83-
# Dist applications either list JARs in a classpath variable (e.g. in Play 2.1.3) or on a -cp parameter (e.g. in Play 2.0),
84-
# so add to the appropriate list.
85-
# Note: for dist applications, @play_root is an immediate subdirectory of @app_dir, so @app_dir is equivalent to @play_root/..
86-
script_dir_relative_path = Pathname.new(@app_dir).relative_path_from(Pathname.new(@play_root)).to_s
87-
88-
additional_classpath = ContainerUtils.libs(@app_dir, @lib_directory).map do |lib|
89-
"$scriptdir/#{script_dir_relative_path}/#{lib}"
90-
end
91-
92-
result = update_file JavaBuildpack::Util::PlayUtils.start_script(@play_root), /^classpath=\"(.*)\"$/, "classpath=\"#{additional_classpath.join(':')}:\\1\""
93-
unless result
94-
link_libs_to_classpath_directory(JavaBuildpack::Util::PlayUtils.lib @play_root)
95-
end
96-
end
67+
KEY_HTTP_PORT = 'http.port'.freeze
9768

9869
def id(version)
9970
"#{@parsable_component_name}=#{version}"
10071
end
10172

102-
def replace_bootstrap(root)
103-
update_file JavaBuildpack::Util::PlayUtils.start_script(root), /play\.core\.server\.NettyServer/, 'org.cloudfoundry.reconfiguration.play.Bootstrap'
104-
end
105-
106-
def start_script_relative(play_root)
107-
"./#{Pathname.new(JavaBuildpack::Util::PlayUtils.start_script(play_root)).relative_path_from(Pathname.new(@app_dir)).to_s}"
108-
end
109-
110-
def update_file(file_name, pattern, replacement)
111-
content = File.open(file_name, 'r') { |file| file.read }
112-
result = content.gsub! pattern, replacement
113-
114-
File.open(file_name, 'w') do |file|
115-
file.write content
116-
file.fsync
117-
end
118-
119-
result
120-
end
121-
12273
end
12374

12475
end

lib/java_buildpack/framework/play_auto_reconfiguration.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
require 'java_buildpack/framework'
1818
require 'java_buildpack/repository/configured_item'
1919
require 'java_buildpack/util/application_cache'
20-
require 'java_buildpack/util/play_utils'
20+
require 'java_buildpack/util/play_app_factory'
2121
require 'java_buildpack/versioned_dependency_component'
2222

2323
module JavaBuildpack::Framework
@@ -41,7 +41,7 @@ def release
4141
protected
4242

4343
def supports?
44-
JavaBuildpack::Util::PlayUtils.root(@app_dir)
44+
JavaBuildpack::Util::PlayAppFactory.create @app_dir
4545
end
4646

4747
private

lib/java_buildpack/framework/play_jpa_plugin.rb

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
require 'java_buildpack/framework'
1818
require 'java_buildpack/repository/configured_item'
1919
require 'java_buildpack/util/application_cache'
20-
require 'java_buildpack/util/play_utils'
20+
require 'java_buildpack/util/play_app_factory'
2121
require 'java_buildpack/versioned_dependency_component'
2222

2323
module JavaBuildpack::Framework
@@ -44,8 +44,8 @@ def release
4444
def supports?
4545
candidate = false
4646

47-
root = JavaBuildpack::Util::PlayUtils.root @app_dir
48-
candidate = uses_jpa?(root) || play20?(root) if root
47+
play_app = JavaBuildpack::Util::PlayAppFactory.create @app_dir
48+
candidate = uses_jpa?(play_app) || play20?(play_app.version) if play_app
4949

5050
candidate
5151
end
@@ -58,14 +58,12 @@ def jar_name
5858
"#{id @version}.jar"
5959
end
6060

61-
def play20?(root)
62-
JavaBuildpack::Util::PlayUtils.version(root) =~ /2.0.[\d]+/
61+
def play20?(play_version)
62+
play_version =~ /^2\.0(\.[\d]+)?$/
6363
end
6464

65-
def uses_jpa?(root)
66-
lib = File.join JavaBuildpack::Util::PlayUtils.lib(root), PLAY_JPA_PLUGIN_JAR
67-
staged = File.join JavaBuildpack::Util::PlayUtils.staged(root), PLAY_JPA_PLUGIN_JAR
68-
Dir[lib, staged].first
65+
def uses_jpa?(play_app)
66+
play_app.contains? PLAY_JPA_PLUGIN_JAR
6967
end
7068

7169
end

0 commit comments

Comments
 (0)