diff --git a/scm-core/src/main/java/sonia/scm/plugin/PluginCircularDependencyException.java b/scm-core/src/main/java/sonia/scm/plugin/PluginCircularDependencyException.java new file mode 100644 index 0000000000..2934ee8a66 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/plugin/PluginCircularDependencyException.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.plugin; + +/** + * + * @author Sebastian Sdorra + * @since 2.0.0 + */ +public class PluginCircularDependencyException extends PluginException +{ + + /** Field description */ + private static final long serialVersionUID = -4163410666933840934L; + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param message + */ + public PluginCircularDependencyException(String message) + { + super(message); + } +} diff --git a/scm-core/src/main/java/sonia/scm/plugin/PluginConstants.java b/scm-core/src/main/java/sonia/scm/plugin/PluginConstants.java new file mode 100644 index 0000000000..60e4916b2d --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/plugin/PluginConstants.java @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.plugin; + +/** + * + * @author Sebastian Sdorra + * @since 2.0.0 + */ +public interface PluginConstants +{ + + /** descriptor xml element artifactId */ + public static final String EL_ARTIFACTID = "artifactId"; + + /** descriptor xml element dependency */ + public static final String EL_DEPENDENCY = "dependency"; + + /** descriptor xml element groupId */ + public static final String EL_GROUPID = "groupId"; + + /** descriptor xml element version */ + public static final String EL_VERSION = "version"; + + /** checksum file */ + public static final String FILE_CHECKSUM = "checksum"; + + /** core file */ + public static final String FILE_CORE = "core"; + + /** Field description */ + public static final String PATH_DESCRIPTOR = + "/WEB-INF/classes/META-INF/scm/plugin.xml"; + + /** Field description */ + public static final String FILE_DESCRIPTOR = PATH_DESCRIPTOR.substring(1); +} diff --git a/scm-core/src/main/java/sonia/scm/plugin/SmpArchive.java b/scm-core/src/main/java/sonia/scm/plugin/SmpArchive.java index 4c57c57385..0920fc1f28 100644 --- a/scm-core/src/main/java/sonia/scm/plugin/SmpArchive.java +++ b/scm-core/src/main/java/sonia/scm/plugin/SmpArchive.java @@ -74,20 +74,6 @@ import javax.xml.parsers.ParserConfigurationException; */ public final class SmpArchive { - - /** Field description */ - public static final String PATH_DESCRIPTOR = - "/WEB-INF/classes/META-INF/scm/plugin.xml"; - - /** Field description */ - private static final String EL_ARTIFACTID = "artifactId"; - - /** Field description */ - private static final String EL_GROUPID = "groupId"; - - /** Field description */ - private static final String EL_VERSION = "version"; - //~--- constructors --------------------------------------------------------- /** @@ -316,7 +302,7 @@ public final class SmpArchive while (entry != null) { - if (PATH_DESCRIPTOR.equals(getPath(entry))) + if (PluginConstants.PATH_DESCRIPTOR.equals(getPath(entry))) { doc = XmlUtil.createDocument(zis); } @@ -352,16 +338,23 @@ public final class SmpArchive */ private PluginId createPluginId() throws IOException { - Multimap entries = XmlUtil.values(getDescriptorDocument(), - EL_GROUPID, EL_ARTIFACTID, EL_VERSION); - String groupId = getSingleValue(entries, EL_GROUPID); + //J- + Multimap entries = XmlUtil.values( + getDescriptorDocument(), + PluginConstants.EL_GROUPID, + PluginConstants.EL_ARTIFACTID, + PluginConstants.EL_VERSION + ); + //J+ + + String groupId = getSingleValue(entries, PluginConstants.EL_GROUPID); if (Strings.isNullOrEmpty(groupId)) { throw new PluginException("could not find groupId in plugin descriptor"); } - String artifactId = getSingleValue(entries, EL_ARTIFACTID); + String artifactId = getSingleValue(entries, PluginConstants.EL_ARTIFACTID); if (Strings.isNullOrEmpty(artifactId)) { @@ -369,7 +362,7 @@ public final class SmpArchive "could not find artifactId in plugin descriptor "); } - String version = getSingleValue(entries, EL_VERSION); + String version = getSingleValue(entries, PluginConstants.EL_VERSION); if (Strings.isNullOrEmpty(version)) { diff --git a/scm-core/src/main/java/sonia/scm/util/Util.java b/scm-core/src/main/java/sonia/scm/util/Util.java index 6f973ba691..5439cc77ec 100644 --- a/scm-core/src/main/java/sonia/scm/util/Util.java +++ b/scm-core/src/main/java/sonia/scm/util/Util.java @@ -36,6 +36,7 @@ package sonia.scm.util; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.base.Strings; +import com.google.common.collect.Multimap; //~--- JDK imports ------------------------------------------------------------ @@ -428,6 +429,24 @@ public final class Util return parseDate(dateString, null); } + /** + * Returns the first value of a {@link Multimap} or {@code null}. + * + * + * @param map multi map + * @param key key + * @param type of key + * @param type of + * + * @return first value of {@code null} + * + * @since 2.0.0 + */ + public static V getFirst(Multimap map, K key) + { + return map.get(key).iterator().next(); + } + /** * Method description * diff --git a/scm-core/src/test/java/sonia/scm/plugin/SmpArchiveTest.java b/scm-core/src/test/java/sonia/scm/plugin/SmpArchiveTest.java index a5e95b41ff..77ed456448 100644 --- a/scm-core/src/test/java/sonia/scm/plugin/SmpArchiveTest.java +++ b/scm-core/src/test/java/sonia/scm/plugin/SmpArchiveTest.java @@ -36,7 +36,6 @@ package sonia.scm.plugin; import com.google.common.base.Charsets; import com.google.common.base.Strings; import com.google.common.base.Throwables; -import com.google.common.io.CharStreams; import com.google.common.io.Files; import org.junit.Rule; @@ -92,7 +91,7 @@ public class SmpArchiveTest IOUtil.mkdirs(target); SmpArchive.create(archive).extract(target); - File descriptor = new File(target, SmpArchive.PATH_DESCRIPTOR.substring(1)); + File descriptor = new File(target, PluginConstants.FILE_DESCRIPTOR); assertTrue(descriptor.exists()); @@ -201,7 +200,7 @@ public class SmpArchiveTest try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(archiveFile), Charsets.UTF_8)) { - zos.putNextEntry(new ZipEntry(SmpArchive.PATH_DESCRIPTOR)); + zos.putNextEntry(new ZipEntry(PluginConstants.PATH_DESCRIPTOR)); Files.copy(descriptor, zos); zos.closeEntry(); zos.putNextEntry(new ZipEntry("/META-INF/")); diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/ExplodedSmp.java b/scm-webapp/src/main/java/sonia/scm/plugin/ExplodedSmp.java new file mode 100644 index 0000000000..2381628e7f --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/plugin/ExplodedSmp.java @@ -0,0 +1,257 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.plugin; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.base.Function; +import com.google.common.collect.Multimap; + +import sonia.scm.util.Util; +import sonia.scm.util.XmlUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; +import java.io.InputStream; + +import java.nio.file.Files; +import java.nio.file.Path; + +import java.util.Collection; + +/** + * + * @author Sebastian Sdorra + */ +public final class ExplodedSmp implements Comparable +{ + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param path + * @param pluginId + * @param dependencies + */ + ExplodedSmp(Path path, PluginId pluginId, Collection dependencies) + { + this.path = path; + this.pluginId = pluginId; + this.dependencies = dependencies; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param directory + * + * @return + * + * @throws IOException + */ + public static ExplodedSmp create(Path directory) throws IOException + { + ExplodedSmp smp; + + Path descriptor = directory.resolve(PluginConstants.FILE_DESCRIPTOR); + + try (InputStream in = Files.newInputStream(descriptor)) + { + //J- + Multimap values = XmlUtil.values(in, + PluginConstants.EL_GROUPID, + PluginConstants.EL_ARTIFACTID, + PluginConstants.EL_VERSION, + PluginConstants.EL_DEPENDENCY + ); + + PluginId pluginId = new PluginId( + Util.getFirst(values, PluginConstants.EL_GROUPID), + Util.getFirst(values, PluginConstants.EL_ARTIFACTID), + Util.getFirst(values, PluginConstants.EL_VERSION) + ); + + smp = new ExplodedSmp( + directory, + pluginId, + values.get(PluginConstants.EL_DEPENDENCY) + ); + //J+ + } + + return smp; + } + + /** + * Method description + * + * + * @param o + * + * @return + */ + @Override + public int compareTo(ExplodedSmp o) + { + int result; + + if (dependencies.isEmpty() && o.dependencies.isEmpty()) + { + result = 0; + } + else if (dependencies.isEmpty() &&!o.dependencies.isEmpty()) + { + result = -1; + } + else if (!dependencies.isEmpty() && o.dependencies.isEmpty()) + { + result = 1; + } + else + { + String id = pluginId.getIdWithoutVersion(); + String oid = o.pluginId.getIdWithoutVersion(); + + if (dependencies.contains(oid) && o.dependencies.contains(id)) + { + StringBuilder b = new StringBuilder("circular dependency detected: "); + + b.append(id).append(" depends on ").append(oid).append(" and "); + b.append(oid).append(" depends on ").append(id); + + throw new PluginCircularDependencyException(b.toString()); + } + else if (dependencies.contains(oid)) + { + result = 999; + } + else if (o.dependencies.contains(id)) + { + result = -999; + } + else + { + result = 0; + } + } + + return result; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + public Collection getDependencies() + { + return dependencies; + } + + /** + * Method description + * + * + * @return + */ + public Path getPath() + { + return path; + } + + /** + * Method description + * + * + * @return + */ + public PluginId getPluginId() + { + return pluginId; + } + + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here..., 14/07/12 + * @author Enter your name here... + */ + public static class PathTransformer implements Function + { + + /** + * Method description + * + * + * @param directory + * + * @return + */ + @Override + public ExplodedSmp apply(Path directory) + { + try + { + return ExplodedSmp.create(directory); + } + catch (IOException ex) + { + throw new PluginException("could not create ExplodedSmp", ex); + } + } + } + + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private final Collection dependencies; + + /** Field description */ + private final Path path; + + /** Field description */ + private final PluginId pluginId; +} diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java b/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java index d34d28358d..cd1a90ed11 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/PluginProcessor.java @@ -33,14 +33,19 @@ package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSet.Builder; +import com.google.common.collect.Lists; +import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import com.google.common.hash.Hashing; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.plugin.ExplodedSmp.PathTransformer; + //~--- JDK imports ------------------------------------------------------------ import java.io.File; @@ -67,6 +72,8 @@ import javax.xml.bind.JAXBException; /** * * @author Sebastian Sdorra + * + * TODO don't mix nio and io */ public final class PluginProcessor { @@ -93,8 +100,7 @@ public final class PluginProcessor private static final String EXTENSION_PLUGIN = ".smp"; /** Field description */ - private static final String FILE_DESCRIPTOR = - SmpArchive.PATH_DESCRIPTOR.substring(1); + private static final String FORMAT_DATE = "yyyy-MM-dd"; /** Field description */ private static final String GLOB_JAR = "*.jar"; @@ -242,15 +248,18 @@ public final class PluginProcessor extract(archives); - Set directories = collectPluginDirectories(pluginDirectory); + List dirs = collectPluginDirectories(pluginDirectory); if (logger.isDebugEnabled()) { - logger.debug("process {} directories", directories.size()); + logger.debug("process {} directories", dirs.size()); } + List smps = Lists.transform(dirs, new PathTransformer()); + Iterable smpOrdered = Ordering.natural().sortedCopy(smps); + Set pluginWrappers = createPluginWrappers(classLoader, - directories); + smpOrdered); if (logger.isDebugEnabled()) { @@ -294,9 +303,9 @@ public final class PluginProcessor * * @throws IOException */ - private Set collectPluginDirectories(Path directory) throws IOException + private List collectPluginDirectories(Path directory) throws IOException { - Builder paths = ImmutableSet.builder(); + Builder paths = ImmutableList.builder(); Filter filter = new DirectoryFilter(); @@ -322,7 +331,7 @@ public final class PluginProcessor */ private String createDate() { - return new SimpleDateFormat("yyyy-MM-dd").format(new Date()); + return new SimpleDateFormat(FORMAT_DATE).format(new Date()); } /** @@ -373,7 +382,7 @@ public final class PluginProcessor throws IOException { PluginWrapper wrapper = null; - Path descriptor = directory.resolve(FILE_DESCRIPTOR); + Path descriptor = directory.resolve(PluginConstants.FILE_DESCRIPTOR); if (Files.exists(descriptor)) { @@ -397,21 +406,21 @@ public final class PluginProcessor * * * @param classLoader - * @param directories + * @param smps * * @return * * @throws IOException */ private Set createPluginWrappers(ClassLoader classLoader, - Iterable directories) + Iterable smps) throws IOException { Set plugins = Sets.newHashSet(); - for (Path directory : directories) + for (ExplodedSmp smp : smps) { - PluginWrapper plugin = createPluginWrapper(classLoader, directory); + PluginWrapper plugin = createPluginWrapper(classLoader, smp.getPath()); if (plugin != null) { @@ -444,7 +453,7 @@ public final class PluginProcessor logger.debug("extract plugin {}", smp.getPluginId()); - File directory = Plugins.createPluginDirectory(archiveFile, + File directory = Plugins.createPluginDirectory(pluginDirectory.toFile(), smp.getPluginId()); String checksum = com.google.common.io.Files.hash(archiveFile, @@ -532,7 +541,8 @@ public final class PluginProcessor @Override public boolean accept(Path entry) throws IOException { - return Files.isDirectory(entry) &&!entry.getFileName().startsWith("."); + return Files.isDirectory(entry) + &&!entry.getFileName().toString().startsWith("."); } } diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/Plugins.java b/scm-webapp/src/main/java/sonia/scm/plugin/Plugins.java index e02e38d451..f94b548ba6 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/Plugins.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/Plugins.java @@ -28,6 +28,7 @@ */ + package sonia.scm.plugin; //~--- non-JDK imports -------------------------------------------------------- @@ -107,11 +108,6 @@ public final class Plugins return new File(new File(parent, id.getGroupId()), id.getArtifactId()); } - /** Field description */ - private static final String FILE_CHECKSUM = "checksum"; - - - /** * Method description * @@ -143,16 +139,12 @@ public final class Plugins if (core) { - if (!new File(directory, "core").createNewFile()) + if (!new File(directory, PluginConstants.FILE_CORE).createNewFile()) { throw new IOException("could not create core plugin marker"); } } } - - public static File getChecksumFile(File pluginDirectory){ - return new File(pluginDirectory, FILE_CHECKSUM); - } /** * Method description @@ -167,6 +159,21 @@ public final class Plugins return Iterables.transform(wrapped, new Unwrap()); } + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param pluginDirectory + * + * @return + */ + public static File getChecksumFile(File pluginDirectory) + { + return new File(pluginDirectory, PluginConstants.FILE_CHECKSUM); + } + //~--- inner classes -------------------------------------------------------- /** diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/ExplodedSmpTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/ExplodedSmpTest.java new file mode 100644 index 0000000000..fd1a01ab84 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/plugin/ExplodedSmpTest.java @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.plugin; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.collect.Lists; + +import org.junit.Test; + +import static org.junit.Assert.*; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.Collections; +import java.util.List; + +/** + * + * @author Sebastian Sdorra + */ +public class ExplodedSmpTest +{ + + /** + * Method description + * + */ + @Test + public void testCompareTo() + { + ExplodedSmp e1 = create("a", "c", "1", "a:a"); + ExplodedSmp e3 = create("a", "a", "1"); + ExplodedSmp e2 = create("a", "b", "1"); + List es = list(e1, e2, e3); + + is(es, 2, "c"); + } + + /** + * Method description + * + */ + @Test(expected = PluginCircularDependencyException.class) + public void testCompareToCyclicDependency() + { + ExplodedSmp e1 = create("a", "a", "1", "a:c"); + ExplodedSmp e2 = create("a", "b", "1"); + ExplodedSmp e3 = create("a", "c", "1", "a:a"); + + list(e1, e2, e3); + } + + /** + * Method description + * + */ + @Test + public void testCompareToTransitiveDependencies() + { + ExplodedSmp e1 = create("a", "a", "1", "a:b"); + ExplodedSmp e2 = create("a", "b", "1"); + ExplodedSmp e3 = create("a", "c", "1", "a:a"); + + List es = list(e1, e2, e3); + + is(es, 0, "b"); + is(es, 1, "a"); + is(es, 2, "c"); + } + + /** + * Method description + * + */ + @Test + public void testMultipleDependencies() + { + ExplodedSmp e1 = create("a", "a", "1", "a:b", "a:c"); + ExplodedSmp e2 = create("a", "b", "1", "a:c"); + ExplodedSmp e3 = create("a", "c", "1"); + List es = list(e1, e2, e3); + + is(es, 2, "a"); + } + + /** + * Method description + * + * + * @param groupId + * @param artifactId + * @param version + * @param dependencies + * + * @return + */ + private ExplodedSmp create(String groupId, String artifactId, String version, + String... dependencies) + { + return new ExplodedSmp(null, new PluginId(groupId, artifactId, version), + Lists.newArrayList(dependencies)); + } + + /** + * Method description + * + * + * @param e + * + * @return + */ + private List list(ExplodedSmp... e) + { + List es = Lists.newArrayList(e); + + Collections.sort(es); + + return es; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param es + * @param p + * @param a + */ + private void is(List es, int p, String a) + { + assertEquals(a, es.get(p).getPluginId().getArtifactId()); + } +}