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
f83fd471
Commit
f83fd471
authored
Sep 19, 2013
by
Dave Syer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add PropertiesLauncher
parent
604b9069
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
872 additions
and
0 deletions
+872
-0
application.properties
...-boot-loader/src/it/executable-dir/application.properties
+2
-0
pom.xml
...ot-tools/spring-boot-loader/src/it/executable-dir/pom.xml
+87
-0
EmbeddedJarStarter.java
...g/springframework/launcher/it/jar/EmbeddedJarStarter.java
+47
-0
ExampleController.java
...rg/springframework/launcher/it/jar/ExampleController.java
+37
-0
SpringConfiguration.java
.../springframework/launcher/it/jar/SpringConfiguration.java
+33
-0
Launcher.java
...c/main/java/org/springframework/boot/loader/Launcher.java
+4
-0
PropertiesLauncher.java
...a/org/springframework/boot/loader/PropertiesLauncher.java
+295
-0
PropertyPlaceholderHelper.java
...framework/boot/loader/util/PropertyPlaceholderHelper.java
+253
-0
SystemPropertyUtils.java
...springframework/boot/loader/util/SystemPropertyUtils.java
+114
-0
No files found.
spring-boot-tools/spring-boot-loader/src/it/executable-dir/application.properties
0 → 100644
View file @
f83fd471
loader.path
:
target,target/lib,.
loader.main
:
org.springframework.boot.load.it.jar.EmbeddedJarStarter
\ No newline at end of file
spring-boot-tools/spring-boot-loader/src/it/executable-dir/pom.xml
0 → 100644
View file @
f83fd471
<?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.launcher.it
</groupId>
<artifactId>
executable-dir
</artifactId>
<version>
0.0.1.BUILD-SNAPSHOT
</version>
<packaging>
jar
</packaging>
<build>
<plugins>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-compiler-plugin
</artifactId>
<version>
3.1
</version>
<configuration>
<source>
1.6
</source>
<target>
1.6
</target>
</configuration>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-dependency-plugin
</artifactId>
<version>
2.6
</version>
<executions>
<execution>
<id>
unpack
</id>
<phase>
prepare-package
</phase>
<goals>
<goal>
copy
</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>
@project.groupId@
</groupId>
<artifactId>
@project.artifactId@
</artifactId>
<version>
@project.version@
</version>
<type>
jar
</type>
</artifactItem>
</artifactItems>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
<execution>
<id>
copy
</id>
<phase>
prepare-package
</phase>
<goals>
<goal>
copy-dependencies
</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>
org.codehaus.mojo
</groupId>
<artifactId>
exec-maven-plugin
</artifactId>
<version>
1.2.1
</version>
<configuration>
<executable>
java
</executable>
<arguments>
<argument>
-cp
</argument>
<argument>
${project.build.directory}/lib/@project.artifactId@-@project.version@.jar
</argument>
<argument>
org.springframework.boot.loader.PropertiesLauncher
</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>
org.eclipse.jetty
</groupId>
<artifactId>
jetty-webapp
</artifactId>
<version>
8.1.8.v20121106
</version>
</dependency>
<dependency>
<groupId>
org.eclipse.jetty
</groupId>
<artifactId>
jetty-annotations
</artifactId>
<version>
8.1.8.v20121106
</version>
</dependency>
<dependency>
<groupId>
org.springframework
</groupId>
<artifactId>
spring-webmvc
</artifactId>
<version>
3.2.0.RELEASE
</version>
</dependency>
</dependencies>
</project>
spring-boot-tools/spring-boot-loader/src/it/executable-dir/src/main/java/org/springframework/launcher/it/jar/EmbeddedJarStarter.java
0 → 100644
View file @
f83fd471
/*
* Copyright 2013 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
.
load
.
it
.
jar
;
import
org.eclipse.jetty.server.Server
;
import
org.eclipse.jetty.servlet.ServletContextHandler
;
import
org.eclipse.jetty.servlet.ServletHolder
;
import
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
;
import
org.springframework.web.servlet.DispatcherServlet
;
/**
* Main class to start the embedded server.
*
* @author Phillip Webb
*/
public
final
class
EmbeddedJarStarter
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
Server
server
=
new
Server
(
8080
);
ServletContextHandler
context
=
new
ServletContextHandler
(
ServletContextHandler
.
SESSIONS
);
context
.
setContextPath
(
"/"
);
server
.
setHandler
(
context
);
AnnotationConfigWebApplicationContext
webApplicationContext
=
new
AnnotationConfigWebApplicationContext
();
webApplicationContext
.
register
(
SpringConfiguration
.
class
);
DispatcherServlet
dispatcherServlet
=
new
DispatcherServlet
(
webApplicationContext
);
context
.
addServlet
(
new
ServletHolder
(
dispatcherServlet
),
"/*"
);
server
.
start
();
server
.
join
();
}
}
spring-boot-tools/spring-boot-loader/src/it/executable-dir/src/main/java/org/springframework/launcher/it/jar/ExampleController.java
0 → 100644
View file @
f83fd471
/*
* Copyright 2013 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
.
load
.
it
.
jar
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
/**
* Simple example Spring MVC Controller.
*
* @author Phillip Webb
*/
@Controller
public
class
ExampleController
{
@RequestMapping
(
"/"
)
@ResponseBody
public
String
helloWorld
()
{
return
"Hello Embedded Jar World!"
;
}
}
spring-boot-tools/spring-boot-loader/src/it/executable-dir/src/main/java/org/springframework/launcher/it/jar/SpringConfiguration.java
0 → 100644
View file @
f83fd471
/*
* Copyright 2013 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
.
load
.
it
.
jar
;
import
org.springframework.context.annotation.ComponentScan
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.servlet.config.annotation.EnableWebMvc
;
/**
* Spring configuration.
*
* @author Phillip Webb
*/
@Configuration
@EnableWebMvc
@ComponentScan
public
class
SpringConfiguration
{
}
spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/Launcher.java
View file @
f83fd471
...
@@ -195,4 +195,8 @@ public abstract class Launcher {
...
@@ -195,4 +195,8 @@ public abstract class Launcher {
return
(
Runnable
)
constructor
.
newInstance
(
mainClass
,
args
);
return
(
Runnable
)
constructor
.
newInstance
(
mainClass
,
args
);
}
}
protected
boolean
isArchive
(
String
name
)
{
return
name
.
endsWith
(
".jar"
)
||
name
.
endsWith
(
".zip"
);
}
}
}
spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java
0 → 100644
View file @
f83fd471
/*
* Copyright 2013 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
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.net.HttpURLConnection
;
import
java.net.URL
;
import
java.net.URLConnection
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Properties
;
import
java.util.logging.Logger
;
import
org.springframework.boot.loader.util.SystemPropertyUtils
;
import
org.springframework.util.ResourceUtils
;
/**
* <p>
* {@link Launcher} for archives with user-configured classpath and main class via a
* properties file. This model is often more flexible and more amenable to creating
* well-behaved OS-level services than a model based on executable jars.
* </p>
*
* <p>
* Looks in various places for a properties file to extract loader settings, defaulting to
* <code>application.properties</code> either on the current classpath or in the current
* working directory. The name of the properties file can be changed by setting a System
* property <code>loader.config.name</code> (e.g. <code>-Dloader.config.name=foo</code>
* will look for <code>foo.properties</code>. If that file doesn't exist then tries
* <code>loader.config.location</code> (with allowed prefixes <code>classpath:</code> and
* <code>file:</code> or any valid URL). Once that file is located turns it into
* Properties and extracts optional values (which can also be provided oroverridden as
* System properties in case the file doesn't exist):
*
* <ul>
* <li><code>loader.path</code>: a comma-separated list of classpath directories
* (containing file resources and/or archives in *.jar or *.zip). Defaults to
* <code>lib</code> (i.e. a directory in the current working directory)</li>
* <li><code>loader.main</code>: the main method to delegate execution to once the class
* loader is set up. No default, but will fall back to looking in a
* <code>MANIFEST.MF</code> if there is one.</li>
* </ul>
* </p>
*
* <p>
*
* </p>
*
* @author Dave Syer
*/
public
class
PropertiesLauncher
extends
Launcher
{
/**
* Properties key for main class
*/
public
static
final
String
MAIN
=
"loader.main"
;
/**
* Properties key for classpath entries (directories possibly containing jars)
*/
public
static
final
String
PATH
=
"loader.path"
;
public
static
final
String
HOME
=
"loader.home"
;
public
static
String
CONFIG_NAME
=
"loader.config.name"
;
public
static
String
CONFIG_LOCATION
=
"loader.config.location"
;
private
Logger
logger
=
Logger
.
getLogger
(
Launcher
.
class
.
getName
());
private
static
final
List
<
String
>
DEFAULT_PATHS
=
Arrays
.
asList
(
"lib/"
);
private
List
<
String
>
paths
=
new
ArrayList
<
String
>(
DEFAULT_PATHS
);
private
Properties
properties
=
new
Properties
();
@Override
public
void
launch
(
String
[]
args
)
{
try
{
launch
(
args
,
new
ExplodedArchive
(
new
File
(
getHomeDirectory
())));
}
catch
(
Exception
ex
)
{
ex
.
printStackTrace
();
System
.
exit
(
1
);
}
}
protected
String
getHomeDirectory
()
{
return
SystemPropertyUtils
.
resolvePlaceholders
(
System
.
getProperty
(
HOME
,
"${user.dir}"
));
}
@Override
protected
boolean
isNestedArchive
(
Archive
.
Entry
entry
)
{
String
name
=
entry
.
getName
();
if
(
entry
.
isDirectory
())
{
for
(
String
path
:
this
.
paths
)
{
if
(
path
.
length
()
>
0
&&
name
.
equals
(
path
))
{
return
true
;
}
}
}
else
{
for
(
String
path
:
this
.
paths
)
{
if
(
path
.
length
()
>
0
&&
name
.
startsWith
(
path
)
&&
isArchive
(
name
))
{
return
true
;
}
}
}
return
false
;
}
@Override
protected
void
postProcessLib
(
Archive
archive
,
List
<
Archive
>
lib
)
throws
Exception
{
lib
.
add
(
0
,
archive
);
}
/**
* Look in various places for a properties file to extract loader settings. Default to
* <code>application.properties</code> either on the current classpath or in the
* current working directory.
*
* @see org.springframework.boot.loader.Launcher#launch(java.lang.String[],
* org.springframework.boot.loader.Archive)
*/
@Override
protected
void
launch
(
String
[]
args
,
Archive
archive
)
throws
Exception
{
initialize
();
super
.
launch
(
args
,
archive
);
}
protected
void
initialize
()
throws
Exception
{
String
config
=
SystemPropertyUtils
.
resolvePlaceholders
(
System
.
getProperty
(
CONFIG_NAME
,
"application"
))
+
".properties"
;
while
(
config
.
startsWith
(
"/"
))
{
config
=
config
.
substring
(
1
);
}
this
.
logger
.
fine
(
"Trying default location: "
+
config
);
InputStream
resource
=
getClass
().
getResourceAsStream
(
"/"
+
config
);
if
(
resource
==
null
)
{
config
=
SystemPropertyUtils
.
resolvePlaceholders
(
System
.
getProperty
(
CONFIG_LOCATION
,
config
));
if
(
config
.
startsWith
(
"classpath:"
))
{
config
=
config
.
substring
(
"classpath:"
.
length
());
while
(
config
.
startsWith
(
"/"
))
{
config
=
config
.
substring
(
1
);
}
config
=
"/"
+
config
;
this
.
logger
.
fine
(
"Trying classpath: "
+
config
);
resource
=
getClass
().
getResourceAsStream
(
config
);
}
else
{
if
(
config
.
startsWith
(
"file:"
))
{
config
=
config
.
substring
(
"file:"
.
length
());
if
(
config
.
startsWith
(
"//"
))
{
config
=
config
.
substring
(
2
);
}
}
if
(!
config
.
contains
(
":"
))
{
File
file
=
new
File
(
config
);
this
.
logger
.
fine
(
"Trying file: "
+
config
);
if
(
file
.
canRead
())
{
resource
=
new
FileInputStream
(
file
);
}
}
else
{
URL
url
=
new
URL
(
config
);
if
(
exists
(
url
))
{
URLConnection
con
=
url
.
openConnection
();
try
{
resource
=
con
.
getInputStream
();
}
catch
(
IOException
ex
)
{
// Close the HTTP connection (if applicable).
if
(
con
instanceof
HttpURLConnection
)
{
((
HttpURLConnection
)
con
).
disconnect
();
}
throw
ex
;
}
}
}
}
}
if
(
resource
!=
null
)
{
this
.
logger
.
info
(
"Found: "
+
config
);
this
.
properties
.
load
(
resource
);
try
{
String
path
=
System
.
getProperty
(
PATH
);
if
(
path
==
null
)
{
path
=
this
.
properties
.
getProperty
(
PATH
);
}
if
(
path
!=
null
)
{
path
=
SystemPropertyUtils
.
resolvePlaceholders
(
path
,
true
);
this
.
paths
=
new
ArrayList
<
String
>(
Arrays
.
asList
(
path
.
split
(
","
)));
for
(
int
i
=
0
;
i
<
this
.
paths
.
size
();
i
++)
{
this
.
paths
.
set
(
i
,
this
.
paths
.
get
(
i
).
trim
());
}
}
}
finally
{
resource
.
close
();
}
}
else
{
this
.
logger
.
info
(
"Not found: "
+
config
);
}
for
(
int
i
=
0
;
i
<
this
.
paths
.
size
();
i
++)
{
if
(
this
.
paths
.
get
(
i
).
startsWith
(
"./"
))
{
this
.
paths
.
set
(
i
,
this
.
paths
.
get
(
i
).
substring
(
2
));
}
}
for
(
Iterator
<
String
>
iter
=
this
.
paths
.
iterator
();
iter
.
hasNext
();)
{
String
path
=
iter
.
next
();
if
(
path
.
equals
(
"."
)
||
path
.
equals
(
""
))
{
iter
.
remove
();
}
}
this
.
logger
.
info
(
"Nested archive paths: "
+
this
.
paths
);
}
private
boolean
exists
(
URL
url
)
throws
IOException
{
// Try a URL connection content-length header...
URLConnection
con
=
url
.
openConnection
();
ResourceUtils
.
useCachesIfNecessary
(
con
);
HttpURLConnection
httpCon
=
(
con
instanceof
HttpURLConnection
?
(
HttpURLConnection
)
con
:
null
);
if
(
httpCon
!=
null
)
{
httpCon
.
setRequestMethod
(
"HEAD"
);
int
code
=
httpCon
.
getResponseCode
();
if
(
code
==
HttpURLConnection
.
HTTP_OK
)
{
return
true
;
}
else
if
(
code
==
HttpURLConnection
.
HTTP_NOT_FOUND
)
{
return
false
;
}
}
if
(
con
.
getContentLength
()
>=
0
)
{
return
true
;
}
if
(
httpCon
!=
null
)
{
// no HTTP OK status, and no content-length header: give up
httpCon
.
disconnect
();
}
return
false
;
}
@Override
protected
String
getMainClass
(
Archive
archive
)
throws
Exception
{
if
(
System
.
getProperty
(
MAIN
)
!=
null
)
{
return
SystemPropertyUtils
.
resolvePlaceholders
(
System
.
getProperty
(
MAIN
),
true
);
}
if
(
this
.
properties
.
containsKey
(
MAIN
))
{
return
SystemPropertyUtils
.
resolvePlaceholders
(
this
.
properties
.
getProperty
(
MAIN
),
true
);
}
return
super
.
getMainClass
(
archive
);
}
public
static
void
main
(
String
[]
args
)
{
new
PropertiesLauncher
().
launch
(
args
);
}
}
spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/PropertyPlaceholderHelper.java
0 → 100644
View file @
f83fd471
/*
* Copyright 2012-2013 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
.
util
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Properties
;
import
java.util.Set
;
/**
* Utility class for working with Strings that have placeholder values in them. A
* placeholder takes the form {@code $ name} . Using {@code PropertyPlaceholderHelper}
* these placeholders can be substituted for user-supplied values.
* <p>
* Values for substitution can be supplied using a {@link Properties} instance or using a
* {@link PlaceholderResolver}.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @since 3.0
*/
public
class
PropertyPlaceholderHelper
{
private
static
final
Map
<
String
,
String
>
wellKnownSimplePrefixes
=
new
HashMap
<
String
,
String
>(
4
);
static
{
wellKnownSimplePrefixes
.
put
(
"}"
,
"{"
);
wellKnownSimplePrefixes
.
put
(
"]"
,
"["
);
wellKnownSimplePrefixes
.
put
(
")"
,
"("
);
}
private
final
String
placeholderPrefix
;
private
final
String
placeholderSuffix
;
private
final
String
simplePrefix
;
private
final
String
valueSeparator
;
private
final
boolean
ignoreUnresolvablePlaceholders
;
/**
* Creates a new {@code PropertyPlaceholderHelper} that uses the supplied prefix and
* suffix. Unresolvable placeholders are ignored.
* @param placeholderPrefix the prefix that denotes the start of a placeholder.
* @param placeholderSuffix the suffix that denotes the end of a placeholder.
*/
public
PropertyPlaceholderHelper
(
String
placeholderPrefix
,
String
placeholderSuffix
)
{
this
(
placeholderPrefix
,
placeholderSuffix
,
null
,
true
);
}
/**
* Creates a new {@code PropertyPlaceholderHelper} that uses the supplied prefix and
* suffix.
* @param placeholderPrefix the prefix that denotes the start of a placeholder
* @param placeholderSuffix the suffix that denotes the end of a placeholder
* @param valueSeparator the separating character between the placeholder variable and
* the associated default value, if any
* @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders
* should be ignored ({@code true}) or cause an exception ({@code false}).
*/
public
PropertyPlaceholderHelper
(
String
placeholderPrefix
,
String
placeholderSuffix
,
String
valueSeparator
,
boolean
ignoreUnresolvablePlaceholders
)
{
Assert
.
notNull
(
placeholderPrefix
,
"placeholderPrefix must not be null"
);
Assert
.
notNull
(
placeholderSuffix
,
"placeholderSuffix must not be null"
);
this
.
placeholderPrefix
=
placeholderPrefix
;
this
.
placeholderSuffix
=
placeholderSuffix
;
String
simplePrefixForSuffix
=
wellKnownSimplePrefixes
.
get
(
this
.
placeholderSuffix
);
if
(
simplePrefixForSuffix
!=
null
&&
this
.
placeholderPrefix
.
endsWith
(
simplePrefixForSuffix
))
{
this
.
simplePrefix
=
simplePrefixForSuffix
;
}
else
{
this
.
simplePrefix
=
this
.
placeholderPrefix
;
}
this
.
valueSeparator
=
valueSeparator
;
this
.
ignoreUnresolvablePlaceholders
=
ignoreUnresolvablePlaceholders
;
}
/**
* Replaces all placeholders of format <code>${name}</code> with the corresponding
* property from the supplied {@link Properties}.
* @param value the value containing the placeholders to be replaced.
* @param properties the {@code Properties} to use for replacement.
* @return the supplied value with placeholders replaced inline.
*/
public
String
replacePlaceholders
(
String
value
,
final
Properties
properties
)
{
Assert
.
notNull
(
properties
,
"Argument 'properties' must not be null."
);
return
replacePlaceholders
(
value
,
new
PlaceholderResolver
()
{
@Override
public
String
resolvePlaceholder
(
String
placeholderName
)
{
return
properties
.
getProperty
(
placeholderName
);
}
});
}
/**
* Replaces all placeholders of format {@code $ name} with the value returned from the
* supplied {@link PlaceholderResolver}.
* @param value the value containing the placeholders to be replaced.
* @param placeholderResolver the {@code PlaceholderResolver} to use for replacement.
* @return the supplied value with placeholders replaced inline.
*/
public
String
replacePlaceholders
(
String
value
,
PlaceholderResolver
placeholderResolver
)
{
Assert
.
notNull
(
value
,
"Argument 'value' must not be null."
);
return
parseStringValue
(
value
,
placeholderResolver
,
new
HashSet
<
String
>());
}
protected
String
parseStringValue
(
String
strVal
,
PlaceholderResolver
placeholderResolver
,
Set
<
String
>
visitedPlaceholders
)
{
StringBuilder
buf
=
new
StringBuilder
(
strVal
);
int
startIndex
=
strVal
.
indexOf
(
this
.
placeholderPrefix
);
while
(
startIndex
!=
-
1
)
{
int
endIndex
=
findPlaceholderEndIndex
(
buf
,
startIndex
);
if
(
endIndex
!=
-
1
)
{
String
placeholder
=
buf
.
substring
(
startIndex
+
this
.
placeholderPrefix
.
length
(),
endIndex
);
String
originalPlaceholder
=
placeholder
;
if
(!
visitedPlaceholders
.
add
(
originalPlaceholder
))
{
throw
new
IllegalArgumentException
(
"Circular placeholder reference '"
+
originalPlaceholder
+
"' in property definitions"
);
}
// Recursive invocation, parsing placeholders contained in the placeholder
// key.
placeholder
=
parseStringValue
(
placeholder
,
placeholderResolver
,
visitedPlaceholders
);
// Now obtain the value for the fully resolved key...
String
propVal
=
placeholderResolver
.
resolvePlaceholder
(
placeholder
);
if
(
propVal
==
null
&&
this
.
valueSeparator
!=
null
)
{
int
separatorIndex
=
placeholder
.
indexOf
(
this
.
valueSeparator
);
if
(
separatorIndex
!=
-
1
)
{
String
actualPlaceholder
=
placeholder
.
substring
(
0
,
separatorIndex
);
String
defaultValue
=
placeholder
.
substring
(
separatorIndex
+
this
.
valueSeparator
.
length
());
propVal
=
placeholderResolver
.
resolvePlaceholder
(
actualPlaceholder
);
if
(
propVal
==
null
)
{
propVal
=
defaultValue
;
}
}
}
if
(
propVal
!=
null
)
{
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal
=
parseStringValue
(
propVal
,
placeholderResolver
,
visitedPlaceholders
);
buf
.
replace
(
startIndex
,
endIndex
+
this
.
placeholderSuffix
.
length
(),
propVal
);
startIndex
=
buf
.
indexOf
(
this
.
placeholderPrefix
,
startIndex
+
propVal
.
length
());
}
else
if
(
this
.
ignoreUnresolvablePlaceholders
)
{
// Proceed with unprocessed value.
startIndex
=
buf
.
indexOf
(
this
.
placeholderPrefix
,
endIndex
+
this
.
placeholderSuffix
.
length
());
}
else
{
throw
new
IllegalArgumentException
(
"Could not resolve placeholder '"
+
placeholder
+
"'"
+
" in string value \""
+
strVal
+
"\""
);
}
visitedPlaceholders
.
remove
(
originalPlaceholder
);
}
else
{
startIndex
=
-
1
;
}
}
return
buf
.
toString
();
}
private
int
findPlaceholderEndIndex
(
CharSequence
buf
,
int
startIndex
)
{
int
index
=
startIndex
+
this
.
placeholderPrefix
.
length
();
int
withinNestedPlaceholder
=
0
;
while
(
index
<
buf
.
length
())
{
if
(
substringMatch
(
buf
,
index
,
this
.
placeholderSuffix
))
{
if
(
withinNestedPlaceholder
>
0
)
{
withinNestedPlaceholder
--;
index
=
index
+
this
.
placeholderSuffix
.
length
();
}
else
{
return
index
;
}
}
else
if
(
substringMatch
(
buf
,
index
,
this
.
simplePrefix
))
{
withinNestedPlaceholder
++;
index
=
index
+
this
.
simplePrefix
.
length
();
}
else
{
index
++;
}
}
return
-
1
;
}
/**
* Strategy interface used to resolve replacement values for placeholders contained in
* Strings.
* @see PropertyPlaceholderHelper
*/
public
static
interface
PlaceholderResolver
{
/**
* Resolves the supplied placeholder name into the replacement value.
* @param placeholderName the name of the placeholder to resolve
* @return the replacement value or {@code null} if no replacement is to be made
*/
String
resolvePlaceholder
(
String
placeholderName
);
}
public
static
boolean
substringMatch
(
CharSequence
str
,
int
index
,
CharSequence
substring
)
{
for
(
int
j
=
0
;
j
<
substring
.
length
();
j
++)
{
int
i
=
index
+
j
;
if
(
i
>=
str
.
length
()
||
str
.
charAt
(
i
)
!=
substring
.
charAt
(
j
))
{
return
false
;
}
}
return
true
;
}
public
static
class
Assert
{
public
static
void
notNull
(
Object
target
,
String
message
)
{
if
(
target
==
null
)
{
throw
new
IllegalStateException
(
message
);
}
}
}
}
\ No newline at end of file
spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/util/SystemPropertyUtils.java
0 → 100644
View file @
f83fd471
/*
* Copyright 2012-2013 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
.
util
;
import
org.springframework.boot.loader.util.PropertyPlaceholderHelper.PlaceholderResolver
;
/**
* Helper class for resolving placeholders in texts. Usually applied to file paths.
*
* <p>
* A text may contain {@code $ ...}} placeholders, to be resolved as system properties:
* e.g. {@code $ user.dir}}. Default values can be supplied using the ":" separator
* between key and value.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @author Dave Syer
* @since 1.2.5
* @see #PLACEHOLDER_PREFIX
* @see #PLACEHOLDER_SUFFIX
* @see System#getProperty(String)
*/
public
abstract
class
SystemPropertyUtils
{
/** Prefix for system property placeholders: "${" */
public
static
final
String
PLACEHOLDER_PREFIX
=
"${"
;
/** Suffix for system property placeholders: "}" */
public
static
final
String
PLACEHOLDER_SUFFIX
=
"}"
;
/** Value separator for system property placeholders: ":" */
public
static
final
String
VALUE_SEPARATOR
=
":"
;
private
static
final
PropertyPlaceholderHelper
strictHelper
=
new
PropertyPlaceholderHelper
(
PLACEHOLDER_PREFIX
,
PLACEHOLDER_SUFFIX
,
VALUE_SEPARATOR
,
false
);
private
static
final
PropertyPlaceholderHelper
nonStrictHelper
=
new
PropertyPlaceholderHelper
(
PLACEHOLDER_PREFIX
,
PLACEHOLDER_SUFFIX
,
VALUE_SEPARATOR
,
true
);
/**
* Resolve ${...} placeholders in the given text, replacing them with corresponding
* system property values.
* @param text the String to resolve
* @return the resolved String
* @see #PLACEHOLDER_PREFIX
* @see #PLACEHOLDER_SUFFIX
* @throws IllegalArgumentException if there is an unresolvable placeholder
*/
public
static
String
resolvePlaceholders
(
String
text
)
{
return
resolvePlaceholders
(
text
,
false
);
}
/**
* Resolve ${...} placeholders in the given text, replacing them with corresponding
* system property values. Unresolvable placeholders with no default value are ignored
* and passed through unchanged if the flag is set to true.
* @param text the String to resolve
* @param ignoreUnresolvablePlaceholders flag to determine is unresolved placeholders
* are ignored
* @return the resolved String
* @see #PLACEHOLDER_PREFIX
* @see #PLACEHOLDER_SUFFIX
* @throws IllegalArgumentException if there is an unresolvable placeholder and the
* flag is false
*/
public
static
String
resolvePlaceholders
(
String
text
,
boolean
ignoreUnresolvablePlaceholders
)
{
PropertyPlaceholderHelper
helper
=
(
ignoreUnresolvablePlaceholders
?
nonStrictHelper
:
strictHelper
);
return
helper
.
replacePlaceholders
(
text
,
new
SystemPropertyPlaceholderResolver
(
text
));
}
private
static
class
SystemPropertyPlaceholderResolver
implements
PlaceholderResolver
{
private
final
String
text
;
public
SystemPropertyPlaceholderResolver
(
String
text
)
{
this
.
text
=
text
;
}
@Override
public
String
resolvePlaceholder
(
String
placeholderName
)
{
try
{
String
propVal
=
System
.
getProperty
(
placeholderName
);
if
(
propVal
==
null
)
{
// Fall back to searching the system environment.
propVal
=
System
.
getenv
(
placeholderName
);
}
return
propVal
;
}
catch
(
Throwable
ex
)
{
System
.
err
.
println
(
"Could not resolve placeholder '"
+
placeholderName
+
"' in ["
+
this
.
text
+
"] as system property: "
+
ex
);
return
null
;
}
}
}
}
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