Backed out changeset 5d23ff274a2f

This commit is contained in:
René Pfeuffer
2018-06-25 11:52:36 +02:00
parent e826b833cc
commit 83d6ab8e9c
48 changed files with 878 additions and 623 deletions

291
pom.xml
View File

@@ -6,7 +6,7 @@
<groupId>sonia.scm</groupId> <groupId>sonia.scm</groupId>
<artifactId>scm</artifactId> <artifactId>scm</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>2.0.0-SNAPSHOT</version> <version>1.61-SNAPSHOT</version>
<description> <description>
The easiest way to share your Git, Mercurial The easiest way to share your Git, Mercurial
and Subversion repositories over http. and Subversion repositories over http.
@@ -59,20 +59,18 @@
<url>https://scm-manager.ci.cloudbees.com/</url> <url>https://scm-manager.ci.cloudbees.com/</url>
</ciManagement> </ciManagement>
<prerequisites>
<maven>3.1.0</maven>
</prerequisites>
<modules> <modules>
<module>scm-annotations</module>
<module>scm-annotation-processor</module>
<module>scm-core</module> <module>scm-core</module>
<module>scm-test</module> <module>scm-test</module>
<module>maven</module>
<module>scm-plugins</module> <module>scm-plugins</module>
<module>scm-samples</module>
<module>scm-dao-xml</module> <module>scm-dao-xml</module>
<module>scm-webapp</module> <module>scm-webapp</module>
<module>scm-server</module> <module>scm-server</module>
<module>scm-plugin-backend</module>
<module>scm-clients</module> <module>scm-clients</module>
<module>support</module>
</modules> </modules>
<repositories> <repositories>
@@ -83,15 +81,6 @@
<url>http://maven.scm-manager.org/nexus/content/groups/public</url> <url>http://maven.scm-manager.org/nexus/content/groups/public</url>
</repository> </repository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</snapshots>
</repository>
</repositories> </repositories>
<pluginRepositories> <pluginRepositories>
@@ -145,46 +134,14 @@
<build> <build>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<executions>
<execution>
<id>enforce-java</id>
<phase>compile</phase>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<!--
enforce minimum 1.8.0-101 to accept Lets Encrypt certificates
-->
<requireJavaVersion>
<version>[1.8.0-101,)</version>
</requireJavaVersion>
<!--
enforce minimum maven 3.1 for the smp plugin
-->
<requireMavenVersion>
<version>[3.1,)</version>
</requireMavenVersion>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId> <artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.15</version> <version>1.16</version>
<configuration> <configuration>
<signature> <signature>
<groupId>org.codehaus.mojo.signature</groupId> <groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java18</artifactId> <artifactId>java17</artifactId>
<version>1.0</version> <version>1.0</version>
</signature> </signature>
</configuration> </configuration>
@@ -200,21 +157,49 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-enforcer-plugin</artifactId>
<version>3.5.1</version> <version>3.0.0-M1</version>
<executions>
<execution>
<id>enforce-java</id>
<phase>compile</phase>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<enforceBytecodeVersion>
<maxJdkVersion>1.7</maxJdkVersion>
<ignoreClasses>
<!--
ignore java 9 module info classes
because jaxb is compiled with java 7 expect of module-info, which is compiled with java 9
-->
<ignoreClass>module-info</ignoreClass>
</ignoreClasses>
</enforceBytecodeVersion>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>extra-enforcer-rules</artifactId>
<version>1.0-beta-7</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration> <configuration>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
<source>${project.build.javaLevel}</source> <source>${project.build.javaLevel}</source>
<target>${project.build.javaLevel}</target> <target>${project.build.javaLevel}</target>
<testSource>${project.test.javaLevel}</testSource>
<testTarget>${project.test.javaLevel}</testTarget>
<encoding>${project.build.sourceEncoding}</encoding> <encoding>${project.build.sourceEncoding}</encoding>
<!--
suppress compiler warning about bootclasspath with older source
see https://blogs.oracle.com/darcy/entry/bootclasspath_older_source
-->
<compilerArgument>-Xlint:unchecked,-options</compilerArgument>
</configuration> </configuration>
</plugin> </plugin>
@@ -259,7 +244,7 @@
<author>true</author> <author>true</author>
<keywords>true</keywords> <keywords>true</keywords>
<links> <links>
<link>http://download.oracle.com/javase/8/docs/api/</link> <link>http://download.oracle.com/javase/7/docs/api/</link>
<link>http://download.oracle.com/docs/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/</link> <link>http://download.oracle.com/docs/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/</link>
<link>http://jersey.java.net/nonav/apidocs/${jersey.version}/jersey/</link> <link>http://jersey.java.net/nonav/apidocs/${jersey.version}/jersey/</link>
<link>https://google.github.io/guice/api-docs/${guice.version}/javadoc</link> <link>https://google.github.io/guice/api-docs/${guice.version}/javadoc</link>
@@ -317,36 +302,20 @@
<version>2.6</version> <version>2.6</version>
</plugin> </plugin>
<!-- code coverage -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.7.201606060606</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- reporting --> <!-- reporting -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId> <artifactId>maven-site-plugin</artifactId>
<version>3.2</version> <version>3.7</version>
<configuration> </plugin>
<reportPlugins>
</plugins>
</build>
<reporting>
<plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@@ -377,19 +346,13 @@
<artifactId>maven-pmd-plugin</artifactId> <artifactId>maven-pmd-plugin</artifactId>
<version>2.7.1</version> <version>2.7.1</version>
<configuration> <configuration>
<linkXref>true</linkXref>
<sourceEncoding>${project.build.sourceEncoding}</sourceEncoding> <sourceEncoding>${project.build.sourceEncoding}</sourceEncoding>
<targetJdk>${project.build.javaLevel}</targetJdk> <targetJdk>${project.build.javaLevel}</targetJdk>
</configuration> </configuration>
</plugin> </plugin>
</reportPlugins>
</configuration>
</plugin>
</plugins> </plugins>
</reporting>
</build>
<profiles> <profiles>
@@ -434,18 +397,9 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>2.8.1</version> <version>3.0.0</version>
<configuration> <configuration>
<doclet>org.jboss.apiviz.APIviz</doclet> <failOnError>false</failOnError>
<docletArtifact>
<groupId>org.jboss.apiviz</groupId>
<artifactId>apiviz</artifactId>
<version>1.3.2.GA</version>
</docletArtifact>
<additionalparam>
-sourceclasspath ${project.build.outputDirectory}
-nopackagediagram
</additionalparam>
</configuration> </configuration>
</plugin> </plugin>
@@ -456,6 +410,101 @@
</profiles> </profiles>
<dependencyManagement>
<dependencies>
<!-- utils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<!-- http -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<!-- logging -->
<dependency>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- json -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- xml -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</dependencyManagement>
<distributionManagement> <distributionManagement>
<repository> <repository>
@@ -479,37 +528,31 @@
<junit.version>4.12</junit.version> <junit.version>4.12</junit.version>
<!-- logging libraries --> <!-- logging libraries -->
<slf4j.version>1.7.22</slf4j.version> <slf4j.version>1.7.25</slf4j.version>
<logback.version>1.2.3</logback.version> <logback.version>1.2.3</logback.version>
<servlet.version>3.0.1</servlet.version> <servlet.version>2.5</servlet.version>
<jaxrs.version>2.0.1</jaxrs.version> <guice.version>3.0</guice.version>
<guice.version>4.0</guice.version>
<jersey.version>1.19.4</jersey.version> <jersey.version>1.19.4</jersey.version>
<!-- event bus -->
<legman.version>1.2.0</legman.version>
<ehcache.version>2.6.6</ehcache.version> <ehcache.version>2.6.6</ehcache.version>
<freemarker.version>2.3.20</freemarker.version> <freemarker.version>2.3.20</freemarker.version>
<jetty.version>7.6.21.v20160908</jetty.version>
<!-- webserver --> <jetty.maven.version>7.6.16.v20140903</jetty.maven.version>
<jetty.version>9.2.10.v20150310</jetty.version> <jackson.version>1.9.13</jackson.version>
<jetty.maven.version>9.2.10.v20150310</jetty.maven.version> <jaxb.version>2.3.0</jaxb.version>
<!-- security libraries --> <!-- security libraries -->
<ssp.version>1.0.0-SNAPSHOT</ssp.version> <shiro.version>1.3.2</shiro.version>
<shiro.version>1.4.0-RC2</shiro.version>
<!-- repostitory libraries --> <!-- repository libraries -->
<jgit.version>v4.5.2.201704071617-r-scm1</jgit.version> <jgit.version>v4.5.3.201708160445-r-scm1</jgit.version>
<svnkit.version>1.8.15-scm1</svnkit.version> <svnkit.version>1.9.0-scm3</svnkit.version>
<!-- util libraries --> <!-- util libraries -->
<guava.version>16.0.1</guava.version> <guava.version>15.0</guava.version>
<quartz.version>2.2.3</quartz.version> <quartz.version>2.2.3</quartz.version>
<!-- build properties --> <!-- build properties -->
<project.build.javaLevel>1.8</project.build.javaLevel> <project.build.javaLevel>1.7</project.build.javaLevel>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<netbeans.hint.license>SCM-BSD</netbeans.hint.license> <netbeans.hint.license>SCM-BSD</netbeans.hint.license>
<jdk.classifier /> <jdk.classifier />

View File

