switch from jersey 1.x to resteasy

This commit is contained in:
Sebastian Sdorra
2017-06-27 20:16:05 +02:00
parent aec3d5d65d
commit 3637a8de20
53 changed files with 415 additions and 568 deletions

View File

@@ -261,7 +261,6 @@
<links> <links>
<link>http://download.oracle.com/javase/8/docs/api/</link> <link>http://download.oracle.com/javase/8/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>https://google.github.io/guice/api-docs/${guice.version}/javadoc</link> <link>https://google.github.io/guice/api-docs/${guice.version}/javadoc</link>
<link>http://www.slf4j.org/api/</link> <link>http://www.slf4j.org/api/</link>
<link>http://shiro.apache.org/static/current/apidocs/</link> <link>http://shiro.apache.org/static/current/apidocs/</link>
@@ -482,8 +481,10 @@
<slf4j.version>1.7.22</slf4j.version> <slf4j.version>1.7.22</slf4j.version>
<logback.version>1.1.10</logback.version> <logback.version>1.1.10</logback.version>
<servlet.version>3.0.1</servlet.version> <servlet.version>3.0.1</servlet.version>
<jaxrs.version>2.0.1</jaxrs.version>
<jersey-client.version>1.19.4</jersey-client.version>
<guice.version>4.0</guice.version> <guice.version>4.0</guice.version>
<jersey.version>1.19.4</jersey.version>
<!-- event bus --> <!-- event bus -->
<legman.version>1.2.0</legman.version> <legman.version>1.2.0</legman.version>

View File

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

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.version}</version> <version>${jersey-client.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.version}</version> <version>${jersey-client.version}</version>
</dependency> </dependency>
<!-- test scope --> <!-- test scope -->

View File

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

View File

@@ -45,8 +45,6 @@ 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;
@@ -60,6 +58,7 @@ 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;
@@ -165,7 +164,7 @@ public class DefaultCipherHandler implements CipherHandler {
String result = null; String result = null;
try { try {
byte[] encodedInput = Base64.decode(value); byte[] encodedInput = Base64.getDecoder().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];
@@ -222,7 +221,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.encode(result), ENCODING); res = new String(Base64.getEncoder().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

@@ -28,89 +28,63 @@
* 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 class UriExtensionsConfig extends PackagesResourceConfig public final class Viewable {
{
/** Field description */ private final String path;
public static final String EXTENSION_JSON = "json"; private final Object context;
/** Field description */ public Viewable(String path, Object context) {
public static final String EXTENSION_XML = "xml"; this.path = path;
this.context = context;
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*/
public UriExtensionsConfig()
{
super();
} }
/** public String getPath() {
* Constructs ... return path;
*
*
* @param props
*/
public UriExtensionsConfig(Map<String, Object> props)
{
super(props);
} }
/** public Object getContext() {
* Constructs ... return context;
*
*
* @param paths
*/
public UriExtensionsConfig(String[] paths)
{
super(paths);
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override @Override
public Map<String, MediaType> getMediaTypeMappings() public int hashCode() {
{ 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);
} }
return mediaTypeMap; @Override
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
public String toString() {
return Objects.toStringHelper(this)
.add("path", path)
.add("context", context)
.toString();
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private Map<String, MediaType> mediaTypeMap;
} }

View File

@@ -62,10 +62,9 @@ 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.Base64;
import java.util.Enumeration; import java.util.Enumeration;
@@ -215,7 +214,8 @@ public class HgCGIServlet extends HttpServlet
String encodedUserInfo = String encodedUserInfo =
authorization.substring( authorization.substring(
HttpUtil.AUTHORIZATION_SCHEME_BASIC.length()).trim(); HttpUtil.AUTHORIZATION_SCHEME_BASIC.length()).trim();
String userInfo = Base64.base64Decode(encodedUserInfo); // TODO check encoding of user-agent ?
String userInfo = new String(Base64.getDecoder().decode(encodedUserInfo));
env.set(SCM_CREDENTIALS, CipherUtil.getInstance().encode(userInfo)); env.set(SCM_CREDENTIALS, CipherUtil.getInstance().encode(userInfo));
} }

