mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-09 06:55:47 +01:00
merge with branch 1.x
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user