/* (c) 2016 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geogig.geoserver.rest; import static org.locationtech.geogig.web.api.RESTUtils.getStringAttribute; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import org.geogig.geoserver.config.RepositoryInfo; import org.geogig.geoserver.config.RepositoryManager; import org.locationtech.geogig.plumbing.ResolveGeogigURI; import org.locationtech.geogig.repository.Hints; import org.locationtech.geogig.repository.Repository; import org.locationtech.geogig.repository.RepositoryConnectionException; import org.locationtech.geogig.repository.RepositoryResolver; import org.locationtech.geogig.repository.impl.GeoGIG; import org.locationtech.geogig.rest.RestletException; import org.locationtech.geogig.rest.repository.InitRequestUtil; import org.locationtech.geogig.rest.repository.RepositoryProvider; import org.restlet.data.Method; import org.restlet.data.Request; import org.restlet.data.Status; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import com.google.common.collect.Iterators; /** * {@link RepositoryProvider} that looks up the coresponding {@link GeoGIG} instance to a given * {@link Request} by asking the geoserver's {@link RepositoryManager} */ public class GeoServerRepositoryProvider implements RepositoryProvider { /** * Init request command string. */ public static final String INIT_CMD = "init"; /** * Import Existing Repository command string. */ public static final String IMPORT_CMD = "importExistingRepo"; private Optional<String> getRepositoryName(Request request) { final String repo = getStringAttribute(request, "repository"); return Optional.fromNullable(repo); } public Optional<RepositoryInfo> findRepository(Request request) { Optional<String> repositoryName = getRepositoryName(request); if (!repositoryName.isPresent()) { return Optional.absent(); } try { String repoName = repositoryName.get(); String repoId = getRepoIdForName(repoName); if (repoId != null) { RepositoryManager repositoryManager = RepositoryManager.get(); RepositoryInfo repositoryInfo; repositoryInfo = repositoryManager.get(repoId); return Optional.of(repositoryInfo); } else { return Optional.absent(); } } catch (NoSuchElementException | IOException e) { return Optional.absent(); } } public List<RepositoryInfo> getRepositoryInfos() { return RepositoryManager.get().getAll(); } private String getRepoIdForName(String repoName) { // get the list of Repos the Manager knows about // loop and return the id if we find one for (RepositoryInfo repo : getRepositoryInfos()) { if (repo.getRepoName().equals(repoName)) { return repo.getId(); } } return null; } @Override public void delete(Request request) { Optional<Repository> geogig = getGeogig(request); Preconditions.checkState(geogig.isPresent(), "No repository to delete."); final String repositoryName = getStringAttribute(request, "repository"); final String repoId = getRepoIdForName(repositoryName); Repository ggig = geogig.get(); Optional<URI> repoUri = ggig.command(ResolveGeogigURI.class).call(); Preconditions.checkState(repoUri.isPresent(), "No repository to delete."); ggig.close(); try { GeoGIG.delete(repoUri.get()); RepositoryManager manager = RepositoryManager.get(); manager.delete(repoId); } catch (Exception e) { Throwables.propagate(e); } } @Override public void invalidate(String repoName) { final String repoId = getRepoIdForName(repoName); if (repoId != null) { RepositoryManager manager = RepositoryManager.get(); manager.invalidate(repoId); } } @Override public Iterator<String> findRepositories() { List<RepositoryInfo> infos = getRepositoryInfos(); return Iterators.transform(infos.iterator(), new Function<RepositoryInfo, String>() { @Override public String apply(RepositoryInfo input) { return input.getRepoName(); } }); } private boolean isInitRequest(Request request) { // if the request is a PUT, and the request path ends in "init", it's an INIT request. if (Method.PUT.equals(request.getMethod())) { Map<String, Object> attributes = request.getAttributes(); if (attributes != null && attributes.containsKey("command")) { return INIT_CMD.equals(attributes.get("command")); } else if (request.getResourceRef() != null) { String path = request.getResourceRef().getPath(); return path != null && path.contains(INIT_CMD); } } return false; } private boolean isImportRequest(Request request) { // if the request is a POST, and the request path ends in "importExistingRepo" if (Method.POST.equals(request.getMethod())) { Map<String, Object> attributes = request.getAttributes(); if (attributes != null && attributes.containsKey("command")) { return IMPORT_CMD.equals(attributes.get("command")); } else if (request.getResourceRef() != null) { String path = request.getResourceRef().getPath(); return path != null && path.contains(IMPORT_CMD); } } return false; } @Override public Optional<Repository> getGeogig(Request request) { Optional<String> repositoryName = getRepositoryName(request); if (!repositoryName.isPresent()) { return Optional.absent(); } // look for one with the provided name first Optional<Repository> geogig = getGeogig(repositoryName.get()); if (!geogig.isPresent()) { if (isInitRequest(request)) { // special handling of INIT requests geogig = AddRepoRequestHandler.createGeoGIG(request); } else if (isImportRequest(request)){ // handles IMPORT requests geogig = AddRepoRequestHandler.importGeogig(request); } } if (!geogig.isPresent()) { // if it's still not present, just generate one. // This is so the CommandResource can get into the runCmd code before failing and // generating the correct responses geogig = Optional.fromNullable(RepositoryManager.get().createRepo(new Hints())); } return geogig; } public Optional<Repository> getGeogig(String repositoryName) { Repository geogig = findRepository(repositoryName); return Optional.fromNullable(geogig); } private Repository findRepository(String repositoryName) { RepositoryManager manager = RepositoryManager.get(); String repoId = getRepoIdForName(repositoryName); if (null == repoId) { return null; } try { RepositoryInfo info = manager.get(repoId); return manager.getRepository(repoId); } catch (IOException e) { throw new RestletException("Error accessing datastore " + repositoryName, Status.SERVER_ERROR_INTERNAL, e); } } private static class AddRepoRequestHandler { private static Optional<Repository> createGeoGIG(Request request) { try { final Hints hints = InitRequestUtil.createHintsFromRequest(request); // now build the repo with the Hints return Optional.fromNullable(RepositoryManager.get().createRepo(hints)); } catch (Exception ex) { Throwables.propagate(ex); } return Optional.absent(); } private static Optional<Repository> importGeogig(Request request) { try { // build URI Hints hint = InitRequestUtil.createHintsFromRequest(request); // now build the repo with the Hints RepositoryInfo repoInfo = new RepositoryInfo(); // set the repo location from the URI if (!hint.get(Hints.REPOSITORY_URL).isPresent()) { return Optional.absent(); } URI uri = new URI(hint.get(Hints.REPOSITORY_URL).get().toString()); repoInfo.setLocation(uri); // check to see if repo is initialized RepositoryResolver repoResolver = RepositoryResolver.lookup(uri); if(!repoResolver.repoExists(uri)) { return Optional.absent(); } // save the repo, this will set a UUID RepositoryManager.get().save(repoInfo); return Optional.of(RepositoryManager.get().getRepository(repoInfo.getId())); } catch (IOException | URISyntaxException e) { Throwables.propagate(e); } catch (RepositoryConnectionException e) { e.printStackTrace(); } return Optional.absent(); } } }