From 8ba068c73b7fea6580ed2f6de34bfeb2b956b47a Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Thu, 9 Aug 2012 19:11:20 +0200 Subject: [PATCH] jetty-9: jetty-plugins module added --- jetty-plugins/pom.xml | 68 ++++++++ .../java/org/eclipse/jetty/plugins/Main.java | 129 +++++++++++++++ .../eclipse/jetty/plugins/MavenService.java | 36 ++++ .../eclipse/jetty/plugins/PluginManager.java | 28 ++++ .../plugins/impl/HttpMavenServiceImpl.java | 126 ++++++++++++++ .../jetty/plugins/impl/PluginManagerImpl.java | 110 ++++++++++++ .../eclipse/jetty/plugins/model/Plugin.java | 22 +++ .../jetty/plugins/util/RepositoryParser.java | 46 ++++++ .../jetty/plugins/util/StreamUtils.java | 21 +++ .../plugins/impl/HttpMavenServiceTest.java | 65 ++++++++ .../jetty/plugins/impl/PluginManagerTest.java | 156 ++++++++++++++++++ .../plugins/util/RepositoryParserTest.java | 35 ++++ .../src/test/resources/example-plugin.jar | Bin 0 -> 629 bytes .../jetty-jmx-7.6.0.v20120127-plugin.jar | Bin 0 -> 22170 bytes .../test/resources/jetty_home/.donotdelete | 0 .../mavenRepoJettyDirectoryListing.html | 55 ++++++ .../mavenRepoJettyJMXDirectoryListing.html | 36 ++++ .../mavenRepoJettyJNDIDirectoryListing.html | 30 ++++ pom.xml | 2 +- 19 files changed, 964 insertions(+), 1 deletion(-) create mode 100644 jetty-plugins/pom.xml create mode 100644 jetty-plugins/src/main/java/org/eclipse/jetty/plugins/Main.java create mode 100644 jetty-plugins/src/main/java/org/eclipse/jetty/plugins/MavenService.java create mode 100644 jetty-plugins/src/main/java/org/eclipse/jetty/plugins/PluginManager.java create mode 100644 jetty-plugins/src/main/java/org/eclipse/jetty/plugins/impl/HttpMavenServiceImpl.java create mode 100644 jetty-plugins/src/main/java/org/eclipse/jetty/plugins/impl/PluginManagerImpl.java create mode 100644 jetty-plugins/src/main/java/org/eclipse/jetty/plugins/model/Plugin.java create mode 100644 jetty-plugins/src/main/java/org/eclipse/jetty/plugins/util/RepositoryParser.java create mode 100644 jetty-plugins/src/main/java/org/eclipse/jetty/plugins/util/StreamUtils.java create mode 100644 jetty-plugins/src/test/java/org/eclipse/jetty/plugins/impl/HttpMavenServiceTest.java create mode 100644 jetty-plugins/src/test/java/org/eclipse/jetty/plugins/impl/PluginManagerTest.java create mode 100644 jetty-plugins/src/test/java/org/eclipse/jetty/plugins/util/RepositoryParserTest.java create mode 100644 jetty-plugins/src/test/resources/example-plugin.jar create mode 100644 jetty-plugins/src/test/resources/jetty-jmx-7.6.0.v20120127-plugin.jar create mode 100644 jetty-plugins/src/test/resources/jetty_home/.donotdelete create mode 100644 jetty-plugins/src/test/resources/mavenRepoJettyDirectoryListing.html create mode 100644 jetty-plugins/src/test/resources/mavenRepoJettyJMXDirectoryListing.html create mode 100644 jetty-plugins/src/test/resources/mavenRepoJettyJNDIDirectoryListing.html diff --git a/jetty-plugins/pom.xml b/jetty-plugins/pom.xml new file mode 100644 index 00000000000..dd7d7b5b95f --- /dev/null +++ b/jetty-plugins/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + jetty-project + org.eclipse.jetty + 7.6.1-SNAPSHOT + + jetty-plugins + jetty-plugins + The jetty plugin artifact. + ${jetty.url} + + 1.13.1 + UTF-8 + + + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + + + + org.eclipse.jetty.plugins.Main + + + + + + package + + single + + + + + + + + + + junit + junit + test + + + org.hamcrest + hamcrest-all + 1.0 + test + + + org.mockito + mockito-core + test + + + diff --git a/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/Main.java b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/Main.java new file mode 100644 index 00000000000..a35f09f3e23 --- /dev/null +++ b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/Main.java @@ -0,0 +1,129 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 +// 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. +// ======================================================================== + +package org.eclipse.jetty.plugins; + +import java.util.List; +import java.util.Map; + +import org.eclipse.jetty.plugins.impl.HttpMavenServiceImpl; +import org.eclipse.jetty.plugins.impl.PluginManagerImpl; + +/* ------------------------------------------------------------ */ +/** + */ +public class Main { + private static final String JETTY_HOME = "JETTY_HOME"; + + private MavenService _mavenService = new HttpMavenServiceImpl(); + private PluginManager _pluginManager; + private String _jettyHome; + private String _installPlugin; + private boolean _listPlugins; + private String _repositoryUrl; + private String _groupId; + private String _version; + + /* ------------------------------------------------------------ */ + /** + * @param args + */ + public static void main(String[] args) { + Main main = new Main(); + main.execute(args); + } + + private void execute(String[] args) { + parseEnvironmentVariables(); + parseCommandline(args); + configureMavenService(); + + _pluginManager = new PluginManagerImpl(_mavenService, _jettyHome); + + if (_listPlugins) { + listPlugins(); + } else if (_installPlugin != null) { + installPlugin(); + } + } + + private void configureMavenService() { + if (_repositoryUrl != null) { + _mavenService.setRepositoryUrl(_repositoryUrl); + } + if (_groupId != null) { + _mavenService.setGroupId(_groupId); + } + if (_version != null) { + _mavenService.setVersion(_version); + } + } + + private void listPlugins() { + List availablePlugins = _pluginManager.listAvailablePlugins(); + for (String pluginName : availablePlugins) { + System.out.println(pluginName); + } + } + + private void installPlugin() { + _pluginManager.installPlugin(_installPlugin); + System.out.println("Successfully installed plugin: " + _installPlugin + + " to " + _jettyHome); + } + + private void parseEnvironmentVariables() { + Map env = System.getenv(); + if (env.containsKey(JETTY_HOME)) { + _jettyHome = env.get(JETTY_HOME); + } + } + + private void parseCommandline(String[] args) { + int i = 0; + for (String arg : args) { + i++; + + if (arg.startsWith("--jettyHome=")) { + _jettyHome = arg.substring(12); + } + if (arg.startsWith("--repositoryUrl=")) { + _repositoryUrl = arg.substring(16); + } + if (arg.startsWith("--groupId=")) { + _groupId = arg.substring(10); + } + if (arg.startsWith("--version=")) { + _version = arg.substring(10); + } + if (arg.startsWith("install")) { + _installPlugin = args[i]; + } + if ("list".equals(arg)) { + _listPlugins = true; + } + } + + // TODO: Usage instead of throwing exceptions + if (_jettyHome == null && _installPlugin != null) + throw new IllegalArgumentException( + "No --jettyHome commandline option specified and no \"JETTY_HOME\" environment variable found!"); + if (_installPlugin == null && _listPlugins == false) + throw new IllegalArgumentException( + "Neither install nor list commandline option specified. Nothing to do for me!"); + if (_installPlugin != null && _listPlugins) + throw new IllegalArgumentException( + "Please specify either install or list commandline options, but not both at the same time!"); + } + +} diff --git a/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/MavenService.java b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/MavenService.java new file mode 100644 index 00000000000..a1db631bee2 --- /dev/null +++ b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/MavenService.java @@ -0,0 +1,36 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 +// 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. +// ======================================================================== + + +package org.eclipse.jetty.plugins; + +import java.util.List; + +import org.eclipse.jetty.plugins.model.Plugin; + + +/* ------------------------------------------------------------ */ +/** + */ +public interface MavenService +{ + public List listAvailablePlugins(); + + public Plugin getPlugin(String pluginName); + + public void setGroupId(String groupId); + + public void setRepositoryUrl(String repositoryUrl); + + public void setVersion(String version); +} diff --git a/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/PluginManager.java b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/PluginManager.java new file mode 100644 index 00000000000..33409e9cd72 --- /dev/null +++ b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/PluginManager.java @@ -0,0 +1,28 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 +// 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. +// ======================================================================== + + +package org.eclipse.jetty.plugins; + +import java.util.List; + + +/* ------------------------------------------------------------ */ +/** + */ +public interface PluginManager +{ + public List listAvailablePlugins(); + + public void installPlugin(String pluginName); +} diff --git a/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/impl/HttpMavenServiceImpl.java b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/impl/HttpMavenServiceImpl.java new file mode 100644 index 00000000000..582d7386b9c --- /dev/null +++ b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/impl/HttpMavenServiceImpl.java @@ -0,0 +1,126 @@ +package org.eclipse.jetty.plugins.impl; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.plugins.MavenService; +import org.eclipse.jetty.plugins.model.Plugin; +import org.eclipse.jetty.plugins.util.RepositoryParser; +import org.eclipse.jetty.plugins.util.StreamUtils; + +public class HttpMavenServiceImpl implements MavenService { + private static final String REPOSITORY_URL = "http://repo2.maven.org/maven2/"; + private static final String GROUP_ID = "org/eclipse/jetty"; + private static final String VERSION = "7.6.0.v20120127"; // TODO: should be + // automatically + // set + private String _repositoryUrl = REPOSITORY_URL; + private String _groupId = GROUP_ID; + private String _version = VERSION; + + public List listAvailablePlugins() { + List availablePlugins = new ArrayList(); + + String moduleListing = fetchDirectoryListingOfJettyModules(); + List modules = RepositoryParser + .parseLinksInDirectoryListing(moduleListing); + + for (String module : modules) { + String listing = fetchModuleDirectoryListing(module); + if (RepositoryParser.isModuleAPlugin(listing)) { + availablePlugins.add(module); + } + } + + return availablePlugins; + } + + private String fetchDirectoryListingOfJettyModules() { + try { + URL url = new URL(_repositoryUrl + _groupId); + URLConnection connection = url.openConnection(); + InputStream inputStream = connection.getInputStream(); + return StreamUtils.inputStreamToString(inputStream); + } catch (MalformedURLException e) { + throw new IllegalStateException(e); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private String fetchModuleDirectoryListing(String module) { + try { + URL configJar = new URL(getModuleDirectory(module)); + URLConnection connection = configJar.openConnection(); + InputStream inputStream = connection.getInputStream(); + return StreamUtils.inputStreamToString(inputStream); + } catch (MalformedURLException e) { + throw new IllegalStateException(e); + } catch (IOException e) { + // Honestly, I'm not a friend of ignoring exceptions as it might + // hide something important. In this case however it "usually" + // just means: THIS IS NOT A PLUGIN! However it still might hide + // things. If that'll be the case, I hope I'm not the one who + // has to debug my own code. ;) + return "not a plugin"; + } + } + + public Plugin getPlugin(String pluginName) { + File configJar = getFile(getModulePrefix(pluginName) + "-plugin.jar"); + return new Plugin(pluginName, configJar); + } + + private String getModuleDirectory(String pluginName) { + return _repositoryUrl + _groupId + "/" + pluginName + "/" + _version + + "/"; + } + + private String getModulePrefix(String pluginName) { + return getModuleDirectory(pluginName) + pluginName + "-" + _version; + } + + private File getFile(String urlString) { + String fileName = urlString.substring(urlString.lastIndexOf("/") + 1); + try { + URL url = new URL(urlString); + URLConnection connection = url.openConnection(); + InputStream inputStream = connection.getInputStream(); + File tempFile = new File(System.getProperty("java.io.tmpdir"), + fileName); + OutputStream out = new FileOutputStream(tempFile); + byte buf[] = new byte[1024]; + int len; + while ((len = inputStream.read(buf)) > 0) + out.write(buf, 0, len); + out.close(); + inputStream.close(); + return tempFile; + } catch (MalformedURLException e) { + throw new IllegalStateException(e); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + public void setGroupId(String groupId) { + this._groupId = groupId.replace(".", "/"); + } + + public void setRepositoryUrl(String repositoryUrl) { + this._repositoryUrl = repositoryUrl; + } + + public void setVersion(String version) { + this._version = version; + } + +} diff --git a/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/impl/PluginManagerImpl.java b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/impl/PluginManagerImpl.java new file mode 100644 index 00000000000..6b00fd66891 --- /dev/null +++ b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/impl/PluginManagerImpl.java @@ -0,0 +1,110 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 +// 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. +// ======================================================================== + +package org.eclipse.jetty.plugins.impl; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.eclipse.jetty.plugins.MavenService; +import org.eclipse.jetty.plugins.PluginManager; +import org.eclipse.jetty.plugins.model.Plugin; + +/* ------------------------------------------------------------ */ +/** + */ +public class PluginManagerImpl implements PluginManager { + private String _jettyHome; + private MavenService _mavenService; + + private static List excludes = Arrays.asList("META-INF"); + + public PluginManagerImpl(MavenService mavenService, String jettyHome) { + this._mavenService = mavenService; + this._jettyHome = jettyHome; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.plugins.PluginManager#listAvailablePlugins() + */ + public List listAvailablePlugins() { + return _mavenService.listAvailablePlugins(); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.plugins.PluginManager#installPlugin(String) + */ + public void installPlugin(String pluginName) { + Plugin plugin = _mavenService.getPlugin(pluginName); + installPlugin(plugin); + } + + private void installPlugin(Plugin plugin) { + try { + JarFile pluginJar = new JarFile(plugin.getPluginJar()); + extractJar(pluginJar); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private void extractJar(JarFile file) { + Enumeration entries = file.entries(); + while (entries.hasMoreElements()) { + extractFileFromJar(file, entries.nextElement()); + } + } + + private void extractFileFromJar(JarFile jarFile, JarEntry jarEntry) { + for (String exclude : excludes) + if (jarEntry.getName().startsWith(exclude)) + return; + + System.out.println("Extracting: " + jarEntry.getName()); + File f = new File(_jettyHome + File.separator + jarEntry.getName()); + if (jarEntry.isDirectory()) { // if its a directory, create it + f.mkdir(); + return; + } + InputStream is = null; + FileOutputStream fos = null; + try { + is = jarFile.getInputStream(jarEntry); + fos = new FileOutputStream(f); + while (is.available() > 0) { + fos.write(is.read()); + } + } catch (IOException e) { + throw new IllegalStateException( + "IOException while extracting plugin jar: ", e); + } finally { + try { + fos.close(); + is.close(); + } catch (IOException e) { + throw new IllegalStateException( + "Couldn't close InputStream or FileOutputStream. This might be a file leak!", + e); + } + } + } +} diff --git a/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/model/Plugin.java b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/model/Plugin.java new file mode 100644 index 00000000000..a9a06defe90 --- /dev/null +++ b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/model/Plugin.java @@ -0,0 +1,22 @@ +package org.eclipse.jetty.plugins.model; + +import java.io.File; + +public class Plugin { + private String name; + + private File pluginJar; + + public Plugin(String name, File configJar) { + this.name = name; + this.pluginJar = configJar; + } + + public String getName() { + return name; + } + + public File getPluginJar() { + return pluginJar; + } +} diff --git a/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/util/RepositoryParser.java b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/util/RepositoryParser.java new file mode 100644 index 00000000000..e7b70381bc2 --- /dev/null +++ b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/util/RepositoryParser.java @@ -0,0 +1,46 @@ +/** + * + */ +package org.eclipse.jetty.plugins.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author tbecker + * + */ +public class RepositoryParser { + private final static List EXCLUDES = Arrays.asList(".."); + + public static List parseLinksInDirectoryListing(String listing) { + List modules = new ArrayList(); + List lines = Arrays.asList(listing.split("\n")); + for (String line : lines) { + Pattern p = Pattern.compile(".*?]+>(?=([^ lines = Arrays.asList(listing.split("\n")); + for (String line : lines) { + Pattern p = Pattern.compile("-plugin\\.jar"); + Matcher m = p.matcher(line); + if (m.find()) { + return true; + } + } + return false; + } + +} diff --git a/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/util/StreamUtils.java b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/util/StreamUtils.java new file mode 100644 index 00000000000..9de4241611c --- /dev/null +++ b/jetty-plugins/src/main/java/org/eclipse/jetty/plugins/util/StreamUtils.java @@ -0,0 +1,21 @@ +package org.eclipse.jetty.plugins.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class StreamUtils { + public static String inputStreamToString(InputStream inputStream) throws IOException { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + StringBuilder stringBuilder = new StringBuilder(); + String line = null; + + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line + "\n"); + } + + bufferedReader.close(); + return stringBuilder.toString(); + } +} diff --git a/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/impl/HttpMavenServiceTest.java b/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/impl/HttpMavenServiceTest.java new file mode 100644 index 00000000000..be4df02e9dd --- /dev/null +++ b/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/impl/HttpMavenServiceTest.java @@ -0,0 +1,65 @@ +package org.eclipse.jetty.plugins.impl; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.eclipse.jetty.plugins.MavenService; +import org.eclipse.jetty.plugins.model.Plugin; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +/** + * This is currently more an integration test downloading real stuff from real + * maven repositories. Actually it's preferred to have a real unit test or at + * least a local repository server. But since HttpClient.send(exchange) has an + * api which is really hard to mock, I will leave that excercise for later. + * + * However this tests should be disabled for the general build and ci. + * + * @author tbecker + * + */ +public class HttpMavenServiceTest { + private MavenService _mavenService = new HttpMavenServiceImpl(); + + private static final String JETTY_JMX_PLUGIN_NAME = "jetty-jmx"; + private static final String PRIVATE_NEXUS_REPOSITORY_URL = "http://gravity-design.de:8080/nexus/content/repositories/releases/"; + private static final String MAVEN_CENTRAL_URL = "http://repo2.maven.org/maven2/"; + + @Before + public void setUp() throws Exception { + _mavenService.setRepositoryUrl(PRIVATE_NEXUS_REPOSITORY_URL); + } + + @Test + @Ignore("requires online repo") + public void testListAvailablePlugins() { + List pluginNames = _mavenService.listAvailablePlugins(); + assertThat(pluginNames.size(), is(2)); + } + + @Test + @Ignore("requires online repo") + public void testGetPluginJar() throws IOException { + Plugin plugin = _mavenService.getPlugin(JETTY_JMX_PLUGIN_NAME); + assertThat("jetty-jmx should contain a plugin-jar", + plugin.getPluginJar(), is(notNullValue())); + } + + @Test + @Ignore("requires online repo") + public void testGetConfigJar() throws IOException { + Plugin plugin = _mavenService.getPlugin(JETTY_JMX_PLUGIN_NAME); + File configJar = plugin.getPluginJar(); + assertThat(configJar, is(not(nullValue()))); + } + +} diff --git a/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/impl/PluginManagerTest.java b/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/impl/PluginManagerTest.java new file mode 100644 index 00000000000..5d7c32542b7 --- /dev/null +++ b/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/impl/PluginManagerTest.java @@ -0,0 +1,156 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// 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 +// 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. +// ======================================================================== + +package org.eclipse.jetty.plugins.impl; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.plugins.MavenService; +import org.eclipse.jetty.plugins.model.Plugin; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/* ------------------------------------------------------------ */ +/** + */ +@RunWith(MockitoJUnitRunner.class) +public class PluginManagerTest { + @Mock + private MavenService _mavenService; + + private PluginManagerImpl _pluginManager; + + private List availablePlugins = createAvailablePluginsTestData(); + private ClassLoader _classLoader = this.getClass().getClassLoader(); + private String _tmpDir; + private File _javaTmpDir = new File(System.getProperty("java.io.tmpdir")); + + /* ------------------------------------------------------------ */ + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + URL resource = this.getClass().getResource("/jetty_home"); + _tmpDir = resource.getFile(); + _pluginManager = new PluginManagerImpl(_mavenService, _tmpDir); + } + + @Test + public void testListAvailablePlugins() { + when(_mavenService.listAvailablePlugins()).thenReturn(availablePlugins); + List availablePlugins = _pluginManager.listAvailablePlugins(); + assertThat("jetty-jmx not found", + availablePlugins.contains("jetty-jmx"), is(true)); + assertThat("jetty-jta not found", + availablePlugins.contains("jetty-jta"), is(true)); + } + + @Test + public void testInstallPluginJar() { + String pluginName = "jetty-plugin-with-plugin-jar"; + String pluginJar = _classLoader.getResource("example-plugin.jar") + .getFile(); + File pluginJarFile = new File(pluginJar); + Plugin plugin = createTestPlugin(pluginName, pluginJarFile); + + when(_mavenService.getPlugin(pluginName)).thenReturn(plugin); + + _pluginManager.installPlugin(pluginName); + + File someJar = new File(_tmpDir + File.separator + "lib" + + File.separator + "someJar.jar"); + assertThat("someJar.jar does not exist", someJar.exists(), is(true)); + File someOtherJar = new File(_tmpDir + File.separator + "lib" + + File.separator + "someOtherJar.jar"); + assertThat("someOtherJar.jar does not exist", someOtherJar.exists(), + is(true)); + } + + @Test + public void testInstallPlugins() throws IOException { + + String pluginName = "jetty-jmx"; + String jmxPluginConfigJar = _classLoader.getResource( + "jetty-jmx-7.6.0.v20120127-plugin.jar").getFile(); + File jmxPluginConfigJarFile = new File(jmxPluginConfigJar); + + // Need to copy it to a temp file since the implementation will move the + // file and we need to keep the test files where they are. + File jmxPluginConfigTempCopy = copyToTempFile(jmxPluginConfigJarFile); + + Plugin plugin = new Plugin(pluginName, jmxPluginConfigTempCopy); + + when(_mavenService.getPlugin(pluginName)).thenReturn(plugin); + + _pluginManager.installPlugin(pluginName); + + File metaInf = new File(_tmpDir + File.separator + "META-INF"); + File jettyXmlConfigFile = new File(_tmpDir + File.separator + "start.d" + + File.separator + "20-jetty-jmx.xml"); + File jettyJmxJarFile = new File(_tmpDir + File.separator + "lib" + + File.separator + "jetty-jmx-7.6.0.v20120127.jar"); + assertThat("META-INF should be skipped", metaInf.exists(), not(true)); + assertThat("20-jetty-jmx.xml does not exist", + jettyXmlConfigFile.exists(), is(true)); + assertThat("jetty-jmx-7.6.0.v20120127.jar does not exist", + jettyJmxJarFile.exists(), is(true)); + } + + public File copyToTempFile(File sourceFile) throws IOException { + File destFile = new File(_javaTmpDir + File.separator + + sourceFile.getName()); + FileChannel source = null; + FileChannel destination = null; + try { + source = new FileInputStream(sourceFile).getChannel(); + destination = new FileOutputStream(destFile).getChannel(); + destination.transferFrom(source, 0, source.size()); + } finally { + if (source != null) { + source.close(); + } + if (destination != null) { + destination.close(); + } + } + return destFile; + } + + private List createAvailablePluginsTestData() { + List availablePlugins = new ArrayList(); + availablePlugins.add("jetty-jmx"); + availablePlugins.add("jetty-jta"); + return availablePlugins; + } + + private Plugin createTestPlugin(String name, File jar) { + Plugin plugin = new Plugin(name, jar); + return plugin; + } + +} diff --git a/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/util/RepositoryParserTest.java b/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/util/RepositoryParserTest.java new file mode 100644 index 00000000000..c8f27aea977 --- /dev/null +++ b/jetty-plugins/src/test/java/org/eclipse/jetty/plugins/util/RepositoryParserTest.java @@ -0,0 +1,35 @@ +package org.eclipse.jetty.plugins.util; + +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.io.IOException; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +public class RepositoryParserTest { + + @Before + public void setUp() throws Exception { + } + + @Test + public void testParseLinksInDirectoryListing() throws IOException { + String listing = StreamUtils.inputStreamToString(this.getClass().getClassLoader().getResourceAsStream("mavenRepoJettyDirectoryListing.html")); + List modules = RepositoryParser.parseLinksInDirectoryListing(listing); + assertThat("At least ten jetty modules expected",modules.size(), greaterThan(10)); + assertThat("jetty-jmx module expected", modules.contains("jetty-jmx"), is(true)); + } + + @Test + public void testIsPlugin() throws IOException{ + String listing = StreamUtils.inputStreamToString(this.getClass().getClassLoader().getResourceAsStream("mavenRepoJettyJMXDirectoryListing.html")); + assertThat("listing describes a plugin", RepositoryParser.isModuleAPlugin(listing), is(true)); + String nonPluginListing = StreamUtils.inputStreamToString(this.getClass().getClassLoader().getResourceAsStream("mavenRepoJettyJNDIDirectoryListing.html")); + assertThat("listing doesn't describe a plugin", RepositoryParser.isModuleAPlugin(nonPluginListing), is(false)); + } + +} diff --git a/jetty-plugins/src/test/resources/example-plugin.jar b/jetty-plugins/src/test/resources/example-plugin.jar new file mode 100644 index 0000000000000000000000000000000000000000..31cd1e04d4b2e0179ee11b0fa3a09ac59af4e2fe GIT binary patch literal 629 zcmWIWW@h1H00FT&F9$FKN^k;cU)K;vT~9wZ{Q#&k4hB)6vac^YmxKeQlYv+SS(&e+ zpQoE^aEP9-+h^Z1r+vJ2^)B*y>uQ}lbAEG>!4=~NPmA=te04m1FP5&_5@cX>!T6%D zk-;TXLxZ3T1v(lhJVQU6@xFHX$pFF|!6g$}|x?4g6u%*cp6tOC4Q*+8mTflv#m#uSJd7y$S0c;^5B literal 0 HcmV?d00001 diff --git a/jetty-plugins/src/test/resources/jetty-jmx-7.6.0.v20120127-plugin.jar b/jetty-plugins/src/test/resources/jetty-jmx-7.6.0.v20120127-plugin.jar new file mode 100644 index 0000000000000000000000000000000000000000..ed99c27732a8a7a36910cb73363d34bddc5fbdc7 GIT binary patch literal 22170 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 D22^Y2 literal 0 HcmV?d00001 diff --git a/jetty-plugins/src/test/resources/jetty_home/.donotdelete b/jetty-plugins/src/test/resources/jetty_home/.donotdelete new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jetty-plugins/src/test/resources/mavenRepoJettyDirectoryListing.html b/jetty-plugins/src/test/resources/mavenRepoJettyDirectoryListing.html new file mode 100644 index 00000000000..cd6549cac38 --- /dev/null +++ b/jetty-plugins/src/test/resources/mavenRepoJettyDirectoryListing.html @@ -0,0 +1,55 @@ + +Index of /maven2/org/eclipse/jetty/ + +

Index of /maven2/org/eclipse/jetty/


../
+aggregate/                                         22-Dec-2011 21:20                   -
+example-async-rest/                                09-Mar-2012 16:06                   -
+example-jetty-embedded/                            09-Mar-2012 16:06                   -
+jetty-ajp/                                         09-Mar-2012 16:06                   -
+jetty-annotations/                                 09-Mar-2012 16:06                   -
+jetty-client/                                      09-Mar-2012 16:06                   -
+jetty-continuation/                                09-Mar-2012 16:06                   -
+jetty-deploy/                                      09-Mar-2012 16:06                   -
+jetty-distribution/                                09-Mar-2012 16:06                   -
+jetty-embedded-examples/                           21-Sep-2009 15:50                   -
+jetty-http/                                        09-Mar-2012 16:06                   -
+jetty-http-spi/                                    09-Mar-2012 16:06                   -
+jetty-io/                                          09-Mar-2012 16:06                   -
+jetty-jaspi/                                       09-Mar-2012 16:06                   -
+jetty-jmx/                                         09-Mar-2012 16:06                   -
+jetty-jndi/                                        09-Mar-2012 16:06                   -
+jetty-jsp/                                         09-Mar-2012 16:06                   -
+jetty-jsp-2.1/                                     25-Oct-2011 01:05                   -
+jetty-monitor/                                     09-Mar-2012 16:06                   -
+jetty-nested/                                      09-Mar-2012 16:06                   -
+jetty-nosql/                                       09-Mar-2012 16:06                   -
+jetty-overlay-deployer/                            09-Mar-2012 16:06                   -
+jetty-parent/                                      20-Sep-2011 16:54                   -
+jetty-plus/                                        09-Mar-2012 16:06                   -
+jetty-policy/                                      09-Mar-2012 16:06                   -
+jetty-project/                                     09-Mar-2012 16:06                   -
+jetty-rewrite/                                     09-Mar-2012 16:06                   -
+jetty-security/                                    09-Mar-2012 16:06                   -
+jetty-server/                                      09-Mar-2012 16:06                   -
+jetty-servlet/                                     09-Mar-2012 16:06                   -
+jetty-servlet-tester/                              21-Sep-2009 15:52                   -
+jetty-servlets/                                    09-Mar-2012 16:06                   -
+jetty-start/                                       09-Mar-2012 16:06                   -
+jetty-test-webapp/                                 21-Sep-2009 15:50                   -
+jetty-util/                                        09-Mar-2012 16:06                   -
+jetty-webapp/                                      09-Mar-2012 16:06                   -
+jetty-websocket/                                   09-Mar-2012 16:06                   -
+jetty-xml/                                         09-Mar-2012 16:06                   -
+npn/                                               09-Mar-2012 16:05                   -
+orbit/                                             24-Jan-2012 23:22                   -
+osgi/                                              27-May-2011 08:34                   -
+spdy/                                              09-Mar-2012 16:05                   -
+test-continuation/                                 01-Apr-2010 13:30                   -
+test-continuation-jetty6/                          01-Apr-2010 13:30                   -
+test-jetty-nested/                                 09-Mar-2012 16:06                   -
+test-jetty-servlet/                                09-Mar-2012 16:06                   -
+test-jetty-webapp/                                 09-Mar-2012 16:06                   -
+tests/                                             30-Nov-2011 02:16                   -
+toolchain/                                         06-Dec-2011 23:32                   -
+

+ \ No newline at end of file diff --git a/jetty-plugins/src/test/resources/mavenRepoJettyJMXDirectoryListing.html b/jetty-plugins/src/test/resources/mavenRepoJettyJMXDirectoryListing.html new file mode 100644 index 00000000000..ac33b1ac140 --- /dev/null +++ b/jetty-plugins/src/test/resources/mavenRepoJettyJMXDirectoryListing.html @@ -0,0 +1,36 @@ + +Index of /maven2/org/eclipse/jetty/jetty-jmx/7.6.0.v20120127/ + +

Index of /maven2/org/eclipse/jetty/jetty-jmx/7.6.0.v20120127/


../
+jetty-jmx-7.6.0.v20120127-plugin.jar               27-Jan-2012 14:24                1873
+jetty-jmx-7.6.0.v20120127-plugin.jar.asc           27-Jan-2012 14:24                 198
+jetty-jmx-7.6.0.v20120127-plugin.jar.asc.md5       27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127-plugin.jar.asc.sha1      27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127-plugin.jar.md5           27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127-plugin.jar.sha1          27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127-javadoc.jar              27-Jan-2012 14:24               52590
+jetty-jmx-7.6.0.v20120127-javadoc.jar.asc          27-Jan-2012 14:24                 198
+jetty-jmx-7.6.0.v20120127-javadoc.jar.asc.md5      27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127-javadoc.jar.asc.sha1     27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127-javadoc.jar.md5          27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127-javadoc.jar.sha1         27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127-sources.jar              27-Jan-2012 14:24               16675
+jetty-jmx-7.6.0.v20120127-sources.jar.asc          27-Jan-2012 14:24                 198
+jetty-jmx-7.6.0.v20120127-sources.jar.asc.md5      27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127-sources.jar.asc.sha1     27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127-sources.jar.md5          27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127-sources.jar.sha1         27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127.jar                      27-Jan-2012 14:24               23187
+jetty-jmx-7.6.0.v20120127.jar.asc                  27-Jan-2012 14:24                 198
+jetty-jmx-7.6.0.v20120127.jar.asc.md5              27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127.jar.asc.sha1             27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127.jar.md5                  27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127.jar.sha1                 27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127.pom                      27-Jan-2012 14:24                2655
+jetty-jmx-7.6.0.v20120127.pom.asc                  27-Jan-2012 14:24                 198
+jetty-jmx-7.6.0.v20120127.pom.asc.md5              27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127.pom.asc.sha1             27-Jan-2012 14:24                  40
+jetty-jmx-7.6.0.v20120127.pom.md5                  27-Jan-2012 14:24                  32
+jetty-jmx-7.6.0.v20120127.pom.sha1                 27-Jan-2012 14:24                  40
+

