aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVioleta Georgieva2010-09-07 04:51:42 (EDT)
committerGlyn Normington2010-09-07 04:51:42 (EDT)
commit5c79742c0fb0c07cda7eb0c077cbad653f89447f (patch)
treeb0d8d9a60888466cd3265cef453fe4a2df652548
parent6dc941d317a9073e42e1262770252ff1062d9650 (diff)
downloadorg.eclipse.gemini.web.gemini-web-container-5c79742c0fb0c07cda7eb0c077cbad653f89447f.zip
org.eclipse.gemini.web.gemini-web-container-5c79742c0fb0c07cda7eb0c077cbad653f89447f.tar.gz
org.eclipse.gemini.web.gemini-web-container-5c79742c0fb0c07cda7eb0c077cbad653f89447f.tar.bz2
bug 307393: web application extraction support
-rw-r--r--org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/DirTransformer.java158
-rw-r--r--org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/DirTransformingURLConnection.java125
-rw-r--r--org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerService.java82
-rw-r--r--org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/DirTransformerTest.java203
-rw-r--r--org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/DirTransformingURLConnectionTest.java76
-rw-r--r--org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerServiceTests.java104
-rw-r--r--org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java23
7 files changed, 753 insertions, 18 deletions
diff --git a/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/DirTransformer.java b/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/DirTransformer.java
new file mode 100644
index 0000000..52b8811
--- /dev/null
+++ b/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/DirTransformer.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2010 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web.internal.url;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.jar.JarFile;
+
+import org.eclipse.virgo.util.io.IOUtils;
+import org.eclipse.virgo.util.io.PathReference;
+
+/**
+ * Utility class for transforming the files in a directory.
+ * <p/>
+ * Files cannot be added, only changed or removed. Actual transformation of files is performed by an implementation of
+ * the {@link DirTransformerCallback} interface.
+ */
+public class DirTransformer {
+
+ /**
+ * Callback interface used to transform files in a directory.
+ *
+ * @see DirTransformer
+ */
+ public static interface DirTransformerCallback {
+
+ /**
+ * Transform the supplied file.
+ * <p/>
+ * File content can be read from the supplied {@link InputStream} and transformed contents can be written to the
+ * supplied {@link File}.
+ * <p/>
+ * Implementations <strong>must</strong> return <code>true</code> if the file was transformed or deleted.
+ * Otherwise, <code>false</code> must be returned. No content should be written when not performing a
+ * transformation.
+ * <p/>
+ * Implementations transforming a file must save the file as <code>toFile</code>. Implementations deleting a
+ * file must not save the file as <code>toFile</code>.
+ *
+ * @param inputStream the {@link InputStream} that will be transformed
+ * @param toFile the transformed {@link File}
+ * @return <code>true</code> if the file was transformed, otherwise <code>false</code>
+ * @throws IOException if transformation fails
+ */
+ boolean transformFile(InputStream inputStream, PathReference toFile) throws IOException;
+ }
+
+ private static final String MANIFEST_VERSION_HEADER = "Manifest-Version: 1.0";
+
+ private final DirTransformerCallback callback;
+
+ /**
+ * Creates a new <code>DirTransformer</code> that uses the supplied {@link DirTransformerCallback} for
+ * transformation.
+ *
+ * @param callback the <code>DirTransformerCallback</code> to use for file transformation.
+ */
+ public DirTransformer(DirTransformerCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Callback must not be null");
+ }
+ this.callback = callback;
+ }
+
+ /**
+ * Transforms the directory content in <code>url</code> and writes the results to <code>transformedUrl</code>.
+ *
+ * @param url the {@link URL} of the directory to transform.
+ * @param transformedUrl the {@link URL} to write the transformed directory to.
+ * @throws IOException if the directory cannot be transformed.
+ */
+ public void transform(URL url, URL transformedUrl) throws IOException {
+ transform(url, transformedUrl, false);
+ }
+
+ /**
+ * Transforms the directory content in <code>url</code> and writes the results to <code>transformedUrl</code>.
+ *
+ * @param url the {@link URL} of the directory to transform.
+ * @param transformedUrl the {@link URL} to write the transformed directory to.
+ * @param ensureManifestIsPresent if <code>true</code> ensures that the transformed directory contains a manifest.
+ * @throws IOException if the directory cannot be transformed.
+ */
+ public void transform(URL url, URL transformedUrl, boolean ensureManifestIsPresent) throws IOException {
+ PathReference fromDirectory = new PathReference(url.getPath());
+ PathReference toDirectory = new PathReference(transformedUrl.getPath());
+ transformDir(fromDirectory, toDirectory);
+
+ PathReference manifest = fromDirectory.newChild(JarFile.MANIFEST_NAME);
+ if (ensureManifestIsPresent && !manifest.exists()) {
+ InputStream defaultManifestStream = getDefaultManifestStream();
+ PathReference toFile = toDirectory.newChild(JarFile.MANIFEST_NAME);
+ toFile.getParent().createDirectory();
+ try {
+ this.callback.transformFile(defaultManifestStream, toFile);
+ } finally {
+ IOUtils.closeQuietly(defaultManifestStream);
+ }
+ }
+ }
+
+ private void transformDir(PathReference fromDirectory, PathReference toDirectory) throws IOException {
+ File[] fileList = fromDirectory.toFile().listFiles();
+ PathReference fromFile = null;
+ for (int i = 0; fileList != null && i < fileList.length; i++) {
+ fromFile = new PathReference(fileList[i]);
+ PathReference toFile = toDirectory.newChild(fromFile.getName());
+ if (!fromFile.isDirectory()) {
+ transformFile(fromFile, toFile);
+ } else {
+ transformDir(fromFile, toFile);
+ }
+ }
+ }
+
+ private void transformFile(PathReference fromFile, PathReference toFile) throws IOException {
+ FileInputStream fis = new FileInputStream(fromFile.toFile());
+ boolean transformed = false;
+ try {
+ transformed = this.callback.transformFile(fis, toFile);
+ } finally {
+ IOUtils.closeQuietly(fis);
+ }
+ if (!transformed) {
+ toFile.getParent().createDirectory();
+ fromFile.copy(toFile);
+ }
+ }
+
+ private InputStream getDefaultManifestStream() {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintWriter writer = new PrintWriter(baos);
+ writer.println(MANIFEST_VERSION_HEADER);
+ writer.println();
+ writer.close();
+ return new ByteArrayInputStream(baos.toByteArray());
+ }
+}
diff --git a/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/DirTransformingURLConnection.java b/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/DirTransformingURLConnection.java
new file mode 100644
index 0000000..6c738c3
--- /dev/null
+++ b/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/DirTransformingURLConnection.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2010 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web.internal.url;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.eclipse.virgo.util.io.PathReference;
+
+/**
+ * Implementation of {@link URLConnection} that transforms directory files as they are read.
+ * <p/>
+ * A {@link URL} is used to source the real connection for the directory data, and a {@link DirTransformer} is used to
+ * customize the exact transformations being performed.
+ *
+ * @see DirTransformer
+ */
+public class DirTransformingURLConnection extends URLConnection {
+
+ private static final String TEMP_DIR = "file:temp/";
+
+ private final DirTransformer transformer;
+
+ private final boolean ensureManifestIsPresent;
+
+ private final Object monitor = new Object();
+
+ private URL transformedURL;
+
+ /**
+ * Creates a new <code>DirTransformingURLConnection</code> that will provide content from the directory identified
+ * by <code>url</code> transformed by <code>transformer</code>.
+ *
+ * @param url the {@link URL} of the directory.
+ * @param transformer the <code>DirTransformer</code> to apply as content is being read.
+ * @throws MalformedURLException the exception is thrown in case the new URL, where is the transformed data, cannot
+ * be created.
+ * @throws URISyntaxException
+ */
+ public DirTransformingURLConnection(URL url, DirTransformer transformer) throws MalformedURLException {
+ this(url, transformer, false);
+ }
+
+ /**
+ * Creates a new <code>DirTransformingURLConnection</code> that will provide content from the directory identified
+ * by <code>url</code> transformed by <code>transformer</code> and that will optionally ensure that a manifest is
+ * provided, creating one if necessary.
+ *
+ * @param url the {@link URL} of the directory.
+ * @param transformer the <code>DirTransformer</code> to apply as content is being read.
+ * @param ensureManifestIsPresent <code>true</code> if the presence of a MANIFEST.MF should be ensured.
+ * @throws MalformedURLException the exception is thrown in case the new URL, where is the transformed data, cannot
+ * be created.
+ * @throws URISyntaxException
+ */
+ public DirTransformingURLConnection(URL url, DirTransformer transformer, boolean ensureManifestIsPresent) throws MalformedURLException {
+ super(url);
+ this.transformer = transformer;
+ this.ensureManifestIsPresent = ensureManifestIsPresent;
+
+ this.transformedURL = new URL(TEMP_DIR + getPath());
+ PathReference transformedDir = new PathReference(this.transformedURL.getPath());
+ transformedDir.delete(true);
+ }
+
+ @Override
+ public void connect() throws IOException {
+ }
+
+ /**
+ * Transform the URL before returning the input stream.
+ */
+ @Override
+ public InputStream getInputStream() throws IOException {
+ synchronized (monitor) {
+ this.transformer.transform(this.url, this.transformedURL, this.ensureManifestIsPresent);
+ return this.transformedURL.openStream();
+ }
+ }
+
+ private String getPath() {
+ String path = this.url.getPath();
+ int index = path.lastIndexOf('/');
+ if (index > -1) {
+ path = path.substring(index + 1);
+ }
+
+ return path;
+ }
+
+ /**
+ * Returns transformed URL instead of the original one.
+ */
+ @Override
+ public URL getURL() {
+ synchronized (monitor) {
+ return this.transformedURL;
+ }
+ }
+
+ void setTransformedURL(URL transformedURL) {
+ synchronized (monitor) {
+ this.transformedURL = transformedURL;
+ }
+ }
+
+}
diff --git a/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerService.java b/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerService.java
index 4743c7e..0740c22 100644
--- a/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerService.java
+++ b/org.eclipse.gemini.web.core/src/main/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerService.java
@@ -16,9 +16,12 @@
package org.eclipse.gemini.web.internal.url;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Dictionary;
@@ -36,9 +39,12 @@ import org.osgi.service.url.URLStreamHandlerService;
import org.eclipse.gemini.web.core.InstallationOptions;
import org.eclipse.gemini.web.core.WebBundleManifestTransformer;
import org.eclipse.gemini.web.internal.WebContainerUtils;
+import org.eclipse.gemini.web.internal.url.DirTransformer.DirTransformerCallback;
+import org.eclipse.virgo.util.io.IOUtils;
import org.eclipse.virgo.util.io.JarTransformer;
import org.eclipse.virgo.util.io.JarTransformingURLConnection;
import org.eclipse.virgo.util.io.JarTransformer.JarTransformerCallback;
+import org.eclipse.virgo.util.io.PathReference;
import org.eclipse.virgo.util.osgi.manifest.BundleManifest;
import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
@@ -50,7 +56,8 @@ import org.eclipse.virgo.util.osgi.manifest.BundleManifestFactory;
* @see WebBundleManifestTransformer
*/
public final class WebBundleUrlStreamHandlerService extends AbstractURLStreamHandlerService {
-
+ private static final String FILE_PROTOCOL = "file";
+
private final WebBundleManifestTransformer transformer;
public WebBundleUrlStreamHandlerService(WebBundleManifestTransformer transformer) {
@@ -61,13 +68,20 @@ public final class WebBundleUrlStreamHandlerService extends AbstractURLStreamHan
public URLConnection openConnection(URL u) throws IOException {
WebBundleUrl url = new WebBundleUrl(u);
URL actualUrl = new URL(url.getLocation());
-
- JarTransformer jarTransformer = new JarTransformer(new Callback(actualUrl, url, this.transformer));
- return new JarTransformingURLConnection(actualUrl, jarTransformer, true);
+
+ if (FILE_PROTOCOL.equals(actualUrl.getProtocol()) && new File(actualUrl.getPath()).isDirectory()) {
+ DirTransformer dirTransformer = new DirTransformer(new Callback(actualUrl, url, this.transformer));
+ return new DirTransformingURLConnection(actualUrl, dirTransformer, true);
+ } else {
+ JarTransformer jarTransformer = new JarTransformer(new Callback(actualUrl, url, this.transformer));
+ return new JarTransformingURLConnection(actualUrl, jarTransformer, true);
+ }
}
- private static final class Callback implements JarTransformerCallback {
-
+ private static final class Callback implements JarTransformerCallback, DirTransformerCallback {
+ private static final String META_INF = "META-INF";
+ private static final String MANIFEST_MF = "MANIFEST.MF";
+
private final WebBundleManifestTransformer transformer;
private final URL sourceURL;
@@ -83,17 +97,7 @@ public final class WebBundleUrlStreamHandlerService extends AbstractURLStreamHan
public boolean transformEntry(String entryName, InputStream is, JarOutputStream jos) throws IOException {
if (JarFile.MANIFEST_NAME.equals(entryName)) {
jos.putNextEntry(new ZipEntry(entryName));
- InputStreamReader reader = new InputStreamReader(is);
- BundleManifest manifest = BundleManifestFactory.createBundleManifest(reader);
- InstallationOptions options = new InstallationOptions(this.webBundleUrl.getOptions());
- if (manifest.getHeader(WebContainerUtils.HEADER_SPRINGSOURCE_DEFAULT_WAB_HEADERS) != null) {
- options.setDefaultWABHeaders(true);
- }
-
- boolean webBundle = WebContainerUtils.isWebApplicationBundle(manifest);
- this.transformer.transform(manifest, sourceURL, options, webBundle);
-
- toManifest(manifest.toDictionary()).write(jos);
+ transformManifest(is, jos);
jos.closeEntry();
return true;
}
@@ -102,10 +106,24 @@ public final class WebBundleUrlStreamHandlerService extends AbstractURLStreamHan
return isSignatureFile(entryName);
}
+ private void transformManifest(InputStream inputStream, OutputStream outputStream) throws IOException {
+ InputStreamReader reader = new InputStreamReader(inputStream);
+ BundleManifest manifest = BundleManifestFactory.createBundleManifest(reader);
+ InstallationOptions options = new InstallationOptions(this.webBundleUrl.getOptions());
+ if (manifest.getHeader(WebContainerUtils.HEADER_SPRINGSOURCE_DEFAULT_WAB_HEADERS) != null) {
+ options.setDefaultWABHeaders(true);
+ }
+
+ boolean webBundle = WebContainerUtils.isWebApplicationBundle(manifest);
+ this.transformer.transform(manifest, sourceURL, options, webBundle);
+
+ toManifest(manifest.toDictionary()).write(outputStream);
+ }
+
private boolean isSignatureFile(String entryName) {
String[] entryNameComponents = entryName.split("/");
if (entryNameComponents.length == 2) {
- if ("META-INF".equals(entryNameComponents[0])) {
+ if (META_INF.equals(entryNameComponents[0])) {
String entryFileName = entryNameComponents[1];
if (entryFileName.endsWith(".SF") || entryFileName.endsWith(".DSA") || entryFileName.endsWith(".RSA")) {
return true;
@@ -129,6 +147,34 @@ public final class WebBundleUrlStreamHandlerService extends AbstractURLStreamHan
return manifest;
}
+ public boolean transformFile(InputStream inputStream, PathReference toFile) throws IOException {
+ if (MANIFEST_MF.equals(toFile.getName()) && META_INF.equals(toFile.getParent().getName())) {
+ toFile.getParent().createDirectory();
+ OutputStream outputStream = null;
+ try {
+ outputStream = new FileOutputStream(toFile.toFile());
+ transformManifest(inputStream, outputStream);
+ } finally {
+ IOUtils.closeQuietly(outputStream);
+ }
+ return true;
+ }
+
+ // Delete signature files. Should be generalized into another
+ // transformer type.
+ return isSignatureFile(toFile);
+ }
+
+ private boolean isSignatureFile(PathReference file) {
+ if (META_INF.equals(file.getParent().getName())) {
+ String fileName = file.getName();
+ if (fileName.endsWith(".SF") || fileName.endsWith(".DSA") || fileName.endsWith(".RSA")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
}
diff --git a/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/DirTransformerTest.java b/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/DirTransformerTest.java
new file mode 100644
index 0000000..4a6c9b4
--- /dev/null
+++ b/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/DirTransformerTest.java
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * Copyright (c) 2010 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web.internal.url;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import org.eclipse.gemini.web.internal.url.DirTransformer.DirTransformerCallback;
+import org.eclipse.virgo.util.io.IOUtils;
+import org.eclipse.virgo.util.io.PathReference;
+import org.junit.Test;
+
+public class DirTransformerTest {
+
+ private static final String WEB_INF = "WEB-INF";
+
+ private static final String META_INF = "META-INF";
+
+ private static final String WEB_XML = "web.xml";
+
+ private static final String MANIFEST_MF = "MANIFEST.MF";
+
+ private static final String HEADER_1 = "Manifest-Version: 1.0";
+
+ private static final String HEADER_2 = "Class-Path: ";
+
+ private static final String HEADER_3 = "Custom-Header: test";
+
+ private static final String SOURCE_URL = "file:target/test-classes/web-app-dir";
+
+ private static final String TARGET_URL = "file:target/test-classes/temp/web-app-dir";
+
+ @Test
+ public void testTransformManifestAdded() throws Exception {
+ URL directory = new URL(SOURCE_URL);
+ URL tempDirectory = new URL(TARGET_URL);
+
+ // Create content
+ PathReference webAppDir = new PathReference(directory.getPath());
+ PathReference webXml = webAppDir.newChild(WEB_INF + File.separator + WEB_XML);
+ webXml.createFile();
+ PathReference manifest = webAppDir.newChild(JarFile.MANIFEST_NAME);
+
+ final List<PathReference> transformedFiles = new ArrayList<PathReference>();
+ DirTransformer transformer = new DirTransformer(new DirTransformerCallback() {
+
+ public boolean transformFile(InputStream inputStream, PathReference toFile) throws IOException {
+ transformedFiles.add(toFile);
+ return false;
+ }
+ });
+
+ PathReference tempWebAppDir = new PathReference(tempDirectory.getPath());
+ transformer.transform(directory, tempDirectory, false);
+ assertEquals(1, transformedFiles.size());
+ assertTrue(!manifest.exists());
+ assertTrue(!transformedFiles.contains(manifest));
+ assertTrue(tempWebAppDir.delete(true));
+ transformedFiles.clear();
+
+ transformer.transform(directory, tempDirectory, true);
+ assertEquals(2, transformedFiles.size());
+ assertTrue(!manifest.exists());
+ assertTrue(transformedFiles.contains(tempWebAppDir.newChild(JarFile.MANIFEST_NAME)));
+
+ assertTrue(tempWebAppDir.delete(true));
+ assertTrue(webAppDir.delete(true));
+ }
+
+ @Test
+ public void testTransformManifestChanged() throws Exception {
+ URL directory = new URL(SOURCE_URL);
+ URL tempDirectory = new URL(TARGET_URL);
+
+ // Create content
+ PathReference webAppDir = new PathReference(directory.getPath());
+ PathReference manifest = webAppDir.newChild(JarFile.MANIFEST_NAME);
+ manifest.getParent().createDirectory();
+ createManifest(manifest.toFile(), HEADER_1, HEADER_2);
+
+ DirTransformer transformer = new DirTransformer(new DirTransformerCallback() {
+
+ public boolean transformFile(InputStream inputStream, PathReference toFile) throws IOException {
+ if (MANIFEST_MF.equals(toFile.getName()) && META_INF.equals(toFile.getParent().getName())) {
+ toFile.getParent().createDirectory();
+ createManifest(toFile.toFile(), HEADER_3);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ });
+
+ transformer.transform(directory, tempDirectory);
+ PathReference tempWebAppDir = new PathReference(tempDirectory.getPath());
+ checkManifest(tempWebAppDir.newChild(JarFile.MANIFEST_NAME).toFile());
+
+ assertTrue(tempWebAppDir.delete(true));
+ assertTrue(webAppDir.delete(true));
+ }
+
+ @Test
+ public void testTransformNoChanges() throws Exception {
+ URL directory = new URL(SOURCE_URL);
+ URL tempDirectory = new URL(TARGET_URL);
+
+ // Create content
+ PathReference webAppDir = new PathReference(directory.getPath());
+ PathReference webXml = webAppDir.newChild(WEB_INF + File.separator + WEB_XML);
+ webXml.createFile();
+
+ DirTransformer transformer;
+ try {
+ transformer = new DirTransformer(null);
+ } catch (Exception e) {
+ assertTrue("Callback must not be null".equals(e.getMessage()));
+ }
+
+ transformer = new DirTransformer(new DirTransformerCallback() {
+
+ public boolean transformFile(InputStream inputStream, PathReference toFile) throws IOException {
+ return false;
+ }
+ });
+
+ transformer.transform(directory, tempDirectory);
+ PathReference tempWebAppDir = new PathReference(tempDirectory.getPath());
+ assertDirsSame(webAppDir.toFile(), tempWebAppDir.toFile());
+
+ assertTrue(tempWebAppDir.delete(true));
+ assertTrue(webAppDir.delete(true));
+ }
+
+ private void assertDirsSame(File source, File destination) throws IOException {
+ assertEquals(source.getName(), destination.getName());
+ assertEquals(source.length(), destination.length());
+
+ File[] sourceFiles = source.listFiles();
+ File[] destinationFiles = destination.listFiles();
+ assertEquals(sourceFiles.length, destinationFiles.length);
+
+ for (int i = 0; i < sourceFiles.length; i++) {
+ File sourceFile = sourceFiles[i];
+ File destinationFile = destinationFiles[i];
+ assertEquals(sourceFile.getName(), destinationFile.getName());
+ assertEquals(sourceFile.length(), destinationFile.length());
+ }
+ }
+
+ private void checkManifest(File manifestFile) throws IOException {
+ InputStream is = new FileInputStream(manifestFile);
+ Manifest manifest = new Manifest(is);
+ Attributes attr = manifest.getMainAttributes();
+ String value = attr.getValue("Custom-Header");
+ assertEquals("test", value);
+ assertEquals(1, attr.size());
+ IOUtils.closeQuietly(is);
+ }
+
+ private void createManifest(File manifest, String... headers) throws IOException {
+ OutputStream outputStream = null;
+ PrintWriter writer = null;
+ try {
+ outputStream = new FileOutputStream(manifest);
+ writer = new PrintWriter(manifest);
+ for (String header : headers) {
+ writer.println(header);
+ }
+ writer.println();
+ } finally {
+ IOUtils.closeQuietly(writer);
+ IOUtils.closeQuietly(outputStream);
+ }
+ }
+}
diff --git a/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/DirTransformingURLConnectionTest.java b/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/DirTransformingURLConnectionTest.java
new file mode 100644
index 0000000..55445b0
--- /dev/null
+++ b/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/DirTransformingURLConnectionTest.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2010 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web.internal.url;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.gemini.web.internal.url.DirTransformer.DirTransformerCallback;
+import org.eclipse.virgo.util.io.PathReference;
+import org.junit.Test;
+
+public class DirTransformingURLConnectionTest {
+
+ private static final String WEB_INF = "WEB-INF";
+
+ private static final String WEB_XML = "web.xml";
+
+ private static final String SOURCE_URL = "file:target/test-classes/web-app-dir";
+
+ private static final String TARGET_URL = "file:target/test-classes/temp/web-app-dir";
+
+ @Test
+ public void testGetURL() throws Exception {
+ URL directory = new URL(SOURCE_URL);
+ URL tempDirectory = new URL(TARGET_URL);
+
+ // Create content
+ PathReference webAppDir = new PathReference(directory.getPath());
+ PathReference webXml = webAppDir.newChild(WEB_INF + File.separator + WEB_XML);
+ webXml.createFile();
+
+ final List<PathReference> files = new ArrayList<PathReference>();
+ DirTransformer transformer = new DirTransformer(new DirTransformerCallback() {
+
+ public boolean transformFile(InputStream inputStream, PathReference toFile) throws IOException {
+ files.add(toFile);
+ return false;
+ }
+ });
+
+ DirTransformingURLConnection connection = new DirTransformingURLConnection(directory, transformer);
+ connection.setTransformedURL(tempDirectory);
+ InputStream is = connection.getInputStream();
+ assertNotNull(is);
+ URL url = connection.getURL();
+ assertTrue(tempDirectory.equals(url));
+
+ PathReference tempWebAppDir = new PathReference(tempDirectory.getPath());
+ assertTrue(tempWebAppDir.newChild(WEB_INF + File.separator + WEB_XML).exists());
+ assertTrue(files.size() == 1);
+
+ assertTrue(tempWebAppDir.delete(true));
+ assertTrue(webAppDir.delete(true));
+ }
+}
diff --git a/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerServiceTests.java b/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerServiceTests.java
index 58d549a..20b03c3 100644
--- a/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerServiceTests.java
+++ b/org.eclipse.gemini.web.core/src/test/java/org/eclipse/gemini/web/internal/url/WebBundleUrlStreamHandlerServiceTests.java
@@ -17,8 +17,15 @@
package org.eclipse.gemini.web.internal.url;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
@@ -27,12 +34,16 @@ import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.jar.Attributes;
+import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import org.eclipse.gemini.web.internal.url.SpecificationWebBundleManifestTransformer;
import org.eclipse.gemini.web.internal.url.WebBundleUrl;
import org.eclipse.gemini.web.internal.url.WebBundleUrlStreamHandlerService;
+import org.eclipse.virgo.util.io.FileSystemUtils;
+import org.eclipse.virgo.util.io.IOUtils;
+import org.eclipse.virgo.util.io.PathReference;
import org.junit.Test;
public class WebBundleUrlStreamHandlerServiceTests {
@@ -56,6 +67,99 @@ public class WebBundleUrlStreamHandlerServiceTests {
}
}
+ @Test
+ public void testOpenDirConnection() throws Exception {
+ URL directory = new URL("file:target/test-classes/web-app-dir");
+ URL tempDirectory = new URL("file:target/test-classes/temp/web-app-dir");
+
+ // Create content
+ PathReference webAppDir = new PathReference(directory.getPath());
+ PathReference webXml = webAppDir.newChild("WEB-INF" + File.separator + "web.xml");
+ webXml.createFile();
+
+ PathReference signatureFile = webAppDir.newChild("META-INF" + File.separator + "signature.SF");
+ signatureFile.createFile();
+
+ // There is no Manifest in the directory
+ // Expectation: Manifest will have Web-ContextPath header
+ WebBundleUrl url = new TestWarUrl("file:target/test-classes/web-app-dir?Web-ContextPath=/test", null);
+ DirTransformingURLConnection connection = (DirTransformingURLConnection) url.toURL().openConnection();
+ assertNotNull(connection);
+ connection.setTransformedURL(tempDirectory);
+ checkContent(connection, "/test", webXml.toFile());
+ assertTrue(FileSystemUtils.deleteRecursively(tempDirectory.getPath()));
+
+ // Create content
+ PathReference manifest = webAppDir.newChild(JarFile.MANIFEST_NAME);
+ manifest.createFile();
+ createManifest(manifest.toFile(), "Manifest-Version: 1.0", "Class-Path: ");
+
+ // There is Manifest in the directory with basic headers
+ // Expectation: Manifest will have Web-ContextPath header
+ url = new TestWarUrl("file:target/test-classes/web-app-dir?Web-ContextPath=/test1", null);
+ connection = (DirTransformingURLConnection) url.toURL().openConnection();
+ assertNotNull(connection);
+ connection.setTransformedURL(tempDirectory);
+ checkContent(connection, "/test1", webXml.toFile());
+ assertTrue(FileSystemUtils.deleteRecursively(tempDirectory.getPath()));
+
+ // Create content
+ createManifest(manifest.toFile(), "Manifest-Version: 1.0", "Class-Path: ", "Web-ContextPath: /test2");
+
+ // There is Manifest in the directory with basic headers +
+ // Web-ContextPath header
+ // Expectation: Manifest will have Web-ContextPath header
+ url = new TestWarUrl("file:target/test-classes/web-app-dir", null);
+ connection = (DirTransformingURLConnection) url.toURL().openConnection();
+ assertNotNull(connection);
+ connection.setTransformedURL(tempDirectory);
+ checkContent(connection, "/test2", webXml.toFile());
+ assertTrue(FileSystemUtils.deleteRecursively(tempDirectory.getPath()));
+
+ assertTrue(FileSystemUtils.deleteRecursively(directory.getPath()));
+ }
+
+ private void checkContent(URLConnection connection, String contextPath, File webXml) throws Exception {
+ InputStream inputStream = connection.getInputStream();
+ assertNotNull(inputStream);
+
+ File webAppDir = new File(connection.getURL().getPath());
+ // Check Manifest
+ InputStream is = new FileInputStream(new File(webAppDir, JarFile.MANIFEST_NAME));
+ Manifest manifest = new Manifest(is);
+
+ if (manifest != null) {
+ Attributes mainAttributes = manifest.getMainAttributes();
+ Set<Entry<Object, Object>> entrySet = mainAttributes.entrySet();
+ for (Entry<Object, Object> entry : entrySet) {
+ System.out.println(entry.getKey() + ": " + entry.getValue());
+ if ("Web-ContextPath".equals(entry.getKey().toString())) {
+ assertTrue(contextPath.equals(entry.getValue().toString()));
+ }
+ }
+ }
+
+ IOUtils.closeQuietly(is);
+
+ // Check web.xml
+ assertEquals(webXml.length(), new File(webAppDir, "WEB-INF" + File.separator + "web.xml").length());
+
+ // Check signature file
+ File signatureFile = new File(webAppDir, "META-INF" + File.separator + "signature.SF");
+ assertTrue(!signatureFile.exists());
+ }
+
+ private void createManifest(File manifest, String... headers) throws Exception {
+ OutputStream os = new FileOutputStream(manifest);
+ PrintWriter writer = new PrintWriter(os);
+ for (String header : headers) {
+ writer.println(header);
+ }
+ writer.println();
+ writer.close();
+ IOUtils.closeQuietly(os);
+ }
+
private static class TestWarUrl extends WebBundleUrl {
public TestWarUrl(String location, Map<String, String> options) throws MalformedURLException {
diff --git a/org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java b/org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java
index 0cd11f8..04acce7 100644
--- a/org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java
+++ b/org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java
@@ -50,6 +50,7 @@ import org.eclipse.gemini.web.core.spi.ServletContainer;
import org.eclipse.gemini.web.core.spi.WebApplicationHandle;
import org.eclipse.virgo.test.framework.OsgiTestRunner;
import org.eclipse.virgo.test.framework.TestFrameworkUtils;
+import org.eclipse.virgo.util.io.FileSystemUtils;
import org.eclipse.virgo.util.io.IOUtils;
import org.eclipse.virgo.util.io.PathReference;
import org.eclipse.virgo.util.io.ZipUtils;
@@ -403,6 +404,28 @@ public class TomcatServletContainerTests {
}
}
+ @Test
+ public void testInstallWebAppDir() throws Exception {
+ //Create web app dir
+ File webAppDir = new File("target/test-classes/simple-web-app-dir");
+ File indexHtml = new File(webAppDir, "index.html");
+ createFileWithContent(indexHtml, "Hello World!");
+
+ Bundle bundle = this.bundleContext.installBundle(LOCATION_PREFIX + webAppDir.getAbsolutePath() + "?Web-ContextPath=/simple-web-app-dir");
+ bundle.start();
+
+ WebApplicationHandle handle = this.container.createWebApplication("/simple-web-app-dir", bundle);
+ this.container.startWebApplication(handle);
+ try {
+ validateURL("http://localhost:8080/simple-web-app-dir/index.html");
+ } finally {
+ this.container.stopWebApplication(handle);
+ bundle.uninstall();
+ FileSystemUtils.deleteRecursively(webAppDir);
+ FileSystemUtils.deleteRecursively(new File("temp"));
+ }
+ }
+
private void createFileWithContent(File file, String content) throws Exception {
file.getParentFile().mkdirs();
FileWriter fWriter = null;