Merged in feature/errorhandling (pull request #99)

Feature Error Handling
This commit is contained in:
Sebastian Sdorra
2018-11-08 09:36:18 +00:00
139 changed files with 1122 additions and 2010 deletions

View File

@@ -1,11 +1,34 @@
package sonia.scm;
public class AlreadyExistsException extends Exception {
import java.util.List;
public AlreadyExistsException(String message) {
super(message);
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.joining;
public class AlreadyExistsException extends ExceptionWithContext {
private static final String CODE = "FtR7UznKU1";
public AlreadyExistsException(ModelObject object) {
this(singletonList(new ContextEntry(object.getClass(), object.getId())));
}
public AlreadyExistsException() {
public static AlreadyExistsException alreadyExists(ContextEntry.ContextBuilder builder) {
return new AlreadyExistsException(builder.build());
}
private AlreadyExistsException(List<ContextEntry> context) {
super(context, createMessage(context));
}
@Override
public String getCode() {
return CODE;
}
private static String createMessage(List<ContextEntry> context) {
return context.stream()
.map(c -> c.getType().toLowerCase() + " with id " + c.getId())
.collect(joining(" in ", "", " already exists"));
}
}

View File

@@ -1,4 +1,34 @@
package sonia.scm;
public class ConcurrentModificationException extends Exception {
import java.util.Collections;
import java.util.List;
import static java.util.stream.Collectors.joining;
public class ConcurrentModificationException extends ExceptionWithContext {
private static final String CODE = "2wR7UzpPG1";
public ConcurrentModificationException(Class type, String id) {
this(Collections.singletonList(new ContextEntry(type, id)));
}
public ConcurrentModificationException(String type, String id) {
this(Collections.singletonList(new ContextEntry(type, id)));
}
private ConcurrentModificationException(List<ContextEntry> context) {
super(context, createMessage(context));
}
@Override
public String getCode() {
return CODE;
}
private static String createMessage(List<ContextEntry> context) {
return context.stream()
.map(c -> c.getType().toLowerCase() + " with id " + c.getId())
.collect(joining(" in ", "", " has been modified concurrently"));
}
}

View File

@@ -0,0 +1,84 @@
package sonia.scm;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository;
import sonia.scm.util.AssertUtil;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class ContextEntry {
private final String type;
private final String id;
ContextEntry(Class type, String id) {
this(type.getSimpleName(), id);
}
ContextEntry(String type, String id) {
AssertUtil.assertIsNotEmpty(type);
AssertUtil.assertIsNotEmpty(id);
this.type = type;
this.id = id;
}
public String getType() {
return type;
}
public String getId() {
return id;
}
public static class ContextBuilder {
private final List<ContextEntry> context = new LinkedList<>();
public static List<ContextEntry> noContext() {
return new ContextBuilder().build();
}
public static List<ContextEntry> only(String type, String id) {
return new ContextBuilder().in(type, id).build();
}
public static ContextBuilder entity(Repository repository) {
return new ContextBuilder().in(repository.getNamespaceAndName());
}
public static ContextBuilder entity(NamespaceAndName namespaceAndName) {
return new ContextBuilder().in(Repository.class, namespaceAndName.logString());
}
public static ContextBuilder entity(Class type, String id) {
return new ContextBuilder().in(type, id);
}
public static ContextBuilder entity(String type, String id) {
return new ContextBuilder().in(type, id);
}
public ContextBuilder in(Repository repository) {
return in(repository.getNamespaceAndName());
}
public ContextBuilder in(NamespaceAndName namespaceAndName) {
return this.in(Repository.class, namespaceAndName.logString());
}
public ContextBuilder in(Class type, String id) {
context.add(new ContextEntry(type, id));
return this;
}
public ContextBuilder in(String type, String id) {
context.add(new ContextEntry(type, id));
return this;
}
public List<ContextEntry> build() {
return Collections.unmodifiableList(context);
}
}
}

View File

@@ -0,0 +1,26 @@
package sonia.scm;
import java.util.List;
import static java.util.Collections.unmodifiableList;
public abstract class ExceptionWithContext extends RuntimeException {
private final List<ContextEntry> context;
public ExceptionWithContext(List<ContextEntry> context, String message) {
super(message);
this.context = context;
}
public ExceptionWithContext(List<ContextEntry> context, String message, Exception cause) {
super(message, cause);
this.context = context;
}
public List<ContextEntry> getContext() {
return unmodifiableList(context);
}
public abstract String getCode();
}

View File

@@ -54,25 +54,21 @@ public interface HandlerBase<T extends TypedObject>
*
* @return The persisted object.
*/
T create(T object) throws AlreadyExistsException;
T create(T object);
/**
* Removes a persistent object.
*
*
* @param object to delete
*
* @throws IOException
*/
void delete(T object) throws NotFoundException;
void delete(T object);
/**
* Modifies a persistent object.
*
*
* @param object to modify
*
* @throws IOException
*/
void modify(T object) throws NotFoundException;
void modify(T object);
}

View File

@@ -58,7 +58,7 @@ public interface Manager<T extends ModelObject>
*
* @throws NotFoundException
*/
void refresh(T object) throws NotFoundException;
void refresh(T object);
//~--- get methods ----------------------------------------------------------

View File

@@ -66,7 +66,7 @@ public class ManagerDecorator<T extends ModelObject> implements Manager<T> {
}
@Override
public T create(T object) throws AlreadyExistsException {
public T create(T object) {
return decorated.create(object);
}

View File

@@ -1,10 +1,38 @@
package sonia.scm;
public class NotFoundException extends RuntimeException {
public NotFoundException(String type, String id) {
super(type + " with id '" + id + "' not found");
import java.util.Collections;
import java.util.List;
import static java.util.stream.Collectors.joining;
public class NotFoundException extends ExceptionWithContext {
private static final String CODE = "AGR7UzkhA1";
public NotFoundException(Class type, String id) {
this(Collections.singletonList(new ContextEntry(type, id)));
}
public NotFoundException() {
public NotFoundException(String type, String id) {
this(Collections.singletonList(new ContextEntry(type, id)));
}
public static NotFoundException notFound(ContextEntry.ContextBuilder contextBuilder) {
return new NotFoundException(contextBuilder.build());
}
private NotFoundException(List<ContextEntry> context) {
super(context, createMessage(context));
}
@Override
public String getCode() {
return CODE;
}
private static String createMessage(List<ContextEntry> context) {
return context.stream()
.map(c -> c.getType().toLowerCase() + " with id " + c.getId())
.collect(joining(" in ", "could not find ", ""));
}
}

View File

@@ -33,33 +33,30 @@
package sonia.scm;
import java.util.Collections;
/**
*
* @author Sebastian Sdorra
* @version 1.6
*/
public class NotSupportedFeatuerException extends Exception
{
public class NotSupportedFeatureException extends ExceptionWithContext {
/** Field description */
private static final long serialVersionUID = 256498734456613496L;
//~--- constructors ---------------------------------------------------------
private static final String CODE = "9SR8G0kmU1";
/**
* Constructs ...
*
*/
public NotSupportedFeatuerException() {}
/**
* Constructs ...
*
*
* @param message
*/
public NotSupportedFeatuerException(String message)
public NotSupportedFeatureException(String feature)
{
super(message);
super(Collections.emptyList(),createMessage(feature));
}
@Override
public String getCode() {
return CODE;
}
private static String createMessage(String feature) {
return "feature " + feature + " is not supported by this repository";
}
}

View File

@@ -37,7 +37,6 @@ package sonia.scm.repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.AlreadyExistsException;
import sonia.scm.repository.ImportResult.Builder;
import java.io.File;
@@ -243,7 +242,7 @@ public abstract class AbstactImportHandler implements AdvancedImportHandler
*/
private void importRepository(RepositoryManager manager,
String repositoryName)
throws IOException, AlreadyExistsException {
throws IOException {
Repository repository =
createRepository(getRepositoryDirectory(repositoryName), repositoryName);

View File

@@ -38,7 +38,7 @@ package sonia.scm.repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.NotSupportedFeatuerException;
import sonia.scm.NotSupportedFeatureException;
import sonia.scm.SCMContextProvider;
import sonia.scm.event.ScmEventBus;
@@ -165,13 +165,12 @@ public abstract class AbstractRepositoryHandler<C extends RepositoryConfig>
*
* @return
*
* @throws NotSupportedFeatuerException
* @throws NotSupportedFeatureException
*/
@Override
public ImportHandler getImportHandler() throws NotSupportedFeatuerException
public ImportHandler getImportHandler() throws NotSupportedFeatureException
{
throw new NotSupportedFeatuerException(
"import handler is not supported by this repository handler");
throw new NotSupportedFeatureException("import");
}
/**

View File

@@ -40,6 +40,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.AlreadyExistsException;
import sonia.scm.ConfigurationException;
import sonia.scm.ContextEntry;
import sonia.scm.io.CommandResult;
import sonia.scm.io.ExtendedCommand;
import sonia.scm.io.FileSystem;
@@ -81,14 +82,14 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
}
@Override
public Repository create(Repository repository) throws AlreadyExistsException {
public Repository create(Repository repository) {
File directory = getDirectory(repository);
if (directory.exists()) {
throw new AlreadyExistsException();
throw new AlreadyExistsException(repository);
}
checkPath(directory);
checkPath(directory, repository);
try {
fileSystem.create(directory);
@@ -128,7 +129,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
try {
fileSystem.destroy(directory);
} catch (IOException e) {
throw new InternalRepositoryException("could not delete repository directory", e);
throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("directory", directory.toString()).in(repository), "could not delete repository directory", e);
}
cleanupEmptyDirectories(config.getRepositoryDirectory(),
directory.getParentFile());
@@ -201,7 +202,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
}
protected void create(Repository repository, File directory)
throws IOException, AlreadyExistsException {
throws IOException {
ExtendedCommand cmd = buildCreateCommand(repository, directory);
CommandResult result = cmd.execute();
@@ -256,9 +257,9 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
* Check path for existing repositories
*
* @param directory repository target directory
* @throws AlreadyExistsException
* @throws RuntimeException when the parent directory already is a repository
*/
private void checkPath(File directory) throws AlreadyExistsException {
private void checkPath(File directory, Repository repository) {
File repositoryDirectory = config.getRepositoryDirectory();
File parent = directory.getParentFile();
@@ -266,9 +267,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
logger.trace("check {} for existing repository", parent);
if (isRepository(parent)) {
logger.error("parent path {} is a repository", parent);
throw new AlreadyExistsException();
throw new InternalRepositoryException(repository, "parent path " + parent + " is a repository");
}
parent = parent.getParentFile();

View File

@@ -1,15 +1,34 @@
package sonia.scm.repository;
public class InternalRepositoryException extends RuntimeException {
public InternalRepositoryException(Throwable ex) {
super(ex);
import sonia.scm.ContextEntry;
import sonia.scm.ExceptionWithContext;
import java.util.List;
public class InternalRepositoryException extends ExceptionWithContext {
public InternalRepositoryException(ContextEntry.ContextBuilder context, String message) {
this(context, message, null);
}
public InternalRepositoryException(String msg, Exception ex) {
super(msg, ex);
public InternalRepositoryException(ContextEntry.ContextBuilder context, String message, Exception cause) {
this(context.build(), message, cause);
}
public InternalRepositoryException(String message) {
super(message);
public InternalRepositoryException(Repository repository, String message) {
this(ContextEntry.ContextBuilder.entity(repository), message, null);
}
public InternalRepositoryException(Repository repository, String message, Exception cause) {
this(ContextEntry.ContextBuilder.entity(repository), message, cause);
}
public InternalRepositoryException(List<ContextEntry> context, String message, Exception cause) {
super(context, message, cause);
}
@Override
public String getCode() {
return null;
}
}

View File

@@ -25,9 +25,13 @@ public class NamespaceAndName implements Comparable<NamespaceAndName> {
return name;
}
public String logString() {
return getNamespace() + "/" + getName();
}
@Override
public String toString() {
return getNamespace() + "/" + getName();
return logString();
}
@Override

View File

@@ -1,84 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.NotFoundException;
import sonia.scm.util.Util;
/**
* Signals that the specified path could be found.
*
* @author Sebastian Sdorra
*/
public class PathNotFoundException extends NotFoundException
{
/** Field description */
private static final long serialVersionUID = 4629690181172951809L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new {@link PathNotFoundException}
* with the specified path.
*
*
* @param path path which could not be found
*/
public PathNotFoundException(String path)
{
super("path", Util.nonNull(path));
this.path = Util.nonNull(path);
}
//~--- get methods ----------------------------------------------------------
/**
* Return the path which could not be found.
*
*
* @return path which could not be found
*/
public String getPath()
{
return path;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private String path;
}

View File

@@ -36,7 +36,7 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.Handler;
import sonia.scm.NotSupportedFeatuerException;
import sonia.scm.NotSupportedFeatureException;
import sonia.scm.plugin.ExtensionPoint;
/**
@@ -70,9 +70,9 @@ public interface RepositoryHandler
* @return {@link ImportHandler} for the repository type of this handler
* @since 1.12
*
* @throws NotSupportedFeatuerException
* @throws NotSupportedFeatureException
*/
public ImportHandler getImportHandler() throws NotSupportedFeatuerException;
public ImportHandler getImportHandler() throws NotSupportedFeatureException;
/**
* Returns informations about the version of the RepositoryHandler.

View File

@@ -35,7 +35,6 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.AlreadyExistsException;
import sonia.scm.TypeManager;
import java.io.IOException;
@@ -73,7 +72,7 @@ public interface RepositoryManager
*
* @throws IOException
*/
public void importRepository(Repository repository) throws IOException, AlreadyExistsException;
public void importRepository(Repository repository) throws IOException;
//~--- get methods ----------------------------------------------------------

View File

@@ -35,7 +35,6 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.AlreadyExistsException;
import sonia.scm.ManagerDecorator;
import sonia.scm.Type;
@@ -82,7 +81,7 @@ public class RepositoryManagerDecorator
* {@inheritDoc}
*/
@Override
public void importRepository(Repository repository) throws IOException, AlreadyExistsException {
public void importRepository(Repository repository) throws IOException {
decorated.importRepository(repository);
}

View File

@@ -1,68 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository;
import sonia.scm.NotFoundException;
/**
* Signals that the specified {@link Repository} could be found.
*
* @author Sebastian Sdorra
* @since 1.6
*/
public class RepositoryNotFoundException extends NotFoundException
{
private static final long serialVersionUID = -6583078808900520166L;
private static final String TYPE_REPOSITORY = "repository";
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new {@link RepositoryNotFoundException} with null as its
* error detail message.
*
*/
public RepositoryNotFoundException(Repository repository) {
super(TYPE_REPOSITORY, repository.getName() + "/" + repository.getNamespace());
}
public RepositoryNotFoundException(String repositoryId) {
super(TYPE_REPOSITORY, repositoryId);
}
public RepositoryNotFoundException(NamespaceAndName namespaceAndName) {
super(TYPE_REPOSITORY, namespaceAndName.toString());
}
}

View File

@@ -1,83 +0,0 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.NotFoundException;
import sonia.scm.util.Util;
/**
* Signals that the specified revision could be found.
*
* @author Sebastian Sdorra
*/
public class RevisionNotFoundException extends NotFoundException {
/** Field description */
private static final long serialVersionUID = -5594008535358811998L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new {@link RevisionNotFoundException}
* with the specified revision.
*
*
* @param revision revision which could not be found
*/
public RevisionNotFoundException(String revision)
{
super("revision", revision);
this.revision = Util.nonNull(revision);
}
//~--- get methods ----------------------------------------------------------
/**
* Return the revision which could not be found.
*
*
* @return revision which could not be found
*/
public String getRevision()
{
return revision;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private String revision;
}

View File

@@ -38,7 +38,6 @@ package sonia.scm.repository.api;
import com.google.common.base.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.NotFoundException;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.repository.BrowserResult;
@@ -46,7 +45,6 @@ import sonia.scm.repository.FileObject;
import sonia.scm.repository.PreProcessorUtil;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryCacheKey;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.spi.BrowseCommand;
import sonia.scm.repository.spi.BrowseCommandRequest;
@@ -136,7 +134,7 @@ public final class BrowseCommandBuilder
*
* @throws IOException
*/
public BrowserResult getBrowserResult() throws IOException, NotFoundException {
public BrowserResult getBrowserResult() throws IOException {
BrowserResult result = null;
if (disableCache)

View File

@@ -37,9 +37,7 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.spi.CatCommand;
import sonia.scm.repository.spi.CatCommandRequest;
import sonia.scm.util.IOUtil;
@@ -107,7 +105,7 @@ public final class CatCommandBuilder
* @param outputStream output stream for the content
* @param path file path
*/
public void retriveContent(OutputStream outputStream, String path) throws IOException, PathNotFoundException, RevisionNotFoundException {
public void retriveContent(OutputStream outputStream, String path) throws IOException {
getCatResult(outputStream, path);
}
@@ -116,7 +114,7 @@ public final class CatCommandBuilder
*
* @param path file path
*/
public InputStream getStream(String path) throws IOException, PathNotFoundException, RevisionNotFoundException {
public InputStream getStream(String path) throws IOException {
Preconditions.checkArgument(!Strings.isNullOrEmpty(path),
"path is required");
@@ -139,7 +137,7 @@ public final class CatCommandBuilder
*
* @throws IOException
*/
public String getContent(String path) throws IOException, PathNotFoundException, RevisionNotFoundException {
public String getContent(String path) throws IOException {
String content = null;
ByteArrayOutputStream baos = null;
@@ -186,7 +184,7 @@ public final class CatCommandBuilder
* @throws IOException
*/
private void getCatResult(OutputStream outputStream, String path)
throws IOException, PathNotFoundException, RevisionNotFoundException {
throws IOException {
Preconditions.checkNotNull(outputStream, "OutputStream is required");
Preconditions.checkArgument(!Strings.isNullOrEmpty(path),
"path is required");

View File

@@ -38,7 +38,6 @@ package sonia.scm.repository.api;
import com.google.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.spi.DiffCommand;
import sonia.scm.repository.spi.DiffCommandRequest;
import sonia.scm.util.IOUtil;
@@ -104,7 +103,7 @@ public final class DiffCommandBuilder
*
* @throws IOException
*/
public DiffCommandBuilder retrieveContent(OutputStream outputStream) throws IOException, RevisionNotFoundException {
public DiffCommandBuilder retrieveContent(OutputStream outputStream) throws IOException {
getDiffResult(outputStream);
return this;
@@ -119,7 +118,7 @@ public final class DiffCommandBuilder
*
* @throws IOException
*/
public String getContent() throws IOException, RevisionNotFoundException {
public String getContent() throws IOException {
String content = null;
ByteArrayOutputStream baos = null;
@@ -199,7 +198,7 @@ public final class DiffCommandBuilder
*
* @throws IOException
*/
private void getDiffResult(OutputStream outputStream) throws IOException, RevisionNotFoundException {
private void getDiffResult(OutputStream outputStream) throws IOException {
Preconditions.checkNotNull(outputStream, "OutputStream is required");
Preconditions.checkArgument(request.isValid(),
"path and/or revision is required");

View File

@@ -46,7 +46,6 @@ import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.PreProcessorUtil;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryCacheKey;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.spi.LogCommand;
import sonia.scm.repository.spi.LogCommandRequest;
@@ -165,7 +164,7 @@ public final class LogCommandBuilder
*
* @throws IOException
*/
public Changeset getChangeset(String id) throws IOException, RevisionNotFoundException {
public Changeset getChangeset(String id) throws IOException {
Changeset changeset;
if (disableCache)
@@ -224,7 +223,7 @@ public final class LogCommandBuilder
*
* @throws IOException
*/
public ChangesetPagingResult getChangesets() throws IOException, RevisionNotFoundException {
public ChangesetPagingResult getChangesets() throws IOException {
ChangesetPagingResult cpr;
if (disableCache)

View File

@@ -13,7 +13,6 @@ import sonia.scm.repository.Modifications;
import sonia.scm.repository.PreProcessorUtil;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryCacheKey;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.spi.ModificationsCommand;
import sonia.scm.repository.spi.ModificationsCommandRequest;
@@ -67,7 +66,7 @@ public final class ModificationsCommandBuilder {
return this;
}
public Modifications getModifications() throws IOException, RevisionNotFoundException {
public Modifications getModifications() throws IOException {
Modifications modifications;
if (disableCache) {
log.info("Get modifications for {} with disabled cache", request);

View File

@@ -45,6 +45,7 @@ import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.HandlerEventType;
import sonia.scm.NotFoundException;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.config.ScmConfiguration;
@@ -57,7 +58,6 @@ import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryCacheKeyPredicate;
import sonia.scm.repository.RepositoryEvent;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RepositoryPermissions;
import sonia.scm.repository.spi.RepositoryServiceProvider;
import sonia.scm.repository.spi.RepositoryServiceResolver;
@@ -65,6 +65,9 @@ import sonia.scm.security.ScmSecurityException;
import java.util.Set;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
//~--- JDK imports ------------------------------------------------------------
/**
@@ -161,7 +164,7 @@ public final class RepositoryServiceFactory
* @return a implementation of RepositoryService
* for the given type of repository
*
* @throws RepositoryNotFoundException if no repository
* @throws NotFoundException if no repository
* with the given id is available
* @throws RepositoryServiceNotFoundException if no repository service
* implementation for this kind of repository is available
@@ -169,7 +172,7 @@ public final class RepositoryServiceFactory
* @throws ScmSecurityException if current user has not read permissions
* for that repository
*/
public RepositoryService create(String repositoryId) throws RepositoryNotFoundException {
public RepositoryService create(String repositoryId) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(repositoryId),
"a non empty repositoryId is required");
@@ -177,7 +180,7 @@ public final class RepositoryServiceFactory
if (repository == null)
{
throw new RepositoryNotFoundException(repositoryId);
throw new NotFoundException(Repository.class, repositoryId);
}
return create(repository);
@@ -192,7 +195,7 @@ public final class RepositoryServiceFactory
* @return a implementation of RepositoryService
* for the given type of repository
*
* @throws RepositoryNotFoundException if no repository
* @throws NotFoundException if no repository
* with the given id is available
* @throws RepositoryServiceNotFoundException if no repository service
* implementation for this kind of repository is available
@@ -201,7 +204,6 @@ public final class RepositoryServiceFactory
* for that repository
*/
public RepositoryService create(NamespaceAndName namespaceAndName)
throws RepositoryNotFoundException
{
Preconditions.checkArgument(namespaceAndName != null,
"a non empty namespace and name is required");
@@ -210,7 +212,7 @@ public final class RepositoryServiceFactory
if (repository == null)
{
throw new RepositoryNotFoundException(namespaceAndName);
throw notFound(entity(namespaceAndName));
}
return create(repository);

View File

@@ -35,7 +35,6 @@ package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.NotFoundException;
import sonia.scm.repository.BrowserResult;
import java.io.IOException;
@@ -60,5 +59,5 @@ public interface BrowseCommand
*
* @throws IOException
*/
BrowserResult getBrowserResult(BrowseCommandRequest request) throws IOException, NotFoundException;
BrowserResult getBrowserResult(BrowseCommandRequest request) throws IOException;
}

View File

@@ -33,9 +33,6 @@
package sonia.scm.repository.spi;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -47,7 +44,7 @@ import java.io.OutputStream;
*/
public interface CatCommand {
void getCatResult(CatCommandRequest request, OutputStream output) throws IOException, RevisionNotFoundException, PathNotFoundException;
void getCatResult(CatCommandRequest request, OutputStream output) throws IOException;
InputStream getCatResultStream(CatCommandRequest request) throws IOException, RevisionNotFoundException, PathNotFoundException;
InputStream getCatResultStream(CatCommandRequest request) throws IOException;
}

View File

@@ -33,8 +33,6 @@
package sonia.scm.repository.spi;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
@@ -56,5 +54,5 @@ public interface DiffCommand
* @throws IOException
* @throws RuntimeException
*/
public void getDiffResult(DiffCommandRequest request, OutputStream output) throws IOException, RevisionNotFoundException;
public void getDiffResult(DiffCommandRequest request, OutputStream output) throws IOException;
}

View File

@@ -40,10 +40,12 @@ import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryHookEvent;
import sonia.scm.repository.RepositoryHookType;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.api.HookContext;
import sonia.scm.repository.api.HookContextFactory;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
/**
*
* @author Sebastian Sdorra
@@ -71,18 +73,18 @@ public final class HookEventFacade
//~--- methods --------------------------------------------------------------
public HookEventHandler handle(String id) throws RepositoryNotFoundException {
public HookEventHandler handle(String id) {
return handle(repositoryManagerProvider.get().get(id));
}
public HookEventHandler handle(NamespaceAndName namespaceAndName) throws RepositoryNotFoundException {
public HookEventHandler handle(NamespaceAndName namespaceAndName) {
return handle(repositoryManagerProvider.get().get(namespaceAndName));
}
public HookEventHandler handle(Repository repository) throws RepositoryNotFoundException {
public HookEventHandler handle(Repository repository) {
if (repository == null)
{
throw new RepositoryNotFoundException(repository);
throw notFound(entity(repository));
}
return new HookEventHandler(repositoryManagerProvider.get(),

View File

@@ -37,7 +37,6 @@ package sonia.scm.repository.spi;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.IOException;
@@ -50,7 +49,7 @@ import java.io.IOException;
*/
public interface LogCommand {
Changeset getChangeset(String id) throws IOException, RevisionNotFoundException;
Changeset getChangeset(String id) throws IOException;
ChangesetPagingResult getChangesets(LogCommandRequest request) throws IOException, RevisionNotFoundException;
ChangesetPagingResult getChangesets(LogCommandRequest request) throws IOException;
}

View File

@@ -32,7 +32,6 @@
package sonia.scm.repository.spi;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.IOException;
@@ -46,8 +45,8 @@ import java.io.IOException;
*/
public interface ModificationsCommand {
Modifications getModifications(String revision) throws IOException, RevisionNotFoundException;
Modifications getModifications(String revision) throws IOException;
Modifications getModifications(ModificationsCommandRequest request) throws IOException, RevisionNotFoundException;
Modifications getModifications(ModificationsCommandRequest request) throws IOException;
}

View File

@@ -1,11 +1,19 @@
package sonia.scm.user;
public class ChangePasswordNotAllowedException extends RuntimeException {
import sonia.scm.ContextEntry;
import sonia.scm.ExceptionWithContext;
public class ChangePasswordNotAllowedException extends ExceptionWithContext {
private static final String CODE = "9BR7qpDAe1";
public static final String WRONG_USER_TYPE = "User of type %s are not allowed to change password";
public ChangePasswordNotAllowedException(String type) {
super(String.format(WRONG_USER_TYPE, type));
public ChangePasswordNotAllowedException(ContextEntry.ContextBuilder context, String type) {
super(context.build(), String.format(WRONG_USER_TYPE, type));
}
@Override
public String getCode() {
return CODE;
}
}

View File

@@ -1,8 +1,18 @@
package sonia.scm.user;
public class InvalidPasswordException extends RuntimeException {
import sonia.scm.ContextEntry;
import sonia.scm.ExceptionWithContext;
public InvalidPasswordException() {
super("The given Password does not match with the stored one.");
public class InvalidPasswordException extends ExceptionWithContext {
private static final String CODE = "8YR7aawFW1";
public InvalidPasswordException(ContextEntry.ContextBuilder context) {
super(context.build(), "The given old password does not match with the stored one.");
}
@Override
public String getCode() {
return CODE;
}
}

View File

@@ -44,6 +44,7 @@ public class VndMediaType {
public static final String ME = PREFIX + "me" + SUFFIX;
public static final String SOURCE = PREFIX + "source" + SUFFIX;
public static final String ERROR_TYPE = PREFIX + "error" + SUFFIX;
private VndMediaType() {
}

View File

@@ -43,7 +43,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import sonia.scm.AlreadyExistsException;
import sonia.scm.NotFoundException;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import sonia.scm.group.GroupNames;
@@ -132,7 +131,7 @@ public class SyncingRealmHelperTest {
* @throws IOException
*/
@Test
public void testStoreGroupCreate() throws AlreadyExistsException {
public void testStoreGroupCreate() {
Group group = new Group("unit-test", "heartOfGold");
helper.store(group);
@@ -143,7 +142,7 @@ public class SyncingRealmHelperTest {
* Tests {@link SyncingRealmHelper#store(Group)}.
*/
@Test(expected = IllegalStateException.class)
public void testStoreGroupFailure() throws AlreadyExistsException {
public void testStoreGroupFailure() {
Group group = new Group("unit-test", "heartOfGold");
doThrow(AlreadyExistsException.class).when(groupManager).create(group);
@@ -169,7 +168,7 @@ public class SyncingRealmHelperTest {
* @throws IOException
*/
@Test
public void testStoreUserCreate() throws AlreadyExistsException {
public void testStoreUserCreate() {
User user = new User("tricia");
helper.store(user);
@@ -180,7 +179,7 @@ public class SyncingRealmHelperTest {
* Tests {@link SyncingRealmHelper#store(User)} with a thrown {@link AlreadyExistsException}.
*/
@Test(expected = IllegalStateException.class)
public void testStoreUserFailure() throws AlreadyExistsException {
public void testStoreUserFailure() {
User user = new User("tricia");
doThrow(AlreadyExistsException.class).when(userManager).create(user);

View File

@@ -56,6 +56,7 @@ import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ContextEntry;
import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
import sonia.scm.web.GitUserAgentProvider;
@@ -204,7 +205,7 @@ public final class GitUtil
}
catch (GitAPIException ex)
{
throw new InternalRepositoryException("could not fetch", ex);
throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("remote", directory.toString()).in(remoteRepository), "could not fetch", ex);
}
}

View File

@@ -160,7 +160,7 @@ public abstract class AbstractGitIncomingOutgoingCommand
}
catch (Exception ex)
{
throw new InternalRepositoryException("could not execute incoming command", ex);
throw new InternalRepositoryException(repository, "could not execute incoming command", ex);
}
finally
{
@@ -200,13 +200,7 @@ public abstract class AbstractGitIncomingOutgoingCommand
{
if (e.getKey().startsWith(prefix))
{
if (ref != null)
{
throw new InternalRepositoryException("could not find remote branch");
}
ref = e.getValue();
break;
}
}

View File

@@ -114,7 +114,7 @@ public abstract class AbstractGitPushOrPullCommand extends AbstractGitCommand
}
catch (Exception ex)
{
throw new InternalRepositoryException("could not execute push/pull command", ex);
throw new InternalRepositoryException(repository, "could not execute push/pull command", ex);
}
return counter;

View File

@@ -55,6 +55,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
//~--- JDK imports ------------------------------------------------------------
/**
@@ -108,9 +110,8 @@ public class GitBlameCommand extends AbstractGitCommand implements BlameCommand
if (gitBlameResult == null)
{
throw new InternalRepositoryException(
"could not create blame result for path ".concat(
request.getPath()));
throw new InternalRepositoryException(entity("path", request.getPath()).in(repository),
"could not create blame result for path");
}
List<BlameLine> blameLines = new ArrayList<BlameLine>();
@@ -150,7 +151,7 @@ public class GitBlameCommand extends AbstractGitCommand implements BlameCommand
}
catch (GitAPIException ex)
{
throw new InternalRepositoryException("could not create blame view", ex);
throw new InternalRepositoryException(repository, "could not create blame view", ex);
}
return result;

View File

@@ -102,7 +102,7 @@ public class GitBranchesCommand extends AbstractGitCommand
}
catch (GitAPIException ex)
{
throw new InternalRepositoryException("could not read branches", ex);
throw new InternalRepositoryException(repository, "could not read branches", ex);
}
return branches;

View File

@@ -55,9 +55,7 @@ import sonia.scm.repository.BrowserResult;
import sonia.scm.repository.FileObject;
import sonia.scm.repository.GitSubModuleParser;
import sonia.scm.repository.GitUtil;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.SubRepository;
import sonia.scm.util.Util;
@@ -104,7 +102,7 @@ public class GitBrowseCommand extends AbstractGitCommand
@Override
@SuppressWarnings("unchecked")
public BrowserResult getBrowserResult(BrowseCommandRequest request)
throws IOException, NotFoundException {
throws IOException {
logger.debug("try to create browse result for {}", request);
BrowserResult result;
@@ -166,7 +164,7 @@ public class GitBrowseCommand extends AbstractGitCommand
*/
private FileObject createFileObject(org.eclipse.jgit.lib.Repository repo,
BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk)
throws IOException, RevisionNotFoundException {
throws IOException {
FileObject file = new FileObject();
@@ -258,7 +256,7 @@ public class GitBrowseCommand extends AbstractGitCommand
return result;
}
private FileObject getEntry(org.eclipse.jgit.lib.Repository repo, BrowseCommandRequest request, ObjectId revId) throws IOException, NotFoundException {
private FileObject getEntry(org.eclipse.jgit.lib.Repository repo, BrowseCommandRequest request, ObjectId revId) throws IOException {
RevWalk revWalk = null;
TreeWalk treeWalk = null;
@@ -309,7 +307,7 @@ public class GitBrowseCommand extends AbstractGitCommand
return Strings.isNullOrEmpty(request.getPath()) || "/".equals(request.getPath());
}
private FileObject findChildren(FileObject parent, org.eclipse.jgit.lib.Repository repo, BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException, NotFoundException {
private FileObject findChildren(FileObject parent, org.eclipse.jgit.lib.Repository repo, BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException {
List<FileObject> files = Lists.newArrayList();
while (treeWalk.next())
{
@@ -337,7 +335,7 @@ public class GitBrowseCommand extends AbstractGitCommand
}
private FileObject findFirstMatch(org.eclipse.jgit.lib.Repository repo,
BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException, NotFoundException {
BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException {
String[] pathElements = request.getPath().split("/");
int currentDepth = 0;
int limit = pathElements.length;
@@ -363,7 +361,7 @@ public class GitBrowseCommand extends AbstractGitCommand
private Map<String,
SubRepository> getSubRepositories(org.eclipse.jgit.lib.Repository repo,
ObjectId revision)
throws IOException, RevisionNotFoundException {
throws IOException {
if (logger.isDebugEnabled())
{
logger.debug("read submodules of {} at {}", repository.getName(),
@@ -377,7 +375,7 @@ public class GitBrowseCommand extends AbstractGitCommand
PATH_MODULES, baos);
subRepositories = GitSubModuleParser.parse(baos.toString());
}
catch (PathNotFoundException ex)
catch (NotFoundException ex)
{
logger.trace("could not find .gitmodules", ex);
subRepositories = Collections.EMPTY_MAP;
@@ -388,7 +386,7 @@ public class GitBrowseCommand extends AbstractGitCommand
private SubRepository getSubRepository(org.eclipse.jgit.lib.Repository repo,
ObjectId revId, String path)
throws IOException, RevisionNotFoundException {
throws IOException {
Map<String, SubRepository> subRepositories = subrepositoryCache.get(revId);
if (subRepositories == null)

View File

@@ -45,8 +45,6 @@ import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.GitUtil;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.util.Util;
import java.io.Closeable;
@@ -55,6 +53,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
public class GitCatCommand extends AbstractGitCommand implements CatCommand {
@@ -65,7 +66,7 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand {
}
@Override
public void getCatResult(CatCommandRequest request, OutputStream output) throws IOException, PathNotFoundException, RevisionNotFoundException {
public void getCatResult(CatCommandRequest request, OutputStream output) throws IOException {
logger.debug("try to read content for {}", request);
try (ClosableObjectLoaderContainer closableObjectLoaderContainer = getLoader(request)) {
closableObjectLoaderContainer.objectLoader.copyTo(output);
@@ -73,24 +74,24 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand {
}
@Override
public InputStream getCatResultStream(CatCommandRequest request) throws IOException, PathNotFoundException, RevisionNotFoundException {
public InputStream getCatResultStream(CatCommandRequest request) throws IOException {
logger.debug("try to read content for {}", request);
return new InputStreamWrapper(getLoader(request));
}
void getContent(org.eclipse.jgit.lib.Repository repo, ObjectId revId, String path, OutputStream output) throws IOException, PathNotFoundException, RevisionNotFoundException {
void getContent(org.eclipse.jgit.lib.Repository repo, ObjectId revId, String path, OutputStream output) throws IOException {
try (ClosableObjectLoaderContainer closableObjectLoaderContainer = getLoader(repo, revId, path)) {
closableObjectLoaderContainer.objectLoader.copyTo(output);
}
}
private ClosableObjectLoaderContainer getLoader(CatCommandRequest request) throws IOException, PathNotFoundException, RevisionNotFoundException {
private ClosableObjectLoaderContainer getLoader(CatCommandRequest request) throws IOException {
org.eclipse.jgit.lib.Repository repo = open();
ObjectId revId = getCommitOrDefault(repo, request.getRevision());
return getLoader(repo, revId, request.getPath());
}
private ClosableObjectLoaderContainer getLoader(Repository repo, ObjectId revId, String path) throws IOException, PathNotFoundException, RevisionNotFoundException {
private ClosableObjectLoaderContainer getLoader(Repository repo, ObjectId revId, String path) throws IOException {
TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.setRecursive(Util.nonNull(path).contains("/"));
@@ -102,7 +103,7 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand {
try {
entry = revWalk.parseCommit(revId);
} catch (MissingObjectException e) {
throw new RevisionNotFoundException(revId.getName());
throw notFound(entity("Revision", revId.getName()).in(repository));
}
RevTree revTree = entry.getTree();
@@ -120,7 +121,7 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand {
return new ClosableObjectLoaderContainer(loader, treeWalk, revWalk);
} else {
throw new PathNotFoundException(path);
throw notFound(entity("Path", path).in("Revision", revId.getName()).in(repository));
}
}

View File

@@ -54,7 +54,6 @@ import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.GitChangesetConverter;
import sonia.scm.repository.GitUtil;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.util.IOUtil;
import java.io.IOException;
@@ -62,6 +61,9 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
//~--- JDK imports ------------------------------------------------------------
/**
@@ -86,7 +88,6 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
*
* @param context
* @param repository
* @param repositoryDirectory
*/
GitLogCommand(GitContext context, sonia.scm.repository.Repository repository)
{
@@ -163,7 +164,7 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
*/
@Override
@SuppressWarnings("unchecked")
public ChangesetPagingResult getChangesets(LogCommandRequest request) throws RevisionNotFoundException {
public ChangesetPagingResult getChangesets(LogCommandRequest request) {
if (logger.isDebugEnabled()) {
logger.debug("fetch changesets for request: {}", request);
}
@@ -261,11 +262,11 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
}
catch (MissingObjectException e)
{
throw new RevisionNotFoundException(e.getObjectId().name());
throw notFound(entity("Revision", e.getObjectId().getName()).in(repository));
}
catch (Exception ex)
{
throw new InternalRepositoryException("could not create change log", ex);
throw new InternalRepositoryException(repository, "could not create change log", ex);
}
finally
{

View File

@@ -17,6 +17,8 @@ import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
@Slf4j
public class GitModificationsCommand extends AbstractGitCommand implements ModificationsCommand {
@@ -26,7 +28,7 @@ public class GitModificationsCommand extends AbstractGitCommand implements Modif
}
private Modifications createModifications(TreeWalk treeWalk, RevCommit commit, RevWalk revWalk, String revision)
throws IOException, UnsupportedModificationTypeException {
throws IOException {
treeWalk.reset();
treeWalk.setRecursive(true);
if (commit.getParentCount() > 0) {
@@ -73,12 +75,7 @@ public class GitModificationsCommand extends AbstractGitCommand implements Modif
}
} catch (IOException ex) {
log.error("could not open repository", ex);
throw new InternalRepositoryException(ex);
} catch (UnsupportedModificationTypeException ex) {
log.error("Unsupported modification type", ex);
throw new InternalRepositoryException(ex);
throw new InternalRepositoryException(entity(repository), "could not open repository", ex);
} finally {
GitUtil.release(revWalk);
GitUtil.close(gitRepository);
@@ -100,7 +97,7 @@ public class GitModificationsCommand extends AbstractGitCommand implements Modif
} else if (type == DiffEntry.ChangeType.DELETE) {
modifications.getRemoved().add(entry.getOldPath());
} else {
throw new UnsupportedModificationTypeException(MessageFormat.format("The modification type: {0} is not supported.", type));
throw new UnsupportedModificationTypeException(entity(repository), MessageFormat.format("The modification type: {0} is not supported.", type));
}
}
}

View File

@@ -249,7 +249,7 @@ public class GitPullCommand extends AbstractGitPushOrPullCommand
}
catch (GitAPIException ex)
{
throw new InternalRepositoryException("error durring pull", ex);
throw new InternalRepositoryException(repository, "error during pull", ex);
}
return response;

View File

@@ -95,7 +95,7 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand
}
catch (GitAPIException ex)
{
throw new InternalRepositoryException("could not read tags from repository", ex);
throw new InternalRepositoryException(repository, "could not read tags from repository", ex);
}
finally
{

View File

@@ -1,9 +1,10 @@
package sonia.scm.repository.spi;
import sonia.scm.ContextEntry;
import sonia.scm.repository.InternalRepositoryException;
public class UnsupportedModificationTypeException extends InternalRepositoryException {
public UnsupportedModificationTypeException(String message) {
super(message);
public UnsupportedModificationTypeException(ContextEntry.ContextBuilder entity, String message) {
super(entity, message);
}
}

View File

@@ -32,7 +32,6 @@
package sonia.scm.repository.spi;
import org.junit.Test;
import sonia.scm.NotFoundException;
import sonia.scm.repository.BrowserResult;
import sonia.scm.repository.FileObject;
import sonia.scm.repository.GitConstants;
@@ -54,7 +53,7 @@ import static org.junit.Assert.assertTrue;
public class GitBrowseCommandTest extends AbstractGitCommandTestBase {
@Test
public void testGetFile() throws IOException, NotFoundException {
public void testDefaultBranch() throws IOException {
BrowseCommandRequest request = new BrowseCommandRequest();
request.setPath("a.txt");
BrowserResult result = createCommand().getBrowserResult(request);
@@ -63,7 +62,7 @@ public class GitBrowseCommandTest extends AbstractGitCommandTestBase {
}
@Test
public void testDefaultDefaultBranch() throws IOException, NotFoundException {
public void testDefaultDefaultBranch() throws IOException {
// without default branch, the repository head should be used
FileObject root = createCommand().getBrowserResult(new BrowseCommandRequest()).getFile();
assertNotNull(root);
@@ -78,7 +77,7 @@ public class GitBrowseCommandTest extends AbstractGitCommandTestBase {
}
@Test
public void testExplicitDefaultBranch() throws IOException, NotFoundException {
public void testExplicitDefaultBranch() throws IOException {
repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch");
FileObject root = createCommand().getBrowserResult(new BrowseCommandRequest()).getFile();
@@ -91,7 +90,7 @@ public class GitBrowseCommandTest extends AbstractGitCommandTestBase {
}
@Test
public void testBrowse() throws IOException, NotFoundException {
public void testBrowse() throws IOException {
FileObject root = createCommand().getBrowserResult(new BrowseCommandRequest()).getFile();
assertNotNull(root);
@@ -113,7 +112,7 @@ public class GitBrowseCommandTest extends AbstractGitCommandTestBase {
}
@Test
public void testBrowseSubDirectory() throws IOException, NotFoundException {
public void testBrowseSubDirectory() throws IOException {
BrowseCommandRequest request = new BrowseCommandRequest();
request.setPath("c");
@@ -143,7 +142,7 @@ public class GitBrowseCommandTest extends AbstractGitCommandTestBase {
}
@Test
public void testRecursive() throws IOException, NotFoundException {
public void testRecusive() throws IOException {
BrowseCommandRequest request = new BrowseCommandRequest();
request.setRecursive(true);

View File

@@ -32,10 +32,13 @@
package sonia.scm.repository.spi;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import sonia.scm.NotFoundException;
import sonia.scm.repository.GitConstants;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -51,9 +54,12 @@ import static org.junit.Assert.assertEquals;
* @author Sebastian Sdorra
*/
public class GitCatCommandTest extends AbstractGitCommandTestBase {
@Rule
public final ExpectedException expectedException = ExpectedException.none();
@Test
public void testDefaultBranch() throws IOException, PathNotFoundException, RevisionNotFoundException {
public void testDefaultBranch() throws IOException {
// without default branch, the repository head should be used
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
@@ -66,7 +72,7 @@ public class GitCatCommandTest extends AbstractGitCommandTestBase {
}
@Test
public void testCat() throws IOException, PathNotFoundException, RevisionNotFoundException {
public void testCat() throws IOException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
@@ -75,32 +81,58 @@ public class GitCatCommandTest extends AbstractGitCommandTestBase {
}
@Test
public void testSimpleCat() throws IOException, PathNotFoundException, RevisionNotFoundException {
public void testSimpleCat() throws IOException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("b.txt");
assertEquals("b", execute(request));
}
@Test(expected = PathNotFoundException.class)
public void testUnknownFile() throws IOException, PathNotFoundException, RevisionNotFoundException {
@Test
public void testUnknownFile() throws IOException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("unknown");
execute(request);
}
@Test(expected = RevisionNotFoundException.class)
public void testUnknownRevision() throws IOException, PathNotFoundException, RevisionNotFoundException {
CatCommandRequest request = new CatCommandRequest();
expectedException.expect(new BaseMatcher<Object>() {
@Override
public void describeTo(Description description) {
description.appendText("expected NotFoundException for path");
}
@Override
public boolean matches(Object item) {
return "Path".equals(((NotFoundException)item).getContext().get(0).getType());
}
});
request.setRevision("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
request.setPath("a.txt");
execute(request);
}
@Test
public void testSimpleStream() throws IOException, PathNotFoundException, RevisionNotFoundException {
public void testUnknownRevision() throws IOException {
CatCommandRequest request = new CatCommandRequest();
request.setRevision("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
request.setPath("a.txt");
expectedException.expect(new BaseMatcher<Object>() {
@Override
public void describeTo(Description description) {
description.appendText("expected NotFoundException for revision");
}
@Override
public boolean matches(Object item) {
return "Revision".equals(((NotFoundException)item).getContext().get(0).getType());
}
});
execute(request);
}
@Test
public void testSimpleStream() throws IOException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("b.txt");
@@ -113,7 +145,7 @@ public class GitCatCommandTest extends AbstractGitCommandTestBase {
catResultStream.close();
}
private String execute(CatCommandRequest request) throws IOException, PathNotFoundException, RevisionNotFoundException {
private String execute(CatCommandRequest request) throws IOException {
String content = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();

View File

@@ -272,7 +272,7 @@ public class AbstractHgHandler
} catch (JAXBException ex) {
logger.error("could not parse result", ex);
throw new InternalRepositoryException("could not parse result", ex);
throw new InternalRepositoryException(repository, "could not parse result", ex);
}
}

View File

@@ -36,6 +36,9 @@ package sonia.scm.repository.spi;
import com.aragost.javahg.commands.ExecutionException;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ContextEntry;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Repository;
import sonia.scm.web.HgUtil;
@@ -46,6 +49,8 @@ import java.io.OutputStream;
public class HgCatCommand extends AbstractCommand implements CatCommand {
private static final Logger log = LoggerFactory.getLogger(HgCatCommand.class);
HgCatCommand(HgCommandContext context, Repository repository) {
super(context, repository);
}
@@ -70,7 +75,8 @@ public class HgCatCommand extends AbstractCommand implements CatCommand {
try {
return cmd.execute(request.getPath());
} catch (ExecutionException e) {
throw new InternalRepositoryException(e);
log.error("could not execute cat command", e);
throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity(getRepository()), "could not execute cat command", e);
}
}
}

View File

@@ -103,7 +103,7 @@ public class HgIncomingCommand extends AbstractCommand
}
else
{
throw new InternalRepositoryException("could not execute incoming command", ex);
throw new InternalRepositoryException(getRepository(), "could not execute incoming command", ex);
}
}

View File

@@ -103,7 +103,7 @@ public class HgOutgoingCommand extends AbstractCommand
}
else
{
throw new InternalRepositoryException("could not execute outgoing command", ex);
throw new InternalRepositoryException(getRepository(), "could not execute outgoing command", ex);
}
}

View File

@@ -97,7 +97,7 @@ public class HgPullCommand extends AbstractHgPushOrPullCommand
}
catch (ExecutionException ex)
{
throw new InternalRepositoryException("could not execute push command", ex);
throw new InternalRepositoryException(getRepository(), "could not execute push command", ex);
}
return new PullResponse(result.size());

View File

@@ -97,7 +97,7 @@ public class HgPushCommand extends AbstractHgPushOrPullCommand
}
catch (ExecutionException ex)
{
throw new InternalRepositoryException("could not execute push command", ex);
throw new InternalRepositoryException(getRepository(), "could not execute push command", ex);
}
return new PushResponse(result.size());

View File

@@ -44,11 +44,11 @@ import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.NotFoundException;
import sonia.scm.repository.HgContext;
import sonia.scm.repository.HgHookManager;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.RepositoryHookType;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RepositoryUtil;
import sonia.scm.repository.api.HgHookMessage;
import sonia.scm.repository.api.HgHookMessage.Severity;
@@ -275,17 +275,11 @@ public class HgHookCallbackServlet extends HttpServlet
printMessages(response, context);
}
catch (RepositoryNotFoundException ex)
catch (NotFoundException ex)
{
if (logger.isErrorEnabled())
{
logger.error("could not find repository with id {}", id);
logger.error(ex.getMessage());
if (logger.isTraceEnabled())
{
logger.trace("repository not found", ex);
}
}
logger.trace("repository not found", ex);
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}

View File

@@ -39,7 +39,6 @@ import org.junit.Test;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.IOException;
@@ -151,7 +150,7 @@ public class HgLogCommandTest extends AbstractHgCommandTestBase
}
@Test
public void testGetCommit() throws IOException, RevisionNotFoundException {
public void testGetCommit() throws IOException {
HgLogCommand command = createComamnd();
String revision = "a9bacaf1b7fa0cebfca71fed4e59ed69a6319427";
Changeset c =

View File

@@ -56,6 +56,8 @@ import sonia.scm.util.Util;
import java.io.File;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
//~--- JDK imports ------------------------------------------------------------
/**
@@ -173,7 +175,8 @@ public class SvnRepositoryHandler
}
catch (SVNException ex)
{
throw new InternalRepositoryException(ex);
logger.error("could not create svn repository", ex);
throw new InternalRepositoryException(entity(repository), "could not create repository", ex);
}
finally
{

View File

@@ -59,6 +59,9 @@ import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
//~--- JDK imports ------------------------------------------------------------
/**
@@ -102,7 +105,7 @@ public final class SvnUtil
//~--- methods --------------------------------------------------------------
public static long parseRevision(String v) throws RevisionNotFoundException {
public static long parseRevision(String v, Repository repository) {
long result = -1l;
if (!Strings.isNullOrEmpty(v))
@@ -113,7 +116,7 @@ public final class SvnUtil
}
catch (NumberFormatException ex)
{
throw new RevisionNotFoundException(v);
throw notFound(entity("Revision", v).in(repository));
}
}
@@ -339,7 +342,7 @@ public final class SvnUtil
}
}
public static long getRevisionNumber(String revision) throws RevisionNotFoundException {
public static long getRevisionNumber(String revision, Repository repository) {
// REVIEW Bei SVN wird ohne Revision die -1 genommen, was zu einem Fehler führt
long revisionNumber = -1;
@@ -351,7 +354,7 @@ public final class SvnUtil
}
catch (NumberFormatException ex)
{
throw new RevisionNotFoundException(revision);
throw notFound(entity("Revision", revision).in(repository));
}
}

View File

@@ -98,7 +98,7 @@ public class SvnBlameCommand extends AbstractSvnCommand implements BlameCommand
}
catch (SVNException ex)
{
throw new InternalRepositoryException("could not create blame result", ex);
throw new InternalRepositoryException(repository, "could not create blame result", ex);
}
return new BlameResult(blameLines.size(), blameLines);

View File

@@ -48,7 +48,6 @@ import org.tmatesoft.svn.core.io.SVNRepository;
import sonia.scm.repository.BrowserResult;
import sonia.scm.repository.FileObject;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.SubRepository;
import sonia.scm.repository.SvnUtil;
import sonia.scm.util.Util;
@@ -79,9 +78,9 @@ public class SvnBrowseCommand extends AbstractSvnCommand
@Override
@SuppressWarnings("unchecked")
public BrowserResult getBrowserResult(BrowseCommandRequest request) throws RevisionNotFoundException {
public BrowserResult getBrowserResult(BrowseCommandRequest request) {
String path = Strings.nullToEmpty(request.getPath());
long revisionNumber = SvnUtil.getRevisionNumber(request.getRevision());
long revisionNumber = SvnUtil.getRevisionNumber(request.getRevision(), repository);
if (logger.isDebugEnabled()) {
logger.debug("browser repository {} in path \"{}\" at revision {}", repository.getName(), path, revisionNumber);

View File

@@ -44,9 +44,7 @@ import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.admin.SVNLookClient;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.SvnUtil;
import java.io.ByteArrayInputStream;
@@ -54,6 +52,9 @@ import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
//~--- JDK imports ------------------------------------------------------------
/**
@@ -79,7 +80,7 @@ public class SvnCatCommand extends AbstractSvnCommand implements CatCommand
//~--- get methods ----------------------------------------------------------
@Override
public void getCatResult(CatCommandRequest request, OutputStream output) throws RevisionNotFoundException, PathNotFoundException {
public void getCatResult(CatCommandRequest request, OutputStream output) {
if (logger.isDebugEnabled())
{
logger.debug("try to get content for {}", request);
@@ -96,14 +97,14 @@ public class SvnCatCommand extends AbstractSvnCommand implements CatCommand
else
{
long revisionNumber = SvnUtil.getRevisionNumber(revision);
long revisionNumber = SvnUtil.getRevisionNumber(revision, repository);
getCatFromRevision(request, output, revisionNumber);
}
}
@Override
public InputStream getCatResultStream(CatCommandRequest request) throws RevisionNotFoundException, PathNotFoundException {
public InputStream getCatResultStream(CatCommandRequest request) {
// There seems to be no method creating an input stream as a result, so
// we have no other possibility then to copy the content into a buffer and
// stream it from there.
@@ -112,7 +113,7 @@ public class SvnCatCommand extends AbstractSvnCommand implements CatCommand
return new ByteArrayInputStream(output.toByteArray());
}
private void getCatFromRevision(CatCommandRequest request, OutputStream output, long revision) throws PathNotFoundException, RevisionNotFoundException {
private void getCatFromRevision(CatCommandRequest request, OutputStream output, long revision) {
logger.debug("try to read content from revision {} and path {}", revision,
request.getPath());
@@ -129,14 +130,14 @@ public class SvnCatCommand extends AbstractSvnCommand implements CatCommand
}
}
private void handleSvnException(CatCommandRequest request, SVNException ex) throws PathNotFoundException, RevisionNotFoundException {
private void handleSvnException(CatCommandRequest request, SVNException ex) {
int svnErrorCode = ex.getErrorMessage().getErrorCode().getCode();
if (SVNErrorCode.FS_NOT_FOUND.getCode() == svnErrorCode) {
throw new PathNotFoundException(request.getPath());
throw notFound(entity("Path", request.getPath()).in("Revision", request.getRevision()).in(repository));
} else if (SVNErrorCode.FS_NO_SUCH_REVISION.getCode() == svnErrorCode) {
throw new RevisionNotFoundException(request.getRevision());
throw notFound(entity("Revision", request.getRevision()).in(repository));
} else {
throw new InternalRepositoryException("could not get content from revision", ex);
throw new InternalRepositoryException(repository, "could not get content from revision", ex);
}
}
@@ -156,7 +157,7 @@ public class SvnCatCommand extends AbstractSvnCommand implements CatCommand
}
catch (SVNException ex)
{
throw new InternalRepositoryException("could not get content from transaction", ex);
throw new InternalRepositoryException(repository, "could not get content from transaction", ex);
}
finally
{

View File

@@ -86,7 +86,7 @@ public class SvnDiffCommand extends AbstractSvnCommand implements DiffCommand {
SVNDiffClient diffClient = clientManager.getDiffClient();
diffClient.setDiffGenerator(new SvnNewDiffGenerator(new SCMSvnDiffGenerator()));
long currentRev = SvnUtil.getRevisionNumber(request.getRevision());
long currentRev = SvnUtil.getRevisionNumber(request.getRevision(), repository);
diffClient.setGitDiffFormat(request.getFormat() == DiffFormat.GIT);
@@ -94,7 +94,7 @@ public class SvnDiffCommand extends AbstractSvnCommand implements DiffCommand {
SVNRevision.create(currentRev - 1), SVNRevision.create(currentRev),
SVNDepth.INFINITY, false, output);
} catch (SVNException ex) {
throw new InternalRepositoryException("could not create diff", ex);
throw new InternalRepositoryException(repository, "could not create diff", ex);
} finally {
SvnUtil.dispose(clientManager);
}

View File

@@ -47,7 +47,6 @@ import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.SvnUtil;
import sonia.scm.util.Util;
@@ -76,7 +75,7 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
@Override
@SuppressWarnings("unchecked")
public Changeset getChangeset(String revision) throws RevisionNotFoundException {
public Changeset getChangeset(String revision) {
Changeset changeset = null;
if (logger.isDebugEnabled())
@@ -86,7 +85,7 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
try
{
long revisioNumber = parseRevision(revision);
long revisioNumber = parseRevision(revision, repository);
SVNRepository repo = open();
Collection<SVNLogEntry> entries = repo.log(null, null, revisioNumber,
revisioNumber, true, true);
@@ -98,7 +97,7 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
}
catch (SVNException ex)
{
throw new InternalRepositoryException("could not open repository", ex);
throw new InternalRepositoryException(repository, "could not open repository", ex);
}
return changeset;
@@ -106,7 +105,7 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
@Override
@SuppressWarnings("unchecked")
public ChangesetPagingResult getChangesets(LogCommandRequest request) throws RevisionNotFoundException {
public ChangesetPagingResult getChangesets(LogCommandRequest request) {
if (logger.isDebugEnabled())
{
logger.debug("fetch changesets for {}", request);
@@ -115,8 +114,8 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
ChangesetPagingResult changesets = null;
int start = request.getPagingStart();
int limit = request.getPagingLimit();
long startRevision = parseRevision(request.getStartChangeset());
long endRevision = parseRevision(request.getEndChangeset());
long startRevision = parseRevision(request.getStartChangeset(), repository);
long endRevision = parseRevision(request.getEndChangeset(), repository);
String[] pathArray = null;
if (!Strings.isNullOrEmpty(request.getPath()))
@@ -140,7 +139,7 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
}
catch (SVNException ex)
{
throw new InternalRepositoryException("could not open repository", ex);
throw new InternalRepositoryException(repository, "could not open repository", ex);
}
return changesets;

View File

@@ -7,11 +7,9 @@ import org.tmatesoft.svn.core.io.SVNRepository;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.SvnUtil;
import sonia.scm.util.Util;
import java.io.IOException;
import java.util.Collection;
@Slf4j
@@ -24,11 +22,11 @@ public class SvnModificationsCommand extends AbstractSvnCommand implements Modif
@Override
@SuppressWarnings("unchecked")
public Modifications getModifications(String revision) throws IOException, RevisionNotFoundException {
public Modifications getModifications(String revision) {
Modifications modifications = null;
log.debug("get modifications {}", revision);
try {
long revisionNumber = SvnUtil.parseRevision(revision);
long revisionNumber = SvnUtil.parseRevision(revision, repository);
SVNRepository repo = open();
Collection<SVNLogEntry> entries = repo.log(null, null, revisionNumber,
revisionNumber, true, true);
@@ -36,13 +34,13 @@ public class SvnModificationsCommand extends AbstractSvnCommand implements Modif
modifications = SvnUtil.createModifications(entries.iterator().next(), revision);
}
} catch (SVNException ex) {
throw new InternalRepositoryException("could not open repository", ex);
throw new InternalRepositoryException(repository, "could not open repository", ex);
}
return modifications;
}
@Override
public Modifications getModifications(ModificationsCommandRequest request) throws IOException, RevisionNotFoundException {
public Modifications getModifications(ModificationsCommandRequest request) {
return getModifications(request.getRevision());
}

View File

@@ -36,7 +36,6 @@ package sonia.scm.repository.spi;
import org.junit.Test;
import sonia.scm.repository.BrowserResult;
import sonia.scm.repository.FileObject;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.IOException;
import java.util.Collection;
@@ -55,7 +54,7 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase
{
@Test
public void testBrowseWithFilePath() throws RevisionNotFoundException {
public void testBrowseWithFilePath() {
BrowseCommandRequest request = new BrowseCommandRequest();
request.setPath("a.txt");
FileObject file = createCommand().getBrowserResult(request).getFile();
@@ -65,7 +64,7 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase
}
@Test
public void testBrowse() throws RevisionNotFoundException {
public void testBrowse() {
Collection<FileObject> foList = getRootFromTip(new BrowseCommandRequest());
FileObject a = getFileObject(foList, "a.txt");
@@ -89,7 +88,7 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase
* @throws IOException
*/
@Test
public void testBrowseSubDirectory() throws RevisionNotFoundException {
public void testBrowseSubDirectory() {
BrowseCommandRequest request = new BrowseCommandRequest();
request.setPath("c");
@@ -136,7 +135,7 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase
}
@Test
public void testDisableLastCommit() throws RevisionNotFoundException {
public void testDisableLastCommit() {
BrowseCommandRequest request = new BrowseCommandRequest();
request.setDisableLastCommit(true);
@@ -150,7 +149,7 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase
}
@Test
public void testRecursive() throws RevisionNotFoundException {
public void testRecursive() {
BrowseCommandRequest request = new BrowseCommandRequest();
request.setRecursive(true);
BrowserResult result = createCommand().getBrowserResult(request);
@@ -199,7 +198,7 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase
.orElseThrow(() -> new AssertionError("file " + name + " not found"));
}
private Collection<FileObject> getRootFromTip(BrowseCommandRequest request) throws RevisionNotFoundException {
private Collection<FileObject> getRootFromTip(BrowseCommandRequest request) {
BrowserResult result = createCommand().getBrowserResult(request);
assertNotNull(result);

View File

@@ -32,9 +32,12 @@
package sonia.scm.repository.spi;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Rule;
import org.junit.Test;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import org.junit.rules.ExpectedException;
import sonia.scm.NotFoundException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -46,8 +49,11 @@ import static org.junit.Assert.assertEquals;
public class SvnCatCommandTest extends AbstractSvnCommandTestBase {
@Rule
public final ExpectedException expectedException = ExpectedException.none();
@Test
public void testCat() throws PathNotFoundException, RevisionNotFoundException {
public void testCat() {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
@@ -56,35 +62,59 @@ public class SvnCatCommandTest extends AbstractSvnCommandTestBase {
}
@Test
public void testSimpleCat() throws PathNotFoundException, RevisionNotFoundException {
public void testSimpleCat() {
CatCommandRequest request = new CatCommandRequest();
request.setPath("c/d.txt");
assertEquals("d", execute(request));
}
@Test(expected = PathNotFoundException.class)
public void testUnknownFile() throws PathNotFoundException, RevisionNotFoundException {
@Test
public void testUnknownFile() {
CatCommandRequest request = new CatCommandRequest();
request.setPath("unknown");
request.setRevision("1");
execute(request);
}
expectedException.expect(new BaseMatcher<Object>() {
@Override
public void describeTo(Description description) {
description.appendText("expected NotFoundException for path");
}
@Test(expected = RevisionNotFoundException.class)
public void testUnknownRevision() throws PathNotFoundException, RevisionNotFoundException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
request.setRevision("42");
@Override
public boolean matches(Object item) {
return "Path".equals(((NotFoundException)item).getContext().get(0).getType());
}
});
execute(request);
}
@Test
public void testSimpleStream() throws IOException, PathNotFoundException, RevisionNotFoundException {
public void testUnknownRevision() {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
request.setRevision("42");
expectedException.expect(new BaseMatcher<Object>() {
@Override
public void describeTo(Description description) {
description.appendText("expected NotFoundException for revision");
}
@Override
public boolean matches(Object item) {
return "Revision".equals(((NotFoundException)item).getContext().get(0).getType());
}
});
execute(request);
}
@Test
public void testSimpleStream() throws IOException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
request.setRevision("1");
@@ -98,7 +128,7 @@ public class SvnCatCommandTest extends AbstractSvnCommandTestBase {
catResultStream.close();
}
private String execute(CatCommandRequest request) throws PathNotFoundException, RevisionNotFoundException {
private String execute(CatCommandRequest request) {
String content = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();

View File

@@ -38,7 +38,6 @@ import org.junit.Test;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.IOException;
@@ -57,7 +56,7 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase
{
@Test
public void testGetAll() throws RevisionNotFoundException {
public void testGetAll() {
ChangesetPagingResult result =
createCommand().getChangesets(new LogCommandRequest());
@@ -67,7 +66,7 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase
}
@Test
public void testGetAllByPath() throws RevisionNotFoundException {
public void testGetAllByPath() {
LogCommandRequest request = new LogCommandRequest();
request.setPath("a.txt");
@@ -83,7 +82,7 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase
}
@Test
public void testGetAllWithLimit() throws RevisionNotFoundException {
public void testGetAllWithLimit() {
LogCommandRequest request = new LogCommandRequest();
request.setPagingLimit(2);
@@ -106,7 +105,7 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase
}
@Test
public void testGetAllWithPaging() throws RevisionNotFoundException {
public void testGetAllWithPaging() {
LogCommandRequest request = new LogCommandRequest();
request.setPagingStart(1);
@@ -130,7 +129,7 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase
}
@Test
public void testGetCommit() throws RevisionNotFoundException, IOException {
public void testGetCommit() {
Changeset c = createCommand().getChangeset("3");
assertNotNull(c);
@@ -151,7 +150,7 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase
}
@Test
public void testGetRange() throws RevisionNotFoundException {
public void testGetRange() {
LogCommandRequest request = new LogCommandRequest();
request.setStartChangeset("2");

View File

@@ -71,10 +71,10 @@ public class DummyRepositoryHandler
@Override
protected void create(Repository repository, File directory) throws AlreadyExistsException {
protected void create(Repository repository, File directory) {
String key = repository.getNamespace() + "/" + repository.getName();
if (existingRepoNames.contains(key)) {
throw new AlreadyExistsException();
throw new AlreadyExistsException(repository);
} else {
existingRepoNames.add(key);
}

View File

@@ -35,7 +35,6 @@ package sonia.scm.repository;
import org.junit.Test;
import sonia.scm.AbstractTestBase;
import sonia.scm.AlreadyExistsException;
import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.store.InMemoryConfigurationStoreFactory;
import sonia.scm.util.IOUtil;
@@ -61,12 +60,12 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase {
ConfigurationStoreFactory factory, File directory);
@Test
public void testCreate() throws AlreadyExistsException {
public void testCreate() {
createRepository();
}
@Test
public void testCreateResourcePath() throws AlreadyExistsException {
public void testCreateResourcePath() {
Repository repository = createRepository();
String path = handler.createResourcePath(repository);
@@ -76,7 +75,7 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase {
}
@Test
public void testDelete() throws Exception {
public void testDelete() {
Repository repository = createRepository();
handler.delete(repository);
@@ -101,7 +100,7 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase {
}
}
private Repository createRepository() throws AlreadyExistsException {
private Repository createRepository() {
Repository repository = RepositoryTestData.createHeartOfGold();
handler.create(repository);

View File

@@ -39,12 +39,10 @@ import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import sonia.scm.AlreadyExistsException;
import sonia.scm.ConcurrentModificationException;
import sonia.scm.Manager;
import sonia.scm.ManagerTestBase;
import sonia.scm.NotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -63,7 +61,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
public static final int THREAD_COUNT = 10;
@Test
public void testCreate() throws AlreadyExistsException {
public void testCreate() {
User zaphod = UserTestData.createZaphod();
manager.create(zaphod);
@@ -75,7 +73,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
}
@Test(expected = AlreadyExistsException.class)
public void testCreateExisting() throws AlreadyExistsException {
public void testCreateExisting() {
User zaphod = UserTestData.createZaphod();
manager.create(zaphod);
@@ -87,7 +85,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
}
@Test
public void testDelete() throws Exception {
public void testDelete() {
User zaphod = UserTestData.createZaphod();
manager.create(zaphod);
@@ -97,12 +95,12 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
}
@Test(expected = NotFoundException.class)
public void testDeleteNotFound() throws Exception {
public void testDeleteNotFound() {
manager.delete(UserTestData.createDent());
}
@Test
public void testGet() throws AlreadyExistsException {
public void testGet() {
User zaphod = UserTestData.createZaphod();
manager.create(zaphod);
@@ -116,7 +114,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
}
@Test
public void testGetAll() throws AlreadyExistsException {
public void testGetAll() {
User zaphod = UserTestData.createZaphod();
manager.create(zaphod);
@@ -181,7 +179,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
}
@Test
public void testModify() throws AlreadyExistsException, NotFoundException, ConcurrentModificationException {
public void testModify() {
User zaphod = UserTestData.createZaphod();
manager.create(zaphod);
@@ -238,7 +236,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
}
@Test
public void testRefresh() throws AlreadyExistsException, NotFoundException {
public void testRefresh() {
User zaphod = UserTestData.createZaphod();
manager.create(zaphod);
@@ -289,7 +287,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
finished = true;
}
private User createUser() throws AlreadyExistsException {
private User createUser() {
String id = UUID.randomUUID().toString();
User user = new User(id, id.concat(" displayName"),
id.concat("@mail.com"));
@@ -299,7 +297,7 @@ public abstract class UserManagerTestBase extends ManagerTestBase<User> {
return user;
}
private void modifyAndDeleteUser(User user) throws IOException, NotFoundException, ConcurrentModificationException {
private void modifyAndDeleteUser(User user) {
String name = user.getName();
String nd = name.concat(" new displayname");

View File

@@ -30,19 +30,19 @@ public class ManagerDaoAdapter<T extends ModelObject> {
afterUpdate.handle(notModified);
} else {
throw new NotFoundException();
throw new NotFoundException(object.getClass(), object.getId());
}
}
public T create(T newObject, Supplier<PermissionCheck> permissionCheck, AroundHandler<T> beforeCreate, AroundHandler<T> afterCreate) throws AlreadyExistsException {
public T create(T newObject, Supplier<PermissionCheck> permissionCheck, AroundHandler<T> beforeCreate, AroundHandler<T> afterCreate) {
return create(newObject, permissionCheck, beforeCreate, afterCreate, dao::contains);
}
public T create(T newObject, Supplier<PermissionCheck> permissionCheck, AroundHandler<T> beforeCreate, AroundHandler<T> afterCreate, Predicate<T> existsCheck) throws AlreadyExistsException {
public T create(T newObject, Supplier<PermissionCheck> permissionCheck, AroundHandler<T> beforeCreate, AroundHandler<T> afterCreate, Predicate<T> existsCheck) {
permissionCheck.get().check();
AssertUtil.assertIsValid(newObject);
if (existsCheck.test(newObject)) {
throw new AlreadyExistsException();
throw new AlreadyExistsException(newObject);
}
newObject.setCreationDate(System.currentTimeMillis());
beforeCreate.handle(newObject);
@@ -58,7 +58,7 @@ public class ManagerDaoAdapter<T extends ModelObject> {
dao.delete(toDelete);
afterDelete.handle(toDelete);
} else {
throw new NotFoundException();
throw new NotFoundException(toDelete.getClass(), toDelete.getId());
}
}

View File

@@ -0,0 +1,43 @@
package sonia.scm.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import sonia.scm.api.v2.resources.ErrorDto;
import sonia.scm.api.v2.resources.ExceptionWithContextToErrorDtoMapper;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import java.util.Collections;
@Provider
public class FallbackExceptionMapper implements ExceptionMapper<Exception> {
private static final Logger logger = LoggerFactory.getLogger(FallbackExceptionMapper.class);
private static final String ERROR_CODE = "CmR8GCJb31";
private final ExceptionWithContextToErrorDtoMapper mapper;
@Inject
public FallbackExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
this.mapper = mapper;
}
@Override
public Response toResponse(Exception exception) {
logger.debug("map {} to status code 500", exception);
ErrorDto errorDto = new ErrorDto();
errorDto.setMessage("internal server error");
errorDto.setContext(Collections.emptyList());
errorDto.setErrorCode(ERROR_CODE);
errorDto.setTransactionId(MDC.get("transaction_id"));
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(errorDto)
.type(VndMediaType.ERROR_TYPE)
.build();
}
}

View File

@@ -1,18 +1,16 @@
package sonia.scm.api.rest;
import sonia.scm.AlreadyExistsException;
import sonia.scm.api.v2.resources.ExceptionWithContextToErrorDtoMapper;
import javax.ws.rs.core.Response;
import javax.inject.Inject;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
@Provider
public class AlreadyExistsExceptionMapper implements ExceptionMapper<AlreadyExistsException> {
@Override
public Response toResponse(AlreadyExistsException exception) {
return Response.status(Status.CONFLICT)
.entity(exception.getMessage())
.build();
public class AlreadyExistsExceptionMapper extends ContextualExceptionMapper<AlreadyExistsException> {
@Inject
public AlreadyExistsExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
super(AlreadyExistsException.class, Status.CONFLICT, mapper);
}
}

View File

@@ -1,15 +1,16 @@
package sonia.scm.api.rest;
import sonia.scm.ConcurrentModificationException;
import sonia.scm.api.v2.resources.ExceptionWithContextToErrorDtoMapper;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
@Provider
public class ConcurrentModificationExceptionMapper implements ExceptionMapper<ConcurrentModificationException> {
@Override
public Response toResponse(ConcurrentModificationException exception) {
return Response.status(Response.Status.CONFLICT).build();
public class ConcurrentModificationExceptionMapper extends ContextualExceptionMapper<ConcurrentModificationException> {
@Inject
public ConcurrentModificationExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
super(ConcurrentModificationException.class, Response.Status.CONFLICT, mapper);
}
}

View File

@@ -0,0 +1,35 @@
package sonia.scm.api.rest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ExceptionWithContext;
import sonia.scm.api.v2.resources.ExceptionWithContextToErrorDtoMapper;
import sonia.scm.web.VndMediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
public class ContextualExceptionMapper<E extends ExceptionWithContext> implements ExceptionMapper<E> {
private static final Logger logger = LoggerFactory.getLogger(ContextualExceptionMapper.class);
private final ExceptionWithContextToErrorDtoMapper mapper;
private final Response.Status status;
private final Class<E> type;
public ContextualExceptionMapper(Class<E> type, Response.Status status, ExceptionWithContextToErrorDtoMapper mapper) {
this.mapper = mapper;
this.type = type;
this.status = status;
}
@Override
public Response toResponse(E exception) {
logger.debug("map {} to status code {}", type.getSimpleName(), status.getStatusCode(), exception);
return Response.status(status)
.entity(mapper.map(exception))
.type(VndMediaType.ERROR_TYPE)
.build();
}
}

View File

@@ -2,8 +2,6 @@ package sonia.scm.api.rest.resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.CatCommandBuilder;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.util.IOUtil;
@@ -34,18 +32,6 @@ public class BrowserStreamingOutput implements StreamingOutput {
public void write(OutputStream output) throws IOException {
try {
builder.retriveContent(output, path);
} catch (PathNotFoundException ex) {
if (logger.isWarnEnabled()) {
logger.warn("could not find path {}", ex.getPath());
}
throw new WebApplicationException(Response.Status.NOT_FOUND);
} catch (RevisionNotFoundException ex) {
if (logger.isWarnEnabled()) {
logger.warn("could not find revision {}", ex.getRevision());
}
throw new WebApplicationException(Response.Status.NOT_FOUND);
} finally {
IOUtil.close(repositoryService);
}

View File

@@ -44,8 +44,6 @@ import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ConcurrentModificationException;
import sonia.scm.NotFoundException;
import sonia.scm.api.rest.RestActionResult;
import sonia.scm.security.Role;
import sonia.scm.security.ScmSecurityException;

View File

@@ -37,7 +37,6 @@ package sonia.scm.api.rest.resources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.DiffCommandBuilder;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.util.IOUtil;
@@ -95,22 +94,6 @@ public class DiffStreamingOutput implements StreamingOutput
{
builder.retrieveContent(output);
}
catch (RevisionNotFoundException ex)
{
if (logger.isWarnEnabled())
{
logger.warn("could not find revision {}", ex.getRevision());
}
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
// catch (RepositoryException ex)
// {
// logger.error("could not write content to page", ex);
//
// throw new WebApplicationException(ex,
// Response.Status.INTERNAL_SERVER_ERROR);
// }
finally
{
IOUtil.close(repositoryService);

View File

@@ -45,11 +45,11 @@ import com.webcohesion.enunciate.metadata.rs.TypeHint;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.AlreadyExistsException;
import sonia.scm.NotFoundException;
import sonia.scm.NotSupportedFeatuerException;
import sonia.scm.NotSupportedFeatureException;
import sonia.scm.Type;
import sonia.scm.api.rest.RestActionUploadResult;
import sonia.scm.api.v2.resources.RepositoryResource;
import sonia.scm.repository.*;
import sonia.scm.repository.api.Command;
import sonia.scm.repository.api.RepositoryService;
@@ -394,7 +394,7 @@ public class RepositoryImportResource
response = Response.ok(result).build();
}
catch (NotSupportedFeatuerException ex)
catch (NotSupportedFeatureException ex)
{
logger
.warn(
@@ -515,13 +515,6 @@ public class RepositoryImportResource
// repository = new Repository(null, type, name);
manager.create(repository);
}
catch (AlreadyExistsException ex)
{
logger.warn("a {} repository with the name {} already exists", type,
name);
throw new WebApplicationException(Response.Status.CONFLICT);
}
catch (InternalRepositoryException ex)
{
handleGenericCreationFailure(ex, type, name);
@@ -616,7 +609,7 @@ public class RepositoryImportResource
types.add(t);
}
}
catch (NotSupportedFeatuerException ex)
catch (NotSupportedFeatureException ex)
{
if (logger.isTraceEnabled())
{
@@ -718,7 +711,7 @@ public class RepositoryImportResource
}
}
}
catch (NotSupportedFeatuerException ex)
catch (NotSupportedFeatureException ex)
{
throw new WebApplicationException(ex, Response.Status.BAD_REQUEST);
}

View File

@@ -28,12 +28,14 @@
*/
package sonia.scm.api.v2.resources;
package sonia.scm.api.v2;
import sonia.scm.NotFoundException;
import sonia.scm.api.rest.StatusExceptionMapper;
import sonia.scm.api.rest.ContextualExceptionMapper;
import sonia.scm.api.v2.resources.ExceptionWithContextToErrorDtoMapper;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
@@ -41,9 +43,9 @@ import javax.ws.rs.ext.Provider;
* @since 2.0.0
*/
@Provider
public class NotFoundExceptionMapper extends StatusExceptionMapper<NotFoundException> {
public NotFoundExceptionMapper() {
super(NotFoundException.class, Response.Status.NOT_FOUND);
public class NotFoundExceptionMapper extends ContextualExceptionMapper<NotFoundException> {
@Inject
public NotFoundExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
super(NotFoundException.class, Response.Status.NOT_FOUND, mapper);
}
}

View File

@@ -0,0 +1,17 @@
package sonia.scm.api.v2;
import sonia.scm.NotSupportedFeatureException;
import sonia.scm.api.rest.ContextualExceptionMapper;
import sonia.scm.api.v2.resources.ExceptionWithContextToErrorDtoMapper;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
@Provider
public class NotSupportedFeatureExceptionMapper extends ContextualExceptionMapper<NotSupportedFeatureException> {
@Inject
public NotSupportedFeatureExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
super(NotSupportedFeatureException.class, Response.Status.BAD_REQUEST, mapper);
}
}

View File

@@ -1,58 +1,30 @@
package sonia.scm.api.v2;
import lombok.Getter;
import org.jboss.resteasy.api.validation.ResteasyViolationException;
import sonia.scm.api.v2.resources.ViolationExceptionToErrorDtoMapper;
import javax.validation.ConstraintViolation;
import javax.inject.Inject;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
import java.util.stream.Collectors;
@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ResteasyViolationException> {
private final ViolationExceptionToErrorDtoMapper mapper;
@Inject
public ValidationExceptionMapper(ViolationExceptionToErrorDtoMapper mapper) {
this.mapper = mapper;
}
@Override
public Response toResponse(ResteasyViolationException exception) {
List<ConstraintViolationBean> violations =
exception.getConstraintViolations()
.stream()
.map(ConstraintViolationBean::new)
.collect(Collectors.toList());
return Response
.status(Response.Status.BAD_REQUEST)
.type(MediaType.APPLICATION_JSON_TYPE)
.entity(new ValidationError(violations))
.entity(mapper.map(exception))
.build();
}
@Getter
public static class ValidationError {
@XmlElement(name = "violation")
@XmlElementWrapper(name = "violations")
private List<ConstraintViolationBean> violations;
public ValidationError(List<ConstraintViolationBean> violations) {
this.violations = violations;
}
}
@XmlRootElement(name = "violation")
@Getter
public static class ConstraintViolationBean {
private String path;
private String message;
public ConstraintViolationBean(ConstraintViolation<?> violation) {
message = violation.getMessage();
path = violation.getPropertyPath().toString();
}
}
}

View File

@@ -11,7 +11,6 @@ import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RepositoryPermissions;
import sonia.scm.repository.api.CommandNotSupportedException;
import sonia.scm.repository.api.RepositoryService;
@@ -29,6 +28,9 @@ import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.List;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
public class BranchRootResource {
private final RepositoryServiceFactory serviceFactory;
@@ -79,7 +81,7 @@ public class BranchRootResource {
.build();
} catch (CommandNotSupportedException ex) {
return Response.status(Response.Status.BAD_REQUEST).build();
} catch (RepositoryNotFoundException e) {
} catch (NotFoundException e) {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
@@ -99,7 +101,7 @@ public class BranchRootResource {
@PathParam("name") String name,
@PathParam("branch") String branchName,
@DefaultValue("0") @QueryParam("page") int page,
@DefaultValue("10") @QueryParam("pageSize") int pageSize) throws Exception {
@DefaultValue("10") @QueryParam("pageSize") int pageSize) throws IOException {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
boolean branchExists = repositoryService.getBranchesCommand()
.getBranches()
@@ -107,7 +109,7 @@ public class BranchRootResource {
.stream()
.anyMatch(branch -> branchName.equals(branch.getName()));
if (!branchExists){
throw new NotFoundException("branch", branchName);
throw notFound(entity(Branch.class, branchName).in(Repository.class, namespace + "/" + name));
}
Repository repository = repositoryService.getRepository();
RepositoryPermissions.read(repository).check();
@@ -195,8 +197,6 @@ public class BranchRootResource {
return Response.ok(branchCollectionToDtoMapper.map(namespace, name, branches.getBranches())).build();
} catch (CommandNotSupportedException ex) {
return Response.status(Response.Status.BAD_REQUEST).build();
} catch (RepositoryNotFoundException e) {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}

View File

@@ -1,17 +1,17 @@
package sonia.scm.api.v2.resources;
import sonia.scm.api.rest.ContextualExceptionMapper;
import sonia.scm.user.ChangePasswordNotAllowedException;
import sonia.scm.user.InvalidPasswordException;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
@Provider
public class ChangePasswordNotAllowedExceptionMapper implements ExceptionMapper<ChangePasswordNotAllowedException> {
@Override
public Response toResponse(ChangePasswordNotAllowedException exception) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(exception.getMessage())
.build();
public class ChangePasswordNotAllowedExceptionMapper extends ContextualExceptionMapper<ChangePasswordNotAllowedException> {
@Inject
public ChangePasswordNotAllowedExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
super(ChangePasswordNotAllowedException.class, Response.Status.BAD_REQUEST, mapper);
}
}

View File

@@ -9,9 +9,7 @@ import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RepositoryPermissions;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.web.VndMediaType;
@@ -56,7 +54,7 @@ public class ChangesetRootResource {
@Produces(VndMediaType.CHANGESET_COLLECTION)
@TypeHint(CollectionDto.class)
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name, @DefaultValue("0") @QueryParam("page") int page,
@DefaultValue("10") @QueryParam("pageSize") int pageSize) throws IOException, RevisionNotFoundException, RepositoryNotFoundException {
@DefaultValue("10") @QueryParam("pageSize") int pageSize) throws IOException {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
Repository repository = repositoryService.getRepository();
RepositoryPermissions.read(repository).check();

View File

@@ -1,7 +1,6 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import sonia.scm.AlreadyExistsException;
import sonia.scm.Manager;
import sonia.scm.ModelObject;
import sonia.scm.PageResult;
@@ -47,7 +46,7 @@ class CollectionResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
* Creates a model object for the given dto and returns a corresponding http response.
* This handles all corner cases, eg. no conflicts or missing privileges.
*/
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws AlreadyExistsException {
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) {
if (dto == null) {
return Response.status(BAD_REQUEST).build();
}

View File

@@ -6,10 +6,8 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.NotFoundException;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.util.IOUtil;
@@ -64,8 +62,8 @@ public class ContentResource {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
Response.ResponseBuilder responseBuilder = Response.ok(stream);
return createContentHeader(namespace, name, revision, path, repositoryService, responseBuilder);
} catch (RepositoryNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
} catch (NotFoundException e) {
LOG.debug(e.getMessage());
return Response.status(Status.NOT_FOUND).build();
}
}
@@ -75,14 +73,8 @@ public class ContentResource {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
repositoryService.getCatCommand().setRevision(revision).retriveContent(os, path);
os.close();
} catch (RepositoryNotFoundException e) {
LOG.debug("repository {}/{} not found", path, namespace, name, e);
throw new WebApplicationException(Status.NOT_FOUND);
} catch (PathNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
throw new WebApplicationException(Status.NOT_FOUND);
} catch (RevisionNotFoundException e) {
LOG.debug("revision '{}' not found in repository {}/{}", revision, namespace, name, e);
} catch (NotFoundException e) {
LOG.debug(e.getMessage());
throw new WebApplicationException(Status.NOT_FOUND);
}
};
@@ -111,8 +103,8 @@ public class ContentResource {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
Response.ResponseBuilder responseBuilder = Response.ok();
return createContentHeader(namespace, name, revision, path, repositoryService, responseBuilder);
} catch (RepositoryNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
} catch (NotFoundException e) {
LOG.debug(e.getMessage());
return Response.status(Status.NOT_FOUND).build();
}
}
@@ -120,12 +112,6 @@ public class ContentResource {
private Response createContentHeader(String namespace, String name, String revision, String path, RepositoryService repositoryService, Response.ResponseBuilder responseBuilder) {
try {
appendContentHeader(path, getHead(revision, path, repositoryService), responseBuilder);
} catch (PathNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
return Response.status(Status.NOT_FOUND).build();
} catch (RevisionNotFoundException e) {
LOG.debug("revision '{}' not found in repository {}/{}", revision, namespace, name, e);
return Response.status(Status.NOT_FOUND).build();
} catch (IOException e) {
LOG.info("error reading repository resource {} from {}/{}", path, namespace, name, e);
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
@@ -139,7 +125,7 @@ public class ContentResource {
contentType.getLanguage().ifPresent(language -> responseBuilder.header("X-Programming-Language", language));
}
private byte[] getHead(String revision, String path, RepositoryService repositoryService) throws IOException, PathNotFoundException, RevisionNotFoundException {
private byte[] getHead(String revision, String path, RepositoryService repositoryService) throws IOException {
InputStream stream = repositoryService.getCatCommand().setRevision(revision).getStream(path);
try {
byte[] buffer = new byte[HEAD_BUFFER_SIZE];

View File

@@ -4,7 +4,6 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import sonia.scm.NotFoundException;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.DiffFormat;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
@@ -19,7 +18,6 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
@@ -62,14 +60,10 @@ public class DiffRootResource {
DiffFormat diffFormat = DiffFormat.valueOf(format);
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
StreamingOutput responseEntry = output -> {
try {
repositoryService.getDiffCommand()
.setRevision(revision)
repositoryService.getDiffCommand()
.setRevision(revision)
.setFormat(diffFormat)
.retrieveContent(output);
} catch (RevisionNotFoundException e) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
.retrieveContent(output);
};
return Response.ok(responseEntry)
.header(HEADER_CONTENT_DISPOSITION, HttpUtil.createContentDispositionAttachmentHeader(String.format("%s-%s.diff", name, revision)))

View File

@@ -0,0 +1,33 @@
package sonia.scm.api.v2.resources;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
import sonia.scm.ContextEntry;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
@Getter @Setter
public class ErrorDto {
private String transactionId;
private String errorCode;
private List<ContextEntry> context;
private String message;
@JsonInclude(JsonInclude.Include.NON_NULL)
@XmlElementWrapper(name = "violations")
private List<ConstraintViolationDto> violations;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String url;
@XmlRootElement(name = "violation")
@Getter @Setter
public static class ConstraintViolationDto {
private String path;
private String message;
}
}

View File

@@ -0,0 +1,23 @@
package sonia.scm.api.v2.resources;
import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.slf4j.MDC;
import sonia.scm.ExceptionWithContext;
@Mapper
public abstract class ExceptionWithContextToErrorDtoMapper {
@Mapping(target = "errorCode", source = "code")
@Mapping(target = "transactionId", ignore = true)
@Mapping(target = "violations", ignore = true)
@Mapping(target = "url", ignore = true)
public abstract ErrorDto map(ExceptionWithContext exception);
@AfterMapping
void setTransactionId(@MappingTarget ErrorDto dto) {
dto.setTransactionId(MDC.get("transaction_id"));
}
}

View File

@@ -7,11 +7,8 @@ import lombok.extern.slf4j.Slf4j;
import sonia.scm.PageResult;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.web.VndMediaType;
@@ -26,6 +23,9 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.io.IOException;
import static sonia.scm.ContextEntry.ContextBuilder.entity;
import static sonia.scm.NotFoundException.notFound;
@Slf4j
public class FileHistoryRootResource {
@@ -51,8 +51,6 @@ public class FileHistoryRootResource {
* @param pageSize pagination
* @return all changesets related to the given file starting with the given revision
* @throws IOException on io error
* @throws RevisionNotFoundException on missing revision
* @throws RepositoryNotFoundException on missing repository
*/
@GET
@Path("{revision}/{path: .*}")
@@ -69,8 +67,9 @@ public class FileHistoryRootResource {
@PathParam("revision") String revision,
@PathParam("path") String path,
@DefaultValue("0") @QueryParam("page") int page,
@DefaultValue("10") @QueryParam("pageSize") int pageSize) throws IOException, RevisionNotFoundException, RepositoryNotFoundException {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
@DefaultValue("10") @QueryParam("pageSize") int pageSize) throws IOException {
NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name);
try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) {
log.info("Get changesets of the file {} and revision {}", path, revision);
Repository repository = repositoryService.getRepository();
ChangesetPagingResult changesets = new PagedLogCommandBuilder(repositoryService)
@@ -84,9 +83,9 @@ public class FileHistoryRootResource {
PageResult<Changeset> pageResult = new PageResult<>(changesets.getChangesets(), changesets.getTotal());
return Response.ok(fileHistoryCollectionToDtoMapper.map(page, pageSize, pageResult, repository, revision, path)).build();
} else {
String message = String.format("for the revision %s and the file %s there is no changesets", revision, path);
String message = String.format("for the revision %s and the file %s there are no changesets", revision, path);
log.error(message);
throw new InternalRepositoryException(message);
throw notFound(entity("path", path).in("revision", revision).in(namespaceAndName));
}
}
}

View File

@@ -5,12 +5,12 @@ import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
import com.webcohesion.enunciate.metadata.rs.ResponseHeaders;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
import sonia.scm.AlreadyExistsException;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.inject.Named;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
@@ -86,7 +86,7 @@ public class GroupCollectionResource {
})
@TypeHint(TypeHint.NO_CONTENT.class)
@ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created group"))
public Response create(@Valid GroupDto groupDto) throws AlreadyExistsException {
public Response create(@Valid @Named("group") GroupDto groupDto) {
return adapter.create(groupDto,
() -> dtoToGroupMapper.map(groupDto),
group -> resourceLinks.group().self(group.getName()));

View File

@@ -3,13 +3,12 @@ package sonia.scm.api.v2.resources;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
import sonia.scm.ConcurrentModificationException;
import sonia.scm.NotFoundException;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.inject.Named;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -98,7 +97,7 @@ public class GroupResource {
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(TypeHint.NO_CONTENT.class)
public Response update(@PathParam("id") String name, @Valid GroupDto groupDto) throws ConcurrentModificationException {
public Response update(@PathParam("id") String name, @Valid @Named("group") GroupDto groupDto) {
return adapter.update(name, existing -> dtoToGroupMapper.map(groupDto));
}
}

View File

@@ -1,10 +1,9 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import sonia.scm.AlreadyExistsException;
import sonia.scm.ConcurrentModificationException;
import sonia.scm.Manager;
import sonia.scm.ModelObject;
import sonia.scm.NotFoundException;
import sonia.scm.PageResult;
import javax.ws.rs.core.Response;
@@ -22,6 +21,7 @@ class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
DTO extends HalRepresentation> {
private final Manager<MODEL_OBJECT> manager;
private final String type;
private final SingleResourceManagerAdapter<MODEL_OBJECT, DTO> singleAdapter;
private final CollectionResourceManagerAdapter<MODEL_OBJECT, DTO> collectionAdapter;
@@ -30,13 +30,14 @@ class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
this.manager = manager;
singleAdapter = new SingleResourceManagerAdapter<>(manager, type);
collectionAdapter = new CollectionResourceManagerAdapter<>(manager, type);
this.type = type.getSimpleName();
}
Response get(String id, Function<MODEL_OBJECT, DTO> mapToDto) {
return singleAdapter.get(loadBy(id), mapToDto);
}
public Response update(String id, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges) throws ConcurrentModificationException {
public Response update(String id, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges) {
return singleAdapter.update(
loadBy(id),
applyChanges,
@@ -48,7 +49,7 @@ class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
return collectionAdapter.getAll(page, pageSize, sortBy, desc, mapToDto);
}
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws AlreadyExistsException {
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) {
return collectionAdapter.create(dto, modelObjectSupplier, uriCreator);
}
@@ -56,8 +57,8 @@ class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
return singleAdapter.delete(id);
}
private Supplier<Optional<MODEL_OBJECT>> loadBy(String id) {
return () -> Optional.ofNullable(manager.get(id));
private Supplier<MODEL_OBJECT> loadBy(String id) {
return () -> Optional.ofNullable(manager.get(id)).orElseThrow(() -> new NotFoundException(type, id));
}
private Predicate<MODEL_OBJECT> idStaysTheSame(String id) {

View File

@@ -1,15 +1,17 @@
package sonia.scm.api.v2.resources;
import sonia.scm.api.rest.StatusExceptionMapper;
import sonia.scm.api.rest.ContextualExceptionMapper;
import sonia.scm.repository.InternalRepositoryException;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
@Provider
public class InternalRepositoryExceptionMapper extends StatusExceptionMapper<InternalRepositoryException> {
public class InternalRepositoryExceptionMapper extends ContextualExceptionMapper<InternalRepositoryException> {
public InternalRepositoryExceptionMapper() {
super(InternalRepositoryException.class, Response.Status.INTERNAL_SERVER_ERROR);
@Inject
public InternalRepositoryExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
super(InternalRepositoryException.class, Response.Status.INTERNAL_SERVER_ERROR, mapper);
}
}

View File

@@ -1,17 +1,17 @@
package sonia.scm.api.v2.resources;
import sonia.scm.api.rest.ContextualExceptionMapper;
import sonia.scm.user.InvalidPasswordException;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
@Provider
public class InvalidPasswordExceptionMapper implements ExceptionMapper<InvalidPasswordException> {
@Override
public Response toResponse(InvalidPasswordException exception) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(exception.getMessage())
.build();
public class InvalidPasswordExceptionMapper extends ContextualExceptionMapper<InvalidPasswordException> {
@Inject
public InvalidPasswordExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
super(InvalidPasswordException.class, Response.Status.BAD_REQUEST, mapper);
}
}

View File

@@ -39,6 +39,9 @@ public class MapperModule extends AbstractModule {
bind(ReducedObjectModelToDtoMapper.class).to(Mappers.getMapper(ReducedObjectModelToDtoMapper.class).getClass());
bind(ViolationExceptionToErrorDtoMapper.class).to(Mappers.getMapper(ViolationExceptionToErrorDtoMapper.class).getClass());
bind(ExceptionWithContextToErrorDtoMapper.class).to(Mappers.getMapper(ExceptionWithContextToErrorDtoMapper.class).getClass());
// no mapstruct required
bind(UIPluginDtoMapper.class);
bind(UIPluginDtoCollectionMapper.class);

Some files were not shown because too many files have changed in this diff Show More