| author | Violeta Georgieva | 2010-09-07 04:51:42 (EDT) |
|---|---|---|
| committer | Glyn Normington | 2010-09-07 04:51:42 (EDT) |
| commit | 5c79742c0fb0c07cda7eb0c077cbad653f89447f (patch) (side-by-side diff) | |
| tree | b0d8d9a60888466cd3265cef453fe4a2df652548 | |
| parent | 6dc941d317a9073e42e1262770252ff1062d9650 (diff) | |
| download | org.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
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 --- a/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 --- a/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 --- a/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 --- a/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; |

