You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2013/02/19 18:04:23 UTC

[2/51] [abbrv] reorganized repository

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/LDPathClient.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/LDPathClient.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/LDPathClient.java
new file mode 100644
index 0000000..c581e9f
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/LDPathClient.java
@@ -0,0 +1,164 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.clients;
+
+import at.newmedialab.lmf.client.ClientConfiguration;
+import at.newmedialab.lmf.client.exception.ContentFormatException;
+import at.newmedialab.lmf.client.exception.LMFClientException;
+import at.newmedialab.lmf.client.exception.NotFoundException;
+import at.newmedialab.lmf.client.model.rdf.RDFNode;
+import at.newmedialab.lmf.client.util.HTTPUtil;
+import at.newmedialab.lmf.client.util.RDFJSONParser;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class LDPathClient {
+
+    private static Logger log = LoggerFactory.getLogger(LDPathClient.class);
+
+    private static final String URL_PATH_SERVICE  = "/ldpath/path";
+    private static final String URL_PROGRAM_SERVICE = "/ldpath/program";
+
+
+    private ClientConfiguration config;
+
+    public LDPathClient(ClientConfiguration config) {
+        this.config = config;
+    }
+
+
+    /**
+     * Evaluate the path query passed as second argument, starting at the resource with the uri given as first argument.
+     * Returns a List of RDFNode objects.
+     *
+     *
+     * @param uri  the uri of the resource where to start the path evaluation
+     * @param path the path to evaluate
+     * @return a list of RDFNodes representing the result of the path evaluation as returned by the server
+     * @throws LMFClientException
+     * @throws IOException
+     */
+    public List<RDFNode> evaluatePath(String uri, String path) throws LMFClientException, IOException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        String serviceUrl = config.getLmfUri() + URL_PATH_SERVICE + "?path=" + URLEncoder.encode(path, "utf-8")
+                                                                  + "&uri="  + URLEncoder.encode(uri, "utf-8");
+
+        HttpGet get = new HttpGet(serviceUrl);
+        get.setHeader("Accept", "application/json");
+        
+        try {
+
+            HttpResponse response = httpClient.execute(get);
+
+            switch(response.getStatusLine().getStatusCode()) {
+                case 200:
+                    log.debug("LDPath Path Query {} evaluated successfully",path);
+                    ObjectMapper mapper = new ObjectMapper();
+                    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+                    List<Map<String,String>> serverResult =
+                            mapper.readValue(response.getEntity().getContent(),new TypeReference<List<Map<String,String>>>(){});
+
+                    
+                    List<RDFNode> result = new ArrayList<RDFNode>();
+                    for(Map<String,String> value : serverResult) {
+                        result.add(RDFJSONParser.parseRDFJSONNode(value));
+                    }
+                    return result;
+                case 400:
+                    log.error("the server did not accept the uri ({}) or path ({}) arguments",uri,path);
+                    throw new ContentFormatException("the server did not accept the uri ("+uri+") or path ("+path+") arguments");
+                case 404:
+                    log.error("the resource with URI {} does not exist on the server",uri);
+                    throw new NotFoundException("the resource with URI "+uri+" does not exist on the server");
+                default:
+                    log.error("error evaluating LDPath Path Query {}: {} {}",new Object[] {path,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
+                    throw new LMFClientException("error evaluating LDPath Path Query "+path+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
+            }
+
+        } finally {
+            get.releaseConnection();
+        }
+
+    }
+    
+    
+    public Map<String,List<RDFNode>> evaluateProgram(String uri, String program) throws LMFClientException, IOException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        String serviceUrl = config.getLmfUri() + URL_PROGRAM_SERVICE + "?program=" + URLEncoder.encode(program, "utf-8")
+                                                                                   + "&uri="  + URLEncoder.encode(uri, "utf-8");
+
+        HttpGet get = new HttpGet(serviceUrl);
+        get.setHeader("Accept", "application/json");
+        
+        try {
+
+            HttpResponse response = httpClient.execute(get);
+
+            switch(response.getStatusLine().getStatusCode()) {
+                case 200:
+                    log.debug("LDPath Program Query evaluated successfully:\n{}",program);
+                    ObjectMapper mapper = new ObjectMapper();
+                    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+                    Map<String,List<Map<String,String>>> serverResult =
+                            mapper.readValue(response.getEntity().getContent(),new TypeReference<Map<String,List<Map<String,String>>>>(){});
+
+
+                    Map<String,List<RDFNode>> result = new HashMap<String, List<RDFNode>>();
+                    for(Map.Entry<String,List<Map<String,String>>> field : serverResult.entrySet()) {
+                        List<RDFNode> row = new ArrayList<RDFNode>();
+                        for(Map<String,String> node : field.getValue()) {
+                            row.add(RDFJSONParser.parseRDFJSONNode(node));
+                        }
+                        result.put(field.getKey(),row);
+                    }
+                    return result;
+                case 400:
+                    log.error("the server did not accept the uri ({}) or program ({}) arguments",uri,program);
+                    throw new ContentFormatException("the server did not accept the uri ("+uri+") or program ("+program+") arguments");
+                case 404:
+                    log.error("the resource with URI {} does not exist on the server",uri);
+                    throw new NotFoundException("the resource with URI "+uri+" does not exist on the server");
+                default:
+                    log.error("error evaluating LDPath Program Query: {} {}",new Object[] {response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
+                    throw new LMFClientException("error evaluating LDPath Program Query: "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
+            }
+
+        } finally {
+            get.releaseConnection();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/ResourceClient.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/ResourceClient.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/ResourceClient.java
new file mode 100644
index 0000000..616be9d
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/ResourceClient.java
@@ -0,0 +1,372 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.clients;
+
+import at.newmedialab.lmf.client.ClientConfiguration;
+import at.newmedialab.lmf.client.exception.ContentFormatException;
+import at.newmedialab.lmf.client.exception.LMFClientException;
+import at.newmedialab.lmf.client.exception.NotFoundException;
+import at.newmedialab.lmf.client.model.content.Content;
+import at.newmedialab.lmf.client.model.content.StreamContent;
+import at.newmedialab.lmf.client.model.meta.Metadata;
+import at.newmedialab.lmf.client.util.HTTPUtil;
+import at.newmedialab.lmf.client.util.RDFJSONParser;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.ByteStreams;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+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.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Map;
+
+/**
+ * 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 LMF installation
+     * @param uri
+     * @return
+     * @throws IOException
+     */
+    public boolean createResource(String uri) throws IOException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+            
+        HttpPost post = new HttpPost(getServiceUrl(uri));
+        
+        try {
+            
+            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 {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        HttpOptions options = new HttpOptions(getServiceUrl(uri));
+        
+        try {
+                
+            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 LMFClientException
+     */
+    public Metadata getResourceMetadata(String uri) throws IOException, LMFClientException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        HttpGet get = new HttpGet(getServiceUrl(uri));
+        get.setHeader("Accept", "application/rdf+json; rel=meta");
+        
+        try {
+            
+            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/json for resource {}, cannot retrieve", uri);
+                    throw new ContentFormatException("server does not support metadata type application/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 LMFClientException("error retrieving resource "+uri+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
+            }
+
+        } catch (UnsupportedEncodingException e) {
+            log.error("could not encode URI parameter",e);
+            throw new LMFClientException("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 Linked Media Framework 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 LMFClientException
+     */
+    public void updateResourceMetadata(final String uri, final Metadata metadata) throws IOException, LMFClientException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        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 {
+            
+            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 LMFClientException("error updating resource "+uri+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
+            }
+
+        } catch (UnsupportedEncodingException e) {
+            log.error("could not encode URI parameter",e);
+            throw new LMFClientException("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 LMFClientException
+     */
+    public Content getResourceContent(String uri, String mimeType) throws IOException, LMFClientException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        HttpGet get = new HttpGet(getServiceUrl(uri));
+        get.setHeader("Accept", mimeType+"; rel=content");
+        
+        try {
+
+            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 LMFClientException("error retrieving resource "+uri+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
+            }
+
+        } catch (UnsupportedEncodingException e) {
+            log.error("could not encode URI parameter",e);
+            throw new LMFClientException("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 LMFClientException
+     */
+    public void updateResourceContent(final String uri, final Content content) throws IOException, LMFClientException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        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 {
+            httpClient.execute(put, handler);
+        } catch(IOException ex) {
+            put.abort();
+            throw ex;
+        } finally {
+            put.releaseConnection();
+        }
+
+    }
+    
+    
+    public void deleteResource(String uri) throws IOException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        HttpDelete delete = new HttpDelete(getServiceUrl(uri));
+        
+        try {
+            
+            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.getLmfUri() + URL_RESOURCE_SERVICE + "?uri=" + URLEncoder.encode(uri,"utf-8");    
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/SPARQLClient.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/SPARQLClient.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/SPARQLClient.java
new file mode 100644
index 0000000..4524928
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/SPARQLClient.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.clients;
+
+import at.newmedialab.lmf.client.ClientConfiguration;
+import at.newmedialab.lmf.client.exception.LMFClientException;
+import at.newmedialab.lmf.client.model.rdf.BNode;
+import at.newmedialab.lmf.client.model.rdf.Literal;
+import at.newmedialab.lmf.client.model.rdf.RDFNode;
+import at.newmedialab.lmf.client.model.rdf.URI;
+import at.newmedialab.lmf.client.model.sparql.SPARQLResult;
+import at.newmedialab.lmf.client.util.HTTPUtil;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class SPARQLClient {
+
+    private static Logger log = LoggerFactory.getLogger(SPARQLClient.class);
+
+    private static final String URL_QUERY_SERVICE  = "/sparql/select";
+    private static final String URL_UPDATE_SERVICE = "/sparql/update";
+
+    private ClientConfiguration config;
+
+    public SPARQLClient(ClientConfiguration config) {
+        this.config = config;
+    }
+
+    /**
+     * Run a SPARQL Select query against the LMF Server and return the results as SPARQL Result. Results will be
+     * transfered and parsed using the SPARQL JSON format.
+     * @param query a SPARQL Select query to run on the database
+     * @return
+     * @throws IOException
+     * @throws LMFClientException
+     */
+    @SuppressWarnings("unchecked")
+    public SPARQLResult select(String query) throws IOException, LMFClientException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        String serviceUrl = config.getLmfUri() + URL_QUERY_SERVICE + "?query=" + URLEncoder.encode(query, "utf-8");
+
+        HttpGet get = new HttpGet(serviceUrl);
+        get.setHeader("Accept", "application/sparql-results+json");
+        
+        try {
+
+            HttpResponse response = httpClient.execute(get);
+
+            switch(response.getStatusLine().getStatusCode()) {
+                case 200:
+                    log.debug("SPARQL Query {} evaluated successfully",query);
+                    ObjectMapper mapper = new ObjectMapper();
+                    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+                    Map<String,Map<String,List<?>>> resultMap =
+                            mapper.readValue(response.getEntity().getContent(),new TypeReference<Map<String,Map<String,List<?>>>>(){});
+
+                    if(resultMap.isEmpty()) {
+                        return null;
+                    } else {
+                        List<?> head = resultMap.get("head").get("vars");
+                        Set<String> fieldNames = new HashSet<String>();
+                        for(Object o : head) {
+                            if(o instanceof String) {
+                                fieldNames.add((String)o);
+                            }
+                        }
+
+                        SPARQLResult result = new SPARQLResult(fieldNames);
+
+                        List<?> bindings = resultMap.get("results").get("bindings");
+                        for(Object o : bindings) {
+                            if(o instanceof Map) {
+                                Map<String,RDFNode> row = new HashMap<String, RDFNode>();
+                                for(Map.Entry<String,?> entry : ((Map<String,?>)o).entrySet()) {
+                                    Map<String,String> nodeDef = (Map<String,String>) entry.getValue();
+                                    RDFNode node = null;
+                                    if("uri".equalsIgnoreCase(nodeDef.get("type"))) {
+                                        node = new URI(nodeDef.get("value"));
+                                    } else if("literal".equalsIgnoreCase(nodeDef.get("type")) ||
+                                              "typed-literal".equalsIgnoreCase(nodeDef.get("type"))) {
+                                        String lang = nodeDef.get("xml:lang");
+                                        String datatype = nodeDef.get("datatype");
+
+                                        if(lang != null) {
+                                            node = new Literal(nodeDef.get("value"),lang);
+                                        } else if(datatype != null) {
+                                            node = new Literal(nodeDef.get("value"),new URI(datatype));
+                                        } else {
+                                            node = new Literal(nodeDef.get("value"));
+                                        }
+                                    } else if("bnode".equalsIgnoreCase(nodeDef.get("type"))) {
+                                        node = new BNode(nodeDef.get("value"));
+                                    } else {
+                                        log.error("unknown result node type: {}",nodeDef.get("type"));
+                                    }
+                                    
+                                    if(node != null) {
+                                        row.put(entry.getKey(),node);
+                                    }
+                                }
+                                result.add(row);
+                            }
+                        }
+                        return result;
+                    }
+                default:
+                    log.error("error evaluating SPARQL Select Query {}: {} {}",new Object[] {query,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
+                    throw new LMFClientException("error evaluating SPARQL Select Query "+query+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
+            }
+
+        } finally {
+            get.releaseConnection();
+        }
+    }
+
+    /**
+     * Carry out a SPARQL ASK Query and return either true or false, depending on the query result.
+     *
+     * @param askQuery
+     * @return
+     * @throws IOException
+     * @throws LMFClientException
+     */
+    public boolean ask(String askQuery) throws IOException, LMFClientException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        String serviceUrl = config.getLmfUri() + URL_QUERY_SERVICE + "?query=" + URLEncoder.encode(askQuery, "utf-8");
+
+        HttpGet get = new HttpGet(serviceUrl);
+        get.setHeader("Accept", "application/sparql-results+json");
+        
+        try {
+
+            HttpResponse response = httpClient.execute(get);
+
+            switch(response.getStatusLine().getStatusCode()) {
+                case 200:
+                    log.debug("SPARQL ASK Query {} evaluated successfully",askQuery);
+                    ObjectMapper mapper = new ObjectMapper();
+                    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
+                    Map<String,Object> resultMap =
+                            mapper.readValue(response.getEntity().getContent(),new TypeReference<Map<String,Object>>(){});
+
+                    if(resultMap.isEmpty()) {
+                        return false;
+                    } else {
+                        Boolean result = resultMap.get("boolean") != null && ((String)resultMap.get("boolean")).equalsIgnoreCase("true");
+                        return result;
+                    }
+                default:
+                    log.error("error evaluating SPARQL ASK Query {}: {} {}",new Object[] {askQuery,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
+                    throw new LMFClientException("error evaluating SPARQL ASK Query "+askQuery+": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
+            }
+
+        } finally {
+            get.releaseConnection();
+        }
+    }
+
+    /**
+     * Execute a SPARQL Update query according to the SPARQL 1.1 standard. The query will only be passed to the server,
+     * which will react either with ok (in this the method simply returns) or with error (in this case, the method
+     * throws an LMFClientException).
+     *
+     * @param updateQuery         the SPARQL Update 1.1 query string
+     * @throws IOException        in case a connection problem occurs
+     * @throws LMFClientException in case the server returned and error and did not execute the update
+     */
+    public void update(String updateQuery) throws IOException, LMFClientException {
+        HttpClient httpClient = HTTPUtil.createClient(config);
+
+        String serviceUrl = config.getLmfUri() + URL_UPDATE_SERVICE + "?update=" + URLEncoder.encode(updateQuery, "utf-8");
+
+        HttpGet get = new HttpGet(serviceUrl);
+        
+        try {
+                
+            HttpResponse response = httpClient.execute(get);
+
+            switch(response.getStatusLine().getStatusCode()) {
+                case 200:
+                    log.debug("SPARQL UPDATE Query {} evaluated successfully",updateQuery);
+                    break;
+                default:
+                    log.error("error evaluating SPARQL UPDATE Query {}: {} {}",new Object[] {updateQuery,response.getStatusLine().getStatusCode(),response.getStatusLine().getReasonPhrase()});
+                    throw new LMFClientException("error evaluating SPARQL UPDATE Query "+updateQuery +": "+response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
+            }
+
+        } finally {
+            get.releaseConnection();
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/SearchClient.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/SearchClient.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/SearchClient.java
new file mode 100644
index 0000000..ef6307e
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/clients/SearchClient.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.clients;
+
+import at.newmedialab.lmf.client.ClientConfiguration;
+import at.newmedialab.lmf.client.exception.LMFClientException;
+import at.newmedialab.lmf.client.util.KiWiCollections;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.HttpSolrServer;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.params.MoreLikeThisParams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provide Semantic Search functionality to the LMF search cores based on SOLRJ queries and results. Any SOLRJ query
+ * can be used and a SOLRJ result is returned, so the client provides maximum flexibility.
+ * <p/>
+ * SOLR updating is not supported through this client, since this is not an intended use of the LMF search cores.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class SearchClient {
+
+    private static Logger log = LoggerFactory.getLogger(CoresClient.class);
+
+    private static final String URL_SOLR_SERVICE  = "/solr";
+
+    private ClientConfiguration config;
+
+    Set<String> cores;
+    
+    public SearchClient(ClientConfiguration config) {
+        this.config = config;
+        
+        CoresClient coresClient = new CoresClient(config);
+        cores = new HashSet<String>();
+        try {
+            cores.addAll(coresClient.listCores());
+        } catch (IOException e) {
+            log.error("could not initialise list of cores; search functionality will not work",e);
+        } catch (LMFClientException e) {
+            log.error("could not initialise list of cores; search functionality will not work", e);
+        }
+    }
+
+    /**
+     * Run a SOLR search against the selected core and return the result as SolrDocumentList.
+     *
+     * @param coreName name of the core to query
+     * @param query    the SolrQuery to run on the core
+     * @return
+     * @throws IOException
+     * @throws LMFClientException
+     */
+    public SolrDocumentList search(String coreName, SolrQuery query) throws IOException, LMFClientException {
+        Preconditions.checkArgument(cores.contains(coreName),"core {} does not exist",coreName);
+
+        SolrServer server = new HttpSolrServer(config.getLmfUri()+URL_SOLR_SERVICE+"/"+ URLEncoder.encode(coreName,"utf-8"));
+
+        try {
+            QueryResponse response = server.query(query);
+            return response.getResults();
+        } catch (SolrServerException e) {
+            log.error("error while evaluating SOLR query",e);
+            throw new LMFClientException("error while evaluating SOLR query",e);
+        }
+
+    }
+
+
+    /**
+     * Perform a simple string search on the given core using default parameters for the SolrQuery.
+     */
+    public SolrDocumentList simpleSearch(String coreName, String queryString, Map<String,String> options) throws IOException, LMFClientException {
+        SolrQuery query = new SolrQuery();
+        query.setQuery(queryString);
+        if(options != null && options.containsKey("fields")) {
+            query.setFields(options.get("fields"));
+        } else {
+            query.setFields("*,score");
+        }
+
+        if(options != null && options.containsKey("sort")) {
+            query.addSortField(options.get("sort"), SolrQuery.ORDER.desc);
+        } else {
+            query.addSortField("score", SolrQuery.ORDER.desc);
+        }
+
+        if(options != null && options.containsKey("facets")) {
+            for(String facet : options.get("facets").split(",")) {
+                query.addFacetField(facet);
+            }
+        }
+        if(options != null && options.containsKey("offset")) {
+            query.setStart(Integer.parseInt(options.get("offset")));
+        }
+        if(options != null && options.containsKey("limit")) {
+            query.setRows(Integer.parseInt(options.get("limit")));
+        }
+        return search(coreName,query);
+
+    }
+
+
+    /**
+     * Retrieve recommendations for the given URI using the SOLR moreLikeThis handler for the core passed as first argument.
+     * The fieldWeights map field names to weights, where 1 is the standard weight. Can be used to improve the significance of
+     * a field in the calculation of recommendations.
+     *
+     * @param coreName
+     * @param uri
+     * @param fieldWeights
+     * @return
+     * @throws IOException
+     * @throws LMFClientException
+     */
+    public SolrDocumentList recommendations(String coreName, String uri, Map<String,Double> fieldWeights) throws IOException, LMFClientException {
+        SolrQuery query = new SolrQuery();
+        query.setQuery("uri:\""+URLEncoder.encode(uri,"utf-8")+"\"");
+        query.setFields("*,score");
+        query.addSortField("score", SolrQuery.ORDER.desc);
+        query.setQueryType("/" + MoreLikeThisParams.MLT);
+        query.set(MoreLikeThisParams.MATCH_INCLUDE, false);
+        query.set(MoreLikeThisParams.MIN_DOC_FREQ, 1);
+        query.set(MoreLikeThisParams.MIN_TERM_FREQ, 1);
+        query.set(MoreLikeThisParams.SIMILARITY_FIELDS, KiWiCollections.fold(fieldWeights.keySet(),","));
+        query.set(MoreLikeThisParams.QF, KiWiCollections.fold(Collections2.transform(fieldWeights.entrySet(), new Function<Map.Entry<String, Double>, Object>() {
+            @Override
+            public Object apply(Map.Entry<String, Double> input) {
+                return input.getKey()+"^"+input.getValue();
+            }
+        })," "));
+        return search(coreName,query);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/ContentFormatException.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/ContentFormatException.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/ContentFormatException.java
new file mode 100644
index 0000000..8a1d140
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/ContentFormatException.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.exception;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class ContentFormatException extends LMFClientException {
+
+    /**
+     * Constructs a new exception with <code>null</code> as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public ContentFormatException() {
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public ContentFormatException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * <code>cause</code> is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     * @since 1.4
+     */
+    public ContentFormatException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *              {@link #getCause()} method).  (A <tt>null</tt> value is
+     *              permitted, and indicates that the cause is nonexistent or
+     *              unknown.)
+     * @since 1.4
+     */
+    public ContentFormatException(Throwable cause) {
+        super(cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/LMFClientException.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/LMFClientException.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/LMFClientException.java
new file mode 100644
index 0000000..f9a97ff
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/LMFClientException.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.exception;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class LMFClientException extends Exception{
+
+    /**
+     * Constructs a new exception with <code>null</code> as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public LMFClientException() {
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public LMFClientException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * <code>cause</code> is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     * @since 1.4
+     */
+    public LMFClientException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *              {@link #getCause()} method).  (A <tt>null</tt> value is
+     *              permitted, and indicates that the cause is nonexistent or
+     *              unknown.)
+     * @since 1.4
+     */
+    public LMFClientException(Throwable cause) {
+        super(cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/NotFoundException.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/NotFoundException.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/NotFoundException.java
new file mode 100644
index 0000000..c4cbca6
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/NotFoundException.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.exception;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class NotFoundException extends LMFClientException {
+    /**
+     * Constructs a new exception with <code>null</code> as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public NotFoundException() {
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public NotFoundException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * <code>cause</code> is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     * @since 1.4
+     */
+    public NotFoundException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *              {@link #getCause()} method).  (A <tt>null</tt> value is
+     *              permitted, and indicates that the cause is nonexistent or
+     *              unknown.)
+     * @since 1.4
+     */
+    public NotFoundException(Throwable cause) {
+        super(cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/ParseException.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/ParseException.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/ParseException.java
new file mode 100644
index 0000000..5039afb
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/exception/ParseException.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.exception;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class ParseException extends LMFClientException {
+
+    /**
+     * Constructs a new exception with <code>null</code> as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public ParseException() {
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param message the detail message. The detail message is saved for
+     *                later retrieval by the {@link #getMessage()} method.
+     */
+    public ParseException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * <code>cause</code> is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *                by the {@link #getMessage()} method).
+     * @param cause   the cause (which is saved for later retrieval by the
+     *                {@link #getCause()} method).  (A <tt>null</tt> value is
+     *                permitted, and indicates that the cause is nonexistent or
+     *                unknown.)
+     * @since 1.4
+     */
+    public ParseException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *              {@link #getCause()} method).  (A <tt>null</tt> value is
+     *              permitted, and indicates that the cause is nonexistent or
+     *              unknown.)
+     * @since 1.4
+     */
+    public ParseException(Throwable cause) {
+        super(cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/classification/Classification.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/classification/Classification.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/classification/Classification.java
new file mode 100644
index 0000000..3bee617
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/classification/Classification.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.classification;
+
+import at.newmedialab.lmf.client.model.rdf.URI;
+
+
+/**
+ * A classification result of the classifier; for each category, provides a probability value indicating how much
+ * the text fits to a category.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class Classification implements Comparable<Classification> {
+
+
+    private URI category;
+    private double probability;
+
+    public Classification(URI category, double probability) {
+        this.category = category;
+        this.probability = probability;
+    }
+
+    /**
+     * The category for which the classifier computed a probability
+     *
+     * @return
+     */
+    public URI getCategory() {
+        return category;
+    }
+
+    /**
+     * The probability the text fits to this category.
+     *
+     * @return
+     */
+    public double getProbability() {
+        return probability;
+    }
+
+    /**
+     * Compares this object with the specified object for order.  Returns a
+     * negative integer, zero, or a positive integer as this object is less
+     * than, equal to, or greater than the specified object.
+     * <p/>
+     * Classifiers with higher probability take precedence (are smaller) than classifiers with lower probability.
+     *
+     * @param o the object to be compared.
+     * @return a negative integer, zero, or a positive integer as this object
+     *         is less than, equal to, or greater than the specified object.
+     * @throws ClassCastException if the specified object's type prevents it
+     *                            from being compared to this object.
+     */
+    @Override
+    public int compareTo(Classification o) {
+        if(getProbability() > o.getProbability()) {
+            return -1;
+        } else if(getProbability() < o.getProbability()) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/config/Configuration.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/config/Configuration.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/config/Configuration.java
new file mode 100644
index 0000000..11593be
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/config/Configuration.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.config;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class Configuration {
+    
+    private String key;
+    
+    private Object value;
+
+
+    public Configuration(String key, Object value) {
+        this.key = key;
+        this.value = value;
+    }
+
+
+    public String getKey() {
+        return key;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+    
+    public String getString() {
+        if(value instanceof Collection) {
+            if(((Collection) value).isEmpty()) {
+                return null;   
+            } else {
+                return ((Collection) value).iterator().next().toString();
+            }
+        } else {
+            return value.toString();
+        }
+    }
+    
+    public List<String> getList() {
+        List<String> result = new ArrayList<String>();
+        if(value instanceof Collection) {
+            for(Object o : (Collection) value) {
+                result.add(o.toString());
+            }
+        } else {
+            result.add(value.toString());
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/ByteContent.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/ByteContent.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/ByteContent.java
new file mode 100644
index 0000000..6814b58
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/ByteContent.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.content;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class ByteContent extends Content {
+
+    private byte[] bytes;
+
+    public ByteContent(byte[] bytes, String mimeType, long size) {
+        super(mimeType, size);
+        this.bytes = bytes;
+    }
+
+    /**
+     * Return the content of this object as stream. Note that the stream is only guaranteed to be consumable once.
+     *
+     * @return
+     */
+    @Override
+    public InputStream getStream() {
+        return new ByteArrayInputStream(bytes);
+    }
+
+    /**
+     * Return the content of this object as byte array. Note that when calling this method it is not safe to
+     * call the getStream method afterwards.
+     *
+     * @return
+     */
+    @Override
+    public byte[] getBytes() {
+        return bytes;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/Content.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/Content.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/Content.java
new file mode 100644
index 0000000..3c6029d
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/Content.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.content;
+
+import java.io.InputStream;
+
+/**
+ * Representation of media content returned by the Linked Media Framework. Provides an InputStream for
+ * reading the media data. Optionally, supports reading all content into a byte array.
+ *
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public abstract class Content {
+    
+    private String mimeType;
+
+    private long size;
+
+
+    public Content(String mimeType, long size) {
+        this.mimeType = mimeType;
+        this.size = size;
+    }
+
+    /**
+     * Return the content of this object as stream. Note that the stream is only guaranteed to be consumable once.
+     * @return
+     */
+    public abstract InputStream getStream();
+
+
+    /**
+     * Return the content of this object as byte array. Note that when calling this method it is not safe to
+     * call the getStream method afterwards.
+     * @return
+     */
+    public abstract byte[] getBytes();
+
+
+    public String getMimeType() {
+        return mimeType;
+    }
+
+    public long getSize() {
+        return size;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/StreamContent.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/StreamContent.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/StreamContent.java
new file mode 100644
index 0000000..a0a8747
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/StreamContent.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.content;
+
+import com.google.common.io.ByteStreams;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class StreamContent extends Content {
+
+    private InputStream data;
+
+    public StreamContent(InputStream data, String mimeType, long size) {
+        super(mimeType, size);
+        this.data = data;
+    }
+
+    /**
+     * Return the content of this object as stream. Note that the stream is only guaranteed to be consumable once.
+     *
+     * @return
+     */
+    @Override
+    public InputStream getStream() {
+        return data;
+    }
+
+    /**
+     * Return the content of this object as byte array. Note that when calling this method it is not safe to
+     * call the getStream method afterwards.
+     *
+     * @return
+     */
+    @Override
+    public byte[] getBytes() {
+        try {
+            return ByteStreams.toByteArray(data);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/StringContent.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/StringContent.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/StringContent.java
new file mode 100644
index 0000000..9b5bfe2
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/content/StringContent.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.content;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class StringContent extends Content {
+    
+    private String data;
+
+    public StringContent(String data, String mimeType)  {
+        super(mimeType, data.getBytes().length);
+        this.data = data;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+
+    /**
+     * Return the content of this object as stream. Note that the stream is only guaranteed to be consumable once.
+     *
+     * @return
+     */
+    @Override
+    public InputStream getStream() {
+        return new ByteArrayInputStream(getBytes());
+    }
+
+    /**
+     * Return the content of this object as byte array. Note that when calling this method it is not safe to
+     * call the getStream method afterwards.
+     *
+     * @return
+     */
+    @Override
+    public byte[] getBytes() {
+        try {
+            return data.getBytes("utf-8");
+        } catch (UnsupportedEncodingException e) {
+            return data.getBytes();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/meta/Metadata.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/meta/Metadata.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/meta/Metadata.java
new file mode 100644
index 0000000..1f711a9
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/meta/Metadata.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.meta;
+
+import at.newmedialab.lmf.client.model.rdf.Literal;
+import at.newmedialab.lmf.client.model.rdf.RDFNode;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class Metadata extends HashMap<String,Set<RDFNode>> {
+    
+    private String subject;
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
+     * (16) and the default load factor (0.75).
+     */
+    public Metadata(String subject) {
+        this.subject = subject;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+    
+    public RDFNode getFirst(String propertyUri) {
+        Preconditions.checkNotNull(get(propertyUri));
+        Preconditions.checkState(get(propertyUri).iterator().hasNext());
+
+        return get(propertyUri).iterator().next();
+    }
+
+
+    /**
+     * Convert a more simple property map into a metadata representation. Note that all keys of the property map still
+     * are required to be valid RDF URI resources. All properties will have string literal values in the resulting metadata.
+     *
+     * @param resource
+     * @param map
+     * @return
+     */
+    public static Metadata fromPropertiesMap(String resource, Map<String,String> map) {
+        Metadata m = new Metadata(resource);
+        for(Map.Entry<String,String> entry : map.entrySet()) {
+            m.put(entry.getKey(), ImmutableSet.<RDFNode>of(new Literal(entry.getValue())));
+        }
+        return m;
+    }
+
+    /**
+     * Convert a metadata representation into a simpler property map, potentially loosing information. Only the
+     * first literal value of a property is copied to the resulting map.
+     *
+     * @param metadata
+     * @return
+     */
+    public static Map<String,String> toPropertiesMap(Metadata metadata) {
+        Map<String,String> result = new HashMap<String, String>();
+        for(Map.Entry<String,Set<RDFNode>> entry : metadata.entrySet()) {
+            for(RDFNode n : entry.getValue())  {
+                if(n instanceof Literal) {
+                    result.put(entry.getKey(),((Literal) n).getContent());
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/BNode.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/BNode.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/BNode.java
new file mode 100644
index 0000000..58f8e66
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/BNode.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.rdf;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class BNode extends RDFNode { 
+    
+    private String anonId;
+
+    public BNode(String anonId) {
+        this.anonId = anonId;
+    }
+
+    public String getAnonId() {
+        return anonId;
+    }
+
+    public void setAnonId(String anonId) {
+        this.anonId = anonId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        BNode bNode = (BNode) o;
+
+        if (anonId != null ? !anonId.equals(bNode.anonId) : bNode.anonId != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return anonId != null ? anonId.hashCode() : 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/Literal.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/Literal.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/Literal.java
new file mode 100644
index 0000000..4374233
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/Literal.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.rdf;
+
+/**
+ * A lightweight RDF Literal implementation providing the base functionalities.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class Literal extends RDFNode {
+    
+    private String content;
+    
+    private String language;
+    
+    private URI type;
+
+
+    public Literal(String content) {
+        this.content = content;
+    }
+
+    public Literal(String content, String language) {
+        this.content = content;
+        this.language = language;
+    }
+
+    public Literal(String content, URI type) {
+        this.content = content;
+        this.type = type;
+    }
+
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public URI getType() {
+        return type;
+    }
+
+    public void setType(URI type) {
+        this.type = type;
+    }
+    
+    
+    public int getInt() {
+        return Integer.parseInt(content);
+    }
+    
+    public long getLong() {
+        return Long.parseLong(content);
+    }
+
+    public double getDouble() {
+        return Double.parseDouble(content);
+    }
+
+    public float getFloat() {
+        return Float.parseFloat(content);
+    }
+
+    public boolean getBoolean() {
+        return Boolean.getBoolean(content);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Literal literal = (Literal) o;
+
+        if (!content.equals(literal.content)) return false;
+        if (language != null ? !language.equals(literal.language) : literal.language != null) return false;
+        if (type != null ? !type.equals(literal.type) : literal.type != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = content.hashCode();
+        result = 31 * result + (language != null ? language.hashCode() : 0);
+        result = 31 * result + (type != null ? type.hashCode() : 0);
+        return result;
+    }
+
+
+    @Override
+    public String toString() {
+        return content;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/RDFNode.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/RDFNode.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/RDFNode.java
new file mode 100644
index 0000000..ec4da16
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/RDFNode.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.rdf;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class RDFNode {
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/75439f3a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/URI.java
----------------------------------------------------------------------
diff --git a/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/URI.java b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/URI.java
new file mode 100644
index 0000000..07c4f94
--- /dev/null
+++ b/client/marmotta-client-java/src/main/java/at/newmedialab/lmf/client/model/rdf/URI.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed 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 at.newmedialab.lmf.client.model.rdf;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class URI extends RDFNode {
+    
+    private String uri;
+
+    public URI(String uri) {
+        this.uri = uri;
+    }
+
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        URI uri1 = (URI) o;
+
+        if (!uri.equals(uri1.uri)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return uri.hashCode();
+    }
+
+    /**
+     * Returns a string representation of the object. In general, the
+     * <code>toString</code> method returns a string that
+     * "textually represents" this object. The result should
+     * be a concise but informative representation that is easy for a
+     * person to read.
+     * It is recommended that all subclasses override this method.
+     * <p/>
+     * The <code>toString</code> method for class <code>Object</code>
+     * returns a string consisting of the name of the class of which the
+     * object is an instance, the at-sign character `<code>@</code>', and
+     * the unsigned hexadecimal representation of the hash code of the
+     * object. In other words, this method returns a string equal to the
+     * value of:
+     * <blockquote>
+     * <pre>
+     * getClass().getName() + '@' + Integer.toHexString(hashCode())
+     * </pre></blockquote>
+     *
+     * @return a string representation of the object.
+     */
+    @Override
+    public String toString() {
+        return uri;
+    }
+}