DataImpl.java
/*
* Copyright (c) 2007-2017 MetaSolutions AB
*
* 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 org.entrystore.impl;
import java.nio.file.Path;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.MessageDigestAlgorithms;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.entrystore.Data;
import org.entrystore.Entry;
import org.entrystore.PrincipalManager.AccessProperty;
import org.entrystore.QuotaException;
import org.entrystore.repository.RepositoryEvent;
import org.entrystore.repository.RepositoryEventObject;
import org.entrystore.repository.config.Settings;
import org.entrystore.repository.util.FileOperations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import static org.apache.commons.codec.Charsets.UTF_8;
import static org.apache.commons.codec.digest.MessageDigestAlgorithms.SHA_256;
import static org.eclipse.rdf4j.model.util.Values.iri;
/**
* Data class to handle binary local resources.
*
* @author Eric Johansson
* @author Hannes Ebner
*/
public class DataImpl extends ResourceImpl implements Data {
private static final Logger log = LoggerFactory.getLogger(DataImpl.class);
public static final String SHA_256_POSTFIX = ".sha256";
private File file = null;
public DataImpl(Entry entry) {
super((EntryImpl) entry, iri(entry.getResourceURI().toString()));
}
private File getFile() throws IOException {
if (file == null) {
String dataDirStr = entry.getRepositoryManager().getConfiguration().getString(Settings.DATA_FOLDER);
if (dataDirStr != null) {
// Workaround to handle allowed "file:" prefixes.
dataDirStr = StringUtils.removeStart(dataDirStr, "file://");
dataDirStr = StringUtils.removeStart(dataDirStr, "file:");
File dataDir = new File(dataDirStr);
if (!dataDir.exists()) {
if (!dataDir.mkdirs()) {
log.error("Unable to create data folder");
}
}
File contextDir = new File(dataDir, entry.getContext().getEntry().getId());
if (!contextDir.exists()) {
contextDir.mkdir();
}
file = new File(contextDir, entry.getId());
}
if (file == null) {
throw new IOException("Unable to get local file of resource");
}
}
return file;
}
public InputStream getData() {
this.entry.getRepositoryManager().getPrincipalManager().checkAuthenticatedUserAuthorized(entry, AccessProperty.ReadResource);
try {
if (getFile() != null) {
return Files.newInputStream(getFile().toPath());
}
} catch (IOException e) {
log.error(e.getMessage());
}
return null;
}
public void setData(InputStream is) throws QuotaException, IOException {
this.entry.getRepositoryManager().getPrincipalManager().checkAuthenticatedUserAuthorized(entry, AccessProperty.WriteResource);
MessageDigest sha = null;
try {
sha = MessageDigest.getInstance(SHA_256);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
Path dataPath = getFile().toPath();
long bytes = FileOperations.copyFile(new DigestInputStream(is, sha), Files.newOutputStream(dataPath));
writeDigest(sha);
if (entry.getRepositoryManager().hasQuotas()) {
try {
entry.getContext().increaseQuotaFillLevel(bytes);
} catch (QuotaException qe) {
if (file.exists()) {
file.delete();
}
File digestFile = getDigestFile();
if (digestFile != null && digestFile.exists()) {
digestFile.delete();
}
throw qe;
}
}
entry.getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(entry, RepositoryEvent.ResourceUpdated));
}
public void useData(File file) throws IOException {
if (file == null) {
throw new IllegalArgumentException("File must not be null");
}
this.entry.getRepositoryManager().getPrincipalManager().checkAuthenticatedUserAuthorized(entry, AccessProperty.WriteResource);
long sizeBefore = 0;
long sizeAfter = 0;
if (entry.getRepositoryManager().hasQuotas()) {
if (getFile() != null && getFile().exists()) {
sizeBefore = getFile().length();
}
if (file != null && file.exists()) {
sizeAfter = file.length();
}
}
FileOperations.copyFile(file, getFile());
if (entry.getRepositoryManager().hasQuotas()) {
entry.getContext().decreaseQuotaFillLevel(sizeBefore);
try {
entry.getContext().increaseQuotaFillLevel(sizeAfter);
} catch (QuotaException qe) {
getFile().delete();
}
}
entry.getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(entry, RepositoryEvent.ResourceUpdated));
}
@Override
public void remove(RepositoryConnection rc) throws Exception {
super.remove(rc);
delete();
}
public boolean delete() {
boolean success = false;
try {
File f = getFile();
File digestFile = getDigestFile();
if (f != null && f.exists()) {
long size = f.length();
success = f.delete();
if (success && entry.getRepositoryManager().hasQuotas()) {
entry.getContext().decreaseQuotaFillLevel(size);
}
if (digestFile != null && digestFile.exists()) {
digestFile.delete();
}
entry.getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(entry, RepositoryEvent.ResourceDeleted));
}
} catch (IOException ioe) {
log.error(ioe.getMessage());
}
return success;
}
public File getDataFile() {
this.entry.getRepositoryManager().getPrincipalManager().checkAuthenticatedUserAuthorized(entry, AccessProperty.ReadResource);
try {
File f = getFile();
if (f != null && f.exists()) {
return f;
}
} catch (IOException ioe) {
log.error(ioe.getMessage());
}
return null;
}
private File getDigestFile() {
File dataFile = getDataFile();
if (dataFile == null) {
return null;
}
String digestFileName = null;
try {
digestFileName = dataFile.getCanonicalPath() + SHA_256_POSTFIX;
} catch (IOException e) {
log.error("Could not get canonical path of: " + dataFile.getAbsolutePath(), e);
return null;
}
File digestFile = new File(digestFileName);
return digestFile;
}
private void writeDigest(MessageDigest messageDigest) throws IOException {
byte[] digest = messageDigest.digest();
String s = String.valueOf(Hex.encodeHex(digest));
FileUtils.writeStringToFile(getDigestFile(), s, UTF_8);
}
public String readDigest() {
File digestFile = getDigestFile();
if (digestFile == null) {
return null;
}
try {
return FileUtils.readFileToString(digestFile, UTF_8);
} catch (IOException e) {
return null;
}
}
}