Browse Source
Allow the Launcher to detect ans run exploded (unpacked) jar/war files. This change is primarily driven by the fact that Cloud Foundry will unpack uploaded files. Issue: #53066255pull/7/head
27 changed files with 1465 additions and 172 deletions
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
<?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.zero.launcher.it</groupId> |
||||
<artifactId>executable-jar</artifactId> |
||||
<version>0.0.1.BUILD-SNAPSHOT</version> |
||||
<packaging>jar</packaging> |
||||
<build> |
||||
<plugins> |
||||
<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>unpack</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}/assembly</outputDirectory> |
||||
</configuration> |
||||
</execution> |
||||
<execution> |
||||
<id>copy</id> |
||||
<phase>prepare-package</phase> |
||||
<goals> |
||||
<goal>copy-dependencies</goal> |
||||
</goals> |
||||
<configuration> |
||||
<outputDirectory>${project.build.directory}/assembly/lib</outputDirectory> |
||||
</configuration> |
||||
</execution> |
||||
</executions> |
||||
</plugin> |
||||
<plugin> |
||||
<artifactId>maven-assembly-plugin</artifactId> |
||||
<version>2.4</version> |
||||
<configuration> |
||||
<descriptors> |
||||
<descriptor>src/main/assembly/jar-with-dependencies.xml</descriptor> |
||||
</descriptors> |
||||
<archive> |
||||
<manifest> |
||||
<mainClass>org.springframework.launcher.JarLauncher</mainClass> |
||||
</manifest> |
||||
<manifestEntries> |
||||
<Start-Class>org.springframework.launcher.it.jar.EmbeddedJarStarter</Start-Class> |
||||
</manifestEntries> |
||||
</archive> |
||||
</configuration> |
||||
<executions> |
||||
<execution> |
||||
<id>jar-with-dependencies</id> |
||||
<phase>package</phase> |
||||
<goals> |
||||
<goal>single</goal> |
||||
</goals> |
||||
</execution> |
||||
</executions> |
||||
</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> |
||||
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<assembly |
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> |
||||
<id>full</id> |
||||
<formats> |
||||
<format>jar</format> |
||||
</formats> |
||||
<includeBaseDirectory>false</includeBaseDirectory> |
||||
<dependencySets> |
||||
<dependencySet> |
||||
<useProjectArtifact/> |
||||
<includes> |
||||
<include>${project.groupId}:${project.artifactId}</include> |
||||
</includes> |
||||
<unpack>true</unpack> |
||||
</dependencySet> |
||||
</dependencySets> |
||||
<fileSets> |
||||
<fileSet> |
||||
<directory>${project.build.directory}/assembly</directory> |
||||
<outputDirectory>/</outputDirectory> |
||||
</fileSet> |
||||
</fileSets> |
||||
</assembly> |
||||
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
/* |
||||
* 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.launcher.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(); |
||||
} |
||||
} |
||||
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/* |
||||
* 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.launcher.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!"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* |
||||
* 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.launcher.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 { |
||||
|
||||
} |
||||
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
<?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.zero.launcher.it</groupId> |
||||
<artifactId>executable-war</artifactId> |
||||
<version>0.0.1.BUILD-SNAPSHOT</version> |
||||
<packaging>war</packaging> |
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-war-plugin</artifactId> |
||||
<version>2.3</version> |
||||
<configuration> |
||||
<archive> |
||||
<manifest> |
||||
<mainClass>org.springframework.launcher.WarLauncher</mainClass> |
||||
</manifest> |
||||
<manifestEntries> |
||||
<Start-Class>org.springframework.launcher.it.war.embedded.EmbeddedWarStarter</Start-Class> |
||||
</manifestEntries> |
||||
</archive> |
||||
<failOnMissingWebXml>false</failOnMissingWebXml> |
||||
</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>unpack</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}/${project.artifactId}-${project.version}</outputDirectory> |
||||
</configuration> |
||||
</execution> |
||||
</executions> |
||||
</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-plus</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> |
||||
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/* |
||||
* 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.launcher.it.war; |
||||
|
||||
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 WAR World!"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* |
||||
* 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.launcher.it.war; |
||||
|
||||
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 { |
||||
|
||||
} |
||||
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
/* |
||||
* 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.launcher.it.war; |
||||
|
||||
import javax.servlet.ServletContext; |
||||
import javax.servlet.ServletException; |
||||
|
||||
import org.springframework.web.WebApplicationInitializer; |
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; |
||||
import org.springframework.web.servlet.DispatcherServlet; |
||||
|
||||
/** |
||||
* Spring {@link WebApplicationInitializer} for classic WAR deployment. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class SpringInitializer implements WebApplicationInitializer { |
||||
|
||||
@Override |
||||
public void onStartup(ServletContext servletContext) throws ServletException { |
||||
AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext(); |
||||
webApplicationContext.register(SpringConfiguration.class); |
||||
servletContext.addServlet("dispatcherServlet", |
||||
new DispatcherServlet(webApplicationContext)).addMapping("/*"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
|
||||
/* |
||||
* 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.launcher.it.war.embedded; |
||||
|
||||
import org.eclipse.jetty.server.Server; |
||||
import org.eclipse.jetty.webapp.Configuration; |
||||
import org.eclipse.jetty.webapp.WebAppContext; |
||||
import org.springframework.launcher.it.war.SpringInitializer; |
||||
|
||||
/** |
||||
* Starter to launch the embedded server. NOTE: Jetty annotation scanning is not |
||||
* compatible with executable WARs so we must specify the {@link SpringInitializer}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public final class EmbeddedWarStarter { |
||||
|
||||
public static void main(String[] args) throws Exception { |
||||
Server server = new Server(8080); |
||||
|
||||
WebAppContext webAppContext = new WebAppContext(); |
||||
webAppContext.setContextPath("/"); |
||||
webAppContext.setConfigurations(new Configuration[] { |
||||
new WebApplicationInitializersConfiguration(SpringInitializer.class) }); |
||||
|
||||
webAppContext.setParentLoaderPriority(true); |
||||
server.setHandler(webAppContext); |
||||
server.start(); |
||||
|
||||
server.join(); |
||||
} |
||||
} |
||||
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
/* |
||||
* 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.launcher.it.war.embedded; |
||||
|
||||
import javax.servlet.ServletContextEvent; |
||||
import javax.servlet.ServletContextListener; |
||||
|
||||
import org.eclipse.jetty.webapp.AbstractConfiguration; |
||||
import org.eclipse.jetty.webapp.Configuration; |
||||
import org.eclipse.jetty.webapp.WebAppContext; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.web.WebApplicationInitializer; |
||||
|
||||
/** |
||||
* Jetty {@link Configuration} that allows Spring {@link WebApplicationInitializer} to be |
||||
* started. This is required because Jetty annotation scanning does not work with packaged |
||||
* WARs. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class WebApplicationInitializersConfiguration extends AbstractConfiguration { |
||||
|
||||
private Class<?>[] webApplicationInitializers; |
||||
|
||||
public WebApplicationInitializersConfiguration(Class<?> webApplicationInitializer, |
||||
Class<?>... webApplicationInitializers) { |
||||
this.webApplicationInitializers = new Class<?>[webApplicationInitializers.length + 1]; |
||||
this.webApplicationInitializers[0] = webApplicationInitializer; |
||||
System.arraycopy(webApplicationInitializers, 0, this.webApplicationInitializers, |
||||
1, webApplicationInitializers.length); |
||||
for (Class<?> i : webApplicationInitializers) { |
||||
Assert.notNull(i, "WebApplicationInitializer must not be null"); |
||||
Assert.isAssignable(WebApplicationInitializer.class, i); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void configure(WebAppContext context) throws Exception { |
||||
context.getServletContext().addListener(new ServletContextListener() { |
||||
|
||||
@Override |
||||
public void contextInitialized(ServletContextEvent sce) { |
||||
try { |
||||
for (Class<?> webApplicationInitializer : webApplicationInitializers) { |
||||
WebApplicationInitializer initializer = (WebApplicationInitializer) webApplicationInitializer.newInstance(); |
||||
initializer.onStartup(sce.getServletContext()); |
||||
} |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void contextDestroyed(ServletContextEvent sce) { |
||||
} |
||||
}); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<settings> |
||||
<profiles> |
||||
<profile> |
||||
<id>it-repo</id> |
||||
<activation> |
||||
<activeByDefault>true</activeByDefault> |
||||
</activation> |
||||
<repositories> |
||||
<repository> |
||||
<id>local.central</id> |
||||
<url>@localRepositoryUrl@</url> |
||||
<releases> |
||||
<enabled>true</enabled> |
||||
</releases> |
||||
<snapshots> |
||||
<enabled>true</enabled> |
||||
</snapshots> |
||||
</repository> |
||||
</repositories> |
||||
<pluginRepositories> |
||||
<pluginRepository> |
||||
<id>local.central</id> |
||||
<url>@localRepositoryUrl@</url> |
||||
<releases> |
||||
<enabled>true</enabled> |
||||
</releases> |
||||
<snapshots> |
||||
<enabled>true</enabled> |
||||
</snapshots> |
||||
</pluginRepository> |
||||
</pluginRepositories> |
||||
</profile> |
||||
</profiles> |
||||
</settings> |
||||
@ -0,0 +1,104 @@
@@ -0,0 +1,104 @@
|
||||
/* |
||||
* 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.launcher; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URL; |
||||
import java.util.jar.Manifest; |
||||
|
||||
/** |
||||
* An archive that can be launched by the {@link Launcher}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @see JarFileArchive |
||||
*/ |
||||
public interface Archive { |
||||
|
||||
/** |
||||
* Returns the manifest of the archive. |
||||
* @return the manifest |
||||
* @throws IOException |
||||
*/ |
||||
Manifest getManifest() throws IOException; |
||||
|
||||
/** |
||||
* Returns archive entries. |
||||
* @return the archive entries |
||||
*/ |
||||
Iterable<Entry> getEntries(); |
||||
|
||||
/** |
||||
* Returns a URL that can be used to load the archive. |
||||
* @return the archive URL |
||||
* @throws MalformedURLException |
||||
*/ |
||||
URL getUrl() throws MalformedURLException; |
||||
|
||||
/** |
||||
* Returns a nest archive from on the the contained entries. |
||||
* @param entry the entry (may be a directory or file) |
||||
* @return the nested archive |
||||
* @throws IOException |
||||
*/ |
||||
Archive getNestedArchive(Entry entry) throws IOException; |
||||
|
||||
/** |
||||
* Returns a filtered version of the archive. |
||||
* @param filter the filter to apply |
||||
* @return a filter archive |
||||
* @throws IOException |
||||
*/ |
||||
Archive getFilteredArchive(EntryFilter filter) throws IOException; |
||||
|
||||
/** |
||||
* Represents a single entry in the archive. |
||||
*/ |
||||
public static interface Entry { |
||||
|
||||
/** |
||||
* Returns {@code true} if the entry represents a directory. |
||||
* @return if the entry is a directory |
||||
*/ |
||||
boolean isDirectory(); |
||||
|
||||
/** |
||||
* Returns the name of the entry |
||||
* @return the name of the entry |
||||
*/ |
||||
String getName(); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* A filter for archive entries. |
||||
*/ |
||||
public static interface EntryFilter { |
||||
|
||||
/** |
||||
* Apply the jar entry filter. |
||||
* @param entryName the current entry name. This may be different that the |
||||
* original entry name if a previous filter has been applied |
||||
* @param entry the entry to filter |
||||
* @return the new name of the entry or {@code null} if the entry should not be |
||||
* included. |
||||
*/ |
||||
String apply(String entryName, Entry entry); |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,194 @@
@@ -0,0 +1,194 @@
|
||||
/* |
||||
* 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.launcher; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.FileNotFoundException; |
||||
import java.io.IOException; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URL; |
||||
import java.net.URLConnection; |
||||
import java.net.URLStreamHandler; |
||||
import java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.HashSet; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.jar.Manifest; |
||||
|
||||
/** |
||||
* {@link Archive} implementation backed by an exploded archive directory. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class ExplodedArchive implements Archive { |
||||
|
||||
private static final Set<String> SKIPPED_NAMES = new HashSet<String>(Arrays.asList( |
||||
".", "..")); |
||||
|
||||
private static final Object MANIFEST_ENTRY_NAME = "META-INF/MANIFEST.MF"; |
||||
|
||||
private File root; |
||||
|
||||
private Map<String, Entry> entries = new LinkedHashMap<String, Entry>(); |
||||
|
||||
private Manifest manifest; |
||||
|
||||
public ExplodedArchive(File root) { |
||||
if (!root.exists() || !root.isDirectory()) { |
||||
throw new IllegalArgumentException("Invalid source folder " + root); |
||||
} |
||||
this.root = root; |
||||
buildEntries(root); |
||||
this.entries = Collections.unmodifiableMap(this.entries); |
||||
} |
||||
|
||||
private ExplodedArchive(File root, Map<String, Entry> entries) { |
||||
this.root = root; |
||||
this.entries = Collections.unmodifiableMap(entries); |
||||
} |
||||
|
||||
private void buildEntries(File file) { |
||||
if (!file.equals(this.root)) { |
||||
String name = file.getAbsolutePath().substring( |
||||
this.root.getAbsolutePath().length() + 1); |
||||
if (file.isDirectory()) { |
||||
name += "/"; |
||||
} |
||||
this.entries.put(name, new FileEntry(name, file)); |
||||
} |
||||
if (file.isDirectory()) { |
||||
for (File child : file.listFiles()) { |
||||
if (!SKIPPED_NAMES.contains(child.getName())) { |
||||
buildEntries(child); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Manifest getManifest() throws IOException { |
||||
if (this.manifest == null && this.entries.containsKey(MANIFEST_ENTRY_NAME)) { |
||||
FileEntry entry = (FileEntry) this.entries.get(MANIFEST_ENTRY_NAME); |
||||
FileInputStream inputStream = new FileInputStream(entry.getFile()); |
||||
try { |
||||
this.manifest = new Manifest(inputStream); |
||||
} |
||||
finally { |
||||
inputStream.close(); |
||||
} |
||||
} |
||||
return this.manifest; |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Entry> getEntries() { |
||||
return this.entries.values(); |
||||
} |
||||
|
||||
@Override |
||||
public URL getUrl() throws MalformedURLException { |
||||
FilteredURLStreamHandler handler = new FilteredURLStreamHandler(); |
||||
return new URL("file", "", -1, this.root.getAbsolutePath() + "/", handler); |
||||
// return this.root.toURI().toURL();
|
||||
} |
||||
|
||||
@Override |
||||
public Archive getNestedArchive(Entry entry) throws IOException { |
||||
File file = ((FileEntry) entry).getFile(); |
||||
return (file.isDirectory() ? new ExplodedArchive(file) : new JarFileArchive(file)); |
||||
} |
||||
|
||||
@Override |
||||
public Archive getFilteredArchive(EntryFilter filter) throws IOException { |
||||
Map<String, Entry> filteredEntries = new LinkedHashMap<String, Archive.Entry>(); |
||||
for (Map.Entry<String, Entry> entry : this.entries.entrySet()) { |
||||
String filteredName = filter.apply(entry.getKey(), entry.getValue()); |
||||
if (filteredName != null) { |
||||
filteredEntries.put(filteredName, new FileEntry(filteredName, |
||||
((FileEntry) entry.getValue()).getFile())); |
||||
} |
||||
} |
||||
return new ExplodedArchive(this.root, filteredEntries); |
||||
} |
||||
|
||||
private class FileEntry implements Entry { |
||||
|
||||
private final String name; |
||||
private final File file; |
||||
|
||||
public FileEntry(String name, File file) { |
||||
this.name = name; |
||||
this.file = file; |
||||
} |
||||
|
||||
public File getFile() { |
||||
return this.file; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isDirectory() { |
||||
return this.file.isDirectory(); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return this.name; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* {@link URLStreamHandler} that respects filtered entries. |
||||
*/ |
||||
private class FilteredURLStreamHandler extends URLStreamHandler { |
||||
|
||||
public FilteredURLStreamHandler() { |
||||
} |
||||
|
||||
@Override |
||||
protected URLConnection openConnection(URL url) throws IOException { |
||||
String name = url.getPath().substring( |
||||
ExplodedArchive.this.root.getAbsolutePath().length() + 1); |
||||
if (ExplodedArchive.this.entries.containsKey(name)) { |
||||
return new URL(url.toString()).openConnection(); |
||||
} |
||||
return new FileNotFoundURLConnection(url, name); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* {@link URLConnection} used to represent a filtered file. |
||||
*/ |
||||
private static class FileNotFoundURLConnection extends URLConnection { |
||||
|
||||
private String name; |
||||
|
||||
public FileNotFoundURLConnection(URL url, String name) { |
||||
super(url); |
||||
this.name = name; |
||||
} |
||||
|
||||
@Override |
||||
public void connect() throws IOException { |
||||
throw new FileNotFoundException(this.name); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,119 @@
@@ -0,0 +1,119 @@
|
||||
/* |
||||
* 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.launcher; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URL; |
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.Enumeration; |
||||
import java.util.List; |
||||
import java.util.jar.JarEntry; |
||||
import java.util.jar.Manifest; |
||||
|
||||
import org.springframework.launcher.jar.JarEntryFilter; |
||||
import org.springframework.launcher.jar.RandomAccessJarFile; |
||||
|
||||
/** |
||||
* {@link Archive} implementation backed by a {@link RandomAccessJarFile}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class JarFileArchive implements Archive { |
||||
|
||||
private final RandomAccessJarFile jarFile; |
||||
|
||||
private final List<Entry> entries; |
||||
|
||||
public JarFileArchive(File file) throws IOException { |
||||
this(new RandomAccessJarFile(file)); |
||||
} |
||||
|
||||
public JarFileArchive(RandomAccessJarFile jarFile) { |
||||
this.jarFile = jarFile; |
||||
ArrayList<Entry> jarFileEntries = new ArrayList<Entry>(); |
||||
Enumeration<JarEntry> entries = jarFile.entries(); |
||||
while (entries.hasMoreElements()) { |
||||
jarFileEntries.add(new JarFileEntry(entries.nextElement())); |
||||
} |
||||
this.entries = Collections.unmodifiableList(jarFileEntries); |
||||
} |
||||
|
||||
@Override |
||||
public Manifest getManifest() throws IOException { |
||||
return this.jarFile.getManifest(); |
||||
} |
||||
|
||||
@Override |
||||
public Iterable<Entry> getEntries() { |
||||
return this.entries; |
||||
} |
||||
|
||||
@Override |
||||
public URL getUrl() throws MalformedURLException { |
||||
return this.jarFile.getUrl(); |
||||
} |
||||
|
||||
@Override |
||||
public Archive getNestedArchive(Entry entry) throws IOException { |
||||
JarEntry jarEntry = ((JarFileEntry) entry).getJarEntry(); |
||||
RandomAccessJarFile jarFile = this.jarFile.getNestedJarFile(jarEntry); |
||||
return new JarFileArchive(jarFile); |
||||
} |
||||
|
||||
@Override |
||||
public Archive getFilteredArchive(final EntryFilter filter) throws IOException { |
||||
RandomAccessJarFile filteredJar = this.jarFile |
||||
.getFilteredJarFile(new JarEntryFilter() { |
||||
@Override |
||||
public String apply(String name, JarEntry entry) { |
||||
return filter.apply(name, new JarFileEntry(entry)); |
||||
} |
||||
}); |
||||
return new JarFileArchive(filteredJar); |
||||
} |
||||
|
||||
/** |
||||
* {@link Archive.Entry} implementation backed by a {@link JarEntry}. |
||||
*/ |
||||
private static class JarFileEntry implements Entry { |
||||
|
||||
private final JarEntry jarEntry; |
||||
|
||||
public JarFileEntry(JarEntry jarEntry) { |
||||
this.jarEntry = jarEntry; |
||||
} |
||||
|
||||
public JarEntry getJarEntry() { |
||||
return this.jarEntry; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isDirectory() { |
||||
return this.jarEntry.isDirectory(); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return this.jarEntry.getName(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,151 @@
@@ -0,0 +1,151 @@
|
||||
/* |
||||
* 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.launcher; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
import java.net.URL; |
||||
import java.net.URLClassLoader; |
||||
import java.util.Enumeration; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.jar.JarEntry; |
||||
import java.util.jar.JarFile; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.TemporaryFolder; |
||||
import org.springframework.launcher.Archive.Entry; |
||||
|
||||
import static org.hamcrest.Matchers.equalTo; |
||||
import static org.hamcrest.Matchers.nullValue; |
||||
import static org.junit.Assert.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link ExplodedArchive}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class ExplodedArchiveTests { |
||||
|
||||
@Rule |
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder(); |
||||
|
||||
private File rootFolder; |
||||
|
||||
private ExplodedArchive archive; |
||||
|
||||
@Before |
||||
public void setup() throws Exception { |
||||
File file = this.temporaryFolder.newFile(); |
||||
TestJarCreator.createTestJar(file); |
||||
|
||||
this.rootFolder = this.temporaryFolder.newFolder(); |
||||
JarFile jarFile = new JarFile(file); |
||||
Enumeration<JarEntry> entries = jarFile.entries(); |
||||
while (entries.hasMoreElements()) { |
||||
JarEntry entry = entries.nextElement(); |
||||
File destination = new File(this.rootFolder.getAbsolutePath() |
||||
+ File.separator + entry.getName()); |
||||
destination.getParentFile().mkdirs(); |
||||
if (entry.isDirectory()) { |
||||
destination.mkdir(); |
||||
} |
||||
else { |
||||
copy(jarFile.getInputStream(entry), new FileOutputStream(destination)); |
||||
} |
||||
} |
||||
this.archive = new ExplodedArchive(this.rootFolder); |
||||
} |
||||
|
||||
private void copy(InputStream in, OutputStream out) throws IOException { |
||||
byte[] buffer = new byte[1024]; |
||||
int len = in.read(buffer); |
||||
while (len != -1) { |
||||
out.write(buffer, 0, len); |
||||
len = in.read(buffer); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void getManifest() throws Exception { |
||||
assertThat(this.archive.getManifest().getMainAttributes().getValue("Built-By"), |
||||
equalTo("j1")); |
||||
} |
||||
|
||||
@Test |
||||
public void getEntries() throws Exception { |
||||
Map<String, Archive.Entry> entries = getEntriesMap(this.archive); |
||||
assertThat(entries.size(), equalTo(7)); |
||||
} |
||||
|
||||
@Test |
||||
public void getUrl() throws Exception { |
||||
URL url = this.archive.getUrl(); |
||||
assertThat(url, equalTo(this.rootFolder.toURI().toURL())); |
||||
} |
||||
|
||||
@Test |
||||
public void getNestedArchive() throws Exception { |
||||
Entry entry = getEntriesMap(this.archive).get("nested.jar"); |
||||
Archive nested = this.archive.getNestedArchive(entry); |
||||
assertThat(nested.getUrl().toString(), |
||||
equalTo("jar:file:" + this.rootFolder.getPath() + "/nested.jar!/")); |
||||
} |
||||
|
||||
@Test |
||||
public void nestedDirArchive() throws Exception { |
||||
Entry entry = getEntriesMap(this.archive).get("d/"); |
||||
Archive nested = this.archive.getNestedArchive(entry); |
||||
Map<String, Entry> nestedEntries = getEntriesMap(nested); |
||||
assertThat(nestedEntries.size(), equalTo(1)); |
||||
assertThat(nested.getUrl().toString(), |
||||
equalTo("file:" + this.rootFolder.getPath() + "/d/")); |
||||
} |
||||
|
||||
@Test |
||||
public void getFilteredArchive() throws Exception { |
||||
Archive filteredArchive = this.archive |
||||
.getFilteredArchive(new Archive.EntryFilter() { |
||||
@Override |
||||
public String apply(String entryName, Entry entry) { |
||||
if (entryName.equals("1.dat")) { |
||||
return entryName; |
||||
} |
||||
return null; |
||||
} |
||||
}); |
||||
Map<String, Entry> entries = getEntriesMap(filteredArchive); |
||||
assertThat(entries.size(), equalTo(1)); |
||||
URLClassLoader classLoader = new URLClassLoader( |
||||
new URL[] { filteredArchive.getUrl() }); |
||||
assertThat(classLoader.getResourceAsStream("1.dat").read(), equalTo(1)); |
||||
assertThat(classLoader.getResourceAsStream("2.dat"), nullValue()); |
||||
} |
||||
|
||||
private Map<String, Archive.Entry> getEntriesMap(Archive archive) { |
||||
Map<String, Archive.Entry> entries = new HashMap<String, Archive.Entry>(); |
||||
for (Archive.Entry entry : archive.getEntries()) { |
||||
entries.put(entry.getName(), entry); |
||||
} |
||||
return entries; |
||||
} |
||||
} |
||||
@ -0,0 +1,104 @@
@@ -0,0 +1,104 @@
|
||||
/* |
||||
* 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.launcher; |
||||
|
||||
import java.io.File; |
||||
import java.net.URL; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.TemporaryFolder; |
||||
import org.springframework.launcher.Archive.Entry; |
||||
|
||||
import static org.hamcrest.Matchers.equalTo; |
||||
import static org.junit.Assert.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link JarFileArchive}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public class JarFileArchiveTests { |
||||
|
||||
@Rule |
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder(); |
||||
|
||||
private File rootJarFile; |
||||
|
||||
private JarFileArchive archive; |
||||
|
||||
@Before |
||||
public void setup() throws Exception { |
||||
this.rootJarFile = this.temporaryFolder.newFile(); |
||||
TestJarCreator.createTestJar(this.rootJarFile); |
||||
this.archive = new JarFileArchive(this.rootJarFile); |
||||
} |
||||
|
||||
@Test |
||||
public void getManifest() throws Exception { |
||||
assertThat(this.archive.getManifest().getMainAttributes().getValue("Built-By"), |
||||
equalTo("j1")); |
||||
} |
||||
|
||||
@Test |
||||
public void getEntries() throws Exception { |
||||
Map<String, Archive.Entry> entries = getEntriesMap(this.archive); |
||||
assertThat(entries.size(), equalTo(7)); |
||||
} |
||||
|
||||
@Test |
||||
public void getUrl() throws Exception { |
||||
URL url = this.archive.getUrl(); |
||||
assertThat(url.toString(), equalTo("jar:file:" + this.rootJarFile.getPath() |
||||
+ "!/")); |
||||
} |
||||
|
||||
@Test |
||||
public void getNestedArchive() throws Exception { |
||||
Entry entry = getEntriesMap(this.archive).get("nested.jar"); |
||||
Archive nested = this.archive.getNestedArchive(entry); |
||||
assertThat(nested.getUrl().toString(), |
||||
equalTo("jar:file:" + this.rootJarFile.getPath() + "!/nested.jar!/")); |
||||
} |
||||
|
||||
@Test |
||||
public void getFilteredArchive() throws Exception { |
||||
Archive filteredArchive = this.archive |
||||
.getFilteredArchive(new Archive.EntryFilter() { |
||||
@Override |
||||
public String apply(String entryName, Entry entry) { |
||||
if (entryName.equals("1.dat")) { |
||||
return entryName; |
||||
} |
||||
return null; |
||||
} |
||||
}); |
||||
Map<String, Entry> entries = getEntriesMap(filteredArchive); |
||||
assertThat(entries.size(), equalTo(1)); |
||||
} |
||||
|
||||
private Map<String, Archive.Entry> getEntriesMap(Archive archive) { |
||||
Map<String, Archive.Entry> entries = new HashMap<String, Archive.Entry>(); |
||||
for (Archive.Entry entry : archive.getEntries()) { |
||||
entries.put(entry.getName(), entry); |
||||
} |
||||
return entries; |
||||
} |
||||
} |
||||
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
/* |
||||
* 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.launcher; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.jar.Attributes; |
||||
import java.util.jar.JarEntry; |
||||
import java.util.jar.JarOutputStream; |
||||
import java.util.jar.Manifest; |
||||
import java.util.zip.CRC32; |
||||
import java.util.zip.ZipEntry; |
||||
|
||||
/** |
||||
* Creates a simple test jar. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
public abstract class TestJarCreator { |
||||
|
||||
public static void createTestJar(File file) throws Exception { |
||||
FileOutputStream fileOutputStream = new FileOutputStream(file); |
||||
JarOutputStream jarOutputStream = new JarOutputStream(fileOutputStream); |
||||
try { |
||||
writeManifest(jarOutputStream, "j1"); |
||||
writeEntry(jarOutputStream, "1.dat", 1); |
||||
writeEntry(jarOutputStream, "2.dat", 2); |
||||
writeDirEntry(jarOutputStream, "d/"); |
||||
writeEntry(jarOutputStream, "d/9.dat", 9); |
||||
|
||||
JarEntry nestedEntry = new JarEntry("nested.jar"); |
||||
byte[] nestedJarData = getNestedJarData(); |
||||
nestedEntry.setSize(nestedJarData.length); |
||||
nestedEntry.setCompressedSize(nestedJarData.length); |
||||
CRC32 crc32 = new CRC32(); |
||||
crc32.update(nestedJarData); |
||||
nestedEntry.setCrc(crc32.getValue()); |
||||
|
||||
nestedEntry.setMethod(ZipEntry.STORED); |
||||
jarOutputStream.putNextEntry(nestedEntry); |
||||
jarOutputStream.write(nestedJarData); |
||||
jarOutputStream.closeEntry(); |
||||
} |
||||
finally { |
||||
jarOutputStream.close(); |
||||
} |
||||
} |
||||
|
||||
private static byte[] getNestedJarData() throws Exception { |
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
||||
JarOutputStream jarOutputStream = new JarOutputStream(byteArrayOutputStream); |
||||
writeManifest(jarOutputStream, "j2"); |
||||
writeEntry(jarOutputStream, "3.dat", 3); |
||||
writeEntry(jarOutputStream, "4.dat", 4); |
||||
jarOutputStream.close(); |
||||
return byteArrayOutputStream.toByteArray(); |
||||
} |
||||
|
||||
private static void writeManifest(JarOutputStream jarOutputStream, String name) |
||||
throws Exception { |
||||
writeDirEntry(jarOutputStream, "META-INF/"); |
||||
Manifest manifest = new Manifest(); |
||||
manifest.getMainAttributes().putValue("Built-By", name); |
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); |
||||
jarOutputStream.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF")); |
||||
manifest.write(jarOutputStream); |
||||
jarOutputStream.closeEntry(); |
||||
} |
||||
|
||||
private static void writeDirEntry(JarOutputStream jarOutputStream, String name) |
||||
throws IOException { |
||||
jarOutputStream.putNextEntry(new JarEntry(name)); |
||||
jarOutputStream.closeEntry(); |
||||
} |
||||
|
||||
private static void writeEntry(JarOutputStream jarOutputStream, String name, int data) |
||||
throws IOException { |
||||
jarOutputStream.putNextEntry(new JarEntry(name)); |
||||
jarOutputStream.write(new byte[] { (byte) data }); |
||||
jarOutputStream.closeEntry(); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue