/*
* Copyright 2012 Research Studios Austria Forschungsges.m.b.H.
*
* 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 won.protocol.model;
import org.apache.jena.query.Dataset;
import org.apache.jena.query.DatasetFactory;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RiotException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URI;
/**
* Encapsulates a jena dataset for storing it in a relational db.
*/
@Entity
@Table(name = "rdf_datasets")
public class DatasetHolder
{
private static final int DEFAULT_BYTE_ARRAY_SIZE = 500;
//the URI of the dataset
@Id
@GeneratedValue
@Column( name = "id" )
private Long id;
@Version
@Column(name="version", columnDefinition = "integer DEFAULT 0", nullable = false)
private int version = 0;
@Transient
private final Logger logger = LoggerFactory.getLogger(getClass());
@Column( name = "datasetURI", unique = true)
@Convert( converter = URIConverter.class )
private URI uri;
//the model as a byte array
@Lob @Column( name = "dataset", nullable = false, length = 10000000)
private byte[] datasetBytes;
//for multiple accesses to model, cache it.
@Transient
private Dataset cachedDataset;
DatasetHolder(){}
public DatasetHolder(final URI uri, final Dataset dataset) {
this.uri = uri;
setDataset(dataset);
this.cachedDataset = dataset;
}
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public URI getUri() {
return uri;
}
public void setUri(final URI uri) {
this.uri = uri;
}
protected void setVersion(final int version) {
this.version = version;
}
public int getVersion() {
return version;
}
public byte[] getDatasetBytes() {
return datasetBytes;
}
void setDatasetBytes(final byte[] datasetBytes) {
this.datasetBytes = datasetBytes;
this.cachedDataset = null;
}
/**
* Careful, expensive operation: writes dataset to string.
* @param dataset
*/
public void setDataset(Dataset dataset) {
assert this.uri != null : "uri must not be null";
assert this.datasetBytes != null : "model must not be null";
ByteArrayOutputStream out = new ByteArrayOutputStream(DEFAULT_BYTE_ARRAY_SIZE);
synchronized(this){
RDFDataMgr.write(out, dataset, Lang.NQUADS);
this.datasetBytes = out.toByteArray();
this.cachedDataset = dataset;
if (logger.isDebugEnabled()){
logger.debug("wrote dataset {} to byte array of length {}", this.uri, this.datasetBytes.length);
}
}
}
/**
* Careful, expensive operation: reads dataset from string.
* @return
*/
public Dataset getDataset(){
assert this.uri != null : "uri must not be null";
assert this.datasetBytes != null : "model must not be null";
if (this.cachedDataset != null) return cachedDataset;
synchronized (this) {
if (this.cachedDataset != null) return cachedDataset;
Dataset dataset = DatasetFactory.createGeneral();
InputStream is = new ByteArrayInputStream(this.datasetBytes);
try {
try {
RDFDataMgr.read(dataset, is, this.uri.toString(), Lang.NQUADS);
} catch (RiotException ex) {
//assume that the data is stored in TRIG old format, try that.
is = new ByteArrayInputStream(this.datasetBytes);
RDFDataMgr.read(dataset, is, Lang.TRIG);
}
} catch (Exception e) {
logger.warn("could not read dataset {} from byte array. Byte array is null: {}, has length {}",
new Object[]{this.uri,
this.datasetBytes == null,
this.datasetBytes == null ? -1 : this.datasetBytes.length}
);
logger.warn("caught exception while reading dataset", e);
}
this.cachedDataset = dataset;
return dataset;
}
}
}