View File

@@ -76,48 +76,74 @@
<version>0.4</version> <version>0.4</version>
</dependency> </dependency>
<!-- json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-base</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- rest api --> <!-- rest api -->
<dependency> <dependency>
<groupId>com.sun.jersey</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>jersey-server</artifactId> <artifactId>resteasy-jaxrs</artifactId>
<version>${jersey.version}</version> <version>${resteasy.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.sun.jersey</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>jersey-json</artifactId> <artifactId>resteasy-jaxb-provider</artifactId>
<version>${jersey.version}</version> <version>${resteasy.version}</version>
<exclusions>
<exclusion>
<artifactId>stax-api</artifactId>
<groupId>stax</groupId>
</exclusion>
<exclusion>
<artifactId>jaxb-impl</artifactId>
<groupId>com.sun.xml.bind</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.sun.jersey</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>jersey-bundle</artifactId> <artifactId>resteasy-jackson2-provider</artifactId>
<version>${jersey.version}</version> <version>${resteasy.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.sun.jersey.contribs</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>jersey-guice</artifactId> <artifactId>resteasy-multipart-provider</artifactId>
<version>${jersey.version}</version> <version>${resteasy.version}</version>
<!-- included by dependency rewrite -->
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.sun.jersey.contribs</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>jersey-multipart</artifactId> <artifactId>resteasy-guice</artifactId>
<version>${jersey.version}</version> <version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>${resteasy.version}</version>
</dependency> </dependency>
<!-- injection --> <!-- injection -->
@@ -262,14 +288,14 @@
<dependency> <dependency>
<groupId>com.sun.jersey</groupId> <groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId> <artifactId>jersey-client</artifactId>
<version>${jersey.version}</version> <version>${jersey-client.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.sun.jersey.contribs</groupId> <groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client</artifactId> <artifactId>jersey-apache-client</artifactId>
<version>${jersey.version}</version> <version>${jersey-client.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -431,49 +457,12 @@
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>repack</id>
<phase>compile</phase>
<goals>
<goal>run</goal>
</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>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId> <artifactId>maven-war-plugin</artifactId>
<version>2.2</version> <version>2.2</version>
<configuration> <configuration>
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors> <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
<webResources>
<resource>
<directory>${project.build.directory}/dependency-rewrite</directory>
</resource>
</webResources>
</configuration> </configuration>
</plugin> </plugin>
@@ -537,6 +526,8 @@
<enunciate.version>2.9.1</enunciate.version> <enunciate.version>2.9.1</enunciate.version>
<wagon.version>1.0</wagon.version> <wagon.version>1.0</wagon.version>
<mustache.version>0.8.17</mustache.version> <mustache.version>0.8.17</mustache.version>
<resteasy.version>3.1.3.Final</resteasy.version>
<jackson.version>2.8.6</jackson.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>
<sonar.issue.ignore.multicriteria.e1.ruleKey>javascript:S3827</sonar.issue.ignore.multicriteria.e1.ruleKey> <sonar.issue.ignore.multicriteria.e1.ruleKey>javascript:S3827</sonar.issue.ignore.multicriteria.e1.ruleKey>

View File

@@ -35,13 +35,11 @@ package sonia.scm;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Stopwatch;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.servlet.GuiceServletContextListener; import java.util.Collections;
import org.apache.shiro.guice.web.ShiroWebModule; import org.apache.shiro.guice.web.ShiroWebModule;
@@ -65,6 +63,7 @@ import java.util.Set;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextEvent;
import org.jboss.resteasy.plugins.guice.GuiceResteasyBootstrapServletContextListener;
import sonia.scm.debug.DebugModule; import sonia.scm.debug.DebugModule;
import sonia.scm.filter.WebElementModule; import sonia.scm.filter.WebElementModule;
import sonia.scm.schedule.Scheduler; import sonia.scm.schedule.Scheduler;
@@ -73,183 +72,65 @@ import sonia.scm.schedule.Scheduler;
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public class ScmContextListener extends GuiceServletContextListener public class ScmContextListener extends GuiceResteasyBootstrapServletContextListener
{ {
/** /**
* the logger for ScmContextListener * the logger for ScmContextListener
*/ */
private static final Logger logger = private static final Logger LOG = LoggerFactory.getLogger(ScmContextListener.class);
LoggerFactory.getLogger(ScmContextListener.class);
private final ClassLoader parent;
private final Set<PluginWrapper> plugins;
private Injector injector;
//~--- constructors --------------------------------------------------------- //~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param parent
* @param plugins
*/
public ScmContextListener(ClassLoader parent, Set<PluginWrapper> plugins) public ScmContextListener(ClassLoader parent, Set<PluginWrapper> plugins)
{ {
this.parent = parent; this.parent = parent;
this.plugins = plugins; this.plugins = plugins;
} }
//~--- methods -------------------------------------------------------------- public Set<PluginWrapper> getPlugins() {
return plugins;
/**
* Method description
*
*
* @param servletContextEvent
*/
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent)
{
if ((globalInjector != null) &&!startupError)
{
// close Scheduler
IOUtil.close(globalInjector.getInstance(Scheduler.class));
// close RepositoryManager
IOUtil.close(globalInjector.getInstance(RepositoryManager.class));
// close GroupManager
IOUtil.close(globalInjector.getInstance(GroupManager.class));
// close UserManager
IOUtil.close(globalInjector.getInstance(UserManager.class));
// close CacheManager
IOUtil.close(globalInjector.getInstance(CacheManager.class));
//J-
// call destroy of servlet context listeners
globalInjector.getInstance(ServletContextListenerHolder.class)
.contextDestroyed(servletContextEvent);
//J+
} }
super.contextDestroyed(servletContextEvent); @Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
beforeInjectorCreation();
super.contextInitialized(servletContextEvent);
afterInjectorCreation(servletContextEvent);
} }
/** private void beforeInjectorCreation() {
* Method description upgradeIfNecessary();
* }
*
* @param servletContextEvent
*/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent)
{
this.servletContext = servletContextEvent.getServletContext();
if (SCMContext.getContext().getStartupError() == null) private void upgradeIfNecessary() {
{ if (!hasStartupErrors()) {
UpgradeManager upgradeHandler = new UpgradeManager(); UpgradeManager upgradeHandler = new UpgradeManager();
upgradeHandler.doUpgrade(); upgradeHandler.doUpgrade();
} }
else
{
startupError = true;
} }
super.contextInitialized(servletContextEvent); private boolean hasStartupErrors() {
return SCMContext.getContext().getStartupError() != null;
// call destroy event
if ((globalInjector != null) &&!startupError)
{
//J-
// bind eager singletons
globalInjector.getInstance(EagerSingletonModule.class)
.initialize(globalInjector);
// init servlet context listeners
globalInjector.getInstance(ServletContextListenerHolder.class)
.contextInitialized(servletContextEvent);
//J+
}
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public Set<PluginWrapper> getPlugins()
{
return plugins;
}
/**
* Method description
*
*
* @return
*/
@Override @Override
protected Injector getInjector() protected List<? extends Module> getModules(ServletContext context) {
{ if (hasStartupErrors()) {
if (startupError) return getErrorModules();
{
globalInjector = getErrorInjector();
} }
else return getDefaultModules(context);
{
globalInjector = getDefaultInjector(servletContext);
} }
return globalInjector; private List<? extends Module> getDefaultModules(ServletContext context) {
} DefaultPluginLoader pluginLoader = new DefaultPluginLoader(context, parent, plugins);
//~--- methods -------------------------------------------------------------- ClassOverrides overrides = ClassOverrides.findOverrides(pluginLoader.getUberClassLoader());
/**
* Method description
*
*
* @param ep
* @param moduleList
*/
private void appendModules(ExtensionProcessor ep, List<Module> moduleList)
{
for (Class<? extends Module> module : ep.byExtensionPoint(Module.class))
{
try
{
logger.info("add module {}", module);
moduleList.add(module.newInstance());
}
catch (IllegalAccessException | InstantiationException ex)
{
throw Throwables.propagate(ex);
}
}
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
*
* @param servletCtx
* @return
*/
private Injector getDefaultInjector(ServletContext servletCtx)
{
Stopwatch sw = Stopwatch.createStarted();
DefaultPluginLoader pluginLoader = new DefaultPluginLoader(servletCtx,
parent, plugins);
ClassOverrides overrides =
ClassOverrides.findOverrides(pluginLoader.getUberClassLoader());
List<Module> moduleList = Lists.newArrayList(); List<Module> moduleList = Lists.newArrayList();
moduleList.add(new ScmInitializerModule()); moduleList.add(new ScmInitializerModule());
@@ -257,9 +138,9 @@ public class ScmContextListener extends GuiceServletContextListener
moduleList.add(new EagerSingletonModule()); moduleList.add(new EagerSingletonModule());
moduleList.add(ShiroWebModule.guiceFilterModule()); moduleList.add(ShiroWebModule.guiceFilterModule());
moduleList.add(new WebElementModule(pluginLoader)); moduleList.add(new WebElementModule(pluginLoader));
moduleList.add(new ScmServletModule(servletCtx, pluginLoader, overrides)); moduleList.add(new ScmServletModule(context, pluginLoader, overrides));
moduleList.add( moduleList.add(
new ScmSecurityModule(servletCtx, pluginLoader.getExtensionProcessor()) new ScmSecurityModule(context, pluginLoader.getExtensionProcessor())
); );
appendModules(pluginLoader.getExtensionProcessor(), moduleList); appendModules(pluginLoader.getExtensionProcessor(), moduleList);
moduleList.addAll(overrides.getModules()); moduleList.addAll(overrides.getModules());
@@ -268,41 +149,75 @@ public class ScmContextListener extends GuiceServletContextListener
moduleList.add(new DebugModule()); moduleList.add(new DebugModule());
} }
SCMContextProvider ctx = SCMContext.getContext(); return moduleList;
Injector injector =
Guice.createInjector(ctx.getStage().getInjectionStage(), moduleList);
logger.info("created injector in {}", sw.stop());
return injector;
} }
/** private void appendModules(ExtensionProcessor ep, List<Module> moduleList) {
* Method description for (Class<? extends Module> module : ep.byExtensionPoint(Module.class)) {
* try {
* LOG.info("add module {}", module);
* @return moduleList.add(module.newInstance());
*/ } catch (IllegalAccessException | InstantiationException ex) {
private Injector getErrorInjector() throw Throwables.propagate(ex);
}
}
}
private List<? extends Module> getErrorModules() {
return Collections.singletonList(new ScmErrorModule());
}
@Override
protected void withInjector(Injector injector) {
this.injector = injector;
}
private void afterInjectorCreation(ServletContextEvent event) {
if (injector != null && !hasStartupErrors()) {
bindEagerSingletons();
initializeServletContextListeners(event);
}
}
private void bindEagerSingletons() {
injector.getInstance(EagerSingletonModule.class).initialize(injector);
}
private void initializeServletContextListeners(ServletContextEvent event) {
injector.getInstance(ServletContextListenerHolder.class).contextInitialized(event);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent)
{ {
return Guice.createInjector(new ScmErrorModule()); if (injector != null &&!hasStartupErrors()) {
closeCloseables();
destroyServletContextListeners(servletContextEvent);
} }
//~--- fields --------------------------------------------------------------- super.contextDestroyed(servletContextEvent);
}
/** Field description */
private final ClassLoader parent; private void closeCloseables() {
// close Scheduler
/** Field description */ IOUtil.close(injector.getInstance(Scheduler.class));
private final Set<PluginWrapper> plugins;
// close RepositoryManager
/** Field description */ IOUtil.close(injector.getInstance(RepositoryManager.class));
private Injector globalInjector;
// close GroupManager
/** Field description */ IOUtil.close(injector.getInstance(GroupManager.class));
private ServletContext servletContext;
// close UserManager
/** Field description */ IOUtil.close(injector.getInstance(UserManager.class));
private boolean startupError = false;
// close CacheManager
IOUtil.close(injector.getInstance(CacheManager.class));
}
private void destroyServletContextListeners(ServletContextEvent event) {
injector.getInstance(ServletContextListenerHolder.class).contextDestroyed(event);
}
} }

