edu.rpi.tw.twks.client.RestTwksClient Maven / Gradle / Ivy
The newest version!
package edu.rpi.tw.twks.client;
import com.google.api.client.http.*;
import com.google.api.client.http.apache.v2.ApacheHttpTransport;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
import com.google.common.reflect.TypeToken;
import edu.rpi.tw.twks.api.TwksLibraryVersion;
import edu.rpi.tw.twks.api.TwksVersion;
import edu.rpi.tw.twks.nanopub.MalformedNanopublicationException;
import edu.rpi.tw.twks.nanopub.Nanopublication;
import edu.rpi.tw.twks.nanopub.NanopublicationParser;
import edu.rpi.tw.twks.uri.Uri;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.query.*;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RDFParserBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.List;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static edu.rpi.tw.twks.vocabulary.Vocabularies.setNsPrefixes;
/**
* TWKS client implementation that communicates with the server via the latter's REST interface.
*/
public final class RestTwksClient implements TwksClient {
private final static Logger logger = LoggerFactory.getLogger(RestTwksClient.class);
private final HttpRequestFactory httpRequestFactory;
private final ApacheHttpTransport httpTransport;
private final String serverBaseUrl;
/**
* Construct a new TWKS client with a default configuration.
*/
public RestTwksClient() {
this(RestTwksClientConfiguration.builder().build());
}
/**
* Construct a new TWKS client.
*/
public RestTwksClient(final RestTwksClientConfiguration configuration) {
this.serverBaseUrl = StringUtils.stripEnd(checkNotNull(configuration.getServerBaseUrl()), "/");
httpTransport = new ApacheHttpTransport();
httpRequestFactory = httpTransport.createRequestFactory(request -> {
request.setParser(new JsonObjectParser(new JacksonFactory()));
});
}
private static HttpContent toContent(final Nanopublication... nanopublications) {
final StringWriter contentStringWriter = new StringWriter();
final Dataset dataset = DatasetFactory.create();
for (final Nanopublication nanopublication : nanopublications) {
nanopublication.toDataset(dataset);
}
RDFDataMgr.write(contentStringWriter, dataset, Lang.TRIG);
final String contentString = contentStringWriter.toString();
final byte[] contentBytes = contentString.getBytes(Charsets.UTF_8);
return new ByteArrayContent("text/trig; charset=utf-8", contentBytes);
}
@Override
public final DeleteNanopublicationResult deleteNanopublication(final Uri uri) {
final HttpResponse response;
try {
response = httpRequestFactory.buildDeleteRequest(newNanopublicationUrl(uri)).execute();
} catch (final HttpResponseException e) {
if (e.getStatusCode() == 404) {
return DeleteNanopublicationResult.NOT_FOUND;
} else {
throw wrapException(e);
}
} catch (final IOException e) {
throw wrapException(e);
}
checkState(response.getStatusCode() == 204);
return DeleteNanopublicationResult.DELETED;
}
@Override
public final void deleteNanopublications() {
throw new UnsupportedOperationException("not supported via the API");
}
@Override
@SuppressWarnings("unchecked")
public final ImmutableList deleteNanopublications(final ImmutableList uris) {
try {
final GenericUrl url = new GenericUrl(serverBaseUrl + "/nanopublication/");
url.set("uri", uris);
final HttpResponse response = httpRequestFactory.buildDeleteRequest(url).execute();
final List resultStrings = (List) response.parseAs(new TypeToken>() {
}.getType());
return resultStrings.stream().map(resultString -> DeleteNanopublicationResult.valueOf(resultString)).collect(ImmutableList.toImmutableList());
} catch (final HttpResponseException e) {
throw wrapException(e);
} catch (final IOException e) {
throw wrapException(e);
}
}
@Override
public void dump() {
try {
httpRequestFactory.buildPostRequest(new GenericUrl(serverBaseUrl + "/dump"), new EmptyContent()).execute();
} catch (final HttpResponseException e) {
throw wrapException(e);
} catch (final IOException e) {
throw wrapException(e);
}
}
@Override
public final Model getAssertions() {
try {
return getAssertions(httpRequestFactory.buildGetRequest(new GenericUrl(serverBaseUrl + "/assertions")));
} catch (final IOException e) {
throw wrapException(e);
}
}
private Model getAssertions(final HttpRequest request) {
request.setHeaders(new HttpHeaders().setAccept("text/trig"));
try {
final HttpResponse response = request.execute();
try (final InputStream inputStream = response.getContent()) {
final Model model = ModelFactory.createDefaultModel();
setNsPrefixes(model);
RDFParserBuilder.create().source(inputStream).lang(Lang.TRIG).parse(model);
return model;
}
} catch (final IOException e) {
throw wrapException(e);
}
}
@Override
public final TwksVersion getClientVersion() {
return TwksLibraryVersion.getInstance();
}
@Override
public final Optional getNanopublication(final Uri uri) {
try {
final HttpResponse response = httpRequestFactory.buildGetRequest(newNanopublicationUrl(uri)).setHeaders(new HttpHeaders().setAccept("text/trig")).execute();
checkState(response.getStatusCode() == 200);
try (final InputStream inputStream = response.getContent()) {
final byte[] contentBytes = ByteStreams.toByteArray(inputStream);
try {
return Optional.of(NanopublicationParser.builder().setLang(Lang.TRIG).setSource(new StringReader(new String(contentBytes, "UTF-8"))).build().parseOne());
} catch (final MalformedNanopublicationException e) {
logger.error("malformed nanopublication from server: ", e);
return Optional.empty();
}
}
} catch (final HttpResponseException e) {
if (e.getStatusCode() == 404) {
return Optional.empty();
} else {
throw wrapException(e);
}
} catch (final IOException e) {
throw wrapException(e);
}
}
@Override
public final Model getOntologyAssertions(final ImmutableSet ontologyUris) {
try {
final GenericUrl url = new GenericUrl(serverBaseUrl + "/assertions/ontology");
url.set("uri", ontologyUris);
return getAssertions(httpRequestFactory.buildGetRequest(url));
} catch (final IOException e) {
throw wrapException(e);
}
}
@Override
public final TwksVersion getServerVersion() {
try {
final HttpResponse response = httpRequestFactory.buildGetRequest(new GenericUrl(serverBaseUrl + "/version")).execute();
final GenericJson json = response.parseAs(GenericJson.class);
return new TwksVersion(((BigDecimal) json.get("incremental")).intValue(), ((BigDecimal) json.get("major")).intValue(), ((BigDecimal) json.get("minor")).intValue());
} catch (final HttpResponseException e) {
throw wrapException(e);
} catch (final IOException e) {
throw wrapException(e);
}
}
private GenericUrl newNanopublicationUrl(final Uri nanopublicationUri) {
try {
return new GenericUrl(serverBaseUrl + "/nanopublication/" + URLEncoder.encode(nanopublicationUri.toString(), "UTF-8"));
} catch (final UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
@Override
public final ImmutableList postNanopublications(final ImmutableList nanopublications) {
try {
final GenericUrl url = new GenericUrl(serverBaseUrl + "/nanopublication/");
final HttpResponse response = httpRequestFactory.buildPostRequest(url, toContent(nanopublications.toArray(new Nanopublication[nanopublications.size()]))).execute();
final List resultStrings = (List) response.parseAs(new TypeToken>() {
}.getType());
return resultStrings.stream().map(resultString -> PutNanopublicationResult.valueOf(resultString)).collect(ImmutableList.toImmutableList());
} catch (final HttpResponseException e) {
throw wrapException(e);
} catch (final IOException e) {
throw wrapException(e);
}
}
@Override
public final PutNanopublicationResult putNanopublication(final Nanopublication nanopublication) {
final HttpResponse response;
try {
response = httpRequestFactory.buildPutRequest(new GenericUrl(serverBaseUrl + "/nanopublication/"), toContent(nanopublication)).execute();
} catch (final IOException e) {
throw wrapException(e);
}
switch (response.getStatusCode()) {
case 201:
return PutNanopublicationResult.CREATED;
case 204:
return PutNanopublicationResult.OVERWROTE;
default:
throw new IllegalStateException();
}
}
@Override
public final QueryExecution queryAssertions(final Query query) {
return QueryExecutionFactory.sparqlService(serverBaseUrl + "/sparql/assertions", query, httpTransport.getHttpClient());
}
@Override
public final QueryExecution queryNanopublications(final Query query) {
return QueryExecutionFactory.sparqlService(serverBaseUrl + "/sparql/nanopublications", query, httpTransport.getHttpClient());
}
private RuntimeException wrapException(final IOException e) {
return new RuntimeException(e);
}
}