Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
ba2ea301
Commit
ba2ea301
authored
Apr 09, 2015
by
Phillip Webb
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'gh-1117'
parents
ffc5d565
ed57adb5
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
907 additions
and
39 deletions
+907
-39
build-tool-plugins.adoc
spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc
+12
-0
deployment.adoc
spring-boot-docs/src/main/asciidoc/deployment.adoc
+91
-12
documentation-overview.adoc
...g-boot-docs/src/main/asciidoc/documentation-overview.adoc
+3
-4
index.adoc
spring-boot-docs/src/main/asciidoc/index.adoc
+1
-1
production-ready-features.adoc
...oot-docs/src/main/asciidoc/production-ready-features.adoc
+2
-2
using-spring-boot.adoc
spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc
+2
-2
SpringBootPluginExtension.groovy
...ingframework/boot/gradle/SpringBootPluginExtension.groovy
+20
-0
RepackageTask.java
.../springframework/boot/gradle/repackage/RepackageTask.java
+17
-4
DefaultLaunchScript.java
...pringframework/boot/loader/tools/DefaultLaunchScript.java
+111
-0
JarWriter.java
...java/org/springframework/boot/loader/tools/JarWriter.java
+34
-1
LaunchScript.java
...a/org/springframework/boot/loader/tools/LaunchScript.java
+33
-0
Repackager.java
...ava/org/springframework/boot/loader/tools/Repackager.java
+18
-6
launch.script
...urces/org/springframework/boot/loader/tools/launch.script
+164
-0
DefaultLaunchScriptTests.java
...framework/boot/loader/tools/DefaultLaunchScriptTests.java
+111
-0
RepackagerTests.java
...rg/springframework/boot/loader/tools/RepackagerTests.java
+34
-3
pom.xml
...ring-boot-maven-plugin/src/it/jar-custom-launcher/pom.xml
+61
-0
custom.script
...gin/src/it/jar-custom-launcher/src/launcher/custom.script
+3
-0
SampleApplication.java
...om-launcher/src/main/java/org/test/SampleApplication.java
+24
-0
verify.groovy
...oot-maven-plugin/src/it/jar-custom-launcher/verify.groovy
+7
-0
pom.xml
...pring-boot-maven-plugin/src/it/jar-non-executable/pom.xml
+58
-0
SampleApplication.java
...-executable/src/main/java/org/test/SampleApplication.java
+24
-0
verify.groovy
...boot-maven-plugin/src/it/jar-non-executable/verify.groovy
+7
-0
verify.groovy
...t-tools/spring-boot-maven-plugin/src/it/jar/verify.groovy
+1
-1
RepackageMojo.java
...in/java/org/springframework/boot/maven/RepackageMojo.java
+36
-1
Verify.java
.../src/test/java/org/springframework/boot/maven/Verify.java
+33
-2
No files found.
spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc
View file @
ba2ea301
...
@@ -383,6 +383,18 @@ want the other Boot features but not this one)
...
@@ -383,6 +383,18 @@ want the other Boot features but not this one)
|`
customConfiguration
`
|`
customConfiguration
`
|
The
name
of
the
custom
configuration
which
is
used
to
populate
the
nested
lib
directory
|
The
name
of
the
custom
configuration
which
is
used
to
populate
the
nested
lib
directory
(
without
specifying
this
you
get
all
compile
and
runtime
dependencies
).
(
without
specifying
this
you
get
all
compile
and
runtime
dependencies
).
|`
executable
`
|
Boolean
flag
to
indicate
if
jar
files
are
fully
executable
on
Unix
like
operating
systems
.
Defaults
to
`
true
`.
|`
embeddedLaunchScript
`
|
The
embedded
launch
script
to
prepend
to
the
front
of
the
jar
if
it
is
fully
executable
.
If
not
specified
the
'Spring Boot'
default
script
will
be
used
.
|`
embeddedLaunchScriptProperties
`
|
Additional
properties
that
to
be
expanded
in
the
launch
script
.
The
default
script
supports
a
`
mode
`
property
which
can
contain
the
values
`
auto
`,
`
service
`
or
`
run
`.
|===
|===
...
...
spring-boot-docs/src/main/asciidoc/
cloud-
deployment.adoc
→
spring-boot-docs/src/main/asciidoc/deployment.adoc
View file @
ba2ea301
[[
cloud-
deployment]]
[[deployment]]
=
Deploying to the cloud
=
= Deploying Spring Boot applications
[partintro]
[partintro]
--
--
Spring Boot's flexible packaging options provide a great deal of choice when it comes to
deploying your application. You can easily deploy Spring Boot applications to a variety
of cloud platforms, to a container images (such as Docker) or to virtual/real machines.
This section covers some of the more common deployment scenarios.
--
[[cloud-deployment]]
== Deploying to the cloud
Spring Boot's executable jars are ready-made for most popular cloud PaaS
Spring Boot's executable jars are ready-made for most popular cloud PaaS
(platform-as-a-service) providers. These providers tend to require that you
(platform-as-a-service) providers. These providers tend to require that you
"`bring your own container`"; they manage application processes (not Java applications
"`bring your own container`"; they manage application processes (not Java applications
...
@@ -23,12 +35,11 @@ to run packaged within it.
...
@@ -23,12 +35,11 @@ to run packaged within it.
In this section we'll look at what it takes to get the
In this section we'll look at what it takes to get the
<<getting-started.adoc#getting-started-first-application, simple application that we
<<getting-started.adoc#getting-started-first-application, simple application that we
developed>> in the "`Getting Started`" section up and running in the Cloud.
developed>> in the "`Getting Started`" section up and running in the Cloud.
--
[[cloud-deployment-cloud-foundry]]
[[cloud-deployment-cloud-foundry]]
== Cloud Foundry
==
=
Cloud Foundry
Cloud Foundry provides default buildpacks that come into play if no other buildpack is
Cloud Foundry provides default buildpacks that come into play if no other buildpack is
specified. The Cloud Foundry https://github.com/cloudfoundry/java-buildpack[Java buildpack]
specified. The Cloud Foundry https://github.com/cloudfoundry/java-buildpack[Java buildpack]
has excellent support for Spring applications, including Spring Boot. You can deploy
has excellent support for Spring applications, including Spring Boot. You can deploy
...
@@ -102,7 +113,7 @@ able to hit the application at the URI given, in this case
...
@@ -102,7 +113,7 @@ able to hit the application at the URI given, in this case
[[cloud-deployment-cloud-foundry-services]]
[[cloud-deployment-cloud-foundry-services]]
=== Binding to services
===
=
Binding to services
By default, metadata about the running application as well as service connection
By default, metadata about the running application as well as service connection
information is exposed to the application as environment variables (for example:
information is exposed to the application as environment variables (for example:
`$VCAP_SERVICES`). This architecture decision is due to Cloud Foundry's polyglot
`$VCAP_SERVICES`). This architecture decision is due to Cloud Foundry's polyglot
...
@@ -142,7 +153,7 @@ auto-configuration support and a `spring-boot-starter-cloud-connectors` starter
...
@@ -142,7 +153,7 @@ auto-configuration support and a `spring-boot-starter-cloud-connectors` starter
[[cloud-deployment-heroku]]
[[cloud-deployment-heroku]]
== Heroku
==
=
Heroku
Heroku is another popular PaaS platform. To customize Heroku builds, you provide a
Heroku is another popular PaaS platform. To customize Heroku builds, you provide a
`Procfile`, which provides the incantation required to deploy an application. Heroku
`Procfile`, which provides the incantation required to deploy an application. Heroku
assigns a `port` for the Java application to use and then ensures that routing to the
assigns a `port` for the Java application to use and then ensures that routing to the
...
@@ -225,7 +236,7 @@ Your application should now be up and running on Heroku.
...
@@ -225,7 +236,7 @@ Your application should now be up and running on Heroku.
[[cloud-deployment-openshift]]
[[cloud-deployment-openshift]]
== Openshift
==
=
Openshift
https://www.openshift.com/[Openshift] is the RedHat public (and enterprise) PaaS solution.
https://www.openshift.com/[Openshift] is the RedHat public (and enterprise) PaaS solution.
Like Heroku, it works by running scripts triggered by git commits, so you can script
Like Heroku, it works by running scripts triggered by git commits, so you can script
the launching of a Spring Boot application in pretty much any way you like as long as the
the launching of a Spring Boot application in pretty much any way you like as long as the
...
@@ -288,14 +299,85 @@ run the app.
...
@@ -288,14 +299,85 @@ run the app.
[[cloud-deployment-gae]]
[[cloud-deployment-gae]]
== Google App Engine
==
=
Google App Engine
Google App Engine is tied to the Servlet 2.5 API, so you can't deploy a Spring Application
Google App Engine is tied to the Servlet 2.5 API, so you can't deploy a Spring Application
there without some modifications. See the <<howto.adoc#howto-servlet-2-5, Servlet 2.5 section>>
there without some modifications. See the <<howto.adoc#howto-servlet-2-5, Servlet 2.5 section>>
of this guide.
of this guide.
[[deployment-service]]
== Installing Spring Boot applications
In additional to running Spring Boot applications using `java -jar` it is also possible
to execute applications directly on Unix systems (Linux, OSX, FreeBSD etc). This makes it
very easy to install and manage Spring Boot applications in common production
environments. As long as you are generating '`fully executable`' jars from your build, and
you are not using a custom `embeddedLaunchScript`, the following techniques can be used.
=== Unix/Linux services
Spring Boot application can be easily started as Unix/Linux services using either `init.d`
or `systemd`.
==== Installation as a init.d (system v) service
The default executable script that is embedded into Spring Boot executable jars will act
as an `init.d` script when it is symlinked to `/etc/init.d`. The standard `start`, `stop`,
`restart` and `status` commands can be used. The script supports the following features:
* Starts the services as the user that owns the jar file
* Tracks application PIDs using `/var/run/<appname>.pid`
* Writes console logs to `/var/log/<appname>.log`
Assuming that you have a Spring Boot application installed in `/var/myapp`, to install a
Spring Boot application as an `init.d` service simply create a symlink:
[indent=0,subs="verbatim,quotes,attributes"]
----
$ sudo link -s /var/myapp/myapp.jar /etc/init.d/myapp
----
TIP: It is advisable to create a specific user account to run you application. Ensure
that you have set the owner of the jar file using `chown` before installing your service.
[[cloud-deployment-whats-next]]
Once installed, you can start and stop the service in the usual way. You can also flag the
application to start automatically using your standard operating system tools. For example,
if you use Debian:
[indent=0,subs="verbatim,quotes,attributes"]
----
$ update-rc.d myapp defaults <priority>
----
==== Installation as a systemd service
Systemd is the successor to `init.d` scripts, and now being used by many many modern Linux
distributions. Although you can continue to use `init.d` script with `systemd`, it is also
possible to launch Spring Boot applications using `systemd` '`service`' scripts.
For example, to run a Spring Boot application installed in `var/myapp` you can add the
following script in `/etc/systemd/system/myapp.service`:
[indent=0]
----
[Unit]
Description=myapp
After=syslog.target
[Service]
ExecStart=/var/myapp/myapp.jar
[Install]
WantedBy=multi-user.target
----
TIP: Remember to change the `Description` and `ExecStart` fields for your application.
[[deployment-whats-next]]
== What to read next
== What to read next
Check out the http://www.cloudfoundry.com/[Cloud Foundry], https://www.heroku.com/[Heroku]
Check out the http://www.cloudfoundry.com/[Cloud Foundry], https://www.heroku.com/[Heroku]
and https://www.openshift.com[Openshift] web sites for more information about the kinds of
and https://www.openshift.com[Openshift] web sites for more information about the kinds of
...
@@ -307,6 +389,3 @@ The next section goes on to cover the _<<spring-boot-cli.adoc#cli, Spring Boot C
...
@@ -307,6 +389,3 @@ The next section goes on to cover the _<<spring-boot-cli.adoc#cli, Spring Boot C
or you can jump ahead to read about
or you can jump ahead to read about
_<<build-tool-plugins.adoc#build-tool-plugins, build tool plugins>>_.
_<<build-tool-plugins.adoc#build-tool-plugins, build tool plugins>>_.
spring-boot-docs/src/main/asciidoc/documentation-overview.adoc
View file @
ba2ea301
...
@@ -136,10 +136,9 @@ When you're ready to push your Spring Boot application to production, we've got
...
@@ -136,10 +136,9 @@ When you're ready to push your Spring Boot application to production, we've got
== Advanced topics
== Advanced topics
Lastly, we have a few topics for the more advanced user.
Lastly, we have a few topics for the more advanced user.
* *Deploy to the cloud:*
* *Deploy Spring Boot Applications:*
<<cloud-deployment.adoc#cloud-deployment-cloud-foundry, Cloud Foundry>> |
<<deployment.adoc#cloud-deployment, Cloud Deployment>> |
<<cloud-deployment.adoc#cloud-deployment-heroku, Heroku>> |
<<deployment.adoc#deployment-service, OS Service>>
<<cloud-deployment.adoc#cloud-deployment-cloudbees, CloudBees>>
* *Build tool plugins:*
* *Build tool plugins:*
<<build-tool-plugins.adoc#build-tool-plugins-maven-plugin, Maven>> |
<<build-tool-plugins.adoc#build-tool-plugins-maven-plugin, Maven>> |
<<build-tool-plugins.adoc#build-tool-plugins-gradle-plugin, Gradle>>
<<build-tool-plugins.adoc#build-tool-plugins-gradle-plugin, Gradle>>
...
...
spring-boot-docs/src/main/asciidoc/index.adoc
View file @
ba2ea301
...
@@ -45,7 +45,7 @@ include::getting-started.adoc[]
...
@@ -45,7 +45,7 @@ include::getting-started.adoc[]
include::using-spring-boot.adoc[]
include::using-spring-boot.adoc[]
include::spring-boot-features.adoc[]
include::spring-boot-features.adoc[]
include::production-ready-features.adoc[]
include::production-ready-features.adoc[]
include::
cloud-
deployment.adoc[]
include::deployment.adoc[]
include::spring-boot-cli.adoc[]
include::spring-boot-cli.adoc[]
include::build-tool-plugins.adoc[]
include::build-tool-plugins.adoc[]
include::howto.adoc[]
include::howto.adoc[]
...
...
spring-boot-docs/src/main/asciidoc/production-ready-features.adoc
View file @
ba2ea301
...
@@ -1043,7 +1043,7 @@ If you want to explore some of the concepts discussed in this chapter, you can t
...
@@ -1043,7 +1043,7 @@ If you want to explore some of the concepts discussed in this chapter, you can t
look at the actuator {github-code}/spring-boot-samples[sample applications]. You also
look at the actuator {github-code}/spring-boot-samples[sample applications]. You also
might want to read about graphing tools such as http://graphite.wikidot.com/[Graphite].
might want to read about graphing tools such as http://graphite.wikidot.com/[Graphite].
Otherwise, you can continue on, to read about <<
cloud-deployment.adoc#cloud-
deployment,
Otherwise, you can continue on, to read about <<
deployment.adoc#
deployment,
'
`
cloud
deployment
options
`
'>> or jump ahead
'
`
deployment
options
`
'>> or jump ahead
for some in-depth information about Spring Boot'
s
for some in-depth information about Spring Boot'
s
_
<<
build
-
tool
-
plugins
.
adoc
#
build
-
tool
-
plugins
,
build
tool
plugins
>>
_
.
_
<<
build
-
tool
-
plugins
.
adoc
#
build
-
tool
-
plugins
,
build
tool
plugins
>>
_
.
spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc
View file @
ba2ea301
...
@@ -5,8 +5,8 @@
...
@@ -5,8 +5,8 @@
[
partintro
]
[
partintro
]
--
--
This
section
goes
into
more
detail
about
how
you
should
use
Spring
Boot
.
It
covers
topics
This
section
goes
into
more
detail
about
how
you
should
use
Spring
Boot
.
It
covers
topics
such
as
build
systems
,
auto
-
configuration
and
run
/
deployment
options
.
We
also
cover
some
such
as
build
systems
,
auto
-
configuration
and
how
to
run
your
applications
.
We
also
cover
Spring
Boot
best
practices
.
Although
there
is
nothing
particularly
special
about
some
Spring
Boot
best
practices
.
Although
there
is
nothing
particularly
special
about
Spring
Boot
(
it
is
just
another
library
that
you
can
consume
),
there
are
a
few
Spring
Boot
(
it
is
just
another
library
that
you
can
consume
),
there
are
a
few
recommendations
that
,
when
followed
,
will
make
your
development
process
just
a
recommendations
that
,
when
followed
,
will
make
your
development
process
just
a
little
easier
.
little
easier
.
...
...
spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/SpringBootPluginExtension.groovy
View file @
ba2ea301
...
@@ -16,6 +16,9 @@
...
@@ -16,6 +16,9 @@
package
org.springframework.boot.gradle
package
org.springframework.boot.gradle
import
java.io.File
;
import
java.util.Map
;
import
org.springframework.boot.loader.tools.Layout
import
org.springframework.boot.loader.tools.Layout
import
org.springframework.boot.loader.tools.Layouts
import
org.springframework.boot.loader.tools.Layouts
...
@@ -130,4 +133,21 @@ public class SpringBootPluginExtension {
...
@@ -130,4 +133,21 @@ public class SpringBootPluginExtension {
*/
*/
boolean
applyExcludeRules
=
true
;
boolean
applyExcludeRules
=
true
;
/**
* If a fully executable jar (for *nix machines) should be generated by prepending a
* launch script to the jar.
*/
boolean
executable
=
true
;
/**
* The embedded launch script to prepend to the front of the jar if it is fully
* executable. If not specified the 'Spring Boot' default script will be used.
*/
File
embeddedLaunchScript
;
/**
* Properties that should be expanded in the embedded launch script.
*/
Map
<
String
,
String
>
embeddedLaunchScriptProperties
;
}
}
spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java
View file @
ba2ea301
...
@@ -28,6 +28,8 @@ import org.gradle.api.Project;
...
@@ -28,6 +28,8 @@ import org.gradle.api.Project;
import
org.gradle.api.tasks.TaskAction
;
import
org.gradle.api.tasks.TaskAction
;
import
org.gradle.api.tasks.bundling.Jar
;
import
org.gradle.api.tasks.bundling.Jar
;
import
org.springframework.boot.gradle.SpringBootPluginExtension
;
import
org.springframework.boot.gradle.SpringBootPluginExtension
;
import
org.springframework.boot.loader.tools.DefaultLaunchScript
;
import
org.springframework.boot.loader.tools.LaunchScript
;
import
org.springframework.boot.loader.tools.Repackager
;
import
org.springframework.boot.loader.tools.Repackager
;
import
org.springframework.util.FileCopyUtils
;
import
org.springframework.util.FileCopyUtils
;
...
@@ -80,6 +82,10 @@ public class RepackageTask extends DefaultTask {
...
@@ -80,6 +82,10 @@ public class RepackageTask extends DefaultTask {
this
.
classifier
=
classifier
;
this
.
classifier
=
classifier
;
}
}
void
setOutputFile
(
File
file
)
{
this
.
outputFile
=
file
;
}
@TaskAction
@TaskAction
public
void
repackage
()
{
public
void
repackage
()
{
Project
project
=
getProject
();
Project
project
=
getProject
();
...
@@ -170,7 +176,8 @@ public class RepackageTask extends DefaultTask {
...
@@ -170,7 +176,8 @@ public class RepackageTask extends DefaultTask {
}
}
repackager
.
setBackupSource
(
this
.
extension
.
isBackupSource
());
repackager
.
setBackupSource
(
this
.
extension
.
isBackupSource
());
try
{
try
{
repackager
.
repackage
(
file
,
this
.
libraries
);
LaunchScript
launchScript
=
getLaunchScript
();
repackager
.
repackage
(
file
,
this
.
libraries
,
launchScript
);
}
}
catch
(
IOException
ex
)
{
catch
(
IOException
ex
)
{
throw
new
IllegalStateException
(
ex
.
getMessage
(),
ex
);
throw
new
IllegalStateException
(
ex
.
getMessage
(),
ex
);
...
@@ -201,6 +208,15 @@ public class RepackageTask extends DefaultTask {
...
@@ -201,6 +208,15 @@ public class RepackageTask extends DefaultTask {
getLogger
().
info
(
"Setting mainClass: "
+
mainClass
);
getLogger
().
info
(
"Setting mainClass: "
+
mainClass
);
repackager
.
setMainClass
(
mainClass
);
repackager
.
setMainClass
(
mainClass
);
}
}
private
LaunchScript
getLaunchScript
()
throws
IOException
{
if
(
this
.
extension
.
isExecutable
())
{
return
new
DefaultLaunchScript
(
this
.
extension
.
getEmbeddedLaunchScript
(),
this
.
extension
.
getEmbeddedLaunchScriptProperties
());
}
return
null
;
}
}
}
/**
/**
...
@@ -228,10 +244,7 @@ public class RepackageTask extends DefaultTask {
...
@@ -228,10 +244,7 @@ public class RepackageTask extends DefaultTask {
}
}
}
}
}
}
}
void
setOutputFile
(
File
file
)
{
this
.
outputFile
=
file
;
}
}
}
}
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultLaunchScript.java
0 → 100644
View file @
ba2ea301
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed 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.
*/
package
org
.
springframework
.
boot
.
loader
.
tools
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.nio.charset.Charset
;
import
java.util.Map
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* Default implementation of {@link LaunchScript}. Provides the default Spring Boot launch
* script or can load a specific script File. Also support mustache style template
* expansion of the form <code>{{name:default}}</code>.
*
* @author Phillip Webb
* @since 1.3.0
*/
public
class
DefaultLaunchScript
implements
LaunchScript
{
private
static
final
Charset
UTF_8
=
Charset
.
forName
(
"UTF-8"
);
private
static
final
int
BUFFER_SIZE
=
4096
;
private
static
final
Pattern
PLACEHOLDER_PATTERN
=
Pattern
.
compile
(
"\\{\\{(\\w+)(:.*?)?\\}\\}"
);
private
final
String
content
;
/**
* Create a new {@link DefaultLaunchScript} instance.
* @param file the source script file or {@code null} to use the default
* @param properties an optional set of script properties used for variable expansion
* @throws IOException if the script cannot be loaded
*/
public
DefaultLaunchScript
(
File
file
,
Map
<?,
?>
properties
)
throws
IOException
{
String
content
=
loadContent
(
file
);
this
.
content
=
expandPlaceholders
(
content
,
properties
);
}
private
String
loadContent
(
File
file
)
throws
IOException
{
if
(
file
==
null
)
{
return
loadContent
(
getClass
().
getResourceAsStream
(
"launch.script"
));
}
return
loadContent
(
new
FileInputStream
(
file
));
}
private
String
loadContent
(
InputStream
inputStream
)
throws
IOException
{
try
{
ByteArrayOutputStream
outputStream
=
new
ByteArrayOutputStream
();
copy
(
inputStream
,
outputStream
);
return
new
String
(
outputStream
.
toByteArray
(),
UTF_8
);
}
finally
{
inputStream
.
close
();
}
}
private
void
copy
(
InputStream
inputStream
,
OutputStream
outputStream
)
throws
IOException
{
byte
[]
buffer
=
new
byte
[
BUFFER_SIZE
];
int
bytesRead
=
-
1
;
while
((
bytesRead
=
inputStream
.
read
(
buffer
))
!=
-
1
)
{
outputStream
.
write
(
buffer
,
0
,
bytesRead
);
}
outputStream
.
flush
();
}
private
String
expandPlaceholders
(
String
content
,
Map
<?,
?>
properties
)
{
StringBuffer
expanded
=
new
StringBuffer
();
Matcher
matcher
=
PLACEHOLDER_PATTERN
.
matcher
(
content
);
while
(
matcher
.
find
())
{
String
name
=
matcher
.
group
(
1
);
String
value
=
matcher
.
group
(
2
);
if
(
properties
!=
null
&&
properties
.
containsKey
(
name
))
{
value
=
(
String
)
properties
.
get
(
name
);
}
else
{
value
=
(
value
==
null
?
matcher
.
group
(
0
)
:
value
.
substring
(
1
));
}
matcher
.
appendReplacement
(
expanded
,
value
);
}
matcher
.
appendTail
(
expanded
);
return
expanded
.
toString
();
}
@Override
public
byte
[]
toByteArray
()
{
return
this
.
content
.
getBytes
(
UTF_8
);
}
}
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java
View file @
ba2ea301
...
@@ -27,6 +27,9 @@ import java.io.IOException;
...
@@ -27,6 +27,9 @@ import java.io.IOException;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.net.URL
;
import
java.net.URL
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.attribute.PosixFilePermission
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Enumeration
;
import
java.util.Enumeration
;
import
java.util.HashSet
;
import
java.util.HashSet
;
...
@@ -63,7 +66,37 @@ public class JarWriter {
...
@@ -63,7 +66,37 @@ public class JarWriter {
* @throws FileNotFoundException
* @throws FileNotFoundException
*/
*/
public
JarWriter
(
File
file
)
throws
FileNotFoundException
,
IOException
{
public
JarWriter
(
File
file
)
throws
FileNotFoundException
,
IOException
{
this
.
jarOutput
=
new
JarOutputStream
(
new
FileOutputStream
(
file
));
this
(
file
,
null
);
}
/**
* Create a new {@link JarWriter} instance.
* @param file the file to write
* @param launchScript an optional launch script to prepend to the front of the jar
* @throws IOException
* @throws FileNotFoundException
*/
public
JarWriter
(
File
file
,
LaunchScript
launchScript
)
throws
FileNotFoundException
,
IOException
{
FileOutputStream
fileOutputStream
=
new
FileOutputStream
(
file
);
if
(
launchScript
!=
null
)
{
fileOutputStream
.
write
(
launchScript
.
toByteArray
());
setExecutableFilePermission
(
file
);
}
this
.
jarOutput
=
new
JarOutputStream
(
fileOutputStream
);
}
private
void
setExecutableFilePermission
(
File
file
)
{
try
{
Path
path
=
file
.
toPath
();
Set
<
PosixFilePermission
>
permissions
=
new
HashSet
<
PosixFilePermission
>(
Files
.
getPosixFilePermissions
(
path
));
permissions
.
add
(
PosixFilePermission
.
OWNER_EXECUTE
);
Files
.
setPosixFilePermissions
(
path
,
permissions
);
}
catch
(
Throwable
ex
)
{
// Ignore and continue creating the jar
}
}
}
/**
/**
...
...
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LaunchScript.java
0 → 100644
View file @
ba2ea301
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed 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.
*/
package
org
.
springframework
.
boot
.
loader
.
tools
;
/**
* A script that can be prepended to the front of a JAR file to make it executable.
*
* @author Phillip Webb
* @since 1.3.0
*/
public
interface
LaunchScript
{
/**
* The the content of the launch script as a byte array.
* @return the script bytes
*/
byte
[]
toByteArray
();
}
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java
View file @
ba2ea301
...
@@ -104,17 +104,29 @@ public class Repackager {
...
@@ -104,17 +104,29 @@ public class Repackager {
* @throws IOException
* @throws IOException
*/
*/
public
void
repackage
(
File
destination
,
Libraries
libraries
)
throws
IOException
{
public
void
repackage
(
File
destination
,
Libraries
libraries
)
throws
IOException
{
repackage
(
destination
,
libraries
,
null
);
}
/**
* Repackage to the given destination so that it can be launched using '
* {@literal java -jar}'
* @param destination the destination file (may be the same as the source)
* @param libraries the libraries required to run the archive
* @param launchScript an optional launch script prepended to the front of the jar
* @throws IOException
* @since 1.3.0
*/
public
void
repackage
(
File
destination
,
Libraries
libraries
,
LaunchScript
launchScript
)
throws
IOException
{
if
(
destination
==
null
||
destination
.
isDirectory
())
{
if
(
destination
==
null
||
destination
.
isDirectory
())
{
throw
new
IllegalArgumentException
(
"Invalid destination"
);
throw
new
IllegalArgumentException
(
"Invalid destination"
);
}
}
if
(
libraries
==
null
)
{
if
(
libraries
==
null
)
{
throw
new
IllegalArgumentException
(
"Libraries must not be null"
);
throw
new
IllegalArgumentException
(
"Libraries must not be null"
);
}
}
if
(
alreadyRepackaged
())
{
if
(
alreadyRepackaged
())
{
return
;
return
;
}
}
destination
=
destination
.
getAbsoluteFile
();
destination
=
destination
.
getAbsoluteFile
();
File
workingSource
=
this
.
source
;
File
workingSource
=
this
.
source
;
if
(
this
.
source
.
equals
(
destination
))
{
if
(
this
.
source
.
equals
(
destination
))
{
...
@@ -127,7 +139,7 @@ public class Repackager {
...
@@ -127,7 +139,7 @@ public class Repackager {
try
{
try
{
JarFile
jarFileSource
=
new
JarFile
(
workingSource
);
JarFile
jarFileSource
=
new
JarFile
(
workingSource
);
try
{
try
{
repackage
(
jarFileSource
,
destination
,
libraries
);
repackage
(
jarFileSource
,
destination
,
libraries
,
launchScript
);
}
}
finally
{
finally
{
jarFileSource
.
close
();
jarFileSource
.
close
();
...
@@ -152,9 +164,9 @@ public class Repackager {
...
@@ -152,9 +164,9 @@ public class Repackager {
}
}
}
}
private
void
repackage
(
JarFile
sourceJar
,
File
destination
,
Libraries
libraries
)
private
void
repackage
(
JarFile
sourceJar
,
File
destination
,
Libraries
libraries
,
throws
IOException
{
LaunchScript
launchScript
)
throws
IOException
{
final
JarWriter
writer
=
new
JarWriter
(
destination
);
final
JarWriter
writer
=
new
JarWriter
(
destination
,
launchScript
);
try
{
try
{
final
Set
<
String
>
seen
=
new
HashSet
<
String
>();
final
Set
<
String
>
seen
=
new
HashSet
<
String
>();
writer
.
writeManifest
(
buildManifest
(
sourceJar
));
writer
.
writeManifest
(
buildManifest
(
sourceJar
));
...
...
spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script
0 → 100644
View file @
ba2ea301
#!/bin/bash
#
# . ____ _ __ _ _
# /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
# ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
# \\/ ___)| |_)| | | | | || (_| | ) ) ) )
# ' |____| .__|_| |_|_| |_\__, | / / / /
# =========|_|==============|___/=/_/_/_/
# :: Spring Boot Startup Script ::
#
WORKING_DIR
=
"
$(
pwd
)
"
PID_FOLDER
=
"/var/run"
USER_PID_FOLDER
=
"/tmp"
LOG_FOLDER
=
"/var/log"
USER_LOG_FOLDER
=
"/tmp"
# Setup defaults
[[
-z
"
$mode
"
]]
&&
mode
=
"{{mode:auto}}"
# modes are "auto", "service" or "run"
# ANSI Colors
echoRed
()
{
echo
$'
\e
[0;31m'
$1
$'
\e
[0m'
;
}
echoGreen
()
{
echo
$'
\e
[0;32m'
$1
$'
\e
[0m'
;
}
echoYellow
()
{
echo
$'
\e
[0;33m'
$1
$'
\e
[0m'
;
}
# Follow symlinks to find the real jar and detect init.d script
cd
$(
dirname
"
$0
"
)
[[
-z
"
$jarfile
"
]]
&&
jarfile
=
$(
pwd
)
/
$(
basename
"
$0
"
)
while
[[
-L
"
$jarfile
"
]]
;
do
[[
"
$jarfile
"
=
~
"init.d"
]]
&&
init_script
=
$(
basename
"
$jarfile
"
)
jarfile
=
$(
readlink
"
$jarfile
"
)
cd
$(
dirname
"
$jarfile
"
)
jarfile
=
$(
pwd
)
/
$(
basename
"
$jarfile
"
)
done
cd
"
$WORKING_DIR
"
# Determine the script mode
action
=
"run"
if
[[
"
$mode
"
==
"auto"
&&
-n
"
$init_script
"
]]
||
[[
"
$mode
"
==
"service"
]]
;
then
action
=
"
$1
"
shift
fi
# Create an identity for log/pid files
if
[[
-n
"
$init_script
"
]]
;
then
identity
=
"
${
init_script
}
"
else
jar_folder
=
$(
dirname
"
$jarfile
"
)
identity
=
$(
basename
"
${
jarfile
%.*
}
"
)
_
${
jar_folder
//\//
}
fi
# Build the pid and log filenames
if
[[
-n
"
$init_script
"
]]
;
then
pid_file
=
"
$PID_FOLDER
/
${
identity
}
/
${
identity
}
.pid"
log_file
=
"
$LOG_FOLDER
/
${
identity
}
.log"
else
pid_file
=
"
$USER_PID_FOLDER
/
${
identity
}
.pid"
log_file
=
"
$USER_LOG_FOLDER
/
${
identity
}
.log"
fi
# Determine the user to run as
[[
$(
id
-u
)
==
"0"
]]
&&
run_user
=
$(
ls
-ld
"
$jarfile
"
|
awk
'{print $3}'
)
# Find Java
if
type
-p
java 2>&1> /dev/null
;
then
javaexe
=
java
elif
[[
-n
"
$JAVA_HOME
"
]]
&&
[[
-x
"
$JAVA_HOME
/bin/java"
]]
;
then
javaexe
=
"
$JAVA_HOME
/bin/java"
elif
[[
-x
"/usr/bin/java"
]]
;
then
javaexe
=
"/usr/bin/java"
else
echo
"Unable to find Java"
exit
1
fi
# Build actual command to execute
command
=
"
$javaexe
-jar -Dsun.misc.URLClassPath.disableJarChecking=true
$jarfile
$@
"
# Utility functions
checkPermissions
()
{
touch
"
$pid_file
"
&> /dev/null
||
{
echoRed
"Operation not permitted (cannot access pid file)"
;
exit
1
;
}
touch
"
$log_file
"
&> /dev/null
||
{
echoRed
"Operation not permitted (cannot access log file)"
;
exit
1
;
}
}
isRunning
()
{
ps
-p
$1
&> /dev/null
}
# Action functions
start
()
{
if
[[
-f
"
$pid_file
"
]]
;
then
pid
=
$(
cat
"
$pid_file
"
)
isRunning
$pid
&&
{
echoYellow
"Already running [
$pid
]"
;
exit
0
;
}
fi
pushd
$(
dirname
"
$jarfile
"
)
>
/dev/null
if
[[
-n
"
$run_user
"
]]
;
then
mkdir
"
$PID_FOLDER
/
${
identity
}
"
&> /dev/null
checkPermissions
chown
"
$run_user
"
"
$PID_FOLDER
/
${
identity
}
"
chown
"
$run_user
"
"
$pid_file
"
chown
"
$run_user
"
"
$log_file
"
su
-c
"
$command
&>
\"
$log_file
\"
& echo
\$
!"
$run_user
>
"
$pid_file
"
pid
=
$(
cat
"
$pid_file
"
)
else
checkPermissions
$command
&>
"
$log_file
"
&
pid
=
$!
disown
$pid
echo
"
$pid
"
>
"
$pid_file
"
fi
[[
-z
$pid
]]
&&
{
echoRed
"Failed to start"
;
exit
1
;
}
echoGreen
"Started [
$pid
]"
}
stop
()
{
[[
-f
$pid_file
]]
||
{
echoRed
"Not running (pidfile not found)"
;
exit
1
;
}
pid
=
$(
cat
"
$pid_file
"
)
isRunning
$pid
||
{
echoRed
"Not running (process
${
pid
}
not found)"
;
exit
1
;
}
kill
-HUP
$pid
&> /dev/null
||
{
echoRed
"Unable to kill process
${
pid
}
"
;
exit
1
;
}
for
i
in
$(
seq
1 20
)
;
do
isRunning
${
pid
}
||
{
echoGreen
"Stopped [
$pid
]"
;
rm
-f
$pid_file
;
exit
0
;
}
sleep
1
done
echoRed
"Unable to kill process
${
pid
}
"
;
exit
3
;
}
restart
()
{
stop
start
}
status
()
{
[[
-f
$pid_file
]]
||
{
echoRed
"Not running"
;
exit
1
;
}
pid
=
$(
cat
"
$pid_file
"
)
isRunning
$pid
||
{
echoRed
"Not running (process
${
pid
}
not found)"
;
exit
1
;
}
echoGreen
"Running [
$pid
]"
exit
0
}
run
()
{
pushd
$(
dirname
"
$jarfile
"
)
>
/dev/null
exec
$command
popd
}
# Call the appropriate action function
case
"
$action
"
in
start
)
start
"
$@
"
;;
stop
)
stop
"
$@
"
;;
restart
)
restart
"
$@
"
;;
status
)
status
"
$@
"
;;
run
)
run
"
$@
"
;;
*
)
echo
"Usage:
$0
{start|stop|restart|status|run}"
;
exit
1
;
esac
exit
0
spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/DefaultLaunchScriptTests.java
0 → 100644
View file @
ba2ea301
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed 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.
*/
package
org
.
springframework
.
boot
.
loader
.
tools
;
import
java.io.File
;
import
java.util.Properties
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.TemporaryFolder
;
import
org.springframework.util.FileCopyUtils
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
junit
.
Assert
.
assertThat
;
/**
* Tests for {@link DefaultLaunchScript}.
*
* @author Phillip Webb
*/
public
class
DefaultLaunchScriptTests
{
@Rule
public
TemporaryFolder
temporaryFolder
=
new
TemporaryFolder
();
@Test
public
void
loadsDefaultScript
()
throws
Exception
{
DefaultLaunchScript
script
=
new
DefaultLaunchScript
(
null
,
null
);
String
content
=
new
String
(
script
.
toByteArray
());
assertThat
(
content
,
containsString
(
"Spring Boot Startup Script"
));
assertThat
(
content
,
containsString
(
"mode=\"auto\""
));
}
@Test
public
void
loadFromFile
()
throws
Exception
{
File
file
=
this
.
temporaryFolder
.
newFile
();
FileCopyUtils
.
copy
(
"ABC"
.
getBytes
(),
file
);
DefaultLaunchScript
script
=
new
DefaultLaunchScript
(
file
,
null
);
String
content
=
new
String
(
script
.
toByteArray
());
assertThat
(
content
,
equalTo
(
"ABC"
));
}
@Test
public
void
expandVariables
()
throws
Exception
{
File
file
=
this
.
temporaryFolder
.
newFile
();
FileCopyUtils
.
copy
(
"h{{a}}ll{{b}}"
.
getBytes
(),
file
);
Properties
properties
=
new
Properties
();
properties
.
put
(
"a"
,
"e"
);
properties
.
put
(
"b"
,
"o"
);
DefaultLaunchScript
script
=
new
DefaultLaunchScript
(
file
,
properties
);
String
content
=
new
String
(
script
.
toByteArray
());
assertThat
(
content
,
equalTo
(
"hello"
));
}
@Test
public
void
expandVariablesMultiLine
()
throws
Exception
{
File
file
=
this
.
temporaryFolder
.
newFile
();
FileCopyUtils
.
copy
(
"h{{a}}l\nl{{b}}"
.
getBytes
(),
file
);
Properties
properties
=
new
Properties
();
properties
.
put
(
"a"
,
"e"
);
properties
.
put
(
"b"
,
"o"
);
DefaultLaunchScript
script
=
new
DefaultLaunchScript
(
file
,
properties
);
String
content
=
new
String
(
script
.
toByteArray
());
assertThat
(
content
,
equalTo
(
"hel\nlo"
));
}
@Test
public
void
expandVariablesWithDefaults
()
throws
Exception
{
File
file
=
this
.
temporaryFolder
.
newFile
();
FileCopyUtils
.
copy
(
"h{{a:e}}ll{{b:o}}"
.
getBytes
(),
file
);
DefaultLaunchScript
script
=
new
DefaultLaunchScript
(
file
,
null
);
String
content
=
new
String
(
script
.
toByteArray
());
assertThat
(
content
,
equalTo
(
"hello"
));
}
@Test
public
void
expandVariablesWithDefaultsOverride
()
throws
Exception
{
File
file
=
this
.
temporaryFolder
.
newFile
();
FileCopyUtils
.
copy
(
"h{{a:e}}ll{{b:o}}"
.
getBytes
(),
file
);
Properties
properties
=
new
Properties
();
properties
.
put
(
"a"
,
"a"
);
DefaultLaunchScript
script
=
new
DefaultLaunchScript
(
file
,
properties
);
String
content
=
new
String
(
script
.
toByteArray
());
assertThat
(
content
,
equalTo
(
"hallo"
));
}
@Test
public
void
expandVariablesMissingAreUnchanged
()
throws
Exception
{
File
file
=
this
.
temporaryFolder
.
newFile
();
FileCopyUtils
.
copy
(
"h{{a}}ll{{b}}"
.
getBytes
(),
file
);
DefaultLaunchScript
script
=
new
DefaultLaunchScript
(
file
,
null
);
String
content
=
new
String
(
script
.
toByteArray
());
assertThat
(
content
,
equalTo
(
"h{{a}}ll{{b}}"
));
}
}
spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/RepackagerTests.java
View file @
ba2ea301
...
@@ -18,6 +18,8 @@ package org.springframework.boot.loader.tools;
...
@@ -18,6 +18,8 @@ package org.springframework.boot.loader.tools;
import
java.io.File
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.nio.file.Files
;
import
java.nio.file.attribute.PosixFilePermission
;
import
java.util.jar.Attributes
;
import
java.util.jar.Attributes
;
import
java.util.jar.JarEntry
;
import
java.util.jar.JarEntry
;
import
java.util.jar.JarFile
;
import
java.util.jar.JarFile
;
...
@@ -34,6 +36,7 @@ import org.springframework.boot.loader.tools.sample.ClassWithoutMainMethod;
...
@@ -34,6 +36,7 @@ import org.springframework.boot.loader.tools.sample.ClassWithoutMainMethod;
import
org.springframework.util.FileCopyUtils
;
import
org.springframework.util.FileCopyUtils
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
hamcrest
.
Matchers
.
hasItem
;
import
static
org
.
hamcrest
.
Matchers
.
startsWith
;
import
static
org
.
hamcrest
.
Matchers
.
startsWith
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
mockito
.
BDDMockito
.
given
;
import
static
org
.
mockito
.
BDDMockito
.
given
;
...
@@ -141,7 +144,6 @@ public class RepackagerTests {
...
@@ -141,7 +144,6 @@ public class RepackagerTests {
Repackager
repackager
=
new
Repackager
(
file
);
Repackager
repackager
=
new
Repackager
(
file
);
repackager
.
repackage
(
NO_LIBRARIES
);
repackager
.
repackage
(
NO_LIBRARIES
);
repackager
.
repackage
(
NO_LIBRARIES
);
repackager
.
repackage
(
NO_LIBRARIES
);
Manifest
actualManifest
=
getManifest
(
file
);
Manifest
actualManifest
=
getManifest
(
file
);
assertThat
(
actualManifest
.
getMainAttributes
().
getValue
(
"Main-Class"
),
assertThat
(
actualManifest
.
getMainAttributes
().
getValue
(
"Main-Class"
),
equalTo
(
"org.springframework.boot.loader.JarLauncher"
));
equalTo
(
"org.springframework.boot.loader.JarLauncher"
));
...
@@ -230,7 +232,6 @@ public class RepackagerTests {
...
@@ -230,7 +232,6 @@ public class RepackagerTests {
equalTo
(
false
));
equalTo
(
false
));
assertThat
(
hasLauncherClasses
(
source
),
equalTo
(
false
));
assertThat
(
hasLauncherClasses
(
source
),
equalTo
(
false
));
assertThat
(
hasLauncherClasses
(
dest
),
equalTo
(
true
));
assertThat
(
hasLauncherClasses
(
dest
),
equalTo
(
true
));
}
}
@Test
@Test
...
@@ -380,7 +381,6 @@ public class RepackagerTests {
...
@@ -380,7 +381,6 @@ public class RepackagerTests {
callback
.
library
(
new
Library
(
nestedFile
,
LibraryScope
.
COMPILE
));
callback
.
library
(
new
Library
(
nestedFile
,
LibraryScope
.
COMPILE
));
}
}
});
});
JarFile
jarFile
=
new
JarFile
(
file
);
JarFile
jarFile
=
new
JarFile
(
file
);
try
{
try
{
assertThat
(
jarFile
.
getEntry
(
"lib/"
+
nestedFile
.
getName
()).
getMethod
(),
assertThat
(
jarFile
.
getEntry
(
"lib/"
+
nestedFile
.
getName
()).
getMethod
(),
...
@@ -393,6 +393,22 @@ public class RepackagerTests {
...
@@ -393,6 +393,22 @@ public class RepackagerTests {
}
}
}
}
@Test
public
void
addLauncherScript
()
throws
Exception
{
this
.
testJarFile
.
addClass
(
"a/b/C.class"
,
ClassWithMainMethod
.
class
);
File
source
=
this
.
testJarFile
.
getFile
();
File
dest
=
this
.
temporaryFolder
.
newFile
(
"dest.jar"
);
Repackager
repackager
=
new
Repackager
(
source
);
LaunchScript
script
=
new
MockLauncherScript
(
"ABC"
);
repackager
.
repackage
(
dest
,
NO_LIBRARIES
,
script
);
byte
[]
bytes
=
FileCopyUtils
.
copyToByteArray
(
dest
);
assertThat
(
Files
.
getPosixFilePermissions
(
dest
.
toPath
()),
hasItem
(
PosixFilePermission
.
OWNER_EXECUTE
));
assertThat
(
new
String
(
bytes
),
startsWith
(
"ABC"
));
assertThat
(
hasLauncherClasses
(
source
),
equalTo
(
false
));
assertThat
(
hasLauncherClasses
(
dest
),
equalTo
(
true
));
}
private
boolean
hasLauncherClasses
(
File
file
)
throws
IOException
{
private
boolean
hasLauncherClasses
(
File
file
)
throws
IOException
{
return
hasEntry
(
file
,
"org/springframework/boot/"
)
return
hasEntry
(
file
,
"org/springframework/boot/"
)
&&
hasEntry
(
file
,
"org/springframework/boot/loader/JarLauncher.class"
);
&&
hasEntry
(
file
,
"org/springframework/boot/loader/JarLauncher.class"
);
...
@@ -422,4 +438,19 @@ public class RepackagerTests {
...
@@ -422,4 +438,19 @@ public class RepackagerTests {
}
}
}
}
private
static
class
MockLauncherScript
implements
LaunchScript
{
private
final
byte
[]
bytes
;
public
MockLauncherScript
(
String
script
)
{
this
.
bytes
=
script
.
getBytes
();
}
@Override
public
byte
[]
toByteArray
()
{
return
this
.
bytes
;
}
}
}
}
spring-boot-tools/spring-boot-maven-plugin/src/it/jar-custom-launcher/pom.xml
0 → 100644
View file @
ba2ea301
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
org.springframework.boot.maven.it
</groupId>
<artifactId>
jar
</artifactId>
<version>
0.0.1.BUILD-SNAPSHOT
</version>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>
@project.groupId@
</groupId>
<artifactId>
@project.artifactId@
</artifactId>
<version>
@project.version@
</version>
<executions>
<execution>
<goals>
<goal>
repackage
</goal>
</goals>
<configuration>
<embeddedLaunchScript>
${basedir}/src/launcher/custom.script
</embeddedLaunchScript>
<embeddedLaunchScriptProperties>
<name>
world
</name>
</embeddedLaunchScriptProperties>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-jar-plugin
</artifactId>
<version>
2.4
</version>
<configuration>
<archive>
<manifest>
<mainClass>
some.random.Main
</mainClass>
</manifest>
<manifestEntries>
<Not-Used>
Foo
</Not-Used>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>
org.springframework
</groupId>
<artifactId>
spring-context
</artifactId>
<version>
@spring.version@
</version>
</dependency>
<dependency>
<groupId>
javax.servlet
</groupId>
<artifactId>
javax.servlet-api
</artifactId>
<version>
@servlet-api.version@
</version>
<scope>
provided
</scope>
</dependency>
</dependencies>
</project>
spring-boot-tools/spring-boot-maven-plugin/src/it/jar-custom-launcher/src/launcher/custom.script
0 → 100644
View file @
ba2ea301
#!/bin/sh
echo
"Hello {{name}}"
spring-boot-tools/spring-boot-maven-plugin/src/it/jar-custom-launcher/src/main/java/org/test/SampleApplication.java
0 → 100644
View file @
ba2ea301
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed 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.
*/
package
org
.
test
;
public
class
SampleApplication
{
public
static
void
main
(
String
[]
args
)
{
}
}
spring-boot-tools/spring-boot-maven-plugin/src/it/jar-custom-launcher/verify.groovy
0 → 100644
View file @
ba2ea301
import
java.io.*
;
import
org.springframework.boot.maven.*
;
Verify
.
verifyJar
(
new
File
(
basedir
,
"target/jar-0.0.1.BUILD-SNAPSHOT.jar"
),
"some.random.Main"
,
"Hello world"
);
spring-boot-tools/spring-boot-maven-plugin/src/it/jar-non-executable/pom.xml
0 → 100644
View file @
ba2ea301
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
org.springframework.boot.maven.it
</groupId>
<artifactId>
jar
</artifactId>
<version>
0.0.1.BUILD-SNAPSHOT
</version>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>
@project.groupId@
</groupId>
<artifactId>
@project.artifactId@
</artifactId>
<version>
@project.version@
</version>
<executions>
<execution>
<goals>
<goal>
repackage
</goal>
</goals>
<configuration>
<executable>
false
</executable>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-jar-plugin
</artifactId>
<version>
2.4
</version>
<configuration>
<archive>
<manifest>
<mainClass>
some.random.Main
</mainClass>
</manifest>
<manifestEntries>
<Not-Used>
Foo
</Not-Used>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>
org.springframework
</groupId>
<artifactId>
spring-context
</artifactId>
<version>
@spring.version@
</version>
</dependency>
<dependency>
<groupId>
javax.servlet
</groupId>
<artifactId>
javax.servlet-api
</artifactId>
<version>
@servlet-api.version@
</version>
<scope>
provided
</scope>
</dependency>
</dependencies>
</project>
spring-boot-tools/spring-boot-maven-plugin/src/it/jar-non-executable/src/main/java/org/test/SampleApplication.java
0 → 100644
View file @
ba2ea301
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed 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.
*/
package
org
.
test
;
public
class
SampleApplication
{
public
static
void
main
(
String
[]
args
)
{
}
}
spring-boot-tools/spring-boot-maven-plugin/src/it/jar-non-executable/verify.groovy
0 → 100644
View file @
ba2ea301
import
java.io.*
;
import
org.springframework.boot.maven.*
;
Verify
.
verifyJar
(
new
File
(
basedir
,
"target/jar-0.0.1.BUILD-SNAPSHOT.jar"
),
"some.random.Main"
,
false
);
spring-boot-tools/spring-boot-maven-plugin/src/it/jar/verify.groovy
View file @
ba2ea301
...
@@ -2,6 +2,6 @@ import java.io.*;
...
@@ -2,6 +2,6 @@ import java.io.*;
import
org.springframework.boot.maven.*
;
import
org.springframework.boot.maven.*
;
Verify
.
verifyJar
(
Verify
.
verifyJar
(
new
File
(
basedir
,
"target/jar-0.0.1.BUILD-SNAPSHOT.jar"
),
"some.random.Main"
new
File
(
basedir
,
"target/jar-0.0.1.BUILD-SNAPSHOT.jar"
),
"some.random.Main"
,
"Spring Boot Startup Script"
);
);
spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java
View file @
ba2ea301
...
@@ -19,6 +19,7 @@ package org.springframework.boot.maven;
...
@@ -19,6 +19,7 @@ package org.springframework.boot.maven;
import
java.io.File
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Properties
;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeUnit
;
import
java.util.jar.JarFile
;
import
java.util.jar.JarFile
;
...
@@ -34,6 +35,8 @@ import org.apache.maven.plugins.annotations.Parameter;
...
@@ -34,6 +35,8 @@ import org.apache.maven.plugins.annotations.Parameter;
import
org.apache.maven.plugins.annotations.ResolutionScope
;
import
org.apache.maven.plugins.annotations.ResolutionScope
;
import
org.apache.maven.project.MavenProject
;
import
org.apache.maven.project.MavenProject
;
import
org.apache.maven.project.MavenProjectHelper
;
import
org.apache.maven.project.MavenProjectHelper
;
import
org.springframework.boot.loader.tools.DefaultLaunchScript
;
import
org.springframework.boot.loader.tools.LaunchScript
;
import
org.springframework.boot.loader.tools.Layout
;
import
org.springframework.boot.loader.tools.Layout
;
import
org.springframework.boot.loader.tools.Layouts
;
import
org.springframework.boot.loader.tools.Layouts
;
import
org.springframework.boot.loader.tools.Libraries
;
import
org.springframework.boot.loader.tools.Libraries
;
...
@@ -124,6 +127,29 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
...
@@ -124,6 +127,29 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
@Parameter
@Parameter
private
List
<
Dependency
>
requiresUnpack
;
private
List
<
Dependency
>
requiresUnpack
;
/**
* Make a fully executable jar for *nix machines by prepending a launch script to the
* jar.
* @since 1.3
*/
@Parameter
(
defaultValue
=
"true"
)
private
boolean
executable
;
/**
* The embedded launch script to prepend to the front of the jar if it is fully
* executable. If not specified the 'Spring Boot' default script will be used.
* @since 1.3
*/
@Parameter
private
File
embeddedLaunchScript
;
/**
* Properties that should be expanded in the embedded launch script.
* @since 1.3
*/
@Parameter
private
Properties
embeddedLaunchScriptProperties
;
@Override
@Override
public
void
execute
()
throws
MojoExecutionException
,
MojoFailureException
{
public
void
execute
()
throws
MojoExecutionException
,
MojoFailureException
{
if
(
this
.
project
.
getPackaging
().
equals
(
"pom"
))
{
if
(
this
.
project
.
getPackaging
().
equals
(
"pom"
))
{
...
@@ -167,7 +193,8 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
...
@@ -167,7 +193,8 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
Libraries
libraries
=
new
ArtifactsLibraries
(
artifacts
,
this
.
requiresUnpack
,
Libraries
libraries
=
new
ArtifactsLibraries
(
artifacts
,
this
.
requiresUnpack
,
getLog
());
getLog
());
try
{
try
{
repackager
.
repackage
(
target
,
libraries
);
LaunchScript
launchScript
=
getLaunchScript
();
repackager
.
repackage
(
target
,
libraries
,
launchScript
);
}
}
catch
(
IOException
ex
)
{
catch
(
IOException
ex
)
{
throw
new
MojoExecutionException
(
ex
.
getMessage
(),
ex
);
throw
new
MojoExecutionException
(
ex
.
getMessage
(),
ex
);
...
@@ -190,6 +217,14 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
...
@@ -190,6 +217,14 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
+
this
.
project
.
getPackaging
());
+
this
.
project
.
getPackaging
());
}
}
private
LaunchScript
getLaunchScript
()
throws
IOException
{
if
(
this
.
executable
)
{
return
new
DefaultLaunchScript
(
this
.
embeddedLaunchScript
,
this
.
embeddedLaunchScriptProperties
);
}
return
null
;
}
public
static
enum
LayoutType
{
public
static
enum
LayoutType
{
/**
/**
...
...
spring-boot-tools/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/Verify.java
View file @
ba2ea301
...
@@ -26,8 +26,12 @@ import java.util.jar.Manifest;
...
@@ -26,8 +26,12 @@ import java.util.jar.Manifest;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
import
java.util.zip.ZipFile
;
import
org.springframework.util.FileCopyUtils
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
/**
...
@@ -44,8 +48,14 @@ public class Verify {
...
@@ -44,8 +48,14 @@ public class Verify {
new
JarArchiveVerification
(
file
,
SAMPLE_APP
).
verify
();
new
JarArchiveVerification
(
file
,
SAMPLE_APP
).
verify
();
}
}
public
static
void
verifyJar
(
File
file
,
String
main
)
throws
Exception
{
public
static
void
verifyJar
(
File
file
,
String
main
,
String
...
scriptContents
)
new
JarArchiveVerification
(
file
,
main
).
verify
();
throws
Exception
{
verifyJar
(
file
,
main
,
true
,
scriptContents
);
}
public
static
void
verifyJar
(
File
file
,
String
main
,
boolean
executable
,
String
...
scriptContents
)
throws
Exception
{
new
JarArchiveVerification
(
file
,
main
).
verify
(
executable
,
scriptContents
);
}
}
public
static
void
verifyWar
(
File
file
)
throws
Exception
{
public
static
void
verifyWar
(
File
file
)
throws
Exception
{
...
@@ -149,9 +159,30 @@ public class Verify {
...
@@ -149,9 +159,30 @@ public class Verify {
}
}
public
void
verify
()
throws
Exception
{
public
void
verify
()
throws
Exception
{
verify
(
true
);
}
public
void
verify
(
boolean
executable
,
String
...
scriptContents
)
throws
Exception
{
assertTrue
(
"Archive missing"
,
this
.
file
.
exists
());
assertTrue
(
"Archive missing"
,
this
.
file
.
exists
());
assertTrue
(
"Archive not a file"
,
this
.
file
.
isFile
());
assertTrue
(
"Archive not a file"
,
this
.
file
.
isFile
());
if
(
scriptContents
.
length
>
0
&&
executable
)
{
String
contents
=
new
String
(
FileCopyUtils
.
copyToByteArray
(
this
.
file
));
contents
=
contents
.
substring
(
0
,
contents
.
indexOf
(
new
String
(
new
byte
[]
{
0x50
,
0x4b
,
0x03
,
0x04
})));
for
(
String
content
:
scriptContents
)
{
assertThat
(
contents
,
containsString
(
content
));
}
}
if
(!
executable
)
{
String
contents
=
new
String
(
FileCopyUtils
.
copyToByteArray
(
this
.
file
));
assertTrue
(
"Is executable"
,
contents
.
startsWith
(
new
String
(
new
byte
[]
{
0x50
,
0x4b
,
0x03
,
0x04
})));
}
ZipFile
zipFile
=
new
ZipFile
(
this
.
file
);
ZipFile
zipFile
=
new
ZipFile
(
this
.
file
);
try
{
try
{
ArchiveVerifier
verifier
=
new
ArchiveVerifier
(
zipFile
);
ArchiveVerifier
verifier
=
new
ArchiveVerifier
(
zipFile
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment