blob: c3534e1a6ff2e7f9f65dea4e71d153cb92cab535 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.marmotta.client.clients;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.marmotta.client.ClientConfiguration;
import org.apache.marmotta.client.exception.ContentFormatException;
import org.apache.marmotta.client.exception.MarmottaClientException;
import org.apache.marmotta.client.exception.NotFoundException;
import org.apache.marmotta.client.model.content.Content;
import org.apache.marmotta.client.model.content.StreamContent;
import org.apache.marmotta.client.model.meta.Metadata;
import org.apache.marmotta.client.util.HTTPUtil;
import org.apache.marmotta.client.util.RDFJSONParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
/**
* Add file description here!
* <p/>
* Author: Sebastian Schaffert
*/
public class ResourceClient {
private static Logger log = LoggerFactory.getLogger(ResourceClient.class);
private static final String URL_RESOURCE_SERVICE = "/resource";
private ClientConfiguration config;
public ResourceClient(ClientConfiguration config) {
this.config = config;
}
/**
* Create a resource in the remote Marmotta installation
* @param uri
* @return
* @throws IOException
*/
public boolean createResource(String uri) throws IOException {
HttpPost post = new HttpPost(getServiceUrl(uri));
try(CloseableHttpClient httpClient = HTTPUtil.createClient(config)) {
HttpResponse response = httpClient.execute(post);
switch(response.getStatusLine().getStatusCode()) {
case 200:
log.debug("resource {} already existed, not creating new",uri);
return true;
case 201:
log.debug("resource {} created",uri);
return true;
default:
log.error("error creating resource {}: {} {}",new Object[] {uri,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
return true;
}
} catch (UnsupportedEncodingException e) {
log.error("could not encode URI parameter",e);
return false;
} finally {
post.releaseConnection();
}
}
/**
* Test whether the resource with the provided URI exists.
* <p/>
* Uses an OPTIONS call to the resource web service to determine whether the resource exists or not
*
* @param uri
* @return
* @throws IOException
*/
public boolean existsResource(String uri) throws IOException {
HttpOptions options = new HttpOptions(getServiceUrl(uri));
try(CloseableHttpClient httpClient = HTTPUtil.createClient(config)) {
HttpResponse response = httpClient.execute(options);
if(response.containsHeader("Access-Control-Allow-Methods") && response.getFirstHeader("Access-Control-Allow-Methods").getValue().equals("POST")) {
return false;
} else if(response.containsHeader("Access-Control-Allow-Methods") && response.getFirstHeader("Access-Control-Allow-Methods").getValue().contains("GET")) {
return true;
} else {
log.warn("OPTIONS response did not contain a access-control-allow-methods header");
return false;
}
} catch (UnsupportedEncodingException e) {
log.error("could not encode URI parameter",e);
return false;
} finally {
options.releaseConnection();
}
}
/**
* Return the resource metadata for the resource with the given URI, if it exists. Returns null if the
* resource exists but there is no metadata. Throws an exception if the resource does not exist or some
* other error code was returned.
*
* @param uri
* @return
* @throws IOException
* @throws MarmottaClientException
*/
public Metadata getResourceMetadata(String uri) throws IOException, MarmottaClientException {
HttpGet get = new HttpGet(getServiceUrl(uri));
get.setHeader("Accept", "application/rdf+json; rel=meta");
try(CloseableHttpClient httpClient = HTTPUtil.createClient(config)) {
HttpResponse response = httpClient.execute(get);
switch(response.getStatusLine().getStatusCode()) {
case 200:
log.debug("metadata for resource {} retrieved",uri);
Map<String,Metadata> result = RDFJSONParser.parseRDFJSON(response.getEntity().getContent());
if(result.containsKey(uri)) {
return result.get(uri);
} else {
return null;
}
case 406:
log.error("server does not support metadata type application/rdf+json for resource {}, cannot retrieve", uri);
throw new ContentFormatException("server does not support metadata type application/rdf+json for resource "+uri);
case 404:
log.error("resource {} does not exist, cannot retrieve", uri);
throw new NotFoundException("resource "+uri+" does not exist, cannot retrieve");
default:
log.error("error retrieving resource {}: {} {}",new Object[] {uri,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
throw new MarmottaClientException("error retrieving resource "+uri+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
}
} catch (UnsupportedEncodingException e) {
log.error("could not encode URI parameter",e);
throw new MarmottaClientException("could not encode URI parameter");
} finally {
get.releaseConnection();
}
}
/**
* Update (overwrite) the metadata of the resource identified by the given uri. The metadata will be serialised to
* application/json and sent to the Apache Marmotta server. The given metadata will override any metadata
* for the resource already existing on the server. The resource has to exist or be created before updating, otherwise
* the method will throw a NotFoundException.
*
* @param uri the URI of the resource to update
* @param metadata the metadata to upload to the resource
* @throws IOException
* @throws MarmottaClientException
*/
public void updateResourceMetadata(final String uri, final Metadata metadata) throws IOException, MarmottaClientException {
HttpPut put = new HttpPut(getServiceUrl(uri));
put.setHeader("Content-Type", "application/rdf+json; rel=meta");
ContentProducer cp = new ContentProducer() {
@Override
public void writeTo(OutputStream outstream) throws IOException {
RDFJSONParser.serializeRDFJSON(ImmutableMap.of(uri, metadata), outstream);
}
};
put.setEntity(new EntityTemplate(cp));
try(CloseableHttpClient httpClient = HTTPUtil.createClient(config)) {
HttpResponse response = httpClient.execute(put);
switch(response.getStatusLine().getStatusCode()) {
case 200:
log.debug("metadata for resource {} updated",uri);
break;
case 415:
log.error("server does not support metadata type application/json for resource {}, cannot update", uri);
throw new ContentFormatException("server does not support metadata type application/json for resource "+uri);
case 404:
log.error("resource {} does not exist, cannot update", uri);
throw new NotFoundException("resource "+uri+" does not exist, cannot update");
default:
log.error("error updating resource {}: {} {}",new Object[] {uri,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
throw new MarmottaClientException("error updating resource "+uri+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
}
} catch (UnsupportedEncodingException e) {
log.error("could not encode URI parameter",e);
throw new MarmottaClientException("could not encode URI parameter");
} finally {
put.releaseConnection();
}
}
/**
* Retrieve the (human-readable) content of the given mimeType of the given resource. Will return a content
* object that allows reading the input stream. In case no content of the given mime type exists for the resource,
* will throw a ContentFormatException.
*
* @param uri
* @param mimeType
* @return
* @throws IOException
* @throws MarmottaClientException
*/
public Content getResourceContent(String uri, String mimeType) throws IOException, MarmottaClientException {
HttpGet get = new HttpGet(getServiceUrl(uri));
get.setHeader("Accept", mimeType+"; rel=content");
try(CloseableHttpClient httpClient = HTTPUtil.createClient(config)) {
HttpResponse response = httpClient.execute(get);
switch(response.getStatusLine().getStatusCode()) {
case 200:
log.debug("metadata for resource {} retrieved",uri);
Content content = new StreamContent(response.getEntity().getContent(),response.getEntity().getContentType().getValue(),response.getEntity().getContentLength());
return content;
case 406:
log.error("server does not offer content type {} for resource {}, cannot retrieve", mimeType, uri);
throw new ContentFormatException("server does not offer content type "+mimeType+" for resource "+uri);
case 404:
log.error("resource {} does not exist, cannot retrieve content", uri);
throw new NotFoundException("resource "+uri+" does not exist, cannot retrieve");
default:
log.error("error retrieving resource {}: {} {}",new Object[] {uri,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
throw new MarmottaClientException("error retrieving resource "+uri+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
}
} catch (UnsupportedEncodingException e) {
log.error("could not encode URI parameter",e);
throw new MarmottaClientException("could not encode URI parameter");
} finally {
get.releaseConnection();
}
}
/**
* Update the content of the resource identified by the URI given as argument. The resource has to exist before
* content can be uploaded to it. Any existing content will be overridden. The stream of the content object
* will be consumed by this method. Throws ContentFormatException if the content type is not supported,
* NotFoundException if the resource does not exist.
* @param uri
* @param content
* @throws IOException
* @throws MarmottaClientException
*/
public void updateResourceContent(final String uri, final Content content) throws IOException, MarmottaClientException {
HttpPut put = new HttpPut(getServiceUrl(uri));
put.setHeader("Content-Type", content.getMimeType()+"; rel=content");
ContentProducer cp = new ContentProducer() {
@Override
public void writeTo(OutputStream outstream) throws IOException {
ByteStreams.copy(content.getStream(),outstream);
}
};
put.setEntity(new EntityTemplate(cp));
ResponseHandler<Boolean> handler = new ResponseHandler<Boolean>() {
@Override
public Boolean handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
EntityUtils.consume(response.getEntity());
switch(response.getStatusLine().getStatusCode()) {
case 200:
log.debug("content for resource {} updated",uri);
return true;
case 406:
log.error("server does not support content type {} for resource {}, cannot update", content.getMimeType(),uri);
return false;
case 404:
log.error("resource {} does not exist, cannot update", uri);
return false;
default:
log.error("error updating resource {}: {} {}",new Object[] {uri,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
return false;
}
}
};
try(CloseableHttpClient httpClient = HTTPUtil.createClient(config)) {
httpClient.execute(put, handler);
} catch(IOException ex) {
put.abort();
throw ex;
} finally {
put.releaseConnection();
}
}
public void deleteResource(String uri) throws IOException {
HttpDelete delete = new HttpDelete(getServiceUrl(uri));
try(CloseableHttpClient httpClient = HTTPUtil.createClient(config)) {
HttpResponse response = httpClient.execute(delete);
switch(response.getStatusLine().getStatusCode()) {
case 200:
log.debug("resource {} deleted",uri);
break;
case 400:
log.error("resource {} invalid, cannot delete", uri);
break;
case 404:
log.error("resource {} does not exist, cannot delete", uri);
break;
default:
log.error("error deleting resource {}: {} {}",new Object[] {uri,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
}
} catch (UnsupportedEncodingException e) {
log.error("could not encode URI parameter",e);
} finally {
delete.releaseConnection();
}
}
private String getServiceUrl(String uri) throws UnsupportedEncodingException {
return config.getMarmottaUri() + URL_RESOURCE_SERVICE + "?uri=" + URLEncoder.encode(uri,"utf-8");
}
}