+ \ No newline at end of file diff --git a/jetty-plugins/src/test/resources/mavenRepoJettyJNDIDirectoryListing.html b/jetty-plugins/src/test/resources/mavenRepoJettyJNDIDirectoryListing.html new file mode 100644 index 00000000000..e1e6bf82ae8 --- /dev/null +++ b/jetty-plugins/src/test/resources/mavenRepoJettyJNDIDirectoryListing.html @@ -0,0 +1,30 @@ + +Index of /maven2/org/eclipse/jetty/jetty-jndi/7.6.0.v20120127/ + +

Index of /maven2/org/eclipse/jetty/jetty-jndi/7.6.0.v20120127/


../
+jetty-jndi-7.6.0.v20120127-javadoc.jar             27-Jan-2012 14:37              127695
+jetty-jndi-7.6.0.v20120127-javadoc.jar.asc         27-Jan-2012 14:37                 198
+jetty-jndi-7.6.0.v20120127-javadoc.jar.asc.md5     27-Jan-2012 14:37                  32
+jetty-jndi-7.6.0.v20120127-javadoc.jar.asc.sha1    27-Jan-2012 14:37                  40
+jetty-jndi-7.6.0.v20120127-javadoc.jar.md5         27-Jan-2012 14:37                  32
+jetty-jndi-7.6.0.v20120127-javadoc.jar.sha1        27-Jan-2012 14:37                  40
+jetty-jndi-7.6.0.v20120127-sources.jar             27-Jan-2012 14:37               26645
+jetty-jndi-7.6.0.v20120127-sources.jar.asc         27-Jan-2012 14:37                 198
+jetty-jndi-7.6.0.v20120127-sources.jar.asc.md5     27-Jan-2012 14:37                  32
+jetty-jndi-7.6.0.v20120127-sources.jar.asc.sha1    27-Jan-2012 14:37                  40
+jetty-jndi-7.6.0.v20120127-sources.jar.md5         27-Jan-2012 14:37                  32
+jetty-jndi-7.6.0.v20120127-sources.jar.sha1        27-Jan-2012 14:37                  40
+jetty-jndi-7.6.0.v20120127.jar                     27-Jan-2012 14:36               38073
+jetty-jndi-7.6.0.v20120127.jar.asc                 27-Jan-2012 14:37                 198
+jetty-jndi-7.6.0.v20120127.jar.asc.md5             27-Jan-2012 14:37                  32
+jetty-jndi-7.6.0.v20120127.jar.asc.sha1            27-Jan-2012 14:37                  40
+jetty-jndi-7.6.0.v20120127.jar.md5                 27-Jan-2012 14:36                  32
+jetty-jndi-7.6.0.v20120127.jar.sha1                27-Jan-2012 14:36                  40
+jetty-jndi-7.6.0.v20120127.pom                     27-Jan-2012 14:36                2810
+jetty-jndi-7.6.0.v20120127.pom.asc                 27-Jan-2012 14:37                 198
+jetty-jndi-7.6.0.v20120127.pom.asc.md5             27-Jan-2012 14:37                  32
+jetty-jndi-7.6.0.v20120127.pom.asc.sha1            27-Jan-2012 14:37                  40
+jetty-jndi-7.6.0.v20120127.pom.md5                 27-Jan-2012 14:37                  32
+jetty-jndi-7.6.0.v20120127.pom.sha1                27-Jan-2012 14:37                  40
+

+ \ No newline at end of file diff --git a/pom.xml b/pom.xml index f087c77d06b..6d832614bff 100644 --- a/pom.xml +++ b/pom.xml @@ -377,7 +377,7 @@ jetty-deploy jetty-start - + jetty-plugins