Java tutorial
/** * This file is part of git-as-svn. It is subject to the license terms * in the LICENSE file found in the top-level directory of this distribution * and at http://www.gnu.org/licenses/gpl-2.0.html. No part of git-as-svn, * including this file, may be copied, modified, propagated, or distributed * except according to the terms contained in the LICENSE file. */ package svnserver.ext.gitlfs.storage.network; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.bozaro.gitlfs.client.Client; import ru.bozaro.gitlfs.client.auth.AuthProvider; import ru.bozaro.gitlfs.client.exceptions.RequestException; import ru.bozaro.gitlfs.client.io.StreamProvider; import ru.bozaro.gitlfs.common.data.Link; import ru.bozaro.gitlfs.common.data.Links; import ru.bozaro.gitlfs.common.data.ObjectRes; import ru.bozaro.gitlfs.common.data.Operation; import svnserver.TemporaryOutputStream; import svnserver.auth.User; import svnserver.ext.gitlfs.storage.LfsReader; import svnserver.ext.gitlfs.storage.LfsStorage; import svnserver.ext.gitlfs.storage.LfsWriter; import svnserver.ext.web.server.WebServer; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; /** * Http remote storage for LFS files. * * @author Artem V. Navrotskiy <bozaro@users.noreply.github.com> */ public class LfsHttpStorage implements LfsStorage { private static final int MAX_CACHE = 1000; @NotNull private static final Logger log = LoggerFactory.getLogger(LfsHttpStorage.class); @NotNull private final URL authUrl; @NotNull private final String authToken; @NotNull private final ObjectMapper mapper; @NotNull private final LoadingCache<User, Link> tokens; @NotNull private final HttpClient httpClient = HttpClients.createDefault(); public LfsHttpStorage(@NotNull URL authUrl, @NotNull String authToken) { this.authUrl = authUrl; this.authToken = authToken; this.mapper = WebServer.createJsonMapper(); this.tokens = CacheBuilder.newBuilder().maximumSize(MAX_CACHE).build(new CacheLoader<User, Link>() { public Link load(@NotNull User user) throws IOException { return getTokenUncached(user); } }); } private void addParameter(@NotNull List<NameValuePair> params, @NotNull String key, @Nullable String value) { if (value != null) { params.add(new BasicNameValuePair(key, value)); } } @NotNull private Link getTokenUncached(@NotNull User user) throws IOException { final HttpPost post = new HttpPost(authUrl.toString()); final List<NameValuePair> params = new ArrayList<>(); addParameter(params, "token", authToken); if (!user.isAnonymous()) { addParameter(params, "username", user.getUserName()); addParameter(params, "realname", user.getRealName()); addParameter(params, "external", user.getExternalId()); addParameter(params, "email", user.getEmail()); } else { addParameter(params, "anonymous", "true"); } post.setEntity(new UrlEncodedFormEntity(params)); try { final HttpResponse response = httpClient.execute(post); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { return mapper.readValue(response.getEntity().getContent(), Link.class); } throw new RequestException(post, response); } finally { post.abort(); } } @NotNull private Link getToken(@NotNull User user) throws IOException { try { return tokens.get(user); } catch (ExecutionException e) { if (e.getCause() instanceof IOException) { throw (IOException) e.getCause(); } if (e.getCause() instanceof Error) { throw (Error) e.getCause(); } if (e.getCause() instanceof RuntimeException) { throw (RuntimeException) e.getCause(); } throw new RuntimeException(e); } } public void invalidate(@NotNull User user) { tokens.invalidate(user); } @Nullable public ObjectRes getMeta(@NotNull String hash) throws IOException { final Client lfsClient = new Client(new UserAuthProvider(User.getAnonymous()), httpClient); return lfsClient.getMeta(hash); } public boolean putObject(@NotNull User user, StreamProvider streamProvider, String sha, long size) throws IOException { final Client lfsClient = new Client(new UserAuthProvider(user), httpClient); return lfsClient.putObject(streamProvider, sha, size); } @NotNull public InputStream getObject(@NotNull Links links) throws IOException { final Client lfsClient = new Client(new UserAuthProvider(User.getAnonymous()), httpClient); return lfsClient.getObject(null, links, TemporaryOutputStream::new).toInputStream(); } @Nullable @Override public LfsReader getReader(@NotNull String oid) throws IOException { try { if (!oid.startsWith(OID_PREFIX)) return null; final String hash = oid.substring(OID_PREFIX.length()); final Client lfsClient = new Client(new UserAuthProvider(User.getAnonymous()), httpClient); final ObjectRes meta = lfsClient.getMeta(hash); if (meta == null || meta.getMeta() == null) { return null; } return new LfsHttpReader(this, meta.getMeta(), meta); } catch (RequestException e) { log.error("HTTP request error:" + e.getMessage() + "\n" + e.getRequestInfo()); throw e; } } @NotNull @Override public LfsWriter getWriter(@Nullable User user) throws IOException { return new LfsHttpWriter(this, user == null ? User.getAnonymous() : user); } private final class UserAuthProvider implements AuthProvider { @NotNull private final User user; public UserAuthProvider(@NotNull User user) { this.user = user; } @NotNull @Override public Link getAuth(@NotNull Operation mode) throws IOException { return getToken(user); } @Override public void invalidateAuth(@NotNull Operation mode, @NotNull Link auth) { tokens.invalidate(user); } } }