diff --git a/maven/pom.xml b/maven/pom.xml index c402181075..5a802c3e9b 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.maven scm-maven-plugins pom - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-maven-plugins @@ -24,7 +24,7 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/maven/scm-plugin-archetype/pom.xml b/maven/scm-plugin-archetype/pom.xml index 666e153ebf..21c440dc97 100644 --- a/maven/scm-plugin-archetype/pom.xml +++ b/maven/scm-plugin-archetype/pom.xml @@ -7,12 +7,12 @@ scm-maven-plugins sonia.scm.maven - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.maven scm-plugin-archetype - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-plugin-archetype diff --git a/maven/scm-plugin-archetype/src/main/resources/archetype-resources/pom.xml b/maven/scm-plugin-archetype/src/main/resources/archetype-resources/pom.xml index ff563938f7..97f5e991f8 100644 --- a/maven/scm-plugin-archetype/src/main/resources/archetype-resources/pom.xml +++ b/maven/scm-plugin-archetype/src/main/resources/archetype-resources/pom.xml @@ -7,7 +7,7 @@ scm-plugins sonia.scm.plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT ${groupId} @@ -31,7 +31,7 @@ sonia.scm scm-test - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT test diff --git a/plugins/pom.xml b/plugins/pom.xml index 531d59e389..b633839dcb 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-plugins pom - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-plugins @@ -31,7 +31,7 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT @@ -58,4 +58,33 @@ + + + release + + + + + sonia.maven + web-compressor + 1.0-SNAPSHOT + + + compile + + compress-directory + + + + + true + ${project.build.directory}/classes + + + + + + + + \ No newline at end of file diff --git a/plugins/scm-activedirectory-auth-plugin/pom.xml b/plugins/scm-activedirectory-auth-plugin/pom.xml index 0c9d5672c2..f7cd9227c9 100644 --- a/plugins/scm-activedirectory-auth-plugin/pom.xml +++ b/plugins/scm-activedirectory-auth-plugin/pom.xml @@ -7,12 +7,12 @@ scm-plugins sonia.scm.plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-activedirectory-auth-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-activedirectory-auth-plugin https://bitbucket.org/sdorra/scm-manager @@ -32,7 +32,7 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/plugins/scm-bzr-plugin/pom.xml b/plugins/scm-bzr-plugin/pom.xml index 81970def67..d8d6b7dd76 100644 --- a/plugins/scm-bzr-plugin/pom.xml +++ b/plugins/scm-bzr-plugin/pom.xml @@ -7,12 +7,12 @@ scm-plugins sonia.scm.plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-bzr-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-bzr-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Bazaar diff --git a/plugins/scm-git-plugin/pom.xml b/plugins/scm-git-plugin/pom.xml index 43d5302853..6aa87c9280 100644 --- a/plugins/scm-git-plugin/pom.xml +++ b/plugins/scm-git-plugin/pom.xml @@ -7,12 +7,12 @@ scm-plugins sonia.scm.plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-git-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Git @@ -50,7 +50,7 @@ sonia.scm scm-test - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT test diff --git a/plugins/scm-graph-plugin/pom.xml b/plugins/scm-graph-plugin/pom.xml index c3faac2041..352544b356 100644 --- a/plugins/scm-graph-plugin/pom.xml +++ b/plugins/scm-graph-plugin/pom.xml @@ -7,12 +7,12 @@ scm-plugins sonia.scm.plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-graph-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-graph-plugin Creates an Google Guice injection graph https://bitbucket.org/sdorra/scm-manager diff --git a/plugins/scm-hg-plugin/pom.xml b/plugins/scm-hg-plugin/pom.xml index 6808c42cb0..f573a55056 100644 --- a/plugins/scm-hg-plugin/pom.xml +++ b/plugins/scm-hg-plugin/pom.xml @@ -7,12 +7,12 @@ sonia.scm.plugins scm-plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-hg-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Mercurial @@ -37,7 +37,7 @@ sonia.scm scm-test - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT test diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/AbstractHgInstaller.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/AbstractHgInstaller.java index 7a514e6031..a647368358 100644 --- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/AbstractHgInstaller.java +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/AbstractHgInstaller.java @@ -29,27 +29,20 @@ * */ + + package sonia.scm.installer; //~--- non-JDK imports -------------------------------------------------------- -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import sonia.scm.io.Command; -import sonia.scm.io.CommandResult; -import sonia.scm.io.SimpleCommand; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.util.IOUtil; -import sonia.scm.util.SystemUtil; //~--- JDK imports ------------------------------------------------------------ import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.List; /** * @@ -61,10 +54,6 @@ public abstract class AbstractHgInstaller implements HgInstaller /** Field description */ public static final String DIRECTORY_REPOSITORY = "repositories"; - /** the logger for AbstractHgInstaller */ - private static final Logger logger = LoggerFactory - .getLogger(AbstractHgInstaller.class); - //~--- constructors --------------------------------------------------------- /** @@ -91,104 +80,15 @@ public abstract class AbstractHgInstaller implements HgInstaller @Override public void install(HgConfig config) throws IOException { - File repoDirectory = new File(baseDirectory, DIRECTORY_REPOSITORY.concat( - File.separator).concat(HgRepositoryHandler.TYPE_NAME)); + File repoDirectory = new File( + baseDirectory, + DIRECTORY_REPOSITORY.concat(File.separator).concat( + HgRepositoryHandler.TYPE_NAME)); IOUtil.mkdirs(repoDirectory); config.setRepositoryDirectory(repoDirectory); } - /** - * TODO check for windows - * - * - * - * @param path - * @param cmd - * - * @return - */ - protected String search(String[] path, String cmd) - { - String cmdPath = null; - - try - { - Command command = new SimpleCommand(cmd, "--version"); - CommandResult result = command.execute(); - - if (result.isSuccessfull()) - { - cmdPath = cmd; - } - } - catch (IOException ex) - {} - - if (cmdPath == null) - { - for (String pathPart : path) - { - List extensions = getExecutableSearchExtensions(); - File file = findFileByExtension(pathPart, cmd, extensions); - if (file != null) - { - cmdPath = file.getAbsolutePath(); - break; - } - } - } - - if (cmdPath != null) - { - if (logger.isInfoEnabled()) - { - logger.info("found {} at {}", cmd, cmdPath); - } - } - else if (logger.isWarnEnabled()) - { - logger.warn("could not find {}", cmd); - } - - return cmdPath; - } - - /** - * Returns a list of file extensions to use when searching for executables. - * The list is in priority order, with the highest priority first. - */ - protected List getExecutableSearchExtensions() - { - List extensions; - if (SystemUtil.isWindows()) - { - extensions = Arrays.asList(".exe"); - } - else - { - extensions = Arrays.asList(""); - } - return extensions; - } - - private File findFileByExtension(String parentPath, String cmd, - List potentialExtensions) - { - File file = null; - for (String potentialExtension : potentialExtensions) - { - String fileName = cmd.concat(potentialExtension); - File potentialFile = new File(parentPath, fileName); - if (potentialFile.exists()) - { - file = potentialFile; - break; - } - } - return file; - } - //~--- fields --------------------------------------------------------------- /** Field description */ diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/UnixHgInstaller.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/UnixHgInstaller.java index 09d75e2a13..cbef81f569 100644 --- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/UnixHgInstaller.java +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/UnixHgInstaller.java @@ -35,10 +35,8 @@ package sonia.scm.installer; //~--- non-JDK imports -------------------------------------------------------- -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import sonia.scm.repository.HgConfig; +import sonia.scm.util.IOUtil; //~--- JDK imports ------------------------------------------------------------ @@ -52,29 +50,6 @@ import java.io.IOException; public class UnixHgInstaller extends AbstractHgInstaller { - /** Field description */ - private static final String[] PATH = new String[] - { - - // default path - "/usr/bin", - - // manually installed - "/usr/local/bin", - - // mac ports - "/opt/local/bin", - - // opencsw - "/opt/csw/bin" - }; - - /** the logger for UnixHgInstaller */ - private static final Logger logger = - LoggerFactory.getLogger(UnixHgInstaller.class); - - //~--- constructors --------------------------------------------------------- - /** * Constructs ... * @@ -100,8 +75,8 @@ public class UnixHgInstaller extends AbstractHgInstaller public void install(HgConfig config) throws IOException { super.install(config); - config.setHgBinary(search(PATH, "hg")); - config.setPythonBinary(search(PATH, "python")); + config.setHgBinary(IOUtil.search("hg")); + config.setPythonBinary(IOUtil.search("python")); } /** diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/WindowsHgInstaller.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/WindowsHgInstaller.java index 84e9c52a21..bf8d2c0d68 100644 --- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/WindowsHgInstaller.java +++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/WindowsHgInstaller.java @@ -29,6 +29,8 @@ * */ + + package sonia.scm.installer; //~--- non-JDK imports -------------------------------------------------------- @@ -36,10 +38,9 @@ package sonia.scm.installer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.io.SimpleCommand; -import sonia.scm.io.SimpleCommandResult; import sonia.scm.repository.HgConfig; import sonia.scm.util.IOUtil; +import sonia.scm.util.RegistryUtil; import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ @@ -48,8 +49,6 @@ import java.io.File; import java.io.FilenameFilter; import java.io.IOException; -import java.util.Scanner; - /** * * @author Sebastian Sdorra @@ -60,20 +59,21 @@ public class WindowsHgInstaller extends AbstractHgInstaller /** Field description */ private static final String FILE_LIBRARY_ZIP = "library.zip"; + /** Field description */ + private static final String FILE_LIB_MERCURIAL = + "Lib\\site-packages\\mercurial"; + /** Field description */ private static final String FILE_MERCURIAL_EXE = "hg.exe"; /** Field description */ private static final String FILE_MERCURIAL_SCRIPT = "hg.bat"; - /** Field description */ - private static final String FILE_TEMPLATES = "templates"; - /** Field description */ private static final String FILE_SCRIPTS = "Scripts"; /** Field description */ - private static final String FILE_LIB_MERCURIAL = "Lib\\site-packages\\mercurial"; + private static final String FILE_TEMPLATES = "templates"; /** Field description */ private static final String[] REGISTRY_HG = new String[] @@ -87,11 +87,12 @@ public class WindowsHgInstaller extends AbstractHgInstaller }; /** Field description */ - private static final String REGISTRY_PYTHON = "HKEY_CLASSES_ROOT\\Python.File\\shell\\open\\command"; + private static final String REGISTRY_PYTHON = + "HKEY_CLASSES_ROOT\\Python.File\\shell\\open\\command"; /** the logger for WindowsHgInstaller */ - private static final Logger logger = LoggerFactory - .getLogger(WindowsHgInstaller.class); + private static final Logger logger = + LoggerFactory.getLogger(WindowsHgInstaller.class); //~--- constructors --------------------------------------------------------- @@ -122,10 +123,12 @@ public class WindowsHgInstaller extends AbstractHgInstaller super.install(config); String pythonBinary = getPythonBinary(); + config.setPythonBinary(pythonBinary); File hgScript = getMercurialScript(pythonBinary); File hgDirectory = getMercurialDirectory(); + if (hgScript != null) { config.setHgBinary(hgScript.getAbsolutePath()); @@ -145,8 +148,7 @@ public class WindowsHgInstaller extends AbstractHgInstaller * @param config */ @Override - public void update(HgConfig config) - {} + public void update(HgConfig config) {} /** * Method description @@ -233,8 +235,8 @@ public class WindowsHgInstaller extends AbstractHgInstaller IOUtil.copy(templateDirectory, new File(libDir, FILE_TEMPLATES)); } - config.setHgBinary(new File(hgDirectory, FILE_MERCURIAL_EXE) - .getAbsolutePath()); + config.setHgBinary(new File(hgDirectory, + FILE_MERCURIAL_EXE).getAbsolutePath()); } //~--- get methods ---------------------------------------------------------- @@ -251,7 +253,7 @@ public class WindowsHgInstaller extends AbstractHgInstaller for (String registryKey : REGISTRY_HG) { - String path = getRegistryValue(registryKey, null, null); + String path = RegistryUtil.getRegistryValue(registryKey); if (path != null) { @@ -275,6 +277,10 @@ public class WindowsHgInstaller extends AbstractHgInstaller * Returns the location of the script to run Mercurial, if Mercurial is * installed as a Python package from source. Only packages that include a * templates directory will be recognized. + * + * @param pythonBinary + * + * @return */ private File getMercurialScript(String pythonBinary) { @@ -283,6 +289,7 @@ public class WindowsHgInstaller extends AbstractHgInstaller if (pythonBinary != null) { File pythonBinaryFile = new File(pythonBinary); + if (pythonBinaryFile.exists()) { File pythonDir = pythonBinaryFile.getParentFile(); @@ -290,10 +297,14 @@ public class WindowsHgInstaller extends AbstractHgInstaller File potentialHgScript = new File(scriptsDir, FILE_MERCURIAL_SCRIPT); File mercurialPackageDir = new File(pythonDir, FILE_LIB_MERCURIAL); File templatesDir = new File(mercurialPackageDir, FILE_TEMPLATES); + if (potentialHgScript.exists() && templatesDir.exists()) + { hgScript = potentialHgScript; + } } } + return hgScript; } @@ -305,80 +316,13 @@ public class WindowsHgInstaller extends AbstractHgInstaller */ private String getPythonBinary() { - String python = getRegistryValue(REGISTRY_PYTHON, null, null); + String python = RegistryUtil.getRegistryValue(REGISTRY_PYTHON); if (python == null) { - python = search(new String[0], "python"); + python = IOUtil.search(new String[0], "python"); } return python; } - - /** - * Method description - * - * - * @param key - * @param subKey - * @param defaultValue - * - * @return - */ - private String getRegistryValue(String key, String subKey, String defaultValue) - { - String programDirectory = defaultValue; - SimpleCommand command = null; - - if (subKey != null) - { - command = new SimpleCommand("reg", "query", key, "/v", subKey); - } - else - { - command = new SimpleCommand("reg", "query", key); - } - - try - { - SimpleCommandResult result = command.execute(); - - if (result.isSuccessfull()) - { - String output = result.getOutput(); - Scanner scanner = new Scanner(output); - - while (scanner.hasNextLine()) - { - String line = scanner.nextLine(); - int index = line.indexOf("REG_SZ"); - - if (index > 0) - { - programDirectory = line.substring(index + "REG_SZ".length()).trim(); - - if (programDirectory.startsWith("\"")) - { - programDirectory = programDirectory.substring(1); - programDirectory = programDirectory.substring(0, programDirectory - .indexOf("\"")); - } - - if (logger.isDebugEnabled()) - { - logger.debug("use program directory {}", programDirectory); - } - - break; - } - } - } - } - catch (IOException ex) - { - logger.error(ex.getMessage(), ex); - } - - return programDirectory; - } } diff --git a/plugins/scm-pam-plugin/pom.xml b/plugins/scm-pam-plugin/pom.xml index 73825fdca2..62d1dd1470 100644 --- a/plugins/scm-pam-plugin/pom.xml +++ b/plugins/scm-pam-plugin/pom.xml @@ -7,12 +7,12 @@ scm-plugins sonia.scm.plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-pam-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-pam-plugin https://bitbucket.org/sdorra/scm-manager Using pam as an authentication handler. diff --git a/plugins/scm-svn-plugin/pom.xml b/plugins/scm-svn-plugin/pom.xml index 06a4b926fd..b96cf290cb 100644 --- a/plugins/scm-svn-plugin/pom.xml +++ b/plugins/scm-svn-plugin/pom.xml @@ -7,22 +7,29 @@ scm-plugins sonia.scm.plugins - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-svn-plugin https://bitbucket.org/sdorra/scm-manager Plugin for the version control system Subversion + + javax.servlet + servlet-api + ${servlet.version} + provided + + org.tmatesoft.svnkit - svnkit - ${svnkit.version} + svnkit-dav + ${svnkit-dav.version} trilead-ssh2 @@ -35,25 +42,19 @@ - - org.tmatesoft.svnkit - svnkit-dav - ${svnkit.version} - - sonia.scm scm-test - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT test - 1.3.4 + 1.3.5.1 diff --git a/pom.xml b/pom.xml index 78a1247a10..a610b1a090 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sonia.scm scm pom - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm http://bitbucket.org/sdorra/scm-manager @@ -277,7 +277,7 @@ 1.6.1 2.5 2.0 - 1.5-ea08 + 1.5 2.3.1 1.6 UTF-8 diff --git a/samples/pom.xml b/samples/pom.xml index 012af0d57c..59ba3607d3 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.samples scm-samples pom - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-samples diff --git a/samples/scm-sample-auth/pom.xml b/samples/scm-sample-auth/pom.xml index b5a91a0ccc..2ec3b8fdc8 100644 --- a/samples/scm-sample-auth/pom.xml +++ b/samples/scm-sample-auth/pom.xml @@ -7,12 +7,12 @@ scm-samples sonia.scm.samples - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.sample scm-sample-auth - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-sample-auth Sample Authentication Plugin https://bitbucket.org/sdorra/scm-manager @@ -29,7 +29,7 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/samples/scm-sample-hello/pom.xml b/samples/scm-sample-hello/pom.xml index 1672efb356..9e4415ab2f 100644 --- a/samples/scm-sample-hello/pom.xml +++ b/samples/scm-sample-hello/pom.xml @@ -7,12 +7,12 @@ scm-samples sonia.scm.samples - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.sample scm-sample-hello - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-sample-hello A simple hello world plugin https://bitbucket.org/sdorra/scm-manager @@ -29,7 +29,7 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/scm-core/pom.xml b/scm-core/pom.xml index 012b75e227..d87329b5ef 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -7,12 +7,12 @@ scm sonia.scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-core diff --git a/scm-core/src/main/java/sonia/scm/resources/ResourceHandler.java b/scm-core/src/main/java/sonia/scm/resources/ResourceHandler.java new file mode 100644 index 0000000000..fcc4bf149f --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/resources/ResourceHandler.java @@ -0,0 +1,75 @@ +/** + * 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.resources; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.plugin.ExtensionPoint; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.InputStream; + +/** + * + * @author Sebastian Sdorra + */ +@ExtensionPoint +public interface ResourceHandler +{ + + /** + * Method description + * + * + * @return + */ + public String getName(); + + /** + * Method description + * + * + * @return + */ + public InputStream getResource(); + + /** + * Method description + * + * + * @return + */ + public ResourceType getType(); +} diff --git a/scm-core/src/main/java/sonia/scm/resources/ResourceHandlerComparator.java b/scm-core/src/main/java/sonia/scm/resources/ResourceHandlerComparator.java new file mode 100644 index 0000000000..d1e30f0780 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/resources/ResourceHandlerComparator.java @@ -0,0 +1,65 @@ +/** + * 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.resources; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.Comparator; + +/** + * + * @author Sebastian Sdorra + */ +public class ResourceHandlerComparator implements Comparator +{ + + /** + * Method description + * + * + * @param handler + * @param otherHandler + * + * @return + */ + @Override + public int compare(ResourceHandler handler, ResourceHandler otherHandler) + { + return Util.compare(handler.getName(), otherHandler.getName()); + } +} diff --git a/scm-core/src/main/java/sonia/scm/resources/ResourceType.java b/scm-core/src/main/java/sonia/scm/resources/ResourceType.java new file mode 100644 index 0000000000..85864cf355 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/resources/ResourceType.java @@ -0,0 +1,40 @@ +/** + * 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.resources; + +/** + * + * @author Sebastian Sdorra + */ +public enum ResourceType { SCRIPT, STYLESHEET } diff --git a/scm-core/src/main/java/sonia/scm/user/User.java b/scm-core/src/main/java/sonia/scm/user/User.java index 8cd188c688..e39059a709 100644 --- a/scm-core/src/main/java/sonia/scm/user/User.java +++ b/scm-core/src/main/java/sonia/scm/user/User.java @@ -131,15 +131,64 @@ public class User * * * @param user + * + * @return */ - public void copyProperties(User user) + public boolean copyProperties(User user) { - user.setAdmin(admin); - user.setDisplayName(displayName); - user.setMail(mail); - user.setName(name); - user.setPassword(password); - user.setType(type); + return copyProperties(user, true); + } + + /** + * Method description + * + * + * @param user + * @param copyPassword + * + * @return + */ + public boolean copyProperties(User user, boolean copyPassword) + { + boolean result = false; + + if (user.isAdmin() != admin) + { + result = true; + user.setAdmin(admin); + } + + if (Util.isNotEquals(user.getDisplayName(), displayName)) + { + result = true; + user.setDisplayName(displayName); + } + + if (Util.isNotEquals(user.getMail(), mail)) + { + result = true; + user.setMail(mail); + } + + if (Util.isNotEquals(user.getName(), name)) + { + result = true; + user.setName(name); + } + + if (copyPassword && Util.isNotEquals(user.getPassword(), password)) + { + result = true; + user.setPassword(password); + } + + if (Util.isNotEquals(user.getType(), type)) + { + result = true; + user.setType(type); + } + + return result; } /** @@ -263,9 +312,9 @@ public class User * * @return */ - public long getLastLogin() + public Long getLastModified() { - return lastLogin; + return lastModified; } /** @@ -378,11 +427,11 @@ public class User * Method description * * - * @param lastLogin + * @param lastModified */ - public void setLastLogin(long lastLogin) + public void setLastModified(long lastModified) { - this.lastLogin = lastLogin; + this.lastModified = lastModified; } /** @@ -444,7 +493,7 @@ public class User /** Field description */ @XmlJavaTypeAdapter(XmlTimestampDateAdapter.class) - private Long lastLogin; + private Long lastModified; /** Field description */ private String mail; diff --git a/scm-core/src/main/java/sonia/scm/util/IOUtil.java b/scm-core/src/main/java/sonia/scm/util/IOUtil.java index 210028b905..5805d8c9e4 100644 --- a/scm-core/src/main/java/sonia/scm/util/IOUtil.java +++ b/scm-core/src/main/java/sonia/scm/util/IOUtil.java @@ -38,6 +38,9 @@ package sonia.scm.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.io.Command; +import sonia.scm.io.CommandResult; +import sonia.scm.io.SimpleCommand; import sonia.scm.io.ZipUnArchiver; //~--- JDK imports ------------------------------------------------------------ @@ -52,6 +55,9 @@ import java.io.OutputStream; import java.io.Reader; import java.io.Writer; +import java.util.Arrays; +import java.util.List; + /** * * @author Sebastian Sdorra @@ -59,6 +65,26 @@ import java.io.Writer; public class IOUtil { + /** Field description */ + public static final String DEFAULT_CHECKPARAMETER = "--version"; + + /** Field description */ + public static final String[] DEFAULT_PATH = new String[] + { + + // default path + "/usr/bin", + + // manually installed + "/usr/local/bin", + + // mac ports + "/opt/local/bin", + + // opencsw + "/opt/csw/bin" + }; + /** Field description */ private static final Logger logger = LoggerFactory.getLogger(IOUtil.class.getName()); @@ -260,6 +286,144 @@ public class IOUtil } } + /** + * + * + * @param cmd + * + * @return + */ + public static String search(String cmd) + { + return search(DEFAULT_PATH, cmd, DEFAULT_CHECKPARAMETER); + } + + /** + * + * + * @param path + * @param cmd + * + * @return + */ + public static String search(String[] path, String cmd) + { + return search(path, cmd, DEFAULT_CHECKPARAMETER); + } + + /** + * TODO check for windows + * + * + * + * @param path + * @param cmd + * @param checkParameter + * + * @return + */ + public static String search(String[] path, String cmd, String checkParameter) + { + String cmdPath = null; + + try + { + Command command = new SimpleCommand(cmd, checkParameter); + CommandResult result = command.execute(); + + if (result.isSuccessfull()) + { + cmdPath = cmd; + } + } + catch (IOException ex) {} + + if (cmdPath == null) + { + for (String pathPart : path) + { + List extensions = getExecutableSearchExtensions(); + File file = findFileByExtension(pathPart, cmd, extensions); + + if (file != null) + { + cmdPath = file.getAbsolutePath(); + + break; + } + } + } + + if (cmdPath != null) + { + if (logger.isInfoEnabled()) + { + logger.info("found {} at {}", cmd, cmdPath); + } + } + else if (logger.isWarnEnabled()) + { + logger.warn("could not find {}", cmd); + } + + return cmdPath; + } + + /** + * Method description + * + * + * @param parentPath + * @param cmd + * @param potentialExtensions + * + * @return + */ + private static File findFileByExtension(String parentPath, String cmd, + List potentialExtensions) + { + File file = null; + + for (String potentialExtension : potentialExtensions) + { + String fileName = cmd.concat(potentialExtension); + File potentialFile = new File(parentPath, fileName); + + if (potentialFile.exists()) + { + file = potentialFile; + + break; + } + } + + return file; + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Returns a list of file extensions to use when searching for executables. + * The list is in priority order, with the highest priority first. + * + * @return + */ + private static List getExecutableSearchExtensions() + { + List extensions; + + if (SystemUtil.isWindows()) + { + extensions = Arrays.asList(".exe"); + } + else + { + extensions = Arrays.asList(""); + } + + return extensions; + } + //~--- inner classes -------------------------------------------------------- /** diff --git a/scm-core/src/main/java/sonia/scm/util/RegistryUtil.java b/scm-core/src/main/java/sonia/scm/util/RegistryUtil.java new file mode 100644 index 0000000000..12a6cfccaa --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/util/RegistryUtil.java @@ -0,0 +1,156 @@ +/** + * 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.util; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.io.SimpleCommand; +import sonia.scm.io.SimpleCommandResult; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +import java.util.Scanner; + +/** + * + * @author Sebastian Sdorra + */ +public class RegistryUtil +{ + + /** the logger for RegistryUtil */ + private static final Logger logger = + LoggerFactory.getLogger(RegistryUtil.class); + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param key + * + * @return + */ + public static String getRegistryValue(String key) + { + return getRegistryValue(key, null, null); + } + + /** + * Method description + * + * + * @param key + * @param defaultValue + * + * @return + */ + public static String getRegistryValue(String key, String defaultValue) + { + return getRegistryValue(key, null, defaultValue); + } + + /** + * Method description + * + * + * @param key + * @param subKey + * @param defaultValue + * + * @return + */ + public static String getRegistryValue(String key, String subKey, + String defaultValue) + { + String value = defaultValue; + SimpleCommand command = null; + + if (subKey != null) + { + command = new SimpleCommand("reg", "query", key, "/v", subKey); + } + else + { + command = new SimpleCommand("reg", "query", key); + } + + try + { + SimpleCommandResult result = command.execute(); + + if (result.isSuccessfull()) + { + String output = result.getOutput(); + Scanner scanner = new Scanner(output); + + while (scanner.hasNextLine()) + { + String line = scanner.nextLine(); + int index = line.indexOf("REG_SZ"); + + if (index > 0) + { + value = line.substring(index + "REG_SZ".length()).trim(); + + if (value.startsWith("\"")) + { + value = value.substring(1); + value = value.substring(0, value.indexOf("\"")); + } + + if (logger.isDebugEnabled()) + { + logger.debug("registry value {} at {}", value, key); + } + + break; + } + } + } + } + catch (IOException ex) + { + logger.error(ex.getMessage(), ex); + } + + return value; + } +} 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 d58528bfc5..e9e7852da5 100644 --- a/scm-core/src/main/java/sonia/scm/util/Util.java +++ b/scm-core/src/main/java/sonia/scm/util/Util.java @@ -54,6 +54,36 @@ public class Util //~--- methods -------------------------------------------------------------- + /** + * Method description + * + * + * @param object + * @param otherObject + * @param + * + * @return + */ + public static int compare(T object, T otherObject) + { + int result = 0; + + if ((object != null) && (otherObject != null)) + { + result = object.compareTo(otherObject); + } + else if ((object == null) && (otherObject != null)) + { + result = 1; + } + else if ((object != null) && (otherObject == null)) + { + result = -1; + } + + return result; + } + /** * Method description * @@ -142,6 +172,33 @@ public class Util return parseDate(dateString, null); } + /** + * Method description + * + * + * @param byteValue + * + * @return + */ + public static String toString(byte[] byteValue) + { + StringBuilder buffer = new StringBuilder(); + + for (int i = 0; i < byteValue.length; i++) + { + int x = byteValue[i] & 0xff; + + if (x < 16) + { + buffer.append('0'); + } + + buffer.append(Integer.toString(x, 16)); + } + + return buffer.toString(); + } + //~--- get methods ---------------------------------------------------------- /** @@ -183,6 +240,22 @@ public class Util return (array == null) || (array.length == 0); } + /** + * Method description + * + * + * @param object + * @param other + * + * @return + */ + public static boolean isEquals(Object object, Object other) + { + return (object == null) + ? other == null + : object.equals(other); + } + /** * Method description * @@ -222,32 +295,17 @@ public class Util return (array != null) && (array.length > 0); } - //~--- methods -------------------------------------------------------------- - /** * Method description * * - * @param byteValue + * @param object + * @param other * * @return */ - public static String toString(byte[] byteValue) + public static boolean isNotEquals(Object object, Object other) { - StringBuilder buffer = new StringBuilder(); - - for (int i = 0; i < byteValue.length; i++) - { - int x = byteValue[i] & 0xff; - - if (x < 16) - { - buffer.append('0'); - } - - buffer.append(Integer.toString(x, 16)); - } - - return buffer.toString(); + return !isEquals(object, other); } } diff --git a/scm-core/src/main/java/sonia/scm/web/security/AuthenticationResult.java b/scm-core/src/main/java/sonia/scm/web/security/AuthenticationResult.java index 73bdf3a698..401872a8f1 100644 --- a/scm-core/src/main/java/sonia/scm/web/security/AuthenticationResult.java +++ b/scm-core/src/main/java/sonia/scm/web/security/AuthenticationResult.java @@ -186,8 +186,35 @@ public class AuthenticationResult return user; } + /** + * Method description + * + * + * @return + */ + public boolean isCacheable() + { + return cacheable; + } + + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param cacheable + */ + public void setCacheable(boolean cacheable) + { + this.cacheable = cacheable; + } + //~--- fields --------------------------------------------------------------- + /** Field description */ + private boolean cacheable = true; + /** Field description */ private Collection groups; diff --git a/scm-core/src/test/java/sonia/scm/resources/ResourceHandlerComparatorTest.java b/scm-core/src/test/java/sonia/scm/resources/ResourceHandlerComparatorTest.java new file mode 100644 index 0000000000..8f3eb8901a --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/resources/ResourceHandlerComparatorTest.java @@ -0,0 +1,141 @@ +/** + * 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.resources; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.junit.Test; + +import static org.junit.Assert.*; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.InputStream; + +import java.util.Arrays; + +/** + * + * @author Sebastian Sdorra + */ +public class ResourceHandlerComparatorTest +{ + + /** + * Method description + * + */ + @Test + public void testCompare() + { + ResourceHandler[] handlers = new ResourceHandler[4]; + + handlers[0] = new DummyResourceHandler("xyz"); + handlers[1] = new DummyResourceHandler("abc"); + handlers[2] = new DummyResourceHandler(null); + handlers[3] = new DummyResourceHandler("mno"); + Arrays.sort(handlers, new ResourceHandlerComparator()); + assertEquals("abc", handlers[0].getName()); + assertEquals("mno", handlers[1].getName()); + assertEquals("xyz", handlers[2].getName()); + assertEquals(null, handlers[3].getName()); + } + + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here..., 2011-01-18 + * @author Sebastian Sdorra + */ + private static class DummyResourceHandler implements ResourceHandler + { + + /** + * Constructs ... + * + * + * @param name + */ + public DummyResourceHandler(String name) + { + this.name = name; + } + + //~--- get methods -------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + public String getName() + { + return name; + } + + /** + * Method description + * + * + * @return + */ + @Override + public InputStream getResource() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + /** + * Method description + * + * + * @return + */ + @Override + public ResourceType getType() + { + throw new UnsupportedOperationException("Not supported yet."); + } + + //~--- fields ------------------------------------------------------------- + + /** Field description */ + private String name; + } +} diff --git a/scm-server-api/pom.xml b/scm-server-api/pom.xml index 4c1b2d28d8..17b6b7a5c0 100644 --- a/scm-server-api/pom.xml +++ b/scm-server-api/pom.xml @@ -7,12 +7,12 @@ scm sonia.scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm scm-server-api - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-server-api @@ -20,7 +20,7 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/scm-server-api/src/main/java/sonia/scm/server/ServerApplication.java b/scm-server-api/src/main/java/sonia/scm/server/ServerApplication.java index f0ab3232b1..fb7a5e3ebd 100644 --- a/scm-server-api/src/main/java/sonia/scm/server/ServerApplication.java +++ b/scm-server-api/src/main/java/sonia/scm/server/ServerApplication.java @@ -29,6 +29,8 @@ * */ + + package sonia.scm.server; //~--- non-JDK imports -------------------------------------------------------- @@ -39,6 +41,7 @@ import org.slf4j.LoggerFactory; import sonia.scm.cli.CliException; import sonia.scm.cli.CliParser; import sonia.scm.cli.DefaultCliHelpBuilder; +import sonia.scm.util.IOUtil; import sonia.scm.util.ServiceUtil; //~--- JDK imports ------------------------------------------------------------ @@ -68,10 +71,51 @@ public class ServerApplication /** Field description */ public static final int RETURNCODE_MISSING_SERVER_IMPLEMENTATION = 3; + /** Field description */ + public static final String SERVERCONFIG = "/config.xml"; + /** Field description */ private static final Logger logger = LoggerFactory.getLogger(ServerApplication.class.getName()); + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + private static ServerConfig getServerConfig() + { + ServerConfig config = null; + InputStream input = + ServerApplication.class.getResourceAsStream(SERVERCONFIG); + + if (input != null) + { + try + { + config = JAXB.unmarshal(input, ServerConfig.class); + } + catch (Exception ex) + { + logger.error(ex.getMessage(), ex); + } + finally + { + IOUtil.close(input); + } + } + + if (config == null) + { + config = new ServerConfig(); + } + + return config; + } + //~--- methods -------------------------------------------------------------- /** @@ -97,10 +141,10 @@ public class ServerApplication ApplicationInformation appInfo = JAXB.unmarshal(input, ApplicationInformation.class); - ServerConfig config = new ServerConfig(); + ServerConfig config = getServerConfig(); CliParser parser = new CliParser(); - parser.parse(parser, args); + parser.parse(config, args); if (config.getShowHelp()) { diff --git a/scm-server-jetty/pom.xml b/scm-server-jetty/pom.xml index dacab19675..f5afddbc99 100644 --- a/scm-server-jetty/pom.xml +++ b/scm-server-jetty/pom.xml @@ -7,12 +7,12 @@ scm sonia.scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm scm-server-jetty - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-server-jetty @@ -20,7 +20,7 @@ sonia.scm scm-server-api - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 37da7c65ab..0a685971e0 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -7,12 +7,12 @@ scm sonia.scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm scm-server - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-server pom @@ -21,19 +21,19 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm scm-server-api - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm scm-server-jetty - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 1b7a6f8abd..cb58d9fe39 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -7,12 +7,12 @@ scm sonia.scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm scm-test - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-test @@ -26,7 +26,7 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 018fd570d9..7532bcff81 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -7,13 +7,13 @@ sonia.scm scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm scm-webapp war - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT scm-webapp @@ -28,25 +28,25 @@ sonia.scm scm-core - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-hg-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-svn-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-git-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT @@ -84,15 +84,9 @@ - org.slf4j - slf4j-log4j12 - ${slf4j.version} - - - - log4j - log4j - 1.2.16 + ch.qos.logback + logback-classic + 0.9.27 @@ -131,6 +125,12 @@ org.sonatype.aether aether-connector-wagon ${aether.version} + + + xbean-reflect + org.apache.xbean + + @@ -164,8 +164,14 @@ sonia.scm scm-test - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT test + + + org.slf4j + slf4j-simple + + @@ -226,7 +232,7 @@ 1.9 1.0-beta-7 - 3.0.1 + 3.0.2 @@ -266,7 +272,6 @@ src/main/webapp/index.html ${project.build.directory}/web-compressor/index.html - false @@ -282,37 +287,37 @@ sonia.scm.plugins scm-graph-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.sample scm-sample-auth - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.sample scm-sample-hello - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-activedirectory-auth-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-pam-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.plugins scm-bzr-plugin - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT diff --git a/scm-webapp/src/main/java/sonia/scm/BindingExtensionProcessor.java b/scm-webapp/src/main/java/sonia/scm/BindingExtensionProcessor.java index 05764efb2b..fe9fcc8988 100644 --- a/scm-webapp/src/main/java/sonia/scm/BindingExtensionProcessor.java +++ b/scm-webapp/src/main/java/sonia/scm/BindingExtensionProcessor.java @@ -47,6 +47,7 @@ import sonia.scm.plugin.ext.Extension; import sonia.scm.plugin.ext.ExtensionProcessor; import sonia.scm.repository.RepositoryHandler; import sonia.scm.repository.RepositoryListener; +import sonia.scm.resources.ResourceHandler; import sonia.scm.security.EncryptionHandler; import sonia.scm.user.UserListener; import sonia.scm.web.security.AuthenticationHandler; @@ -97,6 +98,8 @@ public class BindingExtensionProcessor implements ExtensionProcessor Multibinder.newSetBinder(binder, RepositoryHandler.class); Multibinder authenticators = Multibinder.newSetBinder(binder, AuthenticationHandler.class); + Multibinder resourceHandler = + Multibinder.newSetBinder(binder, ResourceHandler.class); authenticators.addBinding().to(XmlAuthenticationHandler.class); @@ -176,6 +179,15 @@ public class BindingExtensionProcessor implements ExtensionProcessor authenticationListeners.add(listener); } + else if (ResourceHandler.class.isAssignableFrom(extensionClass)) + { + if (logger.isInfoEnabled()) + { + logger.info("bind ResourceHandler {}", extensionClass.getName()); + } + + resourceHandler.addBinding().to(extensionClass); + } else { if (logger.isInfoEnabled()) diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index 68e991c099..8b8845ae77 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -116,6 +116,10 @@ public class ScmServletModule extends ServletModule /** Field description */ public static final String PATTERN_STYLESHEET = "*.css"; + /** Field description */ + public static final String RESOURCE_REGEX = + "^/(?:resources|api|plugins|index)[\\./].*(?:html|\\.css|\\.js|\\.xml|\\.json|\\.txt)"; + /** Field description */ public static final String REST_PACKAGE = "sonia.scm.api.rest"; @@ -192,7 +196,7 @@ public class ScmServletModule extends ServletModule * PATTERN_STATIC_RESOURCES).through(StaticResourceFilter.class); */ filter(PATTERN_ALL).through(SSLFilter.class); - filter(PATTERN_PAGE, PATTERN_COMPRESSABLE).through(GZipFilter.class); + filterRegex(RESOURCE_REGEX).through(GZipFilter.class); filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(SecurityFilter.class); // debug servlet diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java index 52e9c71ad7..3fc33f20c7 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java @@ -41,6 +41,7 @@ import com.google.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.SCMContext; import sonia.scm.ScmState; import sonia.scm.Type; import sonia.scm.repository.RepositoryManager; @@ -78,6 +79,40 @@ public class AuthenticationResource //~--- methods -------------------------------------------------------------- + /** + * Method description + * + * + * @param request + * @param response + * @param username + * @param password + * + * @return + */ + @POST + @Path("login") + public ScmState authenticate(@Context HttpServletRequest request, + @Context HttpServletResponse response, + @FormParam("username") String username, + @FormParam("password") String password) + { + ScmState state = null; + User user = securityContext.authenticate(request, response, username, + password); + + if ((user != null) &&!SCMContext.USER_ANONYMOUS.equals(user.getName())) + { + state = new ScmState(securityContext, repositoryManger.getTypes()); + } + else + { + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + } + + return state; + } + /** * Method description * @@ -112,40 +147,6 @@ public class AuthenticationResource //~--- get methods ---------------------------------------------------------- - /** - * Method description - * - * - * @param request - * @param response - * @param username - * @param password - * - * @return - */ - @POST - @Path("login") - public ScmState getState(@Context HttpServletRequest request, - @Context HttpServletResponse response, - @FormParam("username") String username, - @FormParam("password") String password) - { - ScmState state = null; - User user = securityContext.authenticate(request, response, username, - password); - - if (user != null) - { - state = new ScmState(securityContext, repositoryManger.getTypes()); - } - else - { - throw new WebApplicationException(Response.Status.UNAUTHORIZED); - } - - return state; - } - /** * Method description * diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/ScriptResourceServlet.java b/scm-webapp/src/main/java/sonia/scm/plugin/ScriptResourceServlet.java index b3c7bc5ee1..7f8d31fc1e 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/ScriptResourceServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/ScriptResourceServlet.java @@ -39,6 +39,9 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import sonia.scm.boot.BootstrapUtil; +import sonia.scm.resources.ResourceHandler; +import sonia.scm.resources.ResourceHandlerComparator; +import sonia.scm.resources.ResourceType; import sonia.scm.util.IOUtil; import sonia.scm.util.Util; @@ -48,7 +51,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -75,11 +81,14 @@ public class ScriptResourceServlet extends AbstractResourceServlet * * * @param pluginLoader + * @param resourceHandlers */ @Inject - public ScriptResourceServlet(PluginLoader pluginLoader) + public ScriptResourceServlet(PluginLoader pluginLoader, + Set resourceHandlers) { this.pluginLoader = pluginLoader; + this.resourceHandlers = resourceHandlers; } //~--- methods -------------------------------------------------------------- @@ -110,6 +119,22 @@ public class ScriptResourceServlet extends AbstractResourceServlet appendResource(stream, resource); } } + + if (Util.isNotEmpty(resourceHandlers)) + { + List handlerList = + new ArrayList(resourceHandlers); + + Collections.sort(handlerList, new ResourceHandlerComparator()); + + for (ResourceHandler resourceHandler : resourceHandlers) + { + if (resourceHandler.getType() == ResourceType.SCRIPT) + { + appendResource(resourceHandler.getResource(), stream); + } + } + } } //~--- get methods ---------------------------------------------------------- @@ -143,6 +168,21 @@ public class ScriptResourceServlet extends AbstractResourceServlet { InputStream input = getResourceAsStream(script); + appendResource(input, stream); + } + + /** + * Method description + * + * + * @param input + * @param stream + * + * @throws IOException + */ + private void appendResource(InputStream input, OutputStream stream) + throws IOException + { if (input != null) { try @@ -239,4 +279,7 @@ public class ScriptResourceServlet extends AbstractResourceServlet /** Field description */ private PluginLoader pluginLoader; + + /** Field description */ + private Set resourceHandlers; } diff --git a/scm-webapp/src/main/java/sonia/scm/repository/xml/XmlRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/xml/XmlRepositoryManager.java index 39922bd722..565d8d7c00 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/xml/XmlRepositoryManager.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/xml/XmlRepositoryManager.java @@ -380,7 +380,7 @@ public class XmlRepositoryManager extends AbstractRepositoryManager for (Repository repository : repositoryDB.values()) { - if (isReader(repository)) + if (handlerMap.containsKey(repository.getType()) && isReader(repository)) { repositories.add(repository.clone()); } diff --git a/scm-webapp/src/main/java/sonia/scm/user/xml/XmlUserManager.java b/scm-webapp/src/main/java/sonia/scm/user/xml/XmlUserManager.java index 9851be964f..2ff8301f11 100644 --- a/scm-webapp/src/main/java/sonia/scm/user/xml/XmlUserManager.java +++ b/scm-webapp/src/main/java/sonia/scm/user/xml/XmlUserManager.java @@ -273,6 +273,7 @@ public class XmlUserManager extends AbstractUserManager if (userDB.contains(name)) { AssertUtil.assertIsValid(user); + user.setLastModified(System.currentTimeMillis()); synchronized (XmlUserManager.class) { diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java index d53c04eec7..d78066c35a 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/BasicSecurityContext.java @@ -124,21 +124,13 @@ public class BasicSecurityContext implements WebSecurityContext try { - user.setLastLogin(System.currentTimeMillis()); - User dbUser = userManager.get(username); - if (dbUser != null) + if ((dbUser != null) && dbUser.copyProperties(user, false)) { - - // update properties - dbUser.setDisplayName(user.getDisplayName()); - dbUser.setLastLogin(user.getLastLogin()); - dbUser.setMail(user.getMail()); - dbUser.setType(user.getType()); userManager.modify(dbUser); } - else + else if (dbUser == null) { userManager.create(user); } diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java b/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java index d814b1f5d3..fb45c9cef0 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/ChainAuthenticatonManager.java @@ -42,6 +42,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.SCMContextProvider; +import sonia.scm.cache.CacheManager; +import sonia.scm.cache.SimpleCache; +import sonia.scm.security.EncryptionHandler; import sonia.scm.user.User; import sonia.scm.util.AssertUtil; import sonia.scm.util.IOUtil; @@ -63,6 +66,9 @@ import javax.servlet.http.HttpServletResponse; public class ChainAuthenticatonManager extends AbstractAuthenticationManager { + /** Field description */ + public static final String CACHE_NAME = "sonia.cache.auth"; + /** the logger for ChainAuthenticatonManager */ private static final Logger logger = LoggerFactory.getLogger(ChainAuthenticatonManager.class); @@ -74,13 +80,20 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager * * * @param authenticationHandlerSet + * @param encryptionHandler + * @param cacheManager */ @Inject public ChainAuthenticatonManager( - Set authenticationHandlerSet) + Set authenticationHandlerSet, + EncryptionHandler encryptionHandler, CacheManager cacheManager) { AssertUtil.assertIsNotEmpty(authenticationHandlerSet); + AssertUtil.assertIsNotNull(cacheManager); this.authenticationHandlerSet = authenticationHandlerSet; + this.encryptionHandler = encryptionHandler; + this.cache = cacheManager.getSimpleCache(String.class, + AuthenticationCacheValue.class, CACHE_NAME); } //~--- methods -------------------------------------------------------------- @@ -99,6 +112,74 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager @Override public AuthenticationResult authenticate(HttpServletRequest request, HttpServletResponse response, String username, String password) + { + AssertUtil.assertIsNotEmpty(username); + AssertUtil.assertIsNotEmpty(password); + + String encryptedPassword = encryptionHandler.encrypt(password); + AuthenticationResult ar = getCached(username, encryptedPassword); + + if (ar == null) + { + ar = doAuthentication(request, response, username, password); + + if ((ar != null) && ar.isCacheable()) + { + cache.put(username, + new AuthenticationCacheValue(ar, encryptedPassword)); + } + } + else if (logger.isDebugEnabled()) + { + logger.debug("authenticate {} via cache", username); + } + + return ar; + } + + /** + * Method description + * + * + * @throws IOException + */ + @Override + public void close() throws IOException + { + for (AuthenticationHandler authenticator : authenticationHandlerSet) + { + IOUtil.close(authenticator); + } + } + + /** + * Method description + * + * + * @param context + */ + @Override + public void init(SCMContextProvider context) + { + for (AuthenticationHandler authenticator : authenticationHandlerSet) + { + authenticator.init(context); + } + } + + /** + * Method description + * + * + * @param request + * @param response + * @param username + * @param password + * + * @return + */ + private AuthenticationResult doAuthentication(HttpServletRequest request, + HttpServletResponse response, String username, String password) { AuthenticationResult ar = null; @@ -142,38 +223,80 @@ public class ChainAuthenticatonManager extends AbstractAuthenticationManager return ar; } - /** - * Method description - * - * - * @throws IOException - */ - @Override - public void close() throws IOException - { - for (AuthenticationHandler authenticator : authenticationHandlerSet) - { - IOUtil.close(authenticator); - } - } + //~--- get methods ---------------------------------------------------------- /** * Method description * * - * @param context + * @param username + * @param encryptedPassword + * + * @return */ - @Override - public void init(SCMContextProvider context) + private AuthenticationResult getCached(String username, + String encryptedPassword) { - for (AuthenticationHandler authenticator : authenticationHandlerSet) + AuthenticationResult result = null; + AuthenticationCacheValue value = cache.get(username); + + if (value != null) { - authenticator.init(context); + String cachedPassword = value.password; + + if (cachedPassword.equals(encryptedPassword)) + { + result = value.authenticationResult; + } } + + return result; } + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here..., 2011-01-15 + * @author Sebastian Sdorra + */ + private static class AuthenticationCacheValue + { + + /** + * Constructs ... + * + * + * @param authenticationResult + * @param password + */ + public AuthenticationCacheValue(AuthenticationResult authenticationResult, + String password) + { + this.authenticationResult = authenticationResult; + this.password = password; + } + + //~--- fields ------------------------------------------------------------- + + /** Field description */ + private AuthenticationResult authenticationResult; + + /** Field description */ + private String password; + } + + //~--- fields --------------------------------------------------------------- /** Field description */ private Set authenticationHandlerSet; + + /** Field description */ + private SimpleCache cache; + + /** Field description */ + private EncryptionHandler encryptionHandler; } diff --git a/scm-webapp/src/main/resources/config/ehcache.xml b/scm-webapp/src/main/resources/config/ehcache.xml index 0bbcb6f339..f47b41bb79 100644 --- a/scm-webapp/src/main/resources/config/ehcache.xml +++ b/scm-webapp/src/main/resources/config/ehcache.xml @@ -97,6 +97,16 @@ diskExpiryThreadIntervalSeconds="2400" /> + + + + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/scm-webapp/src/main/webapp/index.html b/scm-webapp/src/main/webapp/index.html index 33a45f3050..b1ac5aeb23 100644 --- a/scm-webapp/src/main/webapp/index.html +++ b/scm-webapp/src/main/webapp/index.html @@ -49,6 +49,7 @@ + diff --git a/scm-webapp/src/main/webapp/resources/extjs/util/CheckColumn.js b/scm-webapp/src/main/webapp/resources/extjs/util/CheckColumn.js new file mode 100644 index 0000000000..5dd143ea96 --- /dev/null +++ b/scm-webapp/src/main/webapp/resources/extjs/util/CheckColumn.js @@ -0,0 +1,71 @@ +/*! + * Ext JS Library 3.3.1 + * Copyright(c) 2006-2010 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns('Ext.ux.grid'); + +/** + * @class Ext.ux.grid.CheckColumn + * @extends Ext.grid.Column + *