View File

@@ -35,17 +35,16 @@ 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.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.api.rest.UriExtensionsConfig;
import sonia.scm.cache.CacheManager; 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;
@@ -114,14 +113,6 @@ import sonia.scm.web.security.DefaultAdministrationContext;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
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.spi.container.servlet.ServletContainer;
import java.util.Map;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.store.ConfigurationStoreFactory;
@@ -144,7 +135,7 @@ 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 */
@@ -366,30 +357,6 @@ public class ScmServletModule extends JerseyServletModule
// bind events // bind events
// bind(LastModifiedUpdateListener.class); // bind(LastModifiedUpdateListener.class);
// jersey
Map<String, String> params = Maps.newHashMap();
/*
* params.put("com.sun.jersey.spi.container.ContainerRequestFilters",
* "com.sun.jersey.api.container.filter.LoggingFilter");
* params.put("com.sun.jersey.spi.container.ContainerResponseFilters",
* "com.sun.jersey.api.container.filter.LoggingFilter");
* params.put("com.sun.jersey.config.feature.Trace", "true");
* params.put("com.sun.jersey.config.feature.TracePerRequest", "true");
*/
params.put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE.toString());
params.put(ResourceConfig.FEATURE_REDIRECT, 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,
UriExtensionsConfig.class.getName());
params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "unbound");
serve(PATTERN_RESTAPI).with(GuiceContainer.class, params);
} }
/** /**

View File

@@ -42,65 +42,50 @@ 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 ViewProcessor<String> public class TemplateEngineViewable implements MessageBodyWriter<Viewable>
{ {
/** 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 String resolve(String name) public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
{ return type.isAssignableFrom(Viewable.class);
return name;
} }
/**
* Method description
*
*
* @param path
* @param viewable
* @param out
*
* @throws IOException
*/
@Override @Override
public void writeTo(String path, Viewable viewable, OutputStream out) public long getSize(Viewable viewable, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
throws IOException return -1;
{ }
@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)
@@ -115,14 +100,9 @@ public class TemplateEngineViewable implements ViewProcessor<String>
throw new IOException("could not find template for ".concat(path)); throw new IOException("could not find template for ".concat(path));
} }
PrintWriter writer = new PrintWriter(out); PrintWriter writer = new PrintWriter(entityStream);
template.execute(writer, viewable.getModel()); template.execute(writer, viewable.getContext());
writer.flush(); writer.flush();
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private TemplateEngineFactory templateEngineFactory;
} }

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_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<Permission> getAll() public List<Permission> getAll()
{ {
return getPermissions(getPredicate()); return getPermissions(getPredicate());

View File

@@ -93,7 +93,7 @@ import sonia.scm.security.Scope;
*/ */
@Singleton @Singleton
@Path("auth") @Path("auth")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class AuthenticationResource public class AuthenticationResource
{ {

View File

@@ -117,7 +117,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@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_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@TypeHint(Group[].class) @TypeHint(Group[].class)
@StatusCodes({ @StatusCodes({
@ResponseCode(code = 200, condition = "success"), @ResponseCode(code = 200, condition = "success"),

View File

@@ -52,7 +52,6 @@ import sonia.scm.plugin.PluginManager;
//~--- 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;
@@ -66,6 +65,7 @@ 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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response install( public Response install(
@FormDataParam("package") InputStream uploadedInputStream) /*@FormParam("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(
@FormDataParam("package") InputStream uploadedInputStream) /*@FormParam("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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Collection<PluginInformation> getOverview() public Collection<PluginInformation> getOverview()
{ {
//J- //J-

View File

@@ -69,8 +69,6 @@ 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;
@@ -89,6 +87,7 @@ 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;
@@ -111,7 +110,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
{ {
@@ -170,8 +169,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, @FormDataParam("name") String name, @PathParam("type") String type, @FormParam("name") String name,
@FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed") @FormParam("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,
@@ -211,8 +210,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,
@FormDataParam("name") String name, @FormParam("name") String name,
@FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed") @FormParam("bundle") InputStream inputStream, @QueryParam("compressed")
@DefaultValue("false") boolean compressed) @DefaultValue("false") boolean compressed)
{ {
Response response; Response response;
@@ -260,7 +259,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_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response importFromUrl(@Context UriInfo uriInfo, public Response importFromUrl(@Context UriInfo uriInfo,
@PathParam("type") String type, UrlImportRequest request) @PathParam("type") String type, UrlImportRequest request)
{ {
@@ -320,7 +319,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response importRepositories(@PathParam("type") String type) public Response importRepositories(@PathParam("type") String type)
{ {
SecurityUtils.getSubject().checkRole(Role.ADMIN); SecurityUtils.getSubject().checkRole(Role.ADMIN);
@@ -352,7 +351,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response importRepositories() public Response importRepositories()
{ {
SecurityUtils.getSubject().checkRole(Role.ADMIN); SecurityUtils.getSubject().checkRole(Role.ADMIN);
@@ -394,7 +393,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response importRepositoriesFromDirectory( public Response importRepositoriesFromDirectory(
@PathParam("type") String type) @PathParam("type") String type)
{ {
@@ -435,7 +434,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(Status.BAD_REQUEST).build(); response = Response.status(Response.Status.BAD_REQUEST).build();
} }
catch (IOException ex) catch (IOException ex)
{ {
@@ -451,7 +450,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(Status.BAD_REQUEST).build(); response = Response.status(Response.Status.BAD_REQUEST).build();
} }
return response; return response;
@@ -475,7 +474,7 @@ public class RepositoryImportResource
), ),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getImportableTypes() public Response getImportableTypes()
{ {
SecurityUtils.getSubject().checkRole(Role.ADMIN); SecurityUtils.getSubject().checkRole(Role.ADMIN);

View File

@@ -163,7 +163,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_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Override @Override
public Response create(@Context UriInfo uriInfo, Repository repository) public Response create(@Context UriInfo uriInfo, Repository repository)
{ {
@@ -288,7 +288,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_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@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)
{ {
@@ -307,7 +307,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
*/ */
@GET @GET
@Path("{id}") @Path("{id}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@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"),
@@ -332,7 +332,7 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
* @return all repositories * @return all repositories
*/ */
@GET @GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@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")
@@ -369,7 +369,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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
@@ -441,7 +441,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getBranches(@PathParam("id") String id) public Response getBranches(@PathParam("id") String id)
throws RepositoryException, IOException throws RepositoryException, IOException
{ {
@@ -503,7 +503,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
//J- //J-
public Response getBrowserResult( public Response getBrowserResult(
@PathParam("id") String id, @PathParam("id") String id,
@@ -583,7 +583,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getByTypeAndName(@PathParam("type") String type, public Response getByTypeAndName(@PathParam("type") String type,
@PathParam("name") String name) @PathParam("name") String name)
{ {
@@ -624,7 +624,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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
@@ -696,7 +696,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
//J- //J-
public Response getChangesets( public Response getChangesets(
@PathParam("id") String id, @PathParam("id") String id,
@@ -936,7 +936,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getTags(@PathParam("id") String id) public Response getTags(@PathParam("id") String id)
throws RepositoryException, IOException throws RepositoryException, IOException
{ {

View File

@@ -50,8 +50,6 @@ 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;
@@ -67,6 +65,7 @@ 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;
/** /**
* *
@@ -76,17 +75,13 @@ import javax.ws.rs.core.MediaType;
public class RepositoryRootResource public class RepositoryRootResource
{ {
/** Field description */ private static final String TEMPLATE = "/templates/repository-root.mustache";
public static final String TEMPLATE = "/templates/repository-root.mustache";
//~--- constructors --------------------------------------------------------- private final RepositoryManager repositoryManager;
/** /**
* Constructs ... * Constructs ...
* *
*
*
* @param templateHandler
* @param repositoryManager * @param repositoryManager
*/ */
@Inject @Inject
@@ -330,10 +325,4 @@ public class RepositoryRootResource
/** Field description */ /** Field description */
private UrlProvider urlProvider; private UrlProvider urlProvider;
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private RepositoryManager repositoryManager;
} }

View File

@@ -153,7 +153,7 @@ public class SearchResource
@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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public SearchResults searchGroups(@QueryParam("query") String queryString) public SearchResults searchGroups(@QueryParam("query") String queryString)
{ {
return groupSearchHandler.search(queryString, return groupSearchHandler.search(queryString,
@@ -188,7 +188,7 @@ public class SearchResource
@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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public SearchResults searchUsers(@QueryParam("query") String queryString) public SearchResults searchUsers(@QueryParam("query") String queryString)
{ {
return userSearchHandler.search(queryString, return userSearchHandler.search(queryString,

View File

@@ -55,8 +55,6 @@ import sonia.scm.util.SystemUtil;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.view.Viewable;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -71,6 +69,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.template.Viewable;
/** /**
* *

View File

@@ -124,7 +124,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)
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Override @Override
public Response create(@Context UriInfo uriInfo, User user) public Response create(@Context UriInfo uriInfo, User user)
{ {
@@ -169,7 +169,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)
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@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)
@@ -196,7 +196,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Override @Override
public Response get(@Context Request request, @PathParam("id") String id) public Response get(@Context Request request, @PathParam("id") String id)
{ {
@@ -232,7 +232,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_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@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_XML, MediaType.APPLICATION_JSON}) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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_XML, MediaType.APPLICATION_JSON}) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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,13 +33,15 @@ package sonia.scm.net.ahc;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.ByteSource; 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 org.codehaus.jackson.map.AnnotationIntrospector; import com.google.common.io.ByteSource;
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.Extension; import sonia.scm.plugin.Extension;
import sonia.scm.util.IOUtil; import sonia.scm.util.IOUtil;
@@ -73,12 +75,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(); AnnotationIntrospector jaxb = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
this.mapper.setAnnotationIntrospector(new AnnotationIntrospector.Pair(jackson, jaxb)); this.mapper.setAnnotationIntrospector(new AnnotationIntrospectorPair(jackson, jaxb));
// do not fail on unknown json properties // do not fail on unknown json properties
this.mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------

View File

@@ -67,7 +67,7 @@ public class ApiAuthenticationFilter extends AuthenticationFilter
{ {
/** login uri */ /** login uri */
public static final String URI_LOGIN = "/api/rest/authentication/login"; public static final String URI_LOGIN = "/api/rest/auth/access_token";
//~--- constructors --------------------------------------------------------- //~--- constructors ---------------------------------------------------------

View File

@@ -93,6 +93,8 @@
<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

@@ -39,12 +39,10 @@
<display-name>SCM-Manager ${project.version}</display-name> <display-name>SCM-Manager ${project.version}</display-name>
<listener> <!-- bootstraping -->
<listener-class>sonia.scm.boot.BootstrapContextListener</listener-class>
</listener>
<listener> <listener>
<listener-class>sonia.scm.HttpSessionListenerHolder</listener-class> <listener-class>sonia.scm.boot.BootstrapContextListener</listener-class>
</listener> </listener>
<filter> <filter>
@@ -57,6 +55,36 @@
<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.json', url: restUrl + 'action/change-password',
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.json', url: restUrl + 'config',
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.json', url: restUrl + 'config',
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) + '.json'; var url = restUrl + 'groups/' + encodeURIComponent(group.name);
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.json'; var url = restUrl + 'groups';
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) + '.json'; var url = restUrl + 'groups/' + encodeURIComponent(item.name);
Ext.MessageBox.show({ Ext.MessageBox.show({
title: this.removeTitleText, title: this.removeTitleText,

View File

@@ -61,7 +61,7 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{
var config = { var config = {
labelWidth: 120, labelWidth: 120,
url: restUrl + "auth/access_token.json", url: restUrl + "auth/access_token",
frame: true, frame: true,
title: this.titleText, title: this.titleText,
defaultType: 'textfield', defaultType: 'textfield',

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 + '.json', url: restUrl + 'plugins/install/' + pluginId,
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 + '.json', url: restUrl + 'plugins/uninstall/' + pluginId,
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 + '.json', url: restUrl + 'plugins/update/' + pluginId,
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.json', url: restUrl + 'plugins/overview',
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.json', url: restUrl + 'repositories/' + this.repositoryId + '/branches',
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.json'; this.url = restUrl + 'repositories/' + this.repository.id + '/changesets';
} }
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 + '.json', url: restUrl + 'repositories/' + this.repository.id + '/changeset/' + this.revision,
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 + '.json'; var url = restUrl + 'repositories/' + item.id;
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.json'; var url = restUrl + 'repositories';
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.json', url: restUrl + 'repositories',
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.json'; var url = restUrl + 'repositories/' + this.repository.id + '/healthcheck';
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.json', url: restUrl + 'import/repositories/' + this.repositoryType + '/url',
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.json', url: restUrl + 'import/repositories/' + this.repositoryType + '/directory',
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 + '.json', url: restUrl + 'repositories/' + id,
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 + '.json'; var url = restUrl + 'repositories/' + item.id;
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 + '.json'; var url = restUrl + 'repositories/' + item.id;
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 + '/browse.json', url: restUrl + 'repositories/' + this.repository.id,
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.json', url: restUrl + 'repositories/' + this.repositoryId + '/tags',
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 + '.json' read: restUrl + this.baseUrl
}, },
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 + '.json', url: restUrl + this.baseUrl,
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) + '.json', url: restUrl + this.baseUrl + '/' + encodeURIComponent(id),
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')) + '.json', url: restUrl + this.baseUrl + '/' + encodeURIComponent(record.get('id')),
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.json', url: restUrl + 'search/users',
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.json', url: restUrl + 'search/groups',
method: 'GET' method: 'GET'
}) })
}); });

View File

@@ -339,7 +339,7 @@ Sonia.scm.Main = Ext.extend(Ext.util.Observable, {
checkLogin: function(){ checkLogin: function(){
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'auth/state.json', url: restUrl + 'auth/state',
method: 'GET', method: 'GET',
scope: this, scope: this,
success: function(response){ success: function(response){
@@ -367,7 +367,7 @@ Sonia.scm.Main = Ext.extend(Ext.util.Observable, {
logout: function(){ logout: function(){
Ext.Ajax.request({ Ext.Ajax.request({
url: restUrl + 'auth/logout.json', url: restUrl + 'auth/logout',
method: 'GET', method: 'GET',
scope: this, scope: this,
success: function(response){ success: function(response){

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) + '.json'; var url = restUrl + 'users/' + encodeURIComponent(item.name);
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.json'; var url = restUrl + 'users';
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.json', url: restUrl + 'users',
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) + '.json'; var url = restUrl + 'users/' + encodeURIComponent(item.name);
Ext.MessageBox.show({ Ext.MessageBox.show({
title: this.removeTitleText, title: this.removeTitleText,

View File

@@ -32,6 +32,9 @@
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;
@@ -41,8 +44,6 @@ 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;
@@ -81,7 +82,7 @@ public class GitLfsITCase {
private Repository repository; private Repository repository;
public GitLfsITCase() { public GitLfsITCase() {
mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector()); mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()));
} }
// lifecycle methods // lifecycle methods