You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by wi...@apache.org on 2013/02/19 13:52:01 UTC
[12/52] [partial] code contribution,
initial import of relevant modules of LMF-3.0.0-SNAPSHOT based on
revision 4bf944319368 of the default branch at https://code.google.com/p/lmf/
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/services/content/ContentServiceImpl.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/services/content/ContentServiceImpl.java b/lmf-core/src/main/java/kiwi/core/services/content/ContentServiceImpl.java
new file mode 100644
index 0000000..4c4b4da
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/services/content/ContentServiceImpl.java
@@ -0,0 +1,327 @@
+/**
+ * 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 kiwi.core.services.content;
+
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.content.ContentReader;
+import kiwi.core.api.content.ContentService;
+import kiwi.core.api.content.ContentWriter;
+import kiwi.core.events.ConfigurationChangedEvent;
+import kiwi.core.exception.LMFException;
+import kiwi.core.exception.WritingNotSupportedException;
+import org.openrdf.model.Resource;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * Service that provides access to the content associated with a resource. It makes use of the ContentReader and
+ * ContentWriter implementations registered in the system.
+ *
+ * User: Thomas Kurz, Sebastian Schaffert
+ * Date: 07.02.11
+ * Time: 12:37
+ */
+@ApplicationScoped
+public class ContentServiceImpl implements ContentService {
+
+ @Inject
+ private Logger log;
+
+ @Inject
+ private ConfigurationService configurationService;
+
+ @Inject
+ private Instance<ContentReader> readers;
+
+ @Inject
+ private Instance<ContentWriter> writers;
+
+ private Map<Pattern,ContentReader> readerMap;
+ private Map<Pattern,ContentWriter> writerMap;
+
+ @Override
+ @PostConstruct
+ public void initialise() {
+ log.info("Content Service starting up ...");
+
+ initialiseReadersWriters();
+ }
+
+ private void initialiseReadersWriters() {
+ readerMap = new HashMap<Pattern, ContentReader>();
+ writerMap = new HashMap<Pattern, ContentWriter>();
+
+ // first read from the config file all content.* keys and store the name of the reader/writer in this set
+ // will e.g. store "triplestore" and "filesystem" if it finds keys of the form "content.triplestore.reader"
+ // and "content.filesystem.writer"
+ Set<String> configNames = new HashSet<String>();
+ for(String key : configurationService.listConfigurationKeys("content")) {
+ String[] components = key.split("\\.");
+ if(components.length > 1) {
+ configNames.add(components[1]);
+ }
+ }
+
+ // then read the configuration for each reader/writer specification in the config file and look whether
+ // the appropriate reader and/or writer is available
+ for(String configName : configNames) {
+ String readerClass = configurationService.getStringConfiguration("content."+configName+".reader");
+ String writerClass = configurationService.getStringConfiguration("content."+configName+".writer");
+ String patternStr = configurationService.getStringConfiguration("content."+configName+".pattern");
+ String enabledStr = configurationService.getStringConfiguration("content."+configName+".enabled");
+
+ if(Boolean.parseBoolean(enabledStr)) {
+ ContentReader reader = null;
+ ContentWriter writer = null;
+ Pattern pattern = null;
+ if(readerClass != null) {
+ for(ContentReader r : readers) {
+ if(r.getClass().getCanonicalName().startsWith(readerClass)) {
+ reader = r;
+ break;
+ }
+ }
+ }
+
+ if(writerClass != null) {
+ for(ContentWriter w : writers) {
+ if(w.getClass().getCanonicalName().startsWith(writerClass)) {
+ writer = w;
+ break;
+ }
+ }
+ }
+
+ try {
+ pattern = Pattern.compile(patternStr);
+ } catch(Exception ex) {
+ log.warn("pattern {} is not a valid regular expression; disabling reader/writer {} (message was {})", patternStr,configName,ex.getMessage());
+ continue;
+ }
+
+ if(pattern != null && reader != null) {
+ readerMap.put(pattern,reader);
+ log.info("enabled content reader '{}' for pattern {}",reader.getName(),pattern);
+ }
+ if(pattern != null && writer != null) {
+ writerMap.put(pattern,writer);
+ log.info("enabled content writer '{}' for pattern {}", writer.getName(), pattern);
+ }
+
+
+ } else {
+ log.info("content reader/writer {} disabled",configName);
+ }
+ }
+ }
+
+
+ public void configurationChangedEvent(@Observes ConfigurationChangedEvent event) {
+ for (String key : event.getKeys())
+ if (key.startsWith("content.")) {
+ log.info("Content Service reinitialising ...");
+ initialiseReadersWriters();
+ break;
+ }
+ }
+
+
+
+
+ @Override
+ public void setContentData(Resource resource, byte[] data, String mimetype) throws WritingNotSupportedException {
+ // iterate over all possible writers; if the pattern matches, try to store the content and return
+ for(Pattern p : writerMap.keySet()) {
+ if(p.matcher(resource.toString()).matches()) {
+ ContentWriter writer = writerMap.get(p);
+ log.debug("setting content for resource {} using writer {}",resource,writer.getName());
+ try {
+ writer.setContentData(resource, data, mimetype);
+ return;
+ } catch(IOException ex) {
+ log.error("could not write content, writer threw an IO Exception",ex);
+ throw new WritingNotSupportedException(ex.getMessage(),ex);
+ }
+ }
+ }
+ throw new WritingNotSupportedException("no writer found for resource "+resource);
+ }
+
+
+ /**
+ * Store the content of the specified mime type for the specified resource. Accepts an input stream containing
+ * the byte data of the content that is read and written to the destination configured for this writer.
+ * <p/>
+ * This method is preferrable for resources with large amounts of data.
+ *
+ * @param resource the resource for which to return the content
+ * @param mimeType the mime type to retrieve of the content
+ * @param in a InputStream containing the content of the resource
+ */
+ @Override
+ public void setContentStream(Resource resource, InputStream in, String mimeType) throws WritingNotSupportedException {
+ // iterate over all possible writers; if the pattern matches, try to store the content and return
+ for(Pattern p : writerMap.keySet()) {
+ if(p.matcher(resource.toString()).matches()) {
+ ContentWriter writer = writerMap.get(p);
+ log.debug("setting content for resource {} using writer {}",resource,writer.getName());
+ try {
+ writer.setContentStream(resource,in,mimeType);
+ return;
+ } catch(IOException ex) {
+ log.error("could not write content, writer threw an IO Exception",ex);
+ throw new WritingNotSupportedException(ex.getMessage(),ex);
+ }
+ }
+ }
+ throw new WritingNotSupportedException("no writer found for resource "+resource);
+ }
+
+ /**
+ * Retrieve the content of the specified mime type for the specified resource. Returns a byte array containing
+ * the byte data of the content, or null, indicating that a content of the specified mime type does not exist
+ * for the resource.
+ * <p/>
+ * Specialised content readers could even transform the resource content from its original form to the new
+ * mimetype, e.g. converting an image from JPEG to PNG.
+ *
+ * @param resource the resource for which to return the content
+ * @param mimetype the mime type to retrieve of the content
+ * @return a byte array containing the content of the resource, or null if no content exists
+ */
+ @Override
+ public byte[] getContentData(Resource resource, String mimetype) {
+ // iterate over all possible writers; if the pattern matches, try to store the content and return
+ for(Pattern p : readerMap.keySet()) {
+ if(p.matcher(resource.toString()).matches()) {
+ ContentReader reader = readerMap.get(p);
+ log.debug("reading content for resource {} using reader {}",resource,reader.getName());
+ try {
+ return reader.getContentData(resource, mimetype);
+ } catch(IOException ex) {
+ log.error("could not read content, reader threw an IO Exception",ex);
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve the content of the specified mime type for the specified resource. Returns a input stream containing
+ * the byte data of the content, or null, indicating that a content of the specified mime type does not exist
+ * for the resource.
+ * <p/>
+ * Specialised content readers could even transform the resource content from its original form to the new
+ * mimetype, e.g. converting an image from JPEG to PNG.
+ * <p/>
+ * This method is preferrable for resources with large amounts of data.
+ *
+ * @param resource the resource for which to return the content
+ * @param mimetype the mime type to retrieve of the content
+ * @return a InputStream containing the content of the resource, or null if no content exists
+ */
+ @Override
+ public InputStream getContentStream(Resource resource, String mimetype) throws IOException {
+ // iterate over all possible writers; if the pattern matches, try to store the content and return
+ for(Pattern p : readerMap.keySet()) {
+ if(p.matcher(resource.toString()).matches()) {
+ ContentReader reader = readerMap.get(p);
+ log.debug("reading content for resource {} using reader {}",resource,reader.getName());
+ try {
+ return reader.getContentStream(resource, mimetype);
+ } catch(IOException ex) {
+ log.error("could not read content for resource {}, reader threw an IO Exception (message: {})",resource,ex.getMessage());
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasContent(Resource resource, String mimetype) {
+ // iterate over all possible writers; if the pattern matches, try to store the content and return
+ for(Pattern p : readerMap.keySet()) {
+ if(p.matcher(resource.toString()).matches()) {
+ ContentReader reader = readerMap.get(p);
+ return reader.hasContent(resource, mimetype);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String getContentType(Resource resource) {
+ // iterate over all possible writers; if the pattern matches, try to store the content and return
+ for(Pattern p : readerMap.keySet()) {
+ if(p.matcher(resource.stringValue()).matches()) {
+ ContentReader reader = readerMap.get(p);
+ return reader.getContentType(resource);
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Return the number of bytes the content of this resource contains.
+ *
+ * @param resource resource for which to return the content length
+ * @return byte count for the resource content
+ */
+ @Override
+ public long getContentLength(Resource resource, String mimetype) {
+ // iterate over all possible writers; if the pattern matches, try to store the content and return
+ for(Pattern p : readerMap.keySet()) {
+ if(p.matcher(resource.toString()).matches()) {
+ ContentReader reader = readerMap.get(p);
+ return reader.getContentLength(resource,mimetype);
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean deleteContent(Resource resource) throws LMFException {
+ // iterate over all possible writers; if the pattern matches, try to store the content and return
+ for(Pattern p : writerMap.keySet()) {
+ if(p.matcher(resource.toString()).matches()) {
+ ContentWriter writer = writerMap.get(p);
+ try {
+ writer.deleteContent(resource,"");
+ return true;
+ } catch(IOException ex) {
+ log.error("could not write content, writer threw an IO Exception",ex);
+ throw new WritingNotSupportedException(ex.getMessage(),ex);
+ }
+ }
+ }
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/services/content/FileSystemContentReader.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/services/content/FileSystemContentReader.java b/lmf-core/src/main/java/kiwi/core/services/content/FileSystemContentReader.java
new file mode 100644
index 0000000..f414a20
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/services/content/FileSystemContentReader.java
@@ -0,0 +1,309 @@
+/**
+ * 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 kiwi.core.services.content;
+
+import at.newmedialab.sesame.facading.FacadingFactory;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.Files;
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.content.ContentReader;
+import kiwi.core.api.triplestore.SesameService;
+import kiwi.core.model.content.MediaContentItem;
+import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
+import org.apache.tika.detect.DefaultDetector;
+import org.apache.tika.metadata.Metadata;
+import org.openrdf.model.Resource;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
+import static at.newmedialab.sesame.commons.repository.ExceptionUtils.handleRepositoryException;
+
+/**
+ * A content reader that reads the content of a resource from the file system.
+ * It uses the kiwi:hasContentPath property to determine the path of the content to access.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+public class FileSystemContentReader implements ContentReader {
+
+ @Inject
+ private Logger log;
+
+
+ @Inject
+ private ConfigurationService configurationService;
+
+ @Inject
+ private SesameService sesameService;
+
+ /** TIKA mime type detector */
+ private DefaultDetector detector;
+
+
+ private String defaultDir;
+
+ public FileSystemContentReader() {
+ }
+
+ @PostConstruct
+ public void initialise() {
+ detector = new DefaultDetector();
+ defaultDir = configurationService.getWorkDir()+File.separator+"resources";
+
+ log.debug("FileSystem Content Reader started (default directory: {})",defaultDir);
+
+ }
+
+ /**
+ * Retrieve the content of the specified mime type for the specified resource. Returns a byte array containing
+ * the byte data of the content, or null, indicating that a content of the specified mime type does not exist
+ * for the resource.
+ * <p/>
+ * Specialised content readers could even transform the resource content from its original form to the new
+ * mimetype, e.g. converting an image from JPEG to PNG.
+ *
+ * @param resource the resource for which to return the content
+ * @param mimetype the mime type to retrieve of the content
+ * @return a byte array containing the content of the resource, or null if no content exists
+ */
+ @Override
+ public byte[] getContentData(Resource resource, String mimetype) throws IOException {
+ InputStream in = getContentStream(resource,mimetype);
+ try {
+ return ByteStreams.toByteArray(in);
+ } finally {
+ in.close();
+ }
+ }
+
+ /**
+ * Return the name of the content reader. Used to identify and display the content reader to admin users.
+ *
+ * @return
+ */
+ @Override
+ public String getName() {
+ return "FileSystem Content Reader";
+ }
+
+ /**
+ * Retrieve the content of the specified mime type for the specified resource. Returns a input stream containing
+ * the byte data of the content, or null, indicating that a content of the specified mime type does not exist
+ * for the resource.
+ * <p/>
+ * Specialised content readers could even transform the resource content from its original form to the new
+ * mimetype, e.g. converting an image from JPEG to PNG.
+ * <p/>
+ * This method is preferrable for resources with large amounts of data.
+ *
+ * @param resource the resource for which to return the content
+ * @param mimetype the mime type to retrieve of the content
+ * @return a InputStream containing the content of the resource, or null if no content exists
+ */
+ @Override
+ public InputStream getContentStream(Resource resource, String mimetype) throws IOException {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String path = mci.getContentPath();
+ if(path == null && resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("file:")) {
+ try {
+ URI uri = new URI(((KiWiUriResource)resource).stringValue());
+ path = uri.getPath();
+ } catch(Exception ex) {}
+ }
+
+ if(path != null) {
+ if(!path.startsWith(defaultDir)) {
+ if(!configurationService.getBooleanConfiguration("content.filesystem.secure")) {
+ log.warn("accessing file {}, which is outside the default directory; this is a potential security risk; " +
+ "enable the option content.filesystem.secure in the configuration",path);
+ } else {
+ throw new FileNotFoundException("the file "+path+" is outside the LMF default directory location; access denied");
+ }
+ }
+
+ File file = new File(path);
+ if(file.exists() && file.canRead()) {
+ log.debug("reading file content from file {} for resource {} ...", file, resource);
+ return Files.newInputStreamSupplier(file).getInput();
+ } else {
+ throw new FileNotFoundException("the file "+path+" does not exist or is not readable");
+ }
+ } else {
+ return null;
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ return null;
+ }
+ }
+
+ /**
+ * Check whether the specified resource has content of the specified mimetype for this reader. Returns true
+ * in this case, false otherwise.
+ *
+ * @param resource the resource to check
+ * @param mimetype the mimetype to look for
+ * @return true if content of this mimetype is associated with the resource, false otherwise
+ */
+ @Override
+ public boolean hasContent(Resource resource, String mimetype) {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String path = mci.getContentPath();
+ if(path == null && resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("file:")) {
+ try {
+ URI uri = new URI(((KiWiUriResource)resource).stringValue());
+ path = uri.getPath();
+ } catch(Exception ex) {}
+ }
+
+ if(path != null) {
+ File file = new File(path);
+ if(file.exists() && file.canRead()) {
+ log.debug("found file content from file {} for resource {} ...", file, resource);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ return false;
+ }
+ }
+
+ /**
+ * Return the MIME content type of the resource passed as argument.
+ *
+ * @param resource resource for which to return the content type
+ * @return the MIME content type of the resource
+ */
+ @Override
+ public String getContentType(Resource resource) {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String path = mci.getContentPath();
+ if(path == null && resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("file:")) {
+ try {
+ URI uri = new URI(((KiWiUriResource)resource).stringValue());
+ path = uri.getPath();
+ } catch(Exception ex) {}
+ }
+
+ if(path != null) {
+ File file = new File(path);
+ if(file.exists() && file.canRead()) {
+
+ String mimeType = null;
+
+ Metadata metadata = new Metadata();
+ metadata.set(Metadata.RESOURCE_NAME_KEY, file.getAbsolutePath());
+ try {
+ InputStream in = new BufferedInputStream(Files.newInputStreamSupplier(file).getInput());
+ mimeType = detector.detect(in,metadata).toString();
+ in.close();
+ } catch (IOException e) {
+ log.error("I/O error while detecting file type for file {}",file,e);
+ }
+ log.debug("detected mime type {} of file {} for resource {} ...", mimeType, file, resource);
+
+ return mimeType;
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ return null;
+ }
+ }
+
+
+ /**
+ * Return the number of bytes the content of this resource contains.
+ *
+ * @param resource resource for which to return the content length
+ * @return byte count for the resource content
+ */
+ @Override
+ public long getContentLength(Resource resource, String mimetype) {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String path = mci.getContentPath();
+ if(path == null && resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("file:")) {
+ try {
+ URI uri = new URI(((KiWiUriResource)resource).stringValue());
+ path = uri.getPath();
+ } catch(Exception ex) {}
+ }
+
+ if(path != null) {
+ File file = new File(path);
+ if(file.exists() && file.canRead()) {
+ return file.length();
+ }
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ }
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/services/content/FileSystemContentWriter.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/services/content/FileSystemContentWriter.java b/lmf-core/src/main/java/kiwi/core/services/content/FileSystemContentWriter.java
new file mode 100644
index 0000000..91f0711
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/services/content/FileSystemContentWriter.java
@@ -0,0 +1,232 @@
+/**
+ * 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 kiwi.core.services.content;
+
+import at.newmedialab.sesame.facading.FacadingFactory;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.Files;
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.content.ContentWriter;
+import kiwi.core.api.triplestore.SesameService;
+import kiwi.core.model.content.MediaContentItem;
+import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
+import org.openrdf.model.Resource;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.slf4j.Logger;
+import sun.net.www.MimeEntry;
+import sun.net.www.MimeTable;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.UUID;
+
+import static at.newmedialab.sesame.commons.repository.ExceptionUtils.handleRepositoryException;
+
+/**
+ * A content writer that writes the content of a resource to the file system.
+ * It uses the kiwi:hasContentPath property to determine the destination path of the content to write to.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+public class FileSystemContentWriter implements ContentWriter {
+
+ @Inject
+ private Logger log;
+
+
+ @Inject
+ private ConfigurationService configurationService;
+
+ @Inject
+ private SesameService sesameService;
+
+ private String defaultDir;
+
+ public FileSystemContentWriter() {
+ }
+
+ @PostConstruct
+ public void initialise() {
+ defaultDir = configurationService.getWorkDir()+File.separator+"resources";
+
+ log.debug("FileSystem Content Writer started (default file location: {})",defaultDir);
+
+ File dir = new File(defaultDir);
+ if(!dir.exists() && !dir.mkdirs()) {
+ log.warn("could not create default directory for file system storage of content (directory: {})",defaultDir);
+ }
+ }
+
+ /**
+ * Delete the content of the speficied mime type for the specified resource.
+ *
+ * @param resource the resource for which to delete the content
+ * @param mimetype the mime type of the content to delete (optional)
+ */
+ @Override
+ public void deleteContent(Resource resource, String mimetype) throws IOException {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String path = mci.getContentPath();
+ if(path != null) {
+ if(!path.startsWith(defaultDir)) {
+ if(!configurationService.getBooleanConfiguration("content.filesystem.secure")) {
+ log.warn("accessing file {}, which is outside the default directory; this is a potential security risk; " +
+ "enable the option content.filesystem.secure in the configuration",path);
+ } else {
+ throw new FileNotFoundException("the file "+path+" is outside the LMF default directory location; access denied");
+ }
+ }
+
+ File file = new File(path);
+ if(file.exists() && file.canWrite()) {
+ log.info("deleting file {} for resource {} ...", file.getPath(), resource);
+ file.delete();
+ } else {
+ throw new FileNotFoundException("could not delete file "+path+"; it does not exist or is not writable");
+ }
+ } else {
+ throw new FileNotFoundException("could not delete file content for resource "+resource+"; no content path has been specified for the resource");
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ }
+ }
+
+ /**
+ * Return the name of the content reader. Used to identify and display the content reader to admin users.
+ *
+ * @return
+ */
+ @Override
+ public String getName() {
+ return "FileSystem Content Writer";
+ }
+
+ /**
+ * Store the content of the specified mime type for the specified resource. Accepts a byte array containing
+ * the byte data of the content that is then written to the destination configured for this writer.
+ * <p/>
+ *
+ * @param resource the resource for which to store the content
+ * @param mimetype the mime type of the content
+ * @param data a byte array containing the content of the resource
+ */
+ @Override
+ public void setContentData(Resource resource, byte[] data, String mimetype) throws IOException {
+ setContentStream(resource, new ByteArrayInputStream(data),mimetype);
+ }
+
+ /**
+ * Store the content of the specified mime type for the specified resource. Accepts an input stream containing
+ * the byte data of the content that is read and written to the destination configured for this writer.
+ * <p/>
+ * This method is preferrable for resources with large amounts of data.
+ *
+ * @param resource the resource for which to return the content
+ * @param mimetype the mime type to retrieve of the content
+ * @param in a InputStream containing the content of the resource
+ */
+ @Override
+ public void setContentStream(Resource resource, InputStream in, String mimetype) throws IOException {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String path = mci.getContentPath();
+
+ if(path == null) {
+ if(resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("file:")) {
+ try {
+ URI uri = new URI(((KiWiUriResource)resource).stringValue());
+ path = uri.getPath();
+ } catch(Exception ex) {}
+ } else {
+ // we store all other resources in the default directory; create a random file name and store it in the hasContentLocation
+ // property
+ String extension = null;
+ MimeEntry entry = MimeTable.getDefaultTable().find(mimetype);
+ if(entry != null && entry.getExtensions().length > 0) {
+ extension = entry.getExtensions()[0];
+ }
+
+ String fileName = UUID.randomUUID().toString();
+ path = defaultDir + File.separator +
+ fileName.substring(0,2) + File.separator +
+ fileName.substring(2,4) + File.separator +
+ fileName.substring(4,6) + File.separator +
+ fileName + (extension != null ? extension : "");
+ mci.setContentPath(path);
+ }
+ }
+
+ if(path != null) {
+ if(!path.startsWith(defaultDir)) {
+ if(!configurationService.getBooleanConfiguration("content.filesystem.secure")) {
+ log.warn("accessing file {}, which is outside the default directory; this is a potential security risk; " +
+ "enable the option content.filesystem.secure in the configuration",path);
+ } else {
+ throw new FileNotFoundException("the file "+path+" is outside the LMF default directory location; access denied");
+ }
+ }
+
+ File file = new File(path);
+ if(!file.exists()) {
+ try {
+ file.getParentFile().mkdirs();
+ file.createNewFile();
+ } catch(IOException ex) {
+ throw new FileNotFoundException("could not create file "+path+"; it is not writable");
+ }
+ }
+ if(file.exists() && file.canWrite()) {
+ log.debug("writing file content to file {} for resource {} ...", file, resource);
+ ByteStreams.copy(in, Files.newOutputStreamSupplier(file));
+ } else {
+ throw new FileNotFoundException("could not write to file "+path+"; it does not exist or is not writable");
+ }
+
+
+
+ } else {
+ throw new FileNotFoundException("could not write file content for resource "+resource+"; no content path has been specified for the resource");
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/services/content/HTTPContentReader.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/services/content/HTTPContentReader.java b/lmf-core/src/main/java/kiwi/core/services/content/HTTPContentReader.java
new file mode 100644
index 0000000..3a6b545
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/services/content/HTTPContentReader.java
@@ -0,0 +1,302 @@
+/**
+ * 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 kiwi.core.services.content;
+
+import at.newmedialab.sesame.facading.FacadingFactory;
+import com.google.common.io.ByteStreams;
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.content.ContentReader;
+import kiwi.core.api.http.HttpClientService;
+import kiwi.core.api.triplestore.SesameService;
+import kiwi.core.model.content.MediaContentItem;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
+import org.openrdf.model.Resource;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static at.newmedialab.sesame.commons.repository.ExceptionUtils.handleRepositoryException;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+public class HTTPContentReader implements ContentReader {
+
+ @Inject
+ private Logger log;
+
+
+ @Inject
+ private SesameService sesameService;
+
+ @Inject
+ private ConfigurationService configurationService;
+
+ @Inject
+ private HttpClientService httpClientService;
+
+ public HTTPContentReader() {
+ }
+
+ @PostConstruct
+ public void initialise() {
+ log.debug("HTTP Content Reader started");
+
+ }
+
+
+ /**
+ * Retrieve the content of the specified mime type for the specified resource. Returns a byte array containing
+ * the byte data of the content, or null, indicating that a content of the specified mime type does not exist
+ * for the resource.
+ * <p/>
+ * Uses the property kiwi:hasContentLocation to access the URL for the resource content. If this property is not
+ * given and the resource is itself a HTTP URI resource, it will try to access the URI itself.
+ *
+ * @param resource the resource for which to return the content
+ * @param mimetype the mime type to retrieve of the content
+ * @return a byte array containing the content of the resource, or null if no content exists
+ */
+ @Override
+ public byte[] getContentData(Resource resource, String mimetype) throws IOException {
+ return ByteStreams.toByteArray(getContentStream(resource, mimetype));
+ }
+
+ /**
+ * Return the name of the content reader. Used to identify and display the content reader to admin users.
+ *
+ * @return
+ */
+ @Override
+ public String getName() {
+ return "HTTP Content Reader";
+ }
+
+ /**
+ * Retrieve the content of the specified mime type for the specified resource. Returns a input stream containing
+ * the byte data of the content, or null, indicating that a content of the specified mime type does not exist
+ * for the resource.
+ * <p/>
+ * Uses the property kiwi:hasContentLocation to access the URL for the resource content. If this property is not
+ * given and the resource is itself a HTTP URI resource, it will try to access the URI itself.
+ * <p/>
+ * This method is preferrable for resources with large amounts of data.
+ *
+ * @param resource the resource for which to return the content
+ * @param mimetype the mime type to retrieve of the content
+ * @return a InputStream containing the content of the resource, or null if no content exists
+ */
+ @Override
+ public InputStream getContentStream(final Resource resource, String mimetype) throws IOException {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String location = mci.getContentLocation();
+
+ // if no location is explicitly specified, use the resource URI itself
+ if(location == null && resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("http://")) {
+ location = ((KiWiUriResource)resource).stringValue();
+ }
+
+ if(location != null) {
+ log.info("reading remote resource {}",location);
+ HttpGet get = new HttpGet(location);
+ get.setHeader("Accept",mimetype);
+
+ HttpResponse response = httpClientService.execute(get);
+ if(response.getStatusLine().getStatusCode() == 200)
+ return response.getEntity().getContent();
+ else {
+ log.info("invalid status code while retrieving HTTP remote content for resource {}: {}",resource,response.getStatusLine());
+ return null;
+ }
+ } else
+ return null;
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ return null;
+ }
+ }
+
+ /**
+ * Check whether the specified resource has content of the specified mimetype for this reader. Returns true
+ * in this case, false otherwise.
+ *
+ * @param resource the resource to check
+ * @param mimetype the mimetype to look for
+ * @return true if content of this mimetype is associated with the resource, false otherwise
+ */
+ @Override
+ public boolean hasContent(Resource resource, String mimetype) {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String location = mci.getContentLocation();
+
+ // if no location is explicitly specified, use the resource URI itself
+ if(location == null && resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("http://")) {
+ location = ((KiWiUriResource)resource).stringValue();
+ }
+
+ try {
+ if(location != null) {
+ log.info("reading remote resource {}",location);
+ HttpHead head = new HttpHead(location);
+ head.setHeader("Accept",mimetype);
+
+ return httpClientService.execute(head, new ResponseHandler<Boolean>() {
+ @Override
+ public Boolean handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
+ return response.getStatusLine().getStatusCode() == 200;
+ }
+ });
+
+ } else
+ return false;
+ } catch(IOException ex) {
+ return false;
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ return false;
+ }
+ }
+
+ /**
+ * Return the MIME content type of the resource passed as argument.
+ *
+ * @param resource resource for which to return the content type
+ * @return the MIME content type of the resource
+ */
+ @Override
+ public String getContentType(Resource resource) {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String location = mci.getContentLocation();
+
+ // if no location is explicitly specified, use the resource URI itself
+ if(location == null && resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("http://")) {
+ location = ((KiWiUriResource)resource).stringValue();
+ }
+
+ try {
+ if(location != null) {
+ log.info("reading remote resource {}",location);
+ HttpHead head = new HttpHead(location);
+
+ return httpClientService.execute(head, new ResponseHandler<String>() {
+ @Override
+ public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
+ if (response.getStatusLine().getStatusCode() == 200)
+ return response.getFirstHeader("Content-Type").getValue().split(";")[0];
+ else
+ return null;
+ }
+ });
+ } else
+ return null;
+ } catch(IOException ex) {
+ return null;
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ return null;
+ }
+ }
+
+ /**
+ * Return the number of bytes the content of this resource contains.
+ *
+ * @param resource resource for which to return the content length
+ * @return byte count for the resource content
+ */
+ @Override
+ public long getContentLength(Resource resource, String mimetype) {
+ try {
+ RepositoryConnection conn = sesameService.getConnection();
+ try {
+ MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
+
+ String location = mci.getContentLocation();
+
+ // if no location is explicitly specified, use the resource URI itself
+ if(location == null && resource instanceof KiWiUriResource && ((KiWiUriResource)resource).stringValue().startsWith("http://")) {
+ location = ((KiWiUriResource)resource).stringValue();
+ }
+
+ try {
+ if(location != null) {
+ log.info("reading remote resource {}",location);
+ HttpHead head = new HttpHead(location);
+
+ return httpClientService.execute(head, new ResponseHandler<Long>() {
+
+ @Override
+ public Long handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
+ if (response.getStatusLine().getStatusCode() == 200)
+ return Long.parseLong(response.getFirstHeader("Content-Length").getValue());
+ else
+ return 0l;
+ }
+ });
+ } else
+ return 0;
+ } catch(Exception ex) {
+ return 0;
+ }
+ } finally {
+ conn.commit();
+ conn.close();
+ }
+ } catch (RepositoryException ex) {
+ handleRepositoryException(ex,FileSystemContentReader.class);
+ return 0;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/services/exporter/ExporterServiceImpl.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/services/exporter/ExporterServiceImpl.java b/lmf-core/src/main/java/kiwi/core/services/exporter/ExporterServiceImpl.java
new file mode 100644
index 0000000..2d4efe5
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/services/exporter/ExporterServiceImpl.java
@@ -0,0 +1,331 @@
+/**
+ * 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 kiwi.core.services.exporter;
+
+import com.google.common.collect.ImmutableSet;
+import kiwi.core.api.exporter.ExportService;
+import kiwi.core.api.io.LMFIOService;
+import kiwi.core.api.triplestore.SesameService;
+import kiwi.core.exception.io.UnsupportedExporterException;
+import org.openrdf.model.URI;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.RDFHandlerException;
+import org.openrdf.rio.RDFWriter;
+import org.openrdf.rio.Rio;
+import org.slf4j.Logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Set;
+
+/**
+ * Methods for writing triple data into different targets using different exporters.
+ *
+ * @author Sebastian Schaffert
+ *
+ */
+@ApplicationScoped
+public class ExporterServiceImpl implements ExportService {
+
+ @Inject
+ private Logger log;
+
+ @Inject
+ private LMFIOService ioService;
+
+
+ @Inject
+ private SesameService sesameService;
+
+
+
+ /**
+ * Get a collection of all mime types accepted by this exporter. Used for automatically
+ * selecting the appropriate exporter in ExportService.
+ *
+ * @return a set of strings representing the mime types accepted by this exporter
+ */
+ @Override
+ public Set<String> getProducedTypes() {
+ return ImmutableSet.copyOf(ioService.getProducedTypes());
+ }
+
+ /**
+ * Export the triple data contained in the named graph passed as argument "context" and return
+ * it as a Java string using the serialisation format specified by "mimeType".
+ * <p/>
+ * The context parameter limits the exported triples to the named graph represented by this
+ * resource. If it is set to null, all named graphs will be exported.
+ * <p/>
+ * The mime type must be supported by at least one of the registered exporters, otherwise an
+ * UnsupportedExporterException. Available mime types can be retrieved using the getProducedTypes()
+ * method.
+ *
+ *
+ * @param context the named graph to export; if null, all named graphs will be exported
+ * @param mimeType a mime type registered by an exporter
+ * @throws kiwi.core.exception.io.UnsupportedExporterException
+ * in case there is no matching exporter for the given mime type
+ */
+ @Override
+ public String exportData(URI context, String mimeType) throws UnsupportedExporterException {
+ RDFFormat serializer = ioService.getSerializer(mimeType);
+ if(serializer == null) {
+ log.warn("could not find serializer for MIME type {}",mimeType);
+ throw new UnsupportedExporterException("No serializer for mime type "+mimeType);
+ }
+ try {
+ StringWriter writer = new StringWriter();
+ exportData(writer,context,mimeType);
+ return writer.toString();
+ } catch (IOException e) {
+ log.error("impossible I/O error while writing to string buffer",e);
+ return null;
+ }
+ }
+
+ /**
+ * Export the triple data contained in the named graph passed as argument "context" and write it
+ * to the writer given as first argument using the serialisation format specified by "mimeType".
+ * <p/>
+ * The context parameter limits the exported triples to the named graph represented by this
+ * resource. If it is set to null, all named graphs will be exported.
+ * <p/>
+ * The mime type must be supported by at least one of the registered exporters, otherwise an
+ * UnsupportedExporterException. Available mime types can be retrieved using the getProducedTypes()
+ * method.
+ *
+ *
+ * @param writer the writer to write the triples to; will be closed when the triples are written
+ * @param context the named graph to export; if null, all named graphs will be exported
+ * @param mimeType a mime type registered by an exporter
+ * @throws kiwi.core.exception.io.UnsupportedExporterException
+ * in case there is no matching exporter for the given mime type
+ * @throws java.io.IOException in case there is an error writing to the output
+ */
+ @Override
+ public void exportData(Writer writer, URI context, String mimeType) throws UnsupportedExporterException, IOException {
+ RDFFormat serializer = ioService.getSerializer(mimeType);
+ if(serializer == null) {
+ log.warn("could not find serializer for MIME type {}",mimeType);
+ throw new UnsupportedExporterException("No serializer for mime type "+mimeType);
+ }
+
+ // HINT: This method might be executed outside a transaction!
+ RDFWriter handler = Rio.createWriter(serializer,writer);
+ try {
+ RepositoryConnection connection = sesameService.getConnection();
+ connection.begin();
+ try {
+ if(context == null) {
+ connection.exportStatements(null,null,null,true,handler);
+ } else {
+ connection.exportStatements(null,null,null,true,handler,context);
+ }
+ } finally {
+ connection.commit();
+ connection.close();
+ }
+ } catch (RepositoryException e) {
+ throw new IOException("error while getting repository connection");
+ } catch (RDFHandlerException e) {
+ throw new IOException("error while writing RDF data to stream");
+ }
+ }
+
+ /**
+ * Export the triple data contained in the named graph passed as argument "context" and write it
+ * to the output stream given as first argument using the serialisation format specified by "mimeType".
+ * <p/>
+ * The context parameter limits the exported triples to the named graph represented by this
+ * resource. If it is set to null, all named graphs will be exported.
+ * <p/>
+ * The mime type must be supported by at least one of the registered exporters, otherwise an
+ * UnsupportedExporterException. Available mime types can be retrieved using the getProducedTypes()
+ * method.
+ *
+ *
+ * @param outputStream the OutputStream to write the triples to; data will be written using UTF-8 encoding;
+ * will be closed when the triples are written
+ * @param context the named graph to export; if null, all named graphs will be exported
+ * @param mimeType a mime type registered by an exporter
+ * @throws kiwi.core.exception.io.UnsupportedExporterException
+ * in case there is no matching exporter for the given mime type
+ * @throws java.io.IOException in case there is an error writing to the output
+ */
+ @Override
+ public void exportData(OutputStream outputStream, URI context, String mimeType) throws UnsupportedExporterException, IOException {
+ RDFFormat serializer = ioService.getSerializer(mimeType);
+ if(serializer == null) {
+ log.warn("could not find serializer for MIME type {}",mimeType);
+ throw new UnsupportedExporterException("No serializer for mime type "+mimeType);
+ }
+ // HINT: This method might be executed outside a transaction!
+ RDFWriter handler = Rio.createWriter(serializer,outputStream);
+ try {
+ RepositoryConnection connection = sesameService.getConnection();
+ try {
+ if(context == null) {
+ connection.exportStatements(null,null,null,true,handler);
+ } else {
+ connection.exportStatements(null,null,null,true,handler,context);
+ }
+ } finally {
+ connection.commit();
+ connection.close();
+ }
+ } catch (RepositoryException e) {
+ throw new IOException("error while getting repository connection");
+ } catch (RDFHandlerException e) {
+ throw new IOException("error while writing RDF data to stream");
+ }
+ }
+
+
+ /**
+ * Export the triple data for the given resource contained in the named graph passed as argument "context" and return
+ * it as a Java string using the serialisation format specified by "mimeType".
+ * <p/>
+ * The context parameter limits the exported triples to the named graph represented by this
+ * resource. If it is set to null, all named graphs will be exported.
+ * <p/>
+ * The mime type must be supported by at least one of the registered exporters, otherwise an
+ * UnsupportedExporterException. Available mime types can be retrieved using the getProducedTypes()
+ * method.
+ *
+ * @param context the named graph to export; if null, all named graphs will be exported
+ * @param mimeType a mime type registered by an exporter
+ * @throws kiwi.core.exception.io.UnsupportedExporterException
+ * in case there is no matching exporter for the given mime type
+ */
+ @Override
+ public String exportData(URI resource, URI context, String mimeType) throws UnsupportedExporterException {
+ RDFFormat serializer = ioService.getSerializer(mimeType);
+ if(serializer == null) {
+ log.warn("could not find serializer for MIME type {}",mimeType);
+ throw new UnsupportedExporterException("No serializer for mime type "+mimeType);
+ }
+ try {
+ StringWriter writer = new StringWriter();
+ exportData(writer,resource,context,mimeType);
+ return writer.toString();
+ } catch (IOException e) {
+ log.error("impossible I/O error while writing to string buffer",e);
+ return null;
+ }
+ }
+
+ /**
+ * Export the triple data for the given resource contained in the named graph passed as argument "context" and write it
+ * to the writer given as first argument using the serialisation format specified by "mimeType".
+ * <p/>
+ * The context parameter limits the exported triples to the named graph represented by this
+ * resource. If it is set to null, all named graphs will be exported.
+ * <p/>
+ * The mime type must be supported by at least one of the registered exporters, otherwise an
+ * UnsupportedExporterException. Available mime types can be retrieved using the getProducedTypes()
+ * method.
+ *
+ *
+ * @param writer the writer to write the triples to; will be closed when the triples are written
+ * @param context the named graph to export; if null, all named graphs will be exported
+ * @param mimeType a mime type registered by an exporter
+ * @throws kiwi.core.exception.io.UnsupportedExporterException
+ * in case there is no matching exporter for the given mime type
+ * @throws java.io.IOException in case there is an error writing to the output
+ */
+ @Override
+ public void exportData(Writer writer, URI resource, URI context, String mimeType) throws UnsupportedExporterException, IOException {
+ RDFFormat serializer = ioService.getSerializer(mimeType);
+ if(serializer == null) {
+ log.warn("could not find serializer for MIME type {}",mimeType);
+ throw new UnsupportedExporterException("No serializer for mime type "+mimeType);
+ }
+
+ // HINT: This method might be executed outside a transaction!
+ RDFWriter handler = Rio.createWriter(serializer,writer);
+ try {
+ RepositoryConnection connection = sesameService.getConnection();
+ try {
+ if(context == null) {
+ connection.exportStatements(resource,null,null,true,handler);
+ } else {
+ connection.exportStatements(resource,null,null,true,handler,context);
+ }
+ } finally {
+ connection.commit();
+ connection.close();
+ }
+ } catch (RepositoryException e) {
+ throw new IOException("error while getting repository connection");
+ } catch (RDFHandlerException e) {
+ throw new IOException("error while writing RDF data to stream");
+ }
+ }
+
+ /**
+ * Export the triple data for the given resource contained in the named graph passed as argument "context" and write it
+ * to the output stream given as first argument using the serialisation format specified by "mimeType".
+ * <p/>
+ * The context parameter limits the exported triples to the named graph represented by this
+ * resource. If it is set to null, all named graphs will be exported.
+ * <p/>
+ * The mime type must be supported by at least one of the registered exporters, otherwise an
+ * UnsupportedExporterException. Available mime types can be retrieved using the getProducedTypes()
+ * method.
+ *
+ * @param outputStream the OutputStream to write the triples to; data will be written using UTF-8 encoding;
+ * will be closed when the triples are written
+ * @param context the named graph to export; if null, all named graphs will be exported
+ * @param mimeType a mime type registered by an exporter
+ * @throws kiwi.core.exception.io.UnsupportedExporterException
+ * in case there is no matching exporter for the given mime type
+ * @throws java.io.IOException in case there is an error writing to the output
+ */
+ @Override
+ public void exportData(OutputStream outputStream, URI resource, URI context, String mimeType) throws UnsupportedExporterException, IOException {
+ RDFFormat serializer = ioService.getSerializer(mimeType);
+ if(serializer == null) {
+ log.warn("could not find serializer for MIME type {}",mimeType);
+ throw new UnsupportedExporterException("No serializer for mime type "+mimeType);
+ }
+ // HINT: This method might be executed outside a transaction!
+ RDFWriter handler = Rio.createWriter(serializer,outputStream);
+ try {
+ RepositoryConnection connection = sesameService.getConnection();
+ try {
+ if(context == null) {
+ connection.exportStatements(resource,null,null,true,handler);
+ } else {
+ connection.exportStatements(resource,null,null,true,handler,context);
+ }
+ } finally {
+ connection.commit();
+ connection.close();
+ }
+ } catch (RepositoryException e) {
+ throw new IOException("error while getting repository connection");
+ } catch (RDFHandlerException e) {
+ throw new IOException("error while writing RDF data to stream");
+ }
+ }
+}