A Column subclass which renders a checkbox in each column cell which toggles the truthiness of the associated data field on click.

+ *

Note. As of ExtJS 3.3 this no longer has to be configured as a plugin of the GridPanel.

+ *

Example usage:

+ *

+var cm = new Ext.grid.ColumnModel([{
+       header: 'Foo',
+       ...
+    },{
+       xtype: 'checkcolumn',
+       header: 'Indoor?',
+       dataIndex: 'indoor',
+       width: 55
+    }
+]);
+
+// create the grid
+var grid = new Ext.grid.EditorGridPanel({
+    ...
+    colModel: cm,
+    ...
+});
+ * 
+ * In addition to toggling a Boolean value within the record data, this + * class toggles a css class between 'x-grid3-check-col' and + * 'x-grid3-check-col-on' to alter the background image used for + * a column. + */ +Ext.ux.grid.CheckColumn = Ext.extend(Ext.grid.Column, { + + /** + * @private + * Process and refire events routed from the GridView's processEvent method. + */ + processEvent : function(name, e, grid, rowIndex, colIndex){ + if (name == 'mousedown') { + var record = grid.store.getAt(rowIndex); + record.set(this.dataIndex, !record.data[this.dataIndex]); + return false; // Cancel row selection. + } else { + return Ext.grid.ActionColumn.superclass.processEvent.apply(this, arguments); + } + }, + + renderer : function(v, p, record){ + p.css += ' x-grid3-check-col-td'; + return String.format('
 
', v ? '-on' : ''); + }, + + // Deprecate use as a plugin. Remove in 4.0 + init: Ext.emptyFn +}); + +// register ptype. Deprecate. Remove in 4.0 +Ext.preg('checkcolumn', Ext.ux.grid.CheckColumn); + +// backwards compat. Remove in 4.0 +Ext.grid.CheckColumn = Ext.ux.grid.CheckColumn; + +// register Column xtype +Ext.grid.Column.types.checkcolumn = Ext.ux.grid.CheckColumn; \ No newline at end of file diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.group.js b/scm-webapp/src/main/webapp/resources/js/sonia.group.js index 0ecbde4a23..168b38b64a 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.group.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.group.js @@ -237,6 +237,10 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ item.members = members; }, + clearModifications: function(){ + Ext.getCmp('memberGrid').getStore().commitChanges(); + }, + update: function(group){ if ( debug ){ console.debug( 'update group ' + group.name ); @@ -258,7 +262,7 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ if ( debug ){ console.debug('update success'); } - // this.clearModifications(); + this.clearModifications(); clearTimeout(tid); el.unmask(); this.execCallback(this.onUpdate, group); diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.repository.js b/scm-webapp/src/main/webapp/resources/js/sonia.repository.js index 2cf6051876..ea7e46e9b9 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.repository.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.repository.js @@ -226,7 +226,11 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ this.permissionStore = new Ext.data.JsonStore({ root: 'permissions', - fields: [ 'name', 'type', 'groupPermission' ], + fields: [ + {name: 'name'}, + {name: 'type'}, + {name: 'groupPermission', type: 'boolean'} + ], sortInfo: { field: 'name' } @@ -237,6 +241,12 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ sortable: true }, columns: [{ + id: 'groupPermission', + xtype: 'checkcolumn', + header: 'Group Permission', + dataIndex: 'groupPermission', + width: 40 + },{ id: 'name', header: 'Name', dataIndex: 'name', @@ -264,12 +274,6 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ ] }) }) - },{ - id: 'groupPermission', - header: 'Group', - dataIndex: 'groupPermission', - width: 60, - editor: new Ext.form.Checkbox() }] }); @@ -323,6 +327,7 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ xtype: 'editorgrid', title: 'Permissions', clicksToEdit: 1, + autoExpandColumn: 'name', frame: true, width: '100%', autoHeight: true, @@ -374,7 +379,7 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{ }, clearModifications: function(){ - // todo + Ext.getCmp('permissionGrid').getStore().commitChanges(); }, update: function(item){ diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js index b443c7cf77..93bb1ce07b 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js @@ -92,13 +92,16 @@ Ext.onReady(function(){ // adds a tab to main TabPanel function addTabPanel(id, xtype, title){ - mainTabPanel.add({ - id: id, - xtype: xtype, - title: title, - closable: true, - autoScroll: true - }); + var tab = mainTabPanel.findById( id ); + if ( tab == null ){ + mainTabPanel.add({ + id: id, + xtype: xtype, + title: title, + closable: true, + autoScroll: true + }); + } mainTabPanel.setActiveTab(id); } diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.user.js b/scm-webapp/src/main/webapp/resources/js/sonia.user.js index 7b399ea9ab..c60a7d788b 100644 --- a/scm-webapp/src/main/webapp/resources/js/sonia.user.js +++ b/scm-webapp/src/main/webapp/resources/js/sonia.user.js @@ -59,7 +59,7 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, { var userStore = new Sonia.rest.JsonStore({ url: restUrl + 'users.json', - fields: [ 'name', 'displayName', 'mail', 'admin', 'creationDate', 'lastLogin', 'type'], + fields: [ 'name', 'displayName', 'mail', 'admin', 'creationDate', 'lastModified', 'type'], sortInfo: { field: 'name' } @@ -77,7 +77,7 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, { {id: 'mail', header: 'Mail', dataIndex: 'mail', renderer: this.renderMailto, width: 200}, {id: 'admin', header: 'Admin', dataIndex: 'admin', renderer: this.renderCheckbox, width: 50}, {id: 'creationDate', header: 'Creation date', dataIndex: 'creationDate'}, - {id: 'lastLogin', header: 'Last login', dataIndex: 'lastLogin'}, + {id: 'lastLogin', header: 'Last modified', dataIndex: 'lastModified'}, {id: 'type', header: 'Type', dataIndex: 'type', width: 80} ] }); diff --git a/scm-webapp/src/test/java/sonia/scm/web/security/ChainAuthenticationManagerTest.java b/scm-webapp/src/test/java/sonia/scm/web/security/ChainAuthenticationManagerTest.java index 27810c5ad1..d1b00e739c 100644 --- a/scm-webapp/src/test/java/sonia/scm/web/security/ChainAuthenticationManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/web/security/ChainAuthenticationManagerTest.java @@ -39,6 +39,9 @@ import org.junit.Test; import sonia.scm.AbstractTestBase; import sonia.scm.SCMContextProvider; +import sonia.scm.cache.CacheManager; +import sonia.scm.cache.EhCacheManager; +import sonia.scm.security.MessageDigestEncryptionHandler; import sonia.scm.user.User; import sonia.scm.user.UserTestData; import sonia.scm.util.MockUtil; @@ -69,8 +72,8 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase @Test public void testAuthenticateFailed() { - AuthenticationResult result = manager.authenticate(request, response, trillian.getName(), - "trillian"); + AuthenticationResult result = manager.authenticate(request, response, + trillian.getName(), "trillian"); assertNull(result); } @@ -82,7 +85,8 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase @Test public void testAuthenticateNotFound() { - AuthenticationResult result = manager.authenticate(request, response, "dent", "trillian"); + AuthenticationResult result = manager.authenticate(request, response, + "dent", "trillian"); assertNull(result); } @@ -94,14 +98,14 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase @Test public void testAuthenticateSuccess() { - AuthenticationResult result = manager.authenticate(request, response, trillian.getName(), - "trillian123"); + AuthenticationResult result = manager.authenticate(request, response, + trillian.getName(), "trillian123"); assertNotNull(result); assertUserEquals(trillian, result.getUser()); assertEquals("trilliansType", result.getUser().getType()); result = manager.authenticate(request, response, perfect.getName(), - "perfect123"); + "perfect123"); assertNotNull(perfect); assertUserEquals(perfect, result.getUser()); assertEquals("perfectsType", result.getUser().getType()); @@ -126,7 +130,8 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase trillian.setPassword("trillian123"); handlerSet.add(new SingleUserAuthenticaionHandler("trilliansType", trillian)); - manager = new ChainAuthenticatonManager(handlerSet); + manager = new ChainAuthenticatonManager(handlerSet, + new MessageDigestEncryptionHandler(), cacheManager); manager.init(contextProvider); request = MockUtil.getHttpServletRequest(); response = MockUtil.getHttpServletResponse(); @@ -266,6 +271,9 @@ public class ChainAuthenticationManagerTest extends AbstractTestBase //~--- fields --------------------------------------------------------------- + /** Field description */ + private CacheManager cacheManager = new EhCacheManager(); + /** Field description */ private ChainAuthenticatonManager manager; diff --git a/third-party/pom.xml b/third-party/pom.xml index 9e07f56236..f72dd7eb27 100644 --- a/third-party/pom.xml +++ b/third-party/pom.xml @@ -6,13 +6,13 @@ sonia.scm scm - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.third-party sonia.scm.third-party pom - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT third-party diff --git a/third-party/shared-libs/pom.xml b/third-party/shared-libs/pom.xml index 1a6e563b4d..120d7b2924 100644 --- a/third-party/shared-libs/pom.xml +++ b/third-party/shared-libs/pom.xml @@ -6,13 +6,13 @@ sonia.scm.third-party sonia.scm.third-party - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT sonia.scm.third-party shared-libs pom - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT shared-libs diff --git a/third-party/svnkit-dav/pom.xml b/third-party/svnkit-dav/pom.xml index ff007168f1..0867adf1b4 100644 --- a/third-party/svnkit-dav/pom.xml +++ b/third-party/svnkit-dav/pom.xml @@ -6,13 +6,13 @@ sonia.scm.third-party sonia.scm.third-party - 1.0-M6-SNAPSHOT + 1.0-M7-SNAPSHOT org.tmatesoft.svnkit svnkit-dav jar - 1.3.4 + 1.3.5.1 svnkit-dav @@ -21,14 +21,19 @@ javax.servlet servlet-api ${servlet.version} + provided
org.tmatesoft.svnkit svnkit - 1.3.4 + ${svnkit.version}
- \ No newline at end of file + + 1.3.5 + + + diff --git a/third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVRepositoryManager.java b/third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVRepositoryManager.java index 5de520f5cb..e02221603d 100644 --- a/third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVRepositoryManager.java +++ b/third-party/svnkit-dav/src/main/java/org/tmatesoft/svn/core/internal/server/dav/DAVRepositoryManager.java @@ -182,6 +182,7 @@ public class DAVRepositoryManager { String uri = DAVPathUtil.addLeadingSlash(url.getURIEncodedPath()); if (uri.startsWith(getResourceContext())) { uri = uri.substring(getResourceContext().length()); + uri = DAVPathUtil.addLeadingSlash(uri); } else { SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_DAV_REQUEST_FAILED, "Invalid URL ''{0}'' requested", url.toString()), SVNLogType.NETWORK); @@ -291,7 +292,7 @@ public class DAVRepositoryManager { } requestContext = SVNPathUtil.append(requestContext, servletPath); } - return SVNEncodingUtil.uriEncode(requestContext); + return encodeRequestContext(requestContext); } String reposName = DAVPathUtil.head(pathInfo); @@ -301,9 +302,13 @@ public class DAVRepositoryManager { } String pathToRepos = SVNPathUtil.append(requestContext, servletPath); requestContext = SVNPathUtil.append(pathToRepos, reposName); - return SVNEncodingUtil.uriEncode(requestContext); + return encodeRequestContext(requestContext); } requestContext = DAVPathUtil.append(requestContext, reposName); - return SVNEncodingUtil.uriEncode(requestContext); + return encodeRequestContext(requestContext); + } + + private String encodeRequestContext(String requestContext){ + return SVNEncodingUtil.uriEncode( DAVPathUtil.addLeadingSlash(requestContext) ); } }