merge with branch 1.x

This commit is contained in:
Sebastian Sdorra
2014-12-06 15:42:10 +01:00
75 changed files with 5923 additions and 516 deletions

View File

@@ -0,0 +1,171 @@
package sonia.scm;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.Sets;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.plugin.Extension;
//~--- JDK imports ------------------------------------------------------------
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* Dispatcher for {@link HttpSessionEvent}. The {@link HttpSessionListenerHolder}
* loads all registered {@link HttpSessionListener}s from the {@link Injector}
* and delegates the events to the them. {@link HttpSessionListener} can be
* registered with the {@link Extension} annotation.
*
* @author Sebastian Sdorra <sebastian.sdorra@gmail.com>
* @since 1.42
*/
public class HttpSessionListenerHolder implements HttpSessionListener
{
/** key type of the session listeners */
private static final Key<Set<HttpSessionListener>> KEY =
Key.get(new TypeLiteral<Set<HttpSessionListener>>() {}
);
/** logger for HttpSessionListenerHolder */
private static final Logger logger =
LoggerFactory.getLogger(HttpSessionListenerHolder.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new HttpSessionListenerHolder.
*
*/
public HttpSessionListenerHolder()
{
if (logger.isDebugEnabled())
{
logger.debug("create instance of {}",
HttpSessionListenerHolder.class.getName());
}
}
//~--- methods --------------------------------------------------------------
/**
* Delegates the create session event to all registered
* {@ĺink HttpSessionListener}s.
*
*
* @param event session event
*/
@Override
public void sessionCreated(HttpSessionEvent event)
{
if (listenerSet == null)
{
listenerSet = loadListeners(event);
}
dispatch(event, true);
}
/**
* Delegates the destroy session event to all registered
* {@ĺink HttpSessionListener}s.
*
*
* @param event session event
*/
@Override
public void sessionDestroyed(HttpSessionEvent event)
{
dispatch(event, false);
}
/**
* Dispatch session events.
*
*
* @param event session event
* @param create {@code true} if the event is a create event
*/
private void dispatch(HttpSessionEvent event, boolean create)
{
if (listenerSet != null)
{
for (HttpSessionListener listener : listenerSet)
{
if (create)
{
listener.sessionCreated(event);
}
else
{
listener.sessionDestroyed(event);
}
}
}
else
{
logger.warn(
"could not dispatch session event, because holder is not initialized");
}
}
/**
* Load listeners from {@link Injector} which is stored in the
* {@link ServletContext}.
*
*
* @param event session event
*
* @return set of session listeners
*/
private synchronized Set<HttpSessionListener> loadListeners(
HttpSessionEvent event)
{
Set<HttpSessionListener> listeners = null;
HttpSession session = event.getSession();
if (session != null)
{
Injector injector = (Injector) session.getServletContext().getAttribute(
Injector.class.getName());
if (injector != null)
{
logger.debug("load HttpSessionListeners from injector");
listeners = injector.getInstance(KEY);
}
else
{
logger.error("could not find injector in servletContext");
}
if (listeners == null)
{
listeners = Sets.newHashSet();
}
}
else
{
logger.warn("received session event without session");
}
return listeners;
}
//~--- fields ---------------------------------------------------------------
/** listener set */
private Set<HttpSessionListener> listenerSet;
}

View File

@@ -37,6 +37,8 @@ import com.google.inject.Inject;
import org.apache.shiro.SecurityUtils;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
import sonia.scm.security.KeyGenerator;
import sonia.scm.security.Role;
@@ -54,6 +56,7 @@ import javax.ws.rs.core.MediaType;
* @since 1.41
*/
@Path("security/key")
@ExternallyManagedLifecycle
public class KeyResource
{
@@ -72,7 +75,7 @@ public class KeyResource
//~--- methods --------------------------------------------------------------
/**
* Generates a unique key. This method can only executed with administration
* Generates a unique key. This method can only executed with administration
* privileges.<br />
* <br />
* <ul>
@@ -93,6 +96,6 @@ public class KeyResource
//~--- fields ---------------------------------------------------------------
/** Field description */
/** key generator */
private final KeyGenerator keyGenerator;
}

View File

@@ -35,8 +35,13 @@ package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.apache.shiro.SecurityUtils;
import org.codehaus.enunciate.jaxrs.TypeHint;
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
@@ -46,31 +51,65 @@ import org.slf4j.LoggerFactory;
import sonia.scm.NotSupportedFeatuerException;
import sonia.scm.Type;
import sonia.scm.api.rest.RestActionUploadResult;
import sonia.scm.repository.AdvancedImportHandler;
import sonia.scm.repository.ImportHandler;
import sonia.scm.repository.ImportResult;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryAllreadyExistExeption;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryHandler;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.util.SecurityUtil;
import sonia.scm.repository.RepositoryType;
import sonia.scm.repository.api.Command;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.repository.api.UnbundleCommandBuilder;
import sonia.scm.security.Role;
import sonia.scm.util.IOUtil;
import static com.google.common.base.Preconditions.*;
//~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.client.ClientResponse.Status;
import com.sun.jersey.multipart.FormDataParam;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
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.Context;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Rest resource for importing repositories.
*
* @author Sebastian Sdorra
*/
@Singleton
@Path("import/repositories")
@ExternallyManagedLifecycle
public class RepositoryImportResource
@@ -85,94 +124,525 @@ public class RepositoryImportResource
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
* Constructs a new repository import resource.
*
*
* @param manager
* @param securityContextProvider
* @param manager repository manager
* @param serviceFactory
*/
@Inject
public RepositoryImportResource(RepositoryManager manager)
public RepositoryImportResource(RepositoryManager manager,
RepositoryServiceFactory serviceFactory)
{
this.manager = manager;
this.serviceFactory = serviceFactory;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
* Imports a repository type specific bundle. The bundle file is uploaded to
* the server which is running scm-manager. After the upload has finished, the
* bundle file is passed to the {@link UnbundleCommandBuilder}. This method
* requires admin privileges.<br />
*
* Status codes:
* <ul>
* <li>201 created</li>
* <li>400 bad request, the import bundle feature is not supported by this
* type of repositories or the parameters are not valid.</li>
* <li>500 internal server error</li>
* <li>409 conflict, a repository with the name already exists.</li>
* </ul>
*
* @param uriInfo uri info
* @param type repository type
* @param name name of the repository
* @param inputStream input bundle
* @param compressed true if the bundle is gzip compressed
*
* @return empty response with location header which points to the imported
* repository
* @since 1.43
*/
@POST
@Path("{type}/bundle")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response importFromBundle(@Context UriInfo uriInfo,
@PathParam("type") String type, @FormDataParam("name") String name,
@FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed")
@DefaultValue("false") boolean compressed)
{
Repository repository = doImportFromBundle(type, name, inputStream,
compressed);
return buildResponse(uriInfo, repository);
}
/**
* This method works exactly like
* {@link #importFromBundle(UriInfo, String, String, InputStream)}, but this
* method returns an html content-type. The method exists only for a
* workaround of the javascript ui extjs. This method requires admin
* privileges.<br />
*
* Status codes:
* <ul>
* <li>201 created</li>
* <li>400 bad request, the import bundle feature is not supported by this
* type of repositories or the parameters are not valid.</li>
* <li>500 internal server error</li>
* <li>409 conflict, a repository with the name already exists.</li>
* </ul>
*
*
* @param type
* @param type repository type
* @param name name of the repository
* @param inputStream input bundle
* @param compressed true if the bundle is gzip compressed
*
* @return
* @return empty response with location header which points to the imported
* repository
* @since 1.43
*/
@POST
@Path("{type}/bundle.html")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_HTML)
public Response importFromBundleUI(@PathParam("type") String type,
@FormDataParam("name") String name,
@FormDataParam("bundle") InputStream inputStream, @QueryParam("compressed")
@DefaultValue("false") boolean compressed)
{
Response response;
try
{
doImportFromBundle(type, name, inputStream, compressed);
response = Response.ok(new RestActionUploadResult(true)).build();
}
catch (WebApplicationException ex)
{
logger.warn("error durring bundle import", ex);
response = Response.fromResponse(ex.getResponse()).entity(
new RestActionUploadResult(false)).build();
}
return response;
}
/**
* Imports a external repository which is accessible via url. The method can
* only be used, if the repository type supports the {@link Command#PULL}. The
* method will return a location header with the url to the imported
* repository. This method requires admin privileges.<br />
*
* Status codes:
* <ul>
* <li>201 created</li>
* <li>400 bad request, the import by url feature is not supported by this
* type of repositories or the parameters are not valid.</li>
* <li>409 conflict, a repository with the name already exists.</li>
* <li>500 internal server error</li>
* </ul>
*
* @param uriInfo uri info
* @param type repository type
* @param request request object
*
* @return empty response with location header which points to the imported
* repository
* @since 1.43
*/
@POST
@Path("{type}/url")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response importFromUrl(@Context UriInfo uriInfo,
@PathParam("type") String type, UrlImportRequest request)
{
SecurityUtils.getSubject().checkRole(Role.ADMIN);
checkNotNull(request, "request is required");
checkArgument(!Strings.isNullOrEmpty(request.getName()),
"request does not contain name of the repository");
checkArgument(!Strings.isNullOrEmpty(request.getUrl()),
"request does not contain url of the remote repository");
Type t = type(type);
checkSupport(t, Command.PULL, request);
logger.info("start {} import for external url {}", type, request.getUrl());
Repository repository = create(type, request.getName());
RepositoryService service = null;
try
{
service = serviceFactory.create(repository);
service.getPullCommand().pull(request.getUrl());
}
catch (RepositoryException ex)
{
handleImportFailure(ex, repository);
}
catch (IOException ex)
{
handleImportFailure(ex, repository);
}
finally
{
IOUtil.close(service);
}
return buildResponse(uriInfo, repository);
}
/**
* Imports repositories of the given type from the configured repository
* directory. This method requires admin privileges.<br />
* <br />
* Status codes:
* <ul>
* <li>200 ok, successful</li>
* <li>400 bad request, the import feature is not
* supported by this type of repositories.</li>
* <li>500 internal server error</li>
* </ul>
*
* @param type repository type
*
* @return imported repositories
*/
@POST
@Path("{type}")
@TypeHint(Repository[].class)
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public GenericEntity<List<Repository>> importRepositories(
@PathParam("type") String type)
public Response importRepositories(@PathParam("type") String type)
{
SecurityUtil.assertIsAdmin();
SecurityUtils.getSubject().checkRole(Role.ADMIN);
List<Repository> repositories = new ArrayList<Repository>();
importFromDirectory(repositories, type);
//J-
return Response.ok(
new GenericEntity<List<Repository>>(repositories) {}
).build();
//J+
}
/**
* Imports repositories of all supported types from the configured repository
* directories. This method requires admin privileges.<br />
* <br />
* Status codes:
* <ul>
* <li>200 ok, successful</li>
* <li>400 bad request, the import feature is not
* supported by this type of repositories.</li>
* <li>500 internal server error</li>
* </ul>
*
* @return imported repositories
*/
@POST
@TypeHint(Repository[].class)
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response importRepositories()
{
SecurityUtils.getSubject().checkRole(Role.ADMIN);
logger.info("start directory import for all supported repository types");
List<Repository> repositories = new ArrayList<Repository>();
for (Type t : findImportableTypes())
{
importFromDirectory(repositories, t.getName());
}
//J-
return Response.ok(
new GenericEntity<List<Repository>>(repositories) {}
).build();
//J+
}
/**
* Imports repositories of the given type from the configured repository
* directory. Returns a list of successfully imported directories and a list
* of failed directories. This method requires admin privileges.<br />
* <br />
* Status codes:
* <ul>
* <li>200 ok, successful</li>
* <li>400 bad request, the import feature is not
* supported by this type of repositories.</li>
* <li>500 internal server error</li>
* </ul>
*
* @param type repository type
*
* @return imported repositories
* @since 1.43
*/
@POST
@Path("{type}/directory")
@TypeHint(ImportResult.class)
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response importRepositoriesFromDirectory(
@PathParam("type") String type)
{
SecurityUtils.getSubject().checkRole(Role.ADMIN);
Response response;
RepositoryHandler handler = manager.getHandler(type);
if (handler != null)
{
logger.info("start directory import for repository type {}", type);
try
{
List<String> repositoryNames =
handler.getImportHandler().importRepositories(manager);
ImportResult result;
ImportHandler importHandler = handler.getImportHandler();
if (repositoryNames != null)
if (importHandler instanceof AdvancedImportHandler)
{
for (String repositoryName : repositoryNames)
{
Repository repository = manager.get(type, repositoryName);
if (repository != null)
{
repositories.add(repository);
}
else if (logger.isWarnEnabled())
{
logger.warn("could not find imported repository {}",
repositoryName);
}
}
logger.debug("start directory import, using advanced import handler");
result =
((AdvancedImportHandler) importHandler)
.importRepositoriesFromDirectory(manager);
}
else
{
logger.debug("start directory import, using normal import handler");
result = new ImportResult(importHandler.importRepositories(manager),
ImmutableList.<String>of());
}
response = Response.ok(result).build();
}
catch (Exception ex)
catch (NotSupportedFeatuerException ex)
{
throw new WebApplicationException(ex);
logger
.warn(
"import feature is not supported by repository handler for type "
.concat(type), ex);
response = Response.status(Status.BAD_REQUEST).build();
}
catch (IOException ex)
{
logger.warn("exception occured durring directory import", ex);
response = Response.serverError().build();
}
catch (RepositoryException ex)
{
logger.warn("exception occured durring directory import", ex);
response = Response.serverError().build();
}
}
else if (logger.isWarnEnabled())
else
{
logger.warn("could not find handler for type {}", type);
logger.warn("could not find reposiotry handler for type {}", type);
response = Response.status(Status.BAD_REQUEST).build();
}
return new GenericEntity<List<Repository>>(repositories) {}
;
return response;
}
//~--- get methods ----------------------------------------------------------
/**
* Returns a list of repository types, which support the directory import
* feature.
*
* This method requires admin privileges.<br />
* <br />
* Status codes:
* <ul>
* <li>200 ok, successful</li>
* <li>400 bad request, the import feature is not
* supported by this type of repositories.</li>
* <li>500 internal server error</li>
* </ul>
*
* @return list of repository types
*/
@GET
@TypeHint(Type[].class)
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response getImportableTypes()
{
SecurityUtils.getSubject().checkRole(Role.ADMIN);
List<Type> types = findImportableTypes();
//J-
return Response.ok(
new GenericEntity<List<Type>>(types) {}
).build();
//J+
}
//~--- methods --------------------------------------------------------------
/**
* Build rest response for repository.
*
*
* @param uriInfo uri info
* @param repository imported repository
*
* @return rest response
*/
private Response buildResponse(UriInfo uriInfo, Repository repository)
{
URI location = uriInfo.getBaseUriBuilder().path(
RepositoryResource.class).path(repository.getId()).build();
return Response.created(location).build();
}
/**
* Check repository type for support for the given command.
*
*
* @param type repository type
* @param cmd command
* @param request request object
*/
private void checkSupport(Type type, Command cmd, Object request)
{
if (!(type instanceof RepositoryType))
{
logger.warn("type {} is not a repository type", type.getName());
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}
Set<Command> cmds = ((RepositoryType) type).getSupportedCommands();
if (!cmds.contains(cmd))
{
logger.warn("type {} does not support this type of import: {}",
type.getName(), request);
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}
}
/**
* Creates a new repository with the given name and type.
*
*
* @param type repository type
* @param name repository name
*
* @return newly created repository
*/
private Repository create(String type, String name)
{
Repository repository = null;
try
{
repository = new Repository(null, type, name);
manager.create(repository);
}
catch (RepositoryAllreadyExistExeption ex)
{
logger.warn("a {} repository with the name {} already exists", ex);
throw new WebApplicationException(Response.Status.CONFLICT);
}
catch (RepositoryException ex)
{
handleGenericCreationFailure(ex, type, name);
}
catch (IOException ex)
{
handleGenericCreationFailure(ex, type, name);
}
return repository;
}
/**
* Start bundle import.
*
*
* @param type repository type
* @param name name of the repository
* @param inputStream bundle stream
* @param compressed true if the bundle is gzip compressed
*
* @return imported repository
*/
private Repository doImportFromBundle(String type, String name,
InputStream inputStream, boolean compressed)
{
SecurityUtils.getSubject().checkRole(Role.ADMIN);
checkArgument(!Strings.isNullOrEmpty(name),
"request does not contain name of the repository");
checkNotNull(inputStream, "bundle inputStream is required");
Repository repository;
try
{
Type t = type(type);
checkSupport(t, Command.UNBUNDLE, "bundle");
repository = create(type, name);
RepositoryService service = null;
File file = File.createTempFile("scm-import-", ".bundle");
try
{
long length = Files.asByteSink(file).writeFrom(inputStream);
logger.info("copied {} bytes to temp, start bundle import", length);
service = serviceFactory.create(repository);
service.getUnbundleCommand().setCompressed(compressed).unbundle(file);
}
catch (RepositoryException ex)
{
handleImportFailure(ex, repository);
}
catch (IOException ex)
{
handleImportFailure(ex, repository);
}
finally
{
IOUtil.close(service);
IOUtil.delete(file);
}
}
catch (IOException ex)
{
logger.warn("could not create temporary file", ex);
throw new WebApplicationException(ex);
}
return repository;
}
/**
* Method description
*
*
* @return
*/
@GET
@TypeHint(Type[].class)
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public GenericEntity<List<Type>> getImportableTypes()
private List<Type> findImportableTypes()
{
SecurityUtil.assertIsAdmin();
List<Type> types = new ArrayList<Type>();
Collection<Type> handlerTypes = manager.getTypes();
@@ -208,12 +678,217 @@ public class RepositoryImportResource
}
}
return new GenericEntity<List<Type>>(types) {}
;
return types;
}
/**
* Handle creation failures.
*
*
* @param ex exception
* @param type repository type
* @param name name of the repository
*/
private void handleGenericCreationFailure(Exception ex, String type,
String name)
{
logger.error(String.format("could not create repository {} with type {}",
type, name), ex);
throw new WebApplicationException(ex);
}
/**
* Handle import failures.
*
*
* @param ex exception
* @param repository repository
*/
private void handleImportFailure(Exception ex, Repository repository)
{
logger.error("import for repository failed, delete repository", ex);
try
{
manager.delete(repository);
}
catch (IOException e)
{
logger.error("can not delete repository", e);
}
catch (RepositoryException e)
{
logger.error("can not delete repository", e);
}
throw new WebApplicationException(ex,
Response.Status.INTERNAL_SERVER_ERROR);
}
/**
* Import repositories from a specific type.
*
*
* @param repositories repository list
* @param type type of repository
*/
private void importFromDirectory(List<Repository> repositories, String type)
{
RepositoryHandler handler = manager.getHandler(type);
if (handler != null)
{
logger.info("start directory import for repository type {}", type);
try
{
List<String> repositoryNames =
handler.getImportHandler().importRepositories(manager);
if (repositoryNames != null)
{
for (String repositoryName : repositoryNames)
{
Repository repository = manager.get(type, repositoryName);
if (repository != null)
{
repositories.add(repository);
}
else if (logger.isWarnEnabled())
{
logger.warn("could not find imported repository {}",
repositoryName);
}
}
}
}
catch (NotSupportedFeatuerException ex)
{
throw new WebApplicationException(ex, Response.Status.BAD_REQUEST);
}
catch (IOException ex)
{
throw new WebApplicationException(ex);
}
catch (RepositoryException ex)
{
throw new WebApplicationException(ex);
}
}
else
{
throw new WebApplicationException(Response.Status.BAD_REQUEST);
}
}
/**
* Method description
*
*
* @param type
*
* @return
*/
private Type type(String type)
{
RepositoryHandler handler = manager.getHandler(type);
if (handler == null)
{
logger.warn("no handler for type {} found", type);
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return handler.getType();
}
//~--- inner classes --------------------------------------------------------
/**
* Request for importing external repositories which are accessible via url.
*/
@XmlRootElement(name = "import")
@XmlAccessorType(XmlAccessType.FIELD)
public static class UrlImportRequest
{
/**
* Constructs ...
*
*/
public UrlImportRequest() {}
/**
* Constructs a new {@link UrlImportRequest}
*
*
* @param name name of the repository
* @param url external url of the repository
*/
public UrlImportRequest(String name, String url)
{
this.name = name;
this.url = url;
}
//~--- methods ------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
//J-
return Objects.toStringHelper(this)
.add("name", name)
.add("url", url)
.toString();
//J+
}
//~--- get methods --------------------------------------------------------
/**
* Returns name of the repository.
*
*
* @return name of the repository
*/
public String getName()
{
return name;
}
/**
* Returns external url of the repository.
*
*
* @return external url of the repository
*/
public String getUrl()
{
return url;
}
//~--- fields -------------------------------------------------------------
/** name of the repository */
private String name;
/** external url of the repository */
private String url;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private RepositoryManager manager;
/** repository manager */
private final RepositoryManager manager;
/** repository service factory */
private final RepositoryServiceFactory serviceFactory;
}

View File

@@ -99,6 +99,10 @@ public class DefaultUserManager extends AbstractUserManager
/**
* Constructs ...
*
<<<<<<< mine
=======
*
>>>>>>> theirs
* @param userDAO
*/
@Inject
@@ -227,8 +231,8 @@ public class DefaultUserManager extends AbstractUserManager
public void init(SCMContextProvider context)
{
// TODO improve
if (!userDAO.contains("scmadmin") &&!userDAO.contains("anonymous"))
// create default account only, if no other account is available
if (userDAO.getAll().isEmpty())
{
createDefaultAccounts();
}
@@ -519,6 +523,8 @@ public class DefaultUserManager extends AbstractUserManager
{
try
{
logger.info("create default accounts");
JAXBContext context = JAXBContext.newInstance(User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();