@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>com.sun.jersey</groupId> <groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId> <artifactId>jersey-client</artifactId>
<version>${jersey-client.version}</version> <version>${jersey.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.sun.jersey.contribs</groupId> <groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId> <artifactId>jersey-multipart</artifactId>
<version>${jersey-client.version}</version> <version>${jersey.version}</version>
</dependency> </dependency>
<!-- test scope --> <!-- test scope -->

View File

@@ -69,9 +69,9 @@
<!-- rest api --> <!-- rest api -->
<dependency> <dependency>
<groupId>javax.ws.rs</groupId> <groupId>com.sun.jersey</groupId>
<artifactId>javax.ws.rs-api</artifactId> <artifactId>jersey-core</artifactId>
<version>${jaxrs.version}</version> <version>${jersey.version}</version>
</dependency> </dependency>
<!-- xml --> <!-- xml -->

View File

@@ -45,6 +45,8 @@ import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.core.util.Base64;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@@ -58,7 +60,6 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
@@ -164,7 +165,7 @@ public class DefaultCipherHandler implements CipherHandler {
String result = null; String result = null;
try { try {
byte[] encodedInput = Base64.getDecoder().decode(value); byte[] encodedInput = Base64.decode(value);
byte[] salt = new byte[SALT_LENGTH]; byte[] salt = new byte[SALT_LENGTH];
byte[] encoded = new byte[encodedInput.length - SALT_LENGTH]; byte[] encoded = new byte[encodedInput.length - SALT_LENGTH];
@@ -221,7 +222,7 @@ public class DefaultCipherHandler implements CipherHandler {
System.arraycopy(salt, 0, result, 0, SALT_LENGTH); System.arraycopy(salt, 0, result, 0, SALT_LENGTH);
System.arraycopy(encodedInput, 0, result, SALT_LENGTH, System.arraycopy(encodedInput, 0, result, SALT_LENGTH,
result.length - SALT_LENGTH); result.length - SALT_LENGTH);
res = new String(Base64.getEncoder().encode(result), ENCODING); res = new String(Base64.encode(result), ENCODING);
} catch (IOException | GeneralSecurityException ex) { } catch (IOException | GeneralSecurityException ex) {
throw new CipherException("could not encode string", ex); throw new CipherException("could not encode string", ex);
} }

View File

@@ -36,7 +36,6 @@ package sonia.scm.web;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.base.Strings;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
@@ -53,21 +52,18 @@ import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryProvider;
import sonia.scm.repository.RepositoryRequestListenerUtil; import sonia.scm.repository.RepositoryRequestListenerUtil;
import sonia.scm.security.CipherUtil;
import sonia.scm.util.AssertUtil; import sonia.scm.util.AssertUtil;
import sonia.scm.util.HttpUtil;
import sonia.scm.web.cgi.CGIExecutor; import sonia.scm.web.cgi.CGIExecutor;
import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.CGIExecutorFactory;
import sonia.scm.web.cgi.EnvList; import sonia.scm.web.cgi.EnvList;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.core.util.Base64;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
@@ -83,17 +79,18 @@ import javax.servlet.http.HttpSession;
public class HgCGIServlet extends HttpServlet public class HgCGIServlet extends HttpServlet
{ {
private static final String ENV_PYTHON_HTTPS_VERIFY = "PYTHONHTTPSVERIFY";
/** Field description */ /** Field description */
public static final String ENV_REPOSITORY_NAME = "REPO_NAME"; public static final String ENV_REPOSITORY_NAME = "REPO_NAME";
/** Field description */ /** Field description */
public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH"; public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH";
/** Field description */ private static final String ENV_HTTP_POST_ARGS = "SCM_HTTP_POST_ARGS";
public static final String ENV_SESSION_PREFIX = "SCM_";
/** Field description */ /** Field description */
private static final String SCM_CREDENTIALS = "SCM_CREDENTIALS"; public static final String ENV_SESSION_PREFIX = "SCM_";
/** Field description */ /** Field description */
private static final long serialVersionUID = -3492811300905099810L; private static final long serialVersionUID = -3492811300905099810L;
@@ -231,7 +228,6 @@ public class HgCGIServlet extends HttpServlet
* @param env * @param env
* @param session * @param session
*/ */
@SuppressWarnings("unchecked")
private void passSessionAttributes(EnvList env, HttpSession session) private void passSessionAttributes(EnvList env, HttpSession session)
{ {
Enumeration<String> enm = session.getAttributeNames(); Enumeration<String> enm = session.getAttributeNames();
@@ -277,19 +273,27 @@ public class HgCGIServlet extends HttpServlet
directory.getAbsolutePath()); directory.getAbsolutePath());
// add hook environment // add hook environment
Map<String, String> environment = executor.getEnvironment().asMutableMap();
if (handler.getConfig().isDisableHookSSLValidation()) {
// disable ssl validation
// Issue 959: https://goo.gl/zH5eY8
environment.put(ENV_PYTHON_HTTPS_VERIFY, "0");
}
// enable experimental httppostargs protocol of mercurial
// Issue 970: https://goo.gl/poascp
environment.put(ENV_HTTP_POST_ARGS, String.valueOf(handler.getConfig().isEnableHttpPostArgs()));
//J- //J-
HgEnvironment.prepareEnvironment( HgEnvironment.prepareEnvironment(
executor.getEnvironment().asMutableMap(), environment,
handler, handler,
hookManager, hookManager,
request request
); );
//J+ //J+
addCredentials(executor.getEnvironment(), request); HttpSession session = request.getSession();
// unused ???
HttpSession session = request.getSession(false);
if (session != null) if (session != null)
{ {

View File

@@ -6,29 +6,20 @@
<parent> <parent>
<groupId>sonia.scm</groupId> <groupId>sonia.scm</groupId>
<artifactId>scm</artifactId> <artifactId>scm</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>1.61-SNAPSHOT</version>
</parent> </parent>
<groupId>sonia.scm</groupId> <groupId>sonia.scm</groupId>
<artifactId>scm-webapp</artifactId> <artifactId>scm-webapp</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<version>2.0.0-SNAPSHOT</version> <version>1.61-SNAPSHOT</version>
<name>scm-webapp</name> <name>scm-webapp</name>
<dependencies> <dependencies>
<!-- annotation processor -->
<dependency>
<groupId>sonia.scm</groupId>
<artifactId>scm-annotation-processor</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>servlet-api</artifactId>
<version>${servlet.version}</version> <version>${servlet.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -47,13 +38,31 @@
<dependency> <dependency>
<groupId>sonia.scm</groupId> <groupId>sonia.scm</groupId>
<artifactId>scm-core</artifactId> <artifactId>scm-core</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>1.61-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>sonia.scm</groupId> <groupId>sonia.scm</groupId>
<artifactId>scm-dao-xml</artifactId> <artifactId>scm-dao-xml</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>1.61-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-hg-plugin</artifactId>
<version>1.61-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-svn-plugin</artifactId>
<version>1.61-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-git-plugin</artifactId>
<version>1.61-SNAPSHOT</version>
</dependency> </dependency>
<!-- security --> <!-- security -->
@@ -70,12 +79,6 @@
<version>${shiro.version}</version> <version>${shiro.version}</version>
</dependency> </dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.4</version>
</dependency>
<!-- rest api --> <!-- rest api -->
<dependency> <dependency>
@@ -128,20 +131,11 @@
<version>${guice.version}</version> <version>${guice.version}</version>
</dependency> </dependency>
<!-- event bus -->
<dependency>
<groupId>com.github.legman.support</groupId>
<artifactId>shiro</artifactId>
<version>${legman.version}</version>
</dependency>
<!-- logging --> <!-- logging -->
<dependency> <dependency>
<groupId>ch.qos.logback</groupId> <groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId> <artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -156,18 +150,34 @@
<version>${slf4j.version}</version> <version>${slf4j.version}</version>
</dependency> </dependency>
<!-- cache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>${ehcache.version}</version>
</dependency>
<!--
fix java.lang.NoClassDefFoundError org/w3c/dom/ElementTraversal
-->
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
</dependency>
<!-- only for BeanComparator, replace with own implementation --> <!-- only for BeanComparator, replace with own implementation -->
<dependency> <dependency>
<groupId>commons-beanutils</groupId> <groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId> <artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-collections</groupId> <groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId> <artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency> </dependency>
<!-- <!--
@@ -199,22 +209,64 @@
</exclusions> </exclusions>
</dependency> </dependency>
<!-- fix version conflict --> <!-- template engine -->
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.freemarker</groupId>
<artifactId>httpclient</artifactId> <artifactId>freemarker</artifactId>
<version>4.2.6</version> <version>${freemarker.version}</version>
</dependency> </dependency>
<!-- template engine -->
<dependency> <dependency>
<groupId>com.github.spullara.mustache.java</groupId> <groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId> <artifactId>compiler</artifactId>
<version>${mustache.version}</version> <version>${mustache.version}</version>
</dependency> </dependency>
<!-- aether -->
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-api</artifactId>
<version>${aether.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-impl</artifactId>
<version>${aether.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-aether-provider</artifactId>
<version>${maven.version}</version>
<exclusions>
<exclusion>
<artifactId>plexus-component-annotations</artifactId>
<groupId>org.codehaus.plexus</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-transport-http</artifactId>
<version>${aether.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-transport-file</artifactId>
<version>${aether.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-connector-basic</artifactId>
<version>${aether.version}</version>
</dependency>
<!-- rest documentation --> <!-- rest documentation -->
<dependency> <dependency>
@@ -228,7 +280,7 @@
<dependency> <dependency>
<groupId>sonia.scm</groupId> <groupId>sonia.scm</groupId>
<artifactId>scm-test</artifactId> <artifactId>scm-test</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>1.61-SNAPSHOT</version>
<scope>test</scope> <scope>test</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
@@ -238,6 +290,30 @@
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-git-plugin</artifactId>
<version>1.61-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-hg-plugin</artifactId>
<version>1.61-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-svn-plugin</artifactId>
<version>1.61-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.seleniumhq.selenium</groupId> <groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId> <artifactId>selenium-java</artifactId>
@@ -273,9 +349,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- core plugins -->
<dependency> <dependency>
<groupId>com.github.sdorra</groupId> <groupId>com.github.sdorra</groupId>
<artifactId>shiro-unit</artifactId> <artifactId>shiro-unit</artifactId>
@@ -283,51 +356,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-git-plugin</artifactId>
<version>2.0.0-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-git-plugin</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-hg-plugin</artifactId>
<version>2.0.0-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-hg-plugin</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-svn-plugin</artifactId>
<version>2.0.0-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-svn-plugin</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<!-- global excludes --> <!-- global excludes -->
<dependency> <dependency>
@@ -347,6 +375,7 @@
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
@@ -371,6 +400,7 @@
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
@@ -390,43 +420,33 @@
</plugin> </plugin>
<plugin> <plugin>
<groupId>sonia.scm.maven</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>smp-maven-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<version>1.0.0-alpha-2</version> <version>1.6</version>
<configuration>
<artifactItems>
<artifactItem>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-hg-plugin</artifactId>
<version>${project.version}</version>
<type>smp</type>
</artifactItem>
<artifactItem>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-svn-plugin</artifactId>
<version>${project.version}</version>
<type>smp</type>
</artifactItem>
<artifactItem>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-git-plugin</artifactId>
<version>${project.version}</version>
<type>smp</type>
</artifactItem>
<artifactItem>
<groupId>sonia.scm.plugins</groupId>
<artifactId>scm-legacy-plugin</artifactId>
<version>${project.version}</version>
<type>smp</type>
</artifactItem>
</artifactItems>
</configuration>
<executions> <executions>
<execution> <execution>
<id>repack</id>
<phase>compile</phase> <phase>compile</phase>
<goals> <goals>
<goal>copy-core-plugins</goal> <goal>run</goal>
</goals> </goals>
<configuration>
<target>
<!--
add beans.xml to jersey-guice
-->
<property name="beans.file" value="src/main/webapp/WEB-INF/beans.xml" />
<property name="temp.dir" value="${project.build.directory}/tmp" />
<property name="rewrite.dir" value="${project.build.directory}/dependency-rewrite/WEB-INF/lib" />
<property name="suffix" value="gfcdifix" />
<!-- jersey guice -->
<property name="jersey.tmp" value="${temp.dir}/jersey-guice" />
<unzip src="${com.sun.jersey.contribs:jersey-guice:jar}" dest="${jersey.tmp}" />
<copy file="${beans.file}" toDir="${jersey.tmp}/META-INF" />
<zip basedir="${jersey.tmp}" destfile="${rewrite.dir}/jersey-guice-${jersey.version}-${suffix}.jar" />
</target>
</configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
@@ -464,7 +484,7 @@
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.eclipse.jetty</groupId> <groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId> <artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.maven.version}</version> <version>${jetty.maven.version}</version>
<configuration> <configuration>
@@ -484,10 +504,19 @@
<value>true</value> <value>true</value>
</systemProperty> </systemProperty>
</systemProperties> </systemProperties>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8081</port>
<maxIdleTime>60000</maxIdleTime>
<requestHeaderSize>16384</requestHeaderSize>
</connector>
</connectors>
<webApp> <webApp>
<contextPath>/scm</contextPath> <contextPath>/scm</contextPath>
</webApp> </webApp>
<jettyXml>${project.basedir}/src/main/conf/jetty.xml</jettyXml> <source>${project.build.javaLevel}</source>
<target>${project.build.javaLevel}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<scanIntervalSeconds>0</scanIntervalSeconds> <scanIntervalSeconds>0</scanIntervalSeconds>
</configuration> </configuration>
</plugin> </plugin>
@@ -503,7 +532,9 @@
<environment.profile>default</environment.profile> <environment.profile>default</environment.profile>
<selenium.version>2.53.1</selenium.version> <selenium.version>2.53.1</selenium.version>
<enunciate.version>2.9.1</enunciate.version> <enunciate.version>2.9.1</enunciate.version>
<aether.version>1.1.0</aether.version>
<wagon.version>1.0</wagon.version> <wagon.version>1.0</wagon.version>
<maven.version>3.3.9</maven.version>
<mustache.version>0.8.17</mustache.version> <mustache.version>0.8.17</mustache.version>
<netbeans.hint.deploy.server>Tomcat</netbeans.hint.deploy.server> <netbeans.hint.deploy.server>Tomcat</netbeans.hint.deploy.server>
<sonar.issue.ignore.multicriteria>e1</sonar.issue.ignore.multicriteria> <sonar.issue.ignore.multicriteria>e1</sonar.issue.ignore.multicriteria>
@@ -514,6 +545,20 @@
<profiles> <profiles>
<profile>
<id>cluster</id>
<dependencies>
<dependency>
<groupId>sonia.scm</groupId>
<artifactId>scm-dao-orientdb</artifactId>
<version>1.58-SNAPSHOT</version>
</dependency>
</dependencies>
</profile>
<profile> <profile>
<id>release</id> <id>release</id>
@@ -594,7 +639,7 @@
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.eclipse.jetty</groupId> <groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId> <artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.maven.version}</version> <version>${jetty.maven.version}</version>
<configuration> <configuration>
@@ -610,7 +655,16 @@
<value>${scm.stage}</value> <value>${scm.stage}</value>
</systemProperty> </systemProperty>
</systemProperties> </systemProperties>
<jettyXml>${project.basedir}/src/main/conf/jetty.xml</jettyXml> <connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8081</port>
<maxIdleTime>60000</maxIdleTime>
<requestHeaderSize>16384</requestHeaderSize>
</connector>
</connectors>
<source>${project.build.javaLevel}</source>
<target>${project.build.javaLevel}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<scanIntervalSeconds>0</scanIntervalSeconds> <scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon> <daemon>true</daemon>
</configuration> </configuration>
@@ -680,13 +734,10 @@
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.eclipse.jetty</groupId> <groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId> <artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.maven.version}</version> <version>${jetty.maven.version}</version>
<configuration> <configuration>
<httpConnector>
<port>8082</port>
</httpConnector>
<stopPort>8086</stopPort> <stopPort>8086</stopPort>
<stopKey>STOP</stopKey> <stopKey>STOP</stopKey>
<systemProperties> <systemProperties>
@@ -695,7 +746,16 @@
<value>target/scm-it</value> <value>target/scm-it</value>
</systemProperty> </systemProperty>
</systemProperties> </systemProperties>
<jettyXml>${project.basedir}/src/main/conf/jetty.xml</jettyXml> <connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8082</port>
<maxIdleTime>60000</maxIdleTime>
<requestHeaderSize>16384</requestHeaderSize>
</connector>
</connectors>
<source>${project.build.javaLevel}</source>
<target>${project.build.javaLevel}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<scanIntervalSeconds>0</scanIntervalSeconds> <scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon> <daemon>true</daemon>
</configuration> </configuration>

View File

@@ -35,13 +35,15 @@ package sonia.scm;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.Maps;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.multibindings.Multibinder; import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names; import com.google.inject.name.Names;
import com.google.inject.servlet.RequestScoped; import com.google.inject.servlet.RequestScoped;
import com.google.inject.servlet.ServletModule;
import com.google.inject.throwingproviders.ThrowingProviderBinder; import com.google.inject.throwingproviders.ThrowingProviderBinder;
import org.apache.shiro.authz.permission.PermissionResolver;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -50,6 +52,11 @@ import sonia.scm.cache.CacheManager;
import sonia.scm.cache.GuavaCacheManager; import sonia.scm.cache.GuavaCacheManager;
import sonia.scm.config.ScmConfiguration; import sonia.scm.config.ScmConfiguration;
import sonia.scm.event.ScmEventBus; import sonia.scm.event.ScmEventBus;
import sonia.scm.filter.AdminSecurityFilter;
import sonia.scm.filter.BaseUrlFilter;
import sonia.scm.filter.GZipFilter;
import sonia.scm.filter.MDCFilter;
import sonia.scm.filter.SecurityFilter;
import sonia.scm.group.DefaultGroupManager; import sonia.scm.group.DefaultGroupManager;
import sonia.scm.group.GroupDAO; import sonia.scm.group.GroupDAO;
import sonia.scm.group.GroupManager; import sonia.scm.group.GroupManager;
@@ -57,14 +64,20 @@ import sonia.scm.group.GroupManagerProvider;
import sonia.scm.group.xml.XmlGroupDAO; import sonia.scm.group.xml.XmlGroupDAO;
import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.DefaultFileSystem;
import sonia.scm.io.FileSystem; import sonia.scm.io.FileSystem;
import sonia.scm.net.HttpClient;
import sonia.scm.net.URLHttpClient;
import sonia.scm.plugin.DefaultPluginLoader; import sonia.scm.plugin.DefaultPluginLoader;
import sonia.scm.plugin.DefaultPluginManager; import sonia.scm.plugin.DefaultPluginManager;
import sonia.scm.plugin.Plugin;
import sonia.scm.plugin.PluginLoader; import sonia.scm.plugin.PluginLoader;
import sonia.scm.plugin.PluginManager; import sonia.scm.plugin.PluginManager;
import sonia.scm.repository.ChangesetViewerUtil;
import sonia.scm.repository.DefaultRepositoryManager; import sonia.scm.repository.DefaultRepositoryManager;
import sonia.scm.repository.DefaultRepositoryProvider; import sonia.scm.repository.DefaultRepositoryProvider;
import sonia.scm.repository.HealthCheckContextListener; import sonia.scm.repository.HealthCheckContextListener;
import sonia.scm.repository.LastModifiedUpdateListener;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryBrowserUtil;
import sonia.scm.repository.RepositoryDAO; import sonia.scm.repository.RepositoryDAO;
import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.RepositoryManagerProvider; import sonia.scm.repository.RepositoryManagerProvider;
@@ -79,9 +92,15 @@ import sonia.scm.resources.ResourceManager;
import sonia.scm.resources.ScriptResourceServlet; import sonia.scm.resources.ScriptResourceServlet;
import sonia.scm.security.CipherHandler; import sonia.scm.security.CipherHandler;
import sonia.scm.security.CipherUtil; import sonia.scm.security.CipherUtil;
import sonia.scm.security.ConfigurableLoginAttemptHandler;
import sonia.scm.security.DefaultKeyGenerator; import sonia.scm.security.DefaultKeyGenerator;
import sonia.scm.security.DefaultSecuritySystem; import sonia.scm.security.DefaultSecuritySystem;
import sonia.scm.security.EncryptionHandler;
import sonia.scm.security.KeyGenerator; import sonia.scm.security.KeyGenerator;
import sonia.scm.security.LoginAttemptHandler;
import sonia.scm.security.MessageDigestEncryptionHandler;
import sonia.scm.security.RepositoryPermissionResolver;
import sonia.scm.security.SecurityContext;
import sonia.scm.security.SecuritySystem; import sonia.scm.security.SecuritySystem;
import sonia.scm.store.BlobStoreFactory; import sonia.scm.store.BlobStoreFactory;
import sonia.scm.store.ConfigurationEntryStoreFactory; import sonia.scm.store.ConfigurationEntryStoreFactory;
@@ -89,10 +108,16 @@ import sonia.scm.store.DataStoreFactory;
import sonia.scm.store.FileBlobStoreFactory; import sonia.scm.store.FileBlobStoreFactory;
import sonia.scm.store.JAXBConfigurationEntryStoreFactory; import sonia.scm.store.JAXBConfigurationEntryStoreFactory;
import sonia.scm.store.JAXBDataStoreFactory; import sonia.scm.store.JAXBDataStoreFactory;
import sonia.scm.store.JAXBConfigurationStoreFactory; import sonia.scm.store.JAXBStoreFactory;
import sonia.scm.store.ListenableStoreFactory;
import sonia.scm.store.StoreFactory;
import sonia.scm.template.DefaultEngine;
import sonia.scm.template.FreemarkerTemplateEngine;
import sonia.scm.template.FreemarkerTemplateHandler;
import sonia.scm.template.MustacheTemplateEngine; import sonia.scm.template.MustacheTemplateEngine;
import sonia.scm.template.TemplateEngine; import sonia.scm.template.TemplateEngine;
import sonia.scm.template.TemplateEngineFactory; import sonia.scm.template.TemplateEngineFactory;
import sonia.scm.template.TemplateHandler;
import sonia.scm.template.TemplateServlet; import sonia.scm.template.TemplateServlet;
import sonia.scm.url.RestJsonUrlProvider; import sonia.scm.url.RestJsonUrlProvider;
import sonia.scm.url.RestXmlUrlProvider; import sonia.scm.url.RestXmlUrlProvider;
@@ -108,16 +133,21 @@ import sonia.scm.util.DebugServlet;
import sonia.scm.util.ScmConfigurationUtil; import sonia.scm.util.ScmConfigurationUtil;
import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.CGIExecutorFactory;
import sonia.scm.web.cgi.DefaultCGIExecutorFactory; import sonia.scm.web.cgi.DefaultCGIExecutorFactory;
import sonia.scm.web.filter.AutoLoginFilter;
import sonia.scm.web.filter.LoggingFilter; import sonia.scm.web.filter.LoggingFilter;
import sonia.scm.web.security.AdministrationContext; import sonia.scm.web.security.AdministrationContext;
import sonia.scm.web.security.ApiBasicAuthenticationFilter;
import sonia.scm.web.security.AuthenticationManager;
import sonia.scm.web.security.BasicSecurityContext;
import sonia.scm.web.security.ChainAuthenticatonManager;
import sonia.scm.web.security.DefaultAdministrationContext; import sonia.scm.web.security.DefaultAdministrationContext;
import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.core.PackagesResourceConfig; import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.api.json.JSONConfiguration; import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.guice.JerseyServletModule;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import com.sun.jersey.spi.container.servlet.ServletContainer; import com.sun.jersey.spi.container.servlet.ServletContainer;
@@ -127,10 +157,6 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.ServletContext;
import sonia.scm.store.ConfigurationStoreFactory;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import sonia.scm.net.SSLContextProvider; import sonia.scm.net.SSLContextProvider;
import sonia.scm.net.ahc.AdvancedHttpClient; import sonia.scm.net.ahc.AdvancedHttpClient;
@@ -140,16 +166,15 @@ import sonia.scm.net.ahc.JsonContentTransformer;
import sonia.scm.net.ahc.XmlContentTransformer; import sonia.scm.net.ahc.XmlContentTransformer;
import sonia.scm.schedule.QuartzScheduler; import sonia.scm.schedule.QuartzScheduler;
import sonia.scm.schedule.Scheduler; import sonia.scm.schedule.Scheduler;
import sonia.scm.security.ConfigurableLoginAttemptHandler;
import sonia.scm.security.LoginAttemptHandler;
import sonia.scm.security.AuthorizationChangedEventProducer; import sonia.scm.security.AuthorizationChangedEventProducer;
import sonia.scm.security.XsrfProtectionFilter;
import sonia.scm.web.UserAgentParser; import sonia.scm.web.UserAgentParser;
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public class ScmServletModule extends JerseyServletModule public class ScmServletModule extends ServletModule
{ {
/** Field description */ /** Field description */
@@ -214,15 +239,11 @@ public class ScmServletModule extends JerseyServletModule
* Constructs ... * Constructs ...
* *
* *
*
* @param servletContext
* @param pluginLoader * @param pluginLoader
* @param overrides * @param overrides
*/ */
ScmServletModule(ServletContext servletContext, ScmServletModule(DefaultPluginLoader pluginLoader, ClassOverrides overrides)
DefaultPluginLoader pluginLoader, ClassOverrides overrides)
{ {
this.servletContext = servletContext;
this.pluginLoader = pluginLoader; this.pluginLoader = pluginLoader;
this.overrides = overrides; this.overrides = overrides;
} }
@@ -242,7 +263,7 @@ public class ScmServletModule extends JerseyServletModule
bind(SCMContextProvider.class).toInstance(context); bind(SCMContextProvider.class).toInstance(context);
ScmConfiguration config = getScmConfiguration(); ScmConfiguration config = getScmConfiguration(context);
CipherUtil cu = CipherUtil.getInstance(); CipherUtil cu = CipherUtil.getInstance();
// bind repository provider // bind repository provider
@@ -250,16 +271,14 @@ public class ScmServletModule extends JerseyServletModule
RepositoryProvider.class, Repository.class).to( RepositoryProvider.class, Repository.class).to(
DefaultRepositoryProvider.class).in(RequestScoped.class); DefaultRepositoryProvider.class).in(RequestScoped.class);
// bind servlet context
bind(ServletContext.class).annotatedWith(Default.class).toInstance(
servletContext);
// bind event api // bind event api
bind(ScmEventBus.class).toInstance(ScmEventBus.getInstance()); bind(ScmEventBus.class).toInstance(ScmEventBus.getInstance());
// bind core // bind core
bind(ConfigurationStoreFactory.class, JAXBConfigurationStoreFactory.class); bind(StoreFactory.class, JAXBStoreFactory.class);
bind(ConfigurationEntryStoreFactory.class, JAXBConfigurationEntryStoreFactory.class); bind(ListenableStoreFactory.class, JAXBStoreFactory.class);
bind(ConfigurationEntryStoreFactory.class,
JAXBConfigurationEntryStoreFactory.class);
bind(DataStoreFactory.class, JAXBDataStoreFactory.class); bind(DataStoreFactory.class, JAXBDataStoreFactory.class);
bind(BlobStoreFactory.class, FileBlobStoreFactory.class); bind(BlobStoreFactory.class, FileBlobStoreFactory.class);
bind(ScmConfiguration.class).toInstance(config); bind(ScmConfiguration.class).toInstance(config);
@@ -272,20 +291,24 @@ public class ScmServletModule extends JerseyServletModule
// note CipherUtil uses an other generator // note CipherUtil uses an other generator
bind(KeyGenerator.class).to(DefaultKeyGenerator.class); bind(KeyGenerator.class).to(DefaultKeyGenerator.class);
bind(CipherHandler.class).toInstance(cu.getCipherHandler()); bind(CipherHandler.class).toInstance(cu.getCipherHandler());
bind(EncryptionHandler.class, MessageDigestEncryptionHandler.class);
bind(FileSystem.class, DefaultFileSystem.class); bind(FileSystem.class, DefaultFileSystem.class);
// bind health check stuff // bind health check stuff
bind(HealthCheckContextListener.class); bind(HealthCheckContextListener.class);
// bind extensions // bind extensions
pluginLoader.getExtensionProcessor().processAutoBindExtensions(binder()); pluginLoader.processExtensions(binder());
// bind security stuff // bind security stuff
bind(LoginAttemptHandler.class).to(ConfigurableLoginAttemptHandler.class);
bind(AuthorizationChangedEventProducer.class); bind(AuthorizationChangedEventProducer.class);
bind(PermissionResolver.class, RepositoryPermissionResolver.class);
bind(AuthenticationManager.class, ChainAuthenticatonManager.class);
bind(SecurityContext.class).to(BasicSecurityContext.class);
bind(WebSecurityContext.class).to(BasicSecurityContext.class);
bind(SecuritySystem.class).to(DefaultSecuritySystem.class); bind(SecuritySystem.class).to(DefaultSecuritySystem.class);
bind(AdministrationContext.class, DefaultAdministrationContext.class); bind(AdministrationContext.class, DefaultAdministrationContext.class);
bind(LoginAttemptHandler.class, ConfigurableLoginAttemptHandler.class);
// bind cache // bind cache
bind(CacheManager.class, GuavaCacheManager.class); bind(CacheManager.class, GuavaCacheManager.class);
@@ -303,10 +326,14 @@ public class ScmServletModule extends JerseyServletModule
bindDecorated(GroupManager.class, DefaultGroupManager.class, bindDecorated(GroupManager.class, DefaultGroupManager.class,
GroupManagerProvider.class); GroupManagerProvider.class);
bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class); bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class);
bind(ChangesetViewerUtil.class);
bind(RepositoryBrowserUtil.class);
// bind sslcontext provider // bind sslcontext provider
bind(SSLContext.class).toProvider(SSLContextProvider.class); bind(SSLContext.class).toProvider(SSLContextProvider.class);
// bind httpclient
bind(HttpClient.class, URLHttpClient.class);
// bind ahc // bind ahc
Multibinder<ContentTransformer> transformers = Multibinder<ContentTransformer> transformers =
@@ -352,6 +379,23 @@ public class ScmServletModule extends JerseyServletModule
filter(PATTERN_ALL).through(LoggingFilter.class); filter(PATTERN_ALL).through(LoggingFilter.class);
} }
// protect api agains xsrf attacks
filter(PATTERN_RESTAPI).through(XsrfProtectionFilter.class);
/*
* filter(PATTERN_PAGE,
* PATTERN_STATIC_RESOURCES).through(StaticResourceFilter.class);
*/
filter(PATTERN_ALL).through(BaseUrlFilter.class);
filter(PATTERN_ALL).through(AutoLoginFilter.class);
filterRegex(RESOURCE_REGEX).through(GZipFilter.class);
filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(ApiBasicAuthenticationFilter.class);
filter(PATTERN_RESTAPI, PATTERN_DEBUG).through(SecurityFilter.class);
filter(PATTERN_CONFIG, PATTERN_ADMIN).through(AdminSecurityFilter.class);
// added mdcs for logging
filter(PATTERN_ALL).through(MDCFilter.class);
// debug servlet // debug servlet
serve(PATTERN_DEBUG).with(DebugServlet.class); serve(PATTERN_DEBUG).with(DebugServlet.class);
@@ -359,21 +403,23 @@ public class ScmServletModule extends JerseyServletModule
serve(PATTERN_PLUGIN_SCRIPT).with(ScriptResourceServlet.class); serve(PATTERN_PLUGIN_SCRIPT).with(ScriptResourceServlet.class);
// template // template
bind(TemplateHandler.class).to(FreemarkerTemplateHandler.class);
serve(PATTERN_INDEX, "/").with(TemplateServlet.class); serve(PATTERN_INDEX, "/").with(TemplateServlet.class);
Multibinder<TemplateEngine> engineBinder = Multibinder<TemplateEngine> engineBinder =
Multibinder.newSetBinder(binder(), TemplateEngine.class); Multibinder.newSetBinder(binder(), TemplateEngine.class);
engineBinder.addBinding().to(MustacheTemplateEngine.class); engineBinder.addBinding().to(MustacheTemplateEngine.class);
bind(TemplateEngine.class).annotatedWith(Default.class).to( engineBinder.addBinding().to(FreemarkerTemplateEngine.class);
bind(TemplateEngine.class).annotatedWith(DefaultEngine.class).to(
MustacheTemplateEngine.class); MustacheTemplateEngine.class);
bind(TemplateEngineFactory.class); bind(TemplateEngineFactory.class);
// bind events // bind events
// bind(LastModifiedUpdateListener.class); bind(LastModifiedUpdateListener.class);
// jersey // jersey
Map<String, String> params = Maps.newHashMap(); Map<String, String> params = new HashMap<String, String>();
/* /*
* params.put("com.sun.jersey.spi.container.ContainerRequestFilters", * params.put("com.sun.jersey.spi.container.ContainerRequestFilters",
@@ -386,17 +432,63 @@ public class ScmServletModule extends JerseyServletModule
params.put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE.toString()); params.put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE.toString());
params.put(ResourceConfig.FEATURE_REDIRECT, Boolean.TRUE.toString()); params.put(ResourceConfig.FEATURE_REDIRECT, Boolean.TRUE.toString());
params.put(ResourceConfig.FEATURE_DISABLE_WADL, Boolean.TRUE.toString()); params.put(ResourceConfig.FEATURE_DISABLE_WADL, Boolean.TRUE.toString());
/*
* TODO remove UriExtensionsConfig and PackagesResourceConfig
* to stop jersey classpath scanning
*/
params.put(ServletContainer.RESOURCE_CONFIG_CLASS, params.put(ServletContainer.RESOURCE_CONFIG_CLASS,
UriExtensionsConfig.class.getName()); UriExtensionsConfig.class.getName());
params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "unbound");
String restPath = getRestPackages();
logger.info("configure jersey with package path: {}", restPath);
params.put(PackagesResourceConfig.PROPERTY_PACKAGES, restPath);
serve(PATTERN_RESTAPI).with(GuiceContainer.class, params); serve(PATTERN_RESTAPI).with(GuiceContainer.class, params);
} }
/**
* Method description
*
*
* @param packageSet
* @param plugin
*/
private void appendPluginPackages(Set<String> packageSet, Plugin plugin)
{
Set<String> pluginPackageSet = plugin.getPackageSet();
if (pluginPackageSet != null)
{
for (String pluginPkg : pluginPackageSet)
{
boolean append = true;
for (String pkg : packageSet)
{
if (pluginPkg.startsWith(pkg))
{
append = false;
break;
}
}
if (append)
{
if (logger.isDebugEnabled())
{
String name = "unknown";
if (plugin.getInformation() != null)
{
name = plugin.getInformation().getName();
}
logger.debug("plugin {} added rest path {}", name, pluginPkg);
}
packageSet.add(pluginPkg);
}
}
}
}
/** /**
* Method description * Method description
* *
@@ -484,6 +576,44 @@ public class ScmServletModule extends JerseyServletModule
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
private String getRestPackages()
{
Set<String> packageSet = new HashSet<String>();
packageSet.add(SCMContext.DEFAULT_PACKAGE);
Collection<Plugin> plugins = pluginLoader.getInstalledPlugins();
if (plugins != null)
{
for (Plugin plugin : plugins)
{
appendPluginPackages(packageSet, plugin);
}
}
StringBuilder buffer = new StringBuilder();
Iterator<String> pkgIterator = packageSet.iterator();
while (pkgIterator.hasNext())
{
buffer.append(pkgIterator.next());
if (pkgIterator.hasNext())
{
buffer.append(";");
}
}
return buffer.toString();
}
/** /**
* Load ScmConfiguration with JAXB * Load ScmConfiguration with JAXB
* *
@@ -492,7 +622,7 @@ public class ScmServletModule extends JerseyServletModule
* *
* @return * @return
*/ */
private ScmConfiguration getScmConfiguration() private ScmConfiguration getScmConfiguration(SCMContextProvider context)
{ {
ScmConfiguration configuration = new ScmConfiguration(); ScmConfiguration configuration = new ScmConfiguration();
@@ -504,11 +634,8 @@ public class ScmServletModule extends JerseyServletModule
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** Field description */ /** Field description */
private final ClassOverrides overrides; private ClassOverrides overrides;
/** Field description */ /** Field description */
private final DefaultPluginLoader pluginLoader; private DefaultPluginLoader pluginLoader;
/** Field description */
private final ServletContext servletContext;
} }

View File

@@ -42,50 +42,65 @@ import sonia.scm.template.TemplateEngineFactory;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.view.Viewable;
import com.sun.jersey.spi.template.ViewProcessor;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.Provider;
import sonia.scm.template.Viewable;
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
@Provider @Provider
public class TemplateEngineViewable implements MessageBodyWriter<Viewable> public class TemplateEngineViewable implements ViewProcessor<String>
{ {
private final TemplateEngineFactory templateEngineFactory; /**
* Constructs ...
*
*
* @param templateEngineFactory
*/
@Inject @Inject
public TemplateEngineViewable(TemplateEngineFactory templateEngineFactory) public TemplateEngineViewable(TemplateEngineFactory templateEngineFactory)
{ {
this.templateEngineFactory = templateEngineFactory; this.templateEngineFactory = templateEngineFactory;
} }
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param name
*
* @return
*/
@Override @Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { public String resolve(String name)
return type.isAssignableFrom(Viewable.class); {
return name;
} }
/**
* Method description
*
*
* @param path
* @param viewable
* @param out
*
* @throws IOException
*/
@Override @Override
public long getSize(Viewable viewable, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { public void writeTo(String path, Viewable viewable, OutputStream out)
return -1; throws IOException
} {
@Override
public void writeTo(Viewable viewable, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
String path = viewable.getPath();
TemplateEngine engine = templateEngineFactory.getEngineByExtension(path); TemplateEngine engine = templateEngineFactory.getEngineByExtension(path);
if (engine == null) if (engine == null)
@@ -100,9 +115,14 @@ public class TemplateEngineViewable implements MessageBodyWriter<Viewable>
throw new IOException("could not find template for ".concat(path)); throw new IOException("could not find template for ".concat(path));
} }
PrintWriter writer = new PrintWriter(entityStream); PrintWriter writer = new PrintWriter(out);
template.execute(writer, viewable.getContext()); template.execute(writer, viewable.getModel());
writer.flush(); writer.flush();
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private TemplateEngineFactory templateEngineFactory;
} }

View File

@@ -28,63 +28,89 @@
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
* *
*/ */
package sonia.scm.template;
import com.google.common.base.Objects;
package sonia.scm.api.rest;
//~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.core.PackagesResourceConfig;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.MediaType;
/** /**
* A viewable holds the path to a template and the context object which is used to render the template. Viewables can
* be used as return type of jax-rs resources.
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
* @since 2.0.0
*/ */
public final class Viewable { public class UriExtensionsConfig extends PackagesResourceConfig
{
private final String path; /** Field description */
private final Object context; public static final String EXTENSION_JSON = "json";
public Viewable(String path, Object context) { /** Field description */
this.path = path; public static final String EXTENSION_XML = "xml";
this.context = context;
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*/
public UriExtensionsConfig()
{
super();
} }
public String getPath() { /**
return path; * Constructs ...
*
*
* @param props
*/
public UriExtensionsConfig(Map<String, Object> props)
{
super(props);
} }
public Object getContext() { /**
return context; * Constructs ...
*
*
* @param paths
*/
public UriExtensionsConfig(String[] paths)
{
super(paths);
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override @Override
public int hashCode() { public Map<String, MediaType> getMediaTypeMappings()
return Objects.hashCode(path, context); {
if (mediaTypeMap == null)
{
mediaTypeMap = new HashMap<String, MediaType>();
mediaTypeMap.put(EXTENSION_JSON, MediaType.APPLICATION_JSON_TYPE);
mediaTypeMap.put(EXTENSION_XML, MediaType.APPLICATION_XML_TYPE);
} }
@Override return mediaTypeMap;
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Viewable other = (Viewable) obj;
return !Objects.equal(this.path, other.path)
&& Objects.equal(this.context, other.context);
} }
@Override //~--- fields ---------------------------------------------------------------
public String toString() {
return Objects.toStringHelper(this)
.add("path", path)
.add("context", context)
.toString();
}
/** Field description */
private Map<String, MediaType> mediaTypeMap;
} }

View File

@@ -133,7 +133,7 @@ public abstract class AbstractPermissionResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response add(@Context UriInfo uriInfo, Permission permission) public Response add(@Context UriInfo uriInfo, Permission permission)
{ {
AssignedPermission ap = transformPermission(permission); AssignedPermission ap = transformPermission(permission);
@@ -185,7 +185,7 @@ public abstract class AbstractPermissionResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response update(@PathParam("id") String id, Permission permission) public Response update(@PathParam("id") String id, Permission permission)
{ {
StoredAssignedPermission sap = getPermission(id); StoredAssignedPermission sap = getPermission(id);
@@ -213,7 +213,7 @@ public abstract class AbstractPermissionResource
@ResponseCode(code = 404, condition = "not found, no permission with the specified id available"), @ResponseCode(code = 404, condition = "not found, no permission with the specified id available"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Permission get(@PathParam("id") String id) public Permission get(@PathParam("id") String id)
{ {
StoredAssignedPermission sap = getPermission(id); StoredAssignedPermission sap = getPermission(id);
@@ -231,7 +231,7 @@ public abstract class AbstractPermissionResource
@ResponseCode(code = 204, condition = "success"), @ResponseCode(code = 204, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public List<Permission> getAll() public List<Permission> getAll()
{ {
return getPermissions(getPredicate()); return getPermissions(getPredicate());

View File

@@ -118,7 +118,7 @@ public class ChangePasswordResource
@ResponseCode(code = 400, condition = "bad request, the old password is not correct"), @ResponseCode(code = 400, condition = "bad request, the old password is not correct"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response changePassword(@FormParam("old-password") String oldPassword, public Response changePassword(@FormParam("old-password") String oldPassword,
@FormParam("new-password") String newPassword) @FormParam("new-password") String newPassword)
throws UserException, IOException throws UserException, IOException

View File

@@ -89,7 +89,7 @@ public class ConfigurationResource
* @return * @return
*/ */
@GET @GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getConfiguration() public Response getConfiguration()
{ {
Response response = null; Response response = null;
@@ -118,7 +118,7 @@ public class ConfigurationResource
* @return * @return
*/ */
@POST @POST
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response setConfig(@Context UriInfo uriInfo, public Response setConfig(@Context UriInfo uriInfo,
ScmConfiguration newConfig) ScmConfiguration newConfig)
{ {

View File

@@ -119,7 +119,7 @@ public class GroupResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response create(@Context UriInfo uriInfo, Group group) public Response create(@Context UriInfo uriInfo, Group group)
{ {
@@ -164,7 +164,7 @@ public class GroupResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response update(@Context UriInfo uriInfo, public Response update(@Context UriInfo uriInfo,
@PathParam("id") String name, Group group) @PathParam("id") String name, Group group)
@@ -191,7 +191,7 @@ public class GroupResource
@ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response get(@Context Request request, @PathParam("id") String id) public Response get(@Context Request request, @PathParam("id") String id)
{ {
@@ -221,7 +221,7 @@ public class GroupResource
* @return * @return
*/ */
@GET @GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@TypeHint(Group[].class) @TypeHint(Group[].class)
@StatusCodes({ @StatusCodes({
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),

View File

@@ -52,6 +52,7 @@ import sonia.scm.plugin.PluginInformationComparator;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.multipart.FormDataParam;
import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint; import com.webcohesion.enunciate.metadata.rs.TypeHint;
@@ -65,7 +66,6 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@@ -124,9 +124,9 @@ public class PluginResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response install( public Response install(
/*@FormParam("package")*/ InputStream uploadedInputStream) @FormDataParam("package") InputStream uploadedInputStream)
throws IOException throws IOException
{ {
Response response = null; Response response = null;
@@ -194,7 +194,7 @@ public class PluginResource
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_HTML) @Produces(MediaType.TEXT_HTML)
public Response installFromUI( public Response installFromUI(
/*@FormParam("package")*/ InputStream uploadedInputStream) @FormDataParam("package") InputStream uploadedInputStream)
throws IOException throws IOException
{ {
return install(uploadedInputStream); return install(uploadedInputStream);
@@ -257,7 +257,7 @@ public class PluginResource
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Collection<PluginInformation> getAll() public Collection<PluginInformation> getAll()
{ {
return pluginManager.getAll(); return pluginManager.getAll();
@@ -274,7 +274,7 @@ public class PluginResource
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Collection<PluginInformation> getAvailable() public Collection<PluginInformation> getAvailable()
{ {
return pluginManager.getAvailable(); return pluginManager.getAvailable();
@@ -291,7 +291,7 @@ public class PluginResource
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Collection<PluginInformation> getAvailableUpdates() public Collection<PluginInformation> getAvailableUpdates()
{ {
return pluginManager.getAvailableUpdates(); return pluginManager.getAvailableUpdates();
@@ -325,7 +325,7 @@ public class PluginResource
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Collection<PluginInformation> getOverview() public Collection<PluginInformation> getOverview()
{ {
//J- //J-

View File

@@ -69,6 +69,8 @@ import static com.google.common.base.Preconditions.*;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.client.ClientResponse.Status;
import com.sun.jersey.multipart.FormDataParam;
import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.ResponseHeader; import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.StatusCodes;
@@ -87,7 +89,6 @@ import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue; import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@@ -110,7 +111,7 @@ import javax.xml.bind.annotation.XmlRootElement;
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
// @Path("import/repositories") @Path("import/repositories")
public class RepositoryImportResource public class RepositoryImportResource
{ {
@@ -169,8 +170,8 @@ public class RepositoryImportResource
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
public Response importFromBundle(@Context UriInfo uriInfo, public Response importFromBundle(@Context UriInfo uriInfo,
@PathParam("type") String type, @FormParam("name") String name, @PathParam("type") String type, @FormDataParam("name") String name,
@FormParam("bundle") InputStream inputStream, @QueryParam("compressed") @FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed")
@DefaultValue("false") boolean compressed) @DefaultValue("false") boolean compressed)
{ {
Repository repository = doImportFromBundle(type, name, inputStream, Repository repository = doImportFromBundle(type, name, inputStream,
@@ -210,8 +211,8 @@ public class RepositoryImportResource
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_HTML) @Produces(MediaType.TEXT_HTML)
public Response importFromBundleUI(@PathParam("type") String type, public Response importFromBundleUI(@PathParam("type") String type,
@FormParam("name") String name, @FormDataParam("name") String name,
@FormParam("bundle") InputStream inputStream, @QueryParam("compressed") @FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed")
@DefaultValue("false") boolean compressed) @DefaultValue("false") boolean compressed)
{ {
Response response; Response response;
@@ -259,7 +260,7 @@ public class RepositoryImportResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response importFromUrl(@Context UriInfo uriInfo, public Response importFromUrl(@Context UriInfo uriInfo,
@PathParam("type") String type, UrlImportRequest request) @PathParam("type") String type, UrlImportRequest request)
{ {
@@ -319,7 +320,7 @@ public class RepositoryImportResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(Repository[].class) @TypeHint(Repository[].class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response importRepositories(@PathParam("type") String type) public Response importRepositories(@PathParam("type") String type)
{ {
SecurityUtils.getSubject().checkRole(Role.ADMIN); SecurityUtils.getSubject().checkRole(Role.ADMIN);
@@ -351,7 +352,7 @@ public class RepositoryImportResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(Repository[].class) @TypeHint(Repository[].class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response importRepositories() public Response importRepositories()
{ {
SecurityUtils.getSubject().checkRole(Role.ADMIN); SecurityUtils.getSubject().checkRole(Role.ADMIN);
@@ -393,7 +394,7 @@ public class RepositoryImportResource
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(ImportResult.class) @TypeHint(ImportResult.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response importRepositoriesFromDirectory( public Response importRepositoriesFromDirectory(
@PathParam("type") String type) @PathParam("type") String type)
{ {
@@ -434,7 +435,7 @@ public class RepositoryImportResource
.warn( .warn(
"import feature is not supported by repository handler for type " "import feature is not supported by repository handler for type "
.concat(type), ex); .concat(type), ex);
response = Response.status(Response.Status.BAD_REQUEST).build(); response = Response.status(Status.BAD_REQUEST).build();
} }
catch (IOException ex) catch (IOException ex)
{ {
@@ -450,7 +451,7 @@ public class RepositoryImportResource
else else
{ {
logger.warn("could not find reposiotry handler for type {}", type); logger.warn("could not find reposiotry handler for type {}", type);
response = Response.status(Response.Status.BAD_REQUEST).build(); response = Response.status(Status.BAD_REQUEST).build();
} }
return response; return response;
@@ -474,7 +475,7 @@ public class RepositoryImportResource
), ),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getImportableTypes() public Response getImportableTypes()
{ {
SecurityUtils.getSubject().checkRole(Role.ADMIN); SecurityUtils.getSubject().checkRole(Role.ADMIN);

View File

@@ -166,7 +166,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response create(@Context UriInfo uriInfo, Repository repository) public Response create(@Context UriInfo uriInfo, Repository repository)
{ {
@@ -296,7 +296,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response update(@Context UriInfo uriInfo, @PathParam("id") String id, Repository repository) public Response update(@Context UriInfo uriInfo, @PathParam("id") String id, Repository repository)
{ {
@@ -315,7 +315,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
*/ */
@GET @GET
@Path("{id}") @Path("{id}")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@StatusCodes({ @StatusCodes({
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 404, condition = "not found, no repository with the specified id available"), @ResponseCode(code = 404, condition = "not found, no repository with the specified id available"),
@@ -340,7 +340,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
* @return all repositories * @return all repositories
*/ */
@GET @GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@StatusCodes({ @StatusCodes({
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
@@ -377,7 +377,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(BlameResult.class) @TypeHint(BlameResult.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getBlame(@PathParam("id") String id, public Response getBlame(@PathParam("id") String id,
@QueryParam("revision") String revision, @QueryParam("path") String path) @QueryParam("revision") String revision, @QueryParam("path") String path)
throws RepositoryException, IOException throws RepositoryException, IOException
@@ -449,7 +449,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(Branches.class) @TypeHint(Branches.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getBranches(@PathParam("id") String id) public Response getBranches(@PathParam("id") String id)
throws RepositoryException, IOException throws RepositoryException, IOException
{ {
@@ -511,7 +511,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(BrowserResult.class) @TypeHint(BrowserResult.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
//J- //J-
public Response getBrowserResult( public Response getBrowserResult(
@PathParam("id") String id, @PathParam("id") String id,
@@ -591,7 +591,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(Repository.class) @TypeHint(Repository.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getByTypeAndName(@PathParam("type") String type, public Response getByTypeAndName(@PathParam("type") String type,
@PathParam("name") String name) @PathParam("name") String name)
{ {
@@ -632,7 +632,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(Changeset.class) @TypeHint(Changeset.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getChangeset(@PathParam("id") String id, public Response getChangeset(@PathParam("id") String id,
@PathParam("revision") String revision) @PathParam("revision") String revision)
throws IOException, RepositoryException throws IOException, RepositoryException
@@ -708,7 +708,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(ChangesetPagingResult.class) @TypeHint(ChangesetPagingResult.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
//J- //J-
public Response getChangesets( public Response getChangesets(
@PathParam("id") String id, @PathParam("id") String id,
@@ -948,7 +948,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(Tags.class) @TypeHint(Tags.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getTags(@PathParam("id") String id) public Response getTags(@PathParam("id") String id)
throws RepositoryException, IOException throws RepositoryException, IOException
{ {

View File

@@ -50,6 +50,8 @@ import sonia.scm.util.HttpUtil;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.view.Viewable;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@@ -65,7 +67,6 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import sonia.scm.template.Viewable;
/** /**
* *
@@ -75,13 +76,17 @@ import sonia.scm.template.Viewable;
public class RepositoryRootResource public class RepositoryRootResource
{ {
private static final String TEMPLATE = "/templates/repository-root.mustache"; /** Field description */
public static final String TEMPLATE = "/templates/repository-root.mustache";
private final RepositoryManager repositoryManager; //~--- constructors ---------------------------------------------------------
/** /**
* Constructs ... * Constructs ...
* *
*
*
* @param templateHandler
* @param repositoryManager * @param repositoryManager
*/ */
@Inject @Inject
@@ -325,4 +330,10 @@ public class RepositoryRootResource
/** Field description */ /** Field description */
private UrlProvider urlProvider; private UrlProvider urlProvider;
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private RepositoryManager repositoryManager;
} }

View File

@@ -154,7 +154,7 @@ public class SearchResource implements UserListener, GroupListener
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public SearchResults searchGroups(@QueryParam("query") String queryString) public SearchResults searchGroups(@QueryParam("query") String queryString)
{ {
return groupSearchHandler.search(queryString, return groupSearchHandler.search(queryString,
@@ -189,7 +189,7 @@ public class SearchResource implements UserListener, GroupListener
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public SearchResults searchUsers(@QueryParam("query") String queryString) public SearchResults searchUsers(@QueryParam("query") String queryString)
{ {
return userSearchHandler.search(queryString, return userSearchHandler.search(queryString,

View File

@@ -125,7 +125,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response create(@Context UriInfo uriInfo, User user) public Response create(@Context UriInfo uriInfo, User user)
{ {
@@ -170,7 +170,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@TypeHint(TypeHint.NO_CONTENT.class) @TypeHint(TypeHint.NO_CONTENT.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response update(@Context UriInfo uriInfo, public Response update(@Context UriInfo uriInfo,
@PathParam("id") String name, User user) @PathParam("id") String name, User user)
@@ -197,7 +197,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
@ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"), @ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response get(@Context Request request, @PathParam("id") String id) public Response get(@Context Request request, @PathParam("id") String id)
{ {
@@ -233,7 +233,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"), @ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override @Override
public Response getAll(@Context Request request, @DefaultValue("0") public Response getAll(@Context Request request, @DefaultValue("0")
@QueryParam("start") int start, @DefaultValue("-1") @QueryParam("start") int start, @DefaultValue("-1")

View File

@@ -67,7 +67,7 @@ public final class DebugResource
* @return all received hook data for the given repository * @return all received hook data for the given repository
*/ */
@GET @GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Collection<DebugHookData> getAll(@PathParam("repository") String repository){ public Collection<DebugHookData> getAll(@PathParam("repository") String repository){
return debugService.getAll(repository); return debugService.getAll(repository);
} }
@@ -81,7 +81,7 @@ public final class DebugResource
*/ */
@GET @GET
@Path("last") @Path("last")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public DebugHookData getLast(@PathParam("repository") String repository){ public DebugHookData getLast(@PathParam("repository") String repository){
return debugService.getLast(repository); return debugService.getLast(repository);
} }

View File

@@ -33,16 +33,14 @@ package sonia.scm.net.ahc;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import com.google.common.io.ByteSource; import com.google.common.io.ByteSource;
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
import sonia.scm.plugin.ext.Extension; import sonia.scm.plugin.ext.Extension;
import sonia.scm.util.IOUtil; import sonia.scm.util.IOUtil;
@@ -75,12 +73,12 @@ public class JsonContentTransformer implements ContentTransformer
// allow jackson and jaxb annotations // allow jackson and jaxb annotations
AnnotationIntrospector jackson = new JacksonAnnotationIntrospector(); AnnotationIntrospector jackson = new JacksonAnnotationIntrospector();
AnnotationIntrospector jaxb = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); AnnotationIntrospector jaxb = new JaxbAnnotationIntrospector();
this.mapper.setAnnotationIntrospector(new AnnotationIntrospectorPair(jackson, jaxb)); this.mapper.setAnnotationIntrospector(new AnnotationIntrospector.Pair(jackson, jaxb));
// do not fail on unknown json properties // do not fail on unknown json properties
this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); this.mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------

View File

@@ -91,8 +91,6 @@
<logger name="net.sf.ehcache" level="DEBUG" /> <logger name="net.sf.ehcache" level="DEBUG" />
--> -->
<logger name="org.jboss.resteasy" level="DEBUG" />
<root level="WARN"> <root level="WARN">
<appender-ref ref="STDOUT" /> <appender-ref ref="STDOUT" />
</root> </root>

View File

@@ -40,7 +40,7 @@
<display-name>SCM-Manager ${project.version}</display-name> <display-name>SCM-Manager ${project.version}</display-name>
<listener> <listener>
<listener-class>sonia.scm.boot.BootstrapContextListener</listener-class> <listener-class>sonia.scm.boot.BootstrapListener</listener-class>
</listener> </listener>
<listener> <listener>
@@ -48,45 +48,15 @@
</listener> </listener>
<filter> <filter>
<filter-name>BootstrapFilter</filter-name> <filter-name>guiceFilter</filter-name>
<filter-class>sonia.scm.boot.BootstrapContextFilter</filter-class> <filter-class>sonia.scm.boot.BootstrapFilter</filter-class>
</filter> </filter>
<filter-mapping> <filter-mapping>
<filter-name>BootstrapFilter</filter-name> <filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping> </filter-mapping>
<!-- rest -->
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/api/rest</param-value>
</context-param>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/api/rest/*</url-pattern>
</servlet-mapping>
<!-- capture sessions -->
<!--
TODO remove, we need no longer a session
-->
<listener>
<listener-class>sonia.scm.HttpSessionListenerHolder</listener-class>
</listener>
<!-- basic configuration -->
<welcome-file-list> <welcome-file-list>
<welcome-file>index.html</welcome-file> <welcome-file>index.html</welcome-file>
</welcome-file-list> </welcome-file-list>

View File

@@ -55,7 +55,7 @@ Sonia.action.ChangePasswordWindow = Ext.extend(Ext.Window,{
title: this.titleText, title: this.titleText,
items: [{ items: [{
id: 'changePasswordForm', id: 'changePasswordForm',
url: restUrl + 'action/change-password', url: restUrl + 'action/change-password.json',
frame: true, frame: true,
xtype: 'form', xtype: 'form',
monitorValid: true, monitorValid: true,

View File

@@ -261,7 +261,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{
onSubmit: function(values){ onSubmit: function(values){
this.el.mask(this.submitText); this.el.mask(this.submitText);
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'config', url: restUrl + 'config.json',
method: 'POST', method: 'POST',
jsonData: values, jsonData: values,
scope: this, scope: this,
@@ -283,7 +283,7 @@ Sonia.config.ScmConfigPanel = Ext.extend(Sonia.config.ConfigPanel,{
onLoad: function(el){ onLoad: function(el){
var tid = setTimeout( function(){ el.mask(this.loadingText); }, 100); var tid = setTimeout( function(){ el.mask(this.loadingText); }, 100);
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'config', url: restUrl + 'config.json',
method: 'GET', method: 'GET',
scope: this, scope: this,
disableCaching: true, disableCaching: true,

View File

@@ -59,7 +59,7 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
// this.updateMembers(group); // this.updateMembers(group);
this.fireEvent('preUpdate', group); this.fireEvent('preUpdate', group);
var url = restUrl + 'groups/' + encodeURIComponent(group.name); var url = restUrl + 'groups/' + encodeURIComponent(group.name) + '.json';
var el = this.el; var el = this.el;
var tid = setTimeout( function(){el.mask('Loading ...');}, 100); var tid = setTimeout( function(){el.mask('Loading ...');}, 100);
@@ -96,7 +96,7 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
} }
item.type = state.defaultUserType; item.type = state.defaultUserType;
var url = restUrl + 'groups'; var url = restUrl + 'groups.json';
var el = this.el; var el = this.el;
var tid = setTimeout( function(){el.mask('Loading ...');}, 100); var tid = setTimeout( function(){el.mask('Loading ...');}, 100);

View File

@@ -95,7 +95,7 @@ Sonia.group.Panel = Ext.extend(Sonia.rest.Panel, {
var selected = grid.getSelectionModel().getSelected(); var selected = grid.getSelectionModel().getSelected();
if ( selected ){ if ( selected ){
var item = selected.data; var item = selected.data;
var url = restUrl + 'groups/' + encodeURIComponent(item.name); var url = restUrl + 'groups/' + encodeURIComponent(item.name) + '.json';
Ext.MessageBox.show({ Ext.MessageBox.show({
title: this.removeTitleText, title: this.removeTitleText,

View File

@@ -41,6 +41,7 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{
failedDescriptionText: 'Incorrect username, password or not enough permission. Please Try again.', failedDescriptionText: 'Incorrect username, password or not enough permission. Please Try again.',
accountLockedText: 'Account is locked.', accountLockedText: 'Account is locked.',
accountTemporaryLockedText: 'Account is temporary locked. Please try again later.', accountTemporaryLockedText: 'Account is temporary locked. Please try again later.',
rememberMeText: 'Remember me',
initComponent: function(){ initComponent: function(){
var buttons = []; var buttons = [];
@@ -94,13 +95,10 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{
} }
} }
},{ },{
name: 'grant_type', xtype: 'checkbox',
value: 'password', fieldLabel: this.rememberMeText,
xtype: 'hidden' name: 'rememberMe',
}, { inputValue: 'true'
name: 'cookie',
value: 'true',
xtype: 'hidden'
}], }],
buttons: buttons buttons: buttons
}; };
@@ -118,7 +116,6 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{
authenticate: function(){ authenticate: function(){
var form = this.getForm(); var form = this.getForm();
form.submit({ form.submit({
scope: this, scope: this,
method: 'POST', method: 'POST',

View File

@@ -81,7 +81,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, {
var loadingBox = this.createLoadingBox( this.installWaitMsgText ); var loadingBox = this.createLoadingBox( this.installWaitMsgText );
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'plugins/install/' + pluginId, url: restUrl + 'plugins/install/' + pluginId + '.json',
method: 'POST', method: 'POST',
scope: this, scope: this,
timeout: 300000, // 5min timeout: 300000, // 5min
@@ -116,7 +116,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, {
var loadingBox = this.createLoadingBox( this.uninstallWaitMsgText ); var loadingBox = this.createLoadingBox( this.uninstallWaitMsgText );
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'plugins/uninstall/' + pluginId, url: restUrl + 'plugins/uninstall/' + pluginId + '.json',
method: 'POST', method: 'POST',
scope: this, scope: this,
success: function(){ success: function(){
@@ -150,7 +150,7 @@ Sonia.plugin.Center = Ext.extend(Ext.util.Observable, {
var loadingBox = this.createLoadingBox( this.updateWaitMsgText ); var loadingBox = this.createLoadingBox( this.updateWaitMsgText );
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'plugins/update/' + pluginId, url: restUrl + 'plugins/update/' + pluginId + '.json',
method: 'POST', method: 'POST',
scope: this, scope: this,
timeout: 300000, // 5min timeout: 300000, // 5min

View File

@@ -81,7 +81,7 @@ Sonia.plugin.Grid = Ext.extend(Sonia.rest.Grid, {
var pluginStore = new Ext.data.GroupingStore({ var pluginStore = new Ext.data.GroupingStore({
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
url: restUrl + 'plugins/overview', url: restUrl + 'plugins/overview.json',
disableCaching: false disableCaching: false
}), }),
reader: new Ext.data.JsonReader({ reader: new Ext.data.JsonReader({

View File

@@ -38,7 +38,7 @@ Sonia.repository.BranchComboBox = Ext.extend(Ext.form.ComboBox, {
initComponent: function(){ initComponent: function(){
var branchStore = new Sonia.rest.JsonStore({ var branchStore = new Sonia.rest.JsonStore({
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
url: restUrl + 'repositories/' + this.repositoryId + '/branches', url: restUrl + 'repositories/' + this.repositoryId + '/branches.json',
method: 'GET', method: 'GET',
disableCaching: false disableCaching: false
}), }),

View File

@@ -46,7 +46,7 @@ Sonia.repository.ChangesetViewerPanel = Ext.extend(Ext.Panel, {
initComponent: function(){ initComponent: function(){
if (! this.url){ if (! this.url){
this.url = restUrl + 'repositories/' + this.repository.id + '/changesets'; this.url = restUrl + 'repositories/' + this.repository.id + '/changesets.json';
} }
if ( ! this.startLimit ){ if ( ! this.startLimit ){

View File

@@ -131,7 +131,7 @@ Sonia.repository.CommitPanel = Ext.extend(Ext.Panel, {
} }
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'repositories/' + this.repository.id + '/changeset/' + this.revision, url: restUrl + 'repositories/' + this.repository.id + '/changeset/' + this.revision + '.json',
method: 'GET', method: 'GET',
scope: this, scope: this,
success: function(response){ success: function(response){

View File

@@ -73,7 +73,7 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
if ( debug ){ if ( debug ){
console.debug( 'update repository: ' + item.name ); console.debug( 'update repository: ' + item.name );
} }
var url = restUrl + 'repositories/' + item.id; var url = restUrl + 'repositories/' + item.id + '.json';
var el = this.el; var el = this.el;
var tid = setTimeout( function(){el.mask('Loading ...');}, 100); var tid = setTimeout( function(){el.mask('Loading ...');}, 100);
@@ -124,7 +124,7 @@ Sonia.repository.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
if ( debug ){ if ( debug ){
console.debug( 'create repository: ' + item.name ); console.debug( 'create repository: ' + item.name );
} }
var url = restUrl + 'repositories'; var url = restUrl + 'repositories.json';
var el = this.el; var el = this.el;
var tid = setTimeout( function(){el.mask('Loading ...');}, 100); var tid = setTimeout( function(){el.mask('Loading ...');}, 100);

View File

@@ -71,7 +71,7 @@ Sonia.repository.Grid = Ext.extend(Sonia.rest.Grid, {
var repositoryStore = new Ext.data.GroupingStore({ var repositoryStore = new Ext.data.GroupingStore({
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
url: restUrl + 'repositories', url: restUrl + 'repositories.json',
disableCaching: false disableCaching: false
}), }),
idProperty: 'id', idProperty: 'id',

View File

@@ -75,7 +75,7 @@ Sonia.repository.HealthCheckFailure = Ext.extend(Ext.Panel, {
}, },
rerunHealthChecks: function(){ rerunHealthChecks: function(){
var url = restUrl + 'repositories/' + this.repository.id + '/healthcheck'; var url = restUrl + 'repositories/' + this.repository.id + '/healthcheck.json';
var el = this.el; var el = this.el;
var tid = setTimeout( function(){el.mask('Loading ...');}, 100); var tid = setTimeout( function(){el.mask('Loading ...');}, 100);

View File

@@ -514,7 +514,7 @@ Sonia.repository.ImportPanel = Ext.extend(Ext.Panel, {
importFromUrl: function(layout, repository){ importFromUrl: function(layout, repository){
var lbox = this.showLoadingBox(); var lbox = this.showLoadingBox();
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'import/repositories/' + this.repositoryType + '/url', url: restUrl + 'import/repositories/' + this.repositoryType + '/url.json',
method: 'POST', method: 'POST',
scope: this, scope: this,
timeout: 300000, // 5min timeout: 300000, // 5min
@@ -533,7 +533,7 @@ Sonia.repository.ImportPanel = Ext.extend(Ext.Panel, {
importFromDirectory: function(layout){ importFromDirectory: function(layout){
var lbox = this.showLoadingBox(); var lbox = this.showLoadingBox();
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'import/repositories/' + this.repositoryType + '/directory', url: restUrl + 'import/repositories/' + this.repositoryType + '/directory.json',
timeout: 300000, // 5min timeout: 300000, // 5min
method: 'POST', method: 'POST',
scope: this, scope: this,

View File

@@ -181,7 +181,7 @@ Sonia.repository.get = function(id, callback){
execCallback(repository); execCallback(repository);
} else { } else {
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'repositories/' + id, url: restUrl + 'repositories/' + id + '.json',
method: 'GET', method: 'GET',
scope: this, scope: this,
success: function(response){ success: function(response){

View File

@@ -311,7 +311,7 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, {
console.debug('toggle repository ' + item.name + ' archive to ' + item.archived); console.debug('toggle repository ' + item.name + ' archive to ' + item.archived);
} }
var url = restUrl + 'repositories/' + item.id; var url = restUrl + 'repositories/' + item.id + '.json';
this.executeRemoteCall(title, String.format(msg, item.name), this.executeRemoteCall(title, String.format(msg, item.name),
'PUT', url, item, function(result){ 'PUT', url, item, function(result){
main.handleFailure( main.handleFailure(
@@ -331,7 +331,7 @@ Sonia.repository.Panel = Ext.extend(Sonia.rest.Panel, {
console.debug( 'remove repository ' + item.name ); console.debug( 'remove repository ' + item.name );
} }
var url = restUrl + 'repositories/' + item.id; var url = restUrl + 'repositories/' + item.id + '.json';
this.executeRemoteCall(this.removeTitleText, this.executeRemoteCall(this.removeTitleText,
String.format(this.removeMsgText, item.name), String.format(this.removeMsgText, item.name),
'DELETE', url, null, function(result){ 'DELETE', url, null, function(result){

View File

@@ -58,7 +58,7 @@ Sonia.repository.RepositoryBrowser = Ext.extend(Ext.grid.GridPanel, {
var browserStore = new Sonia.rest.JsonStore({ var browserStore = new Sonia.rest.JsonStore({
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
url: restUrl + 'repositories/' + this.repository.id, url: restUrl + 'repositories/' + this.repository.id + '/browse.json',
method: 'GET' method: 'GET'
}), }),
fields: ['path', 'name', 'length', 'lastModified', 'directory', 'description', 'subrepository'], fields: ['path', 'name', 'length', 'lastModified', 'directory', 'description', 'subrepository'],

View File

@@ -37,7 +37,7 @@ Sonia.repository.TagComboBox = Ext.extend(Ext.form.ComboBox, {
initComponent: function(){ initComponent: function(){
var tagStore = new Sonia.rest.JsonStore({ var tagStore = new Sonia.rest.JsonStore({
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
url: restUrl + 'repositories/' + this.repositoryId + '/tags', url: restUrl + 'repositories/' + this.repositoryId + '/tags.json',
method: 'GET', method: 'GET',
disableCaching: false disableCaching: false
}), }),

View File

@@ -53,7 +53,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, {
this.permissionStore = new Sonia.rest.JsonStore({ this.permissionStore = new Sonia.rest.JsonStore({
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
api: { api: {
read: restUrl + this.baseUrl read: restUrl + this.baseUrl + '.json'
}, },
disableCaching: false disableCaching: false
}), }),
@@ -179,7 +179,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, {
addPermission: function(record){ addPermission: function(record){
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + this.baseUrl, url: restUrl + this.baseUrl + '.json',
method: 'POST', method: 'POST',
jsonData: record.data, jsonData: record.data,
scope: this, scope: this,
@@ -194,7 +194,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, {
modifyPermission: function(id, record){ modifyPermission: function(id, record){
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + this.baseUrl + '/' + encodeURIComponent(id), url: restUrl + this.baseUrl + '/' + encodeURIComponent(id) + '.json',
method: 'PUT', method: 'PUT',
jsonData: record.data, jsonData: record.data,
scope: this, scope: this,
@@ -207,7 +207,7 @@ Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, {
removePermission: function(store, record){ removePermission: function(store, record){
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + this.baseUrl + '/' + encodeURIComponent(record.get('id')), url: restUrl + this.baseUrl + '/' + encodeURIComponent(record.get('id')) + '.json',
method: 'DELETE', method: 'DELETE',
scope: this, scope: this,
success: function(){ success: function(){

View File

@@ -83,7 +83,7 @@ var userSearchStore = new Ext.data.JsonStore({
idProperty: 'value', idProperty: 'value',
fields: ['value','label'], fields: ['value','label'],
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
url: restUrl + 'search/users', url: restUrl + 'search/users.json',
method: 'GET' method: 'GET'
}) })
}); });
@@ -93,7 +93,7 @@ var groupSearchStore = new Ext.data.JsonStore({
idProperty: 'value', idProperty: 'value',
fields: ['value','label'], fields: ['value','label'],
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
url: restUrl + 'search/groups', url: restUrl + 'search/groups.json',
method: 'GET' method: 'GET'
}) })
}); });

View File

@@ -129,7 +129,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
console.debug( 'update user: ' + item.name ); console.debug( 'update user: ' + item.name );
} }
this.fixRequest(item); this.fixRequest(item);
var url = restUrl + 'users/' + encodeURIComponent(item.name); var url = restUrl + 'users/' + encodeURIComponent(item.name) + '.json';
Ext.Ajax.request({ Ext.Ajax.request({
url: url, url: url,
jsonData: item, jsonData: item,
@@ -159,7 +159,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
this.fixRequest(user); this.fixRequest(user);
// set user type // set user type
user.type = state.defaultUserType; user.type = state.defaultUserType;
var url = restUrl + 'users'; var url = restUrl + 'users.json';
Ext.Ajax.request({ Ext.Ajax.request({
url: url, url: url,
jsonData: user, jsonData: user,

View File

@@ -49,7 +49,7 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, {
var userStore = new Sonia.rest.JsonStore({ var userStore = new Sonia.rest.JsonStore({
proxy: new Ext.data.HttpProxy({ proxy: new Ext.data.HttpProxy({
url: restUrl + 'users', url: restUrl + 'users.json',
disableCaching: false disableCaching: false
}), }),
idProperty: 'name', idProperty: 'name',

View File

@@ -126,7 +126,7 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, {
var selected = grid.getSelectionModel().getSelected(); var selected = grid.getSelectionModel().getSelected();
if ( selected ){ if ( selected ){
var item = selected.data; var item = selected.data;
var url = restUrl + 'users/' + encodeURIComponent(item.name); var url = restUrl + 'users/' + encodeURIComponent(item.name) + '.json';
Ext.MessageBox.show({ Ext.MessageBox.show({
title: this.removeTitleText, title: this.removeTitleText,

View File

@@ -32,9 +32,6 @@
package sonia.scm.it; package sonia.scm.it;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.client.UniformInterfaceException;
@@ -44,6 +41,8 @@ import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import org.apache.shiro.crypto.hash.Sha256Hash; import org.apache.shiro.crypto.hash.Sha256Hash;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
@@ -82,7 +81,7 @@ public class GitLfsITCase {
private Repository repository; private Repository repository;
public GitLfsITCase() { public GitLfsITCase() {
mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(TypeFactory.defaultInstance())); mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector());
} }
// lifecycle methods // lifecycle methods