EntryImpl.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 lombok.Getter;
import lombok.Setter;
import org.eclipse.rdf4j.common.iteration.Iterations;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.impl.LinkedHashModel;
import org.eclipse.rdf4j.model.util.Models;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.repository.RepositoryResult;
import org.entrystore.Context;
import org.entrystore.Entry;
import org.entrystore.EntryType;
import org.entrystore.GraphType;
import org.entrystore.Group;
import org.entrystore.Metadata;
import org.entrystore.PrincipalManager;
import org.entrystore.PrincipalManager.AccessProperty;
import org.entrystore.Provenance;
import org.entrystore.Resource;
import org.entrystore.ResourceType;
import org.entrystore.User;
import org.entrystore.repository.RepositoryEvent;
import org.entrystore.repository.RepositoryEventObject;
import org.entrystore.repository.RepositoryManager;
import org.entrystore.repository.util.URISplit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.net.URI;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static org.eclipse.rdf4j.model.util.Values.iri;
//TODO change expression to match paper.
public class EntryImpl implements Entry {
@Getter
protected volatile String id;
@Setter
protected volatile Resource resource;
protected volatile MetadataImpl localMetadata;
@Getter
protected volatile Metadata cachedExternalMetadata;
protected volatile IRI localMdURI;
protected volatile IRI relationURI;
protected volatile IRI externalMdURI;
protected volatile IRI cachedExternalMdURI;
protected ContextImpl context;
@Getter
protected final Repository repository;
protected RepositoryManagerImpl repositoryManager;
protected volatile IRI entryURI;
protected volatile IRI resURI;
protected volatile EntryType locType = EntryType.Local;
protected volatile ResourceType repType = ResourceType.InformationResource;
@Getter
protected volatile GraphType graphType = GraphType.None;
protected volatile XMLGregorianCalendar created;
protected volatile XMLGregorianCalendar modified;
protected volatile XMLGregorianCalendar cachedAt;
protected volatile IRI creator;
//protected Set<URI> referredIn = new HashSet<URI>();
protected volatile Set<IRI> contributors = new HashSet<>();
protected volatile URI status;
Logger log = LoggerFactory.getLogger(EntryImpl.class);
private volatile Set<URI> administerPrincipals;
private volatile Set<URI> readMetadataPrincipals;
private volatile Set<URI> writeMetadataPrincipals;
private volatile Set<URI> writeResourcePrincipals;
private volatile Set<URI> readResourcePrincipals;
private volatile List<Statement> relations;
protected boolean invRelations = false;
private volatile String format;
private volatile long fileSize = -1;
private volatile String filename;
private Boolean readOrWrite;
private String originalList;
private ProvenanceImpl provenance;
@Getter
private volatile boolean deleted = false;
//A ugly hack to be able to initialize the ContextManager itself.
EntryImpl(RepositoryManagerImpl repositoryManager, Repository repository) {
this.repositoryManager = repositoryManager;
this.repository = repository;
if (repositoryManager.getProvenanceRepository() != null) {
this.provenance = new ProvenanceImpl(this);
}
}
public EntryImpl(String id, ContextImpl context, RepositoryManagerImpl repositoryManager, Repository repository) {
this.id = id;
String base = repositoryManager.getRepositoryURL().toString();
ValueFactory vf = repository.getValueFactory();
this.entryURI = vf.createIRI(URISplit.createURI(base, context.id, RepositoryProperties.ENTRY_PATH, id).toString());
this.relationURI = vf.createIRI(URISplit.createURI(base, context.id, RepositoryProperties.RELATION, id).toString());
this.localMdURI = vf.createIRI(URISplit.createURI(base, context.id, RepositoryProperties.MD_PATH, this.id).toString());
this.context = context;
this.repositoryManager = repositoryManager;
this.repository = repository;
if (repositoryManager.getProvenanceRepository() != null) {
this.provenance = new ProvenanceImpl(this);
}
}
/**
* Loads an MetaMetadataImpl by listing all statements for the named graph given by uri.
*/
protected boolean load() {
try {
RepositoryConnection rc = repository.getConnection();
try {
if (loadFromStatements(rc.getStatements(null, null, null, false, this.entryURI).asList())) {
initMetadataObjects();
return true;
}
return false;
} catch (Exception e) {
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
} catch (RepositoryException e) {
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
/**
* Loads an entry information from existing list of statements.
* @throws RepositoryException
*/
protected boolean load(RepositoryConnection rc) throws RepositoryException {
if (loadFromStatements(rc.getStatements(null, null, null, false, this.entryURI).asList())) {
initMetadataObjects();
return true;
}
return false;
}
protected void initMetadataObjects() {
if (locType == EntryType.Local || locType == EntryType.Link) {
this.localMetadata = new MetadataImpl(this, localMdURI, resURI, false);
}
if (locType == EntryType.LinkReference) {
this.localMetadata = new MetadataImpl(this, localMdURI, resURI, false);
if (externalMdURI.stringValue().startsWith(this.repositoryManager.getRepositoryURL().toString())) {
this.cachedExternalMetadata = new LocalMetadataWrapper(this);
} else {
this.cachedExternalMetadata = new MetadataImpl(this, cachedExternalMdURI, resURI, true);
}
}
if (locType == EntryType.Reference) {
if (externalMdURI.stringValue().startsWith(this.repositoryManager.getRepositoryURL().toString())) {
this.cachedExternalMetadata = new LocalMetadataWrapper(this);
} else {
this.cachedExternalMetadata = new MetadataImpl(this, cachedExternalMdURI, resURI, true);
}
}
}
/**
* Use when a new entry information object are to be created within an existing transaction.
* @throws DatatypeConfigurationException
* @throws RepositoryException
*/
protected void create(IRI resURI, IRI externalMetadataURI, GraphType bType, EntryType lType, ResourceType rType, RepositoryConnection rc) throws RepositoryException, DatatypeConfigurationException {
String base = repositoryManager.getRepositoryURL().toString();
ValueFactory vf = repository.getValueFactory();
this.resURI = resURI;
if (lType == EntryType.LinkReference) {
this.cachedExternalMdURI = vf.createIRI(URISplit.createURI(base, context.id, RepositoryProperties.EXTERNAL_MD_PATH, this.id).toString());
this.externalMdURI = externalMetadataURI;
}
if (lType == EntryType.Reference) {
this.cachedExternalMdURI = vf.createIRI(URISplit.createURI(base, context.id, RepositoryProperties.EXTERNAL_MD_PATH, this.id).toString());
this.externalMdURI = externalMetadataURI;
}
initialize(bType, lType, rType, rc);
initMetadataObjects();
}
private void initialize(GraphType bt, EntryType locT, ResourceType repT, RepositoryConnection rc) throws RepositoryException, DatatypeConfigurationException {
ValueFactory vf = rc.getRepository().getValueFactory();
if (bt != null) {
setGraphType(bt, rc);
}
if (repT != null && graphType == GraphType.None) {
setResourceType(repT, rc);
}
setLocationType(locT, rc);
rc.add(entryURI, RepositoryProperties.resource, this.resURI, entryURI);
created = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
rc.add(entryURI, RepositoryProperties.Created, vf.createLiteral(created), entryURI);
registerEntryModified(rc, vf);
/*
* Adds a statement with the entry URI as subject,
* relation as predicate, and the relation URI as
* an object to the scam repository, the named context is the entry.
*/
rc.add(entryURI, RepositoryProperties.relation, this.relationURI, entryURI);
if (locT != EntryType.Reference) {
rc.add(entryURI, RepositoryProperties.metadata, this.localMdURI, entryURI);
}
if (locT == EntryType.Reference || locT == EntryType.LinkReference) {
rc.add(entryURI, RepositoryProperties.externalMetadata, this.externalMdURI, entryURI);
rc.add(entryURI, RepositoryProperties.cachedExternalMetadata, this.cachedExternalMdURI, entryURI);
}
PrincipalManager pm = this.repositoryManager.getPrincipalManager();
if (pm != null) {
URI userURI = pm.getAuthenticatedUserURI();
if (userURI != null) {
this.creator = vf.createIRI(userURI.toString());
rc.add(entryURI, RepositoryProperties.Creator, this.creator, entryURI);
}
}
//referredIn = new HashSet<URI>();
//TODO Check so that not a Context is a NamedResource and other restrictions.
}
protected void refreshFromRepository(RepositoryConnection rc) throws RepositoryException {
loadFromStatements(rc.getStatements(null, null, null, false, entryURI).asList());
}
private boolean loadFromStatements(List<Statement> existingStatements) throws RepositoryException {
if (existingStatements.isEmpty()) {
return false;
}
Set<URI> administerPrincipals = null;
Set<URI> readMetadataPrincipals = null;
Set<URI> writeMetadataPrincipals = null;
Set<URI> readResourcePrincipals = null;
Set<URI> writeResourcePrincipals = null;
Set<IRI> contributors = new HashSet<>();
IRI entryURI = null;
IRI resURI = null;
IRI localMdURI = null;
IRI cachedExternalMdURI = null;
IRI relationURI = null;
XMLGregorianCalendar created = null;
IRI creator = null;
XMLGregorianCalendar modified = null;
IRI externalMdURI = null;
XMLGregorianCalendar cachedAt = null;
EntryType locType = EntryType.Local;
ResourceType repType = ResourceType.InformationResource;
GraphType graphType = GraphType.None;
//Following are cached on request. (Move more values here if possible)
String format = null;
long fileSize = -1;
String filename = null;
IRI status = null;
boolean invRelations = false;
RepositoryConnection rc = null;
try {
String base = repositoryManager.getRepositoryURL().toString();
rc = this.repository.getConnection();
// referredIn = new HashSet<URI>();
for (Statement statement : existingStatements) {
IRI predicate = statement.getPredicate();
if (predicate.equals(RepositoryProperties.resource)) {
entryURI = (IRI) statement.getSubject();
resURI = (IRI) statement.getObject();
} else if (predicate.equals(RepositoryProperties.metadata)) {
localMdURI = ((IRI) statement.getObject());
} else if (predicate.equals(RepositoryProperties.externalMetadata)) {
externalMdURI = ((IRI) statement.getObject());
} else if (predicate.equals(RepositoryProperties.cachedExternalMetadata)) {
cachedExternalMdURI = ((IRI) statement.getObject());
} else if (predicate.equals(RepositoryProperties.relation)) {
relationURI = ((IRI) statement.getObject());
} else if (predicate.equals(RepositoryProperties.cached)) {
// TODO: also wrong
cachedAt = ((Literal) statement.getObject()).calendarValue();
// } else if (predicate.equals(RepositoryProperties.referredIn)) {
// referredIn.add(URI.create(statement.getObject().stringValue()));
} else if (predicate.equals(RepositoryProperties.Created)) {
created = ((Literal) statement.getObject()).calendarValue();
} else if (predicate.equals(RepositoryProperties.Creator)) {
creator = ((IRI) statement.getObject());
} else if (predicate.equals(RepositoryProperties.Contributor)) {
contributors.add((IRI) statement.getObject());
} else if (predicate.equals(RepositoryProperties.Modified)) {
try {
//log.info(statement.getObject().stringValue());
modified = ((Literal) statement.getObject()).calendarValue();
} catch (NullPointerException e) {
log.error(e.getMessage());
}
} else {
//Check if statement refer other entries that affect their inv-rel cache.
if (!predicate.equals(RepositoryProperties.Read)
&& !predicate.equals(RepositoryProperties.Write)
&& !predicate.equals(RepositoryProperties.Pipeline)
&& !predicate.equals(RepositoryProperties.originallyCreatedIn)) {
Value obj = statement.getObject();
org.eclipse.rdf4j.model.Resource subj = statement.getSubject();
//Check for relations between this resource and another entry (resourceURI (has to be a repository resource), metadataURI, or entryURI)
if (obj instanceof IRI
&& obj.stringValue().startsWith(base)
&& subj.stringValue().startsWith(base)) {
invRelations = true;
}
}
}
}
//Detect types.
for (Statement statement : existingStatements) {
org.eclipse.rdf4j.model.Resource subject = statement.getSubject();
if (statement.getPredicate().equals(RDF.TYPE)) {
if (resURI.equals(subject)) {
GraphType gt = getGraphType(statement.getObject());
if (gt != null) {
graphType = gt;
} else {
ResourceType rt = getResourceType(statement.getObject());
if (rt != null) {
repType = rt;
}
}
} else if (entryURI.equals(subject)) {
EntryType lt = getEntryType(statement.getObject());
if (lt != null) {
locType = lt;
}
}
}
}
} catch (RepositoryException e) {
log.error(e.getMessage());
throw e;
} finally {
rc.close();
}
// We set all values at once to avoid any delays and possible
// inconsistencies that could occur when setting in the loop above
this.administerPrincipals = administerPrincipals;
this.readMetadataPrincipals = readMetadataPrincipals;
this.writeMetadataPrincipals = writeMetadataPrincipals;
this.readResourcePrincipals = readResourcePrincipals;
this.writeResourcePrincipals = writeResourcePrincipals;
this.contributors = contributors;
this.entryURI = entryURI;
this.resURI = resURI;
this.localMdURI = localMdURI;
this.cachedExternalMdURI = cachedExternalMdURI;
this.relationURI = relationURI;
this.created = created;
this.creator = creator;
this.modified = modified;
this.externalMdURI = externalMdURI;
this.cachedAt = cachedAt;
this.locType = locType;
this.repType = repType;
this.graphType = graphType;
this.format = format;
this.fileSize = fileSize;
this.filename = filename;
this.invRelations = invRelations;
return true;
}
private ResourceType getResourceType(Value rt) {
if (rt.equals(RepositoryProperties.NamedResource)) {
return ResourceType.NamedResource;
} else if (rt.equals(RepositoryProperties.ResolvableInformationResource)) {
return ResourceType.ResolvableInformationResource;
} else if (rt.equals(RepositoryProperties.Unknown)) {
return ResourceType.Unknown;
} else if (rt.equals(RepositoryProperties.InformationResource)) { //Default, unneccessary expression.
return ResourceType.InformationResource;
}
return null;
}
private GraphType getGraphType(Value bt) {
if (bt.equals(RepositoryProperties.Context)) {
return GraphType.Context;
} else if (bt.equals(RepositoryProperties.SystemContext)) {
return GraphType.SystemContext;
} else if (bt.equals(RepositoryProperties.List)) {
return GraphType.List;
} else if (bt.equals(RepositoryProperties.ResultList)) {
return GraphType.ResultList;
} else if (bt.equals(RepositoryProperties.User)) {
return GraphType.User;
} else if (bt.equals(RepositoryProperties.Group)) {
return GraphType.Group;
} else if (bt.equals(RepositoryProperties.Pipeline)) {
return GraphType.Pipeline;
} else if (bt.equals(RepositoryProperties.PipelineResult)) {
return GraphType.PipelineResult;
} else if (bt.equals(RepositoryProperties.String)) {
return GraphType.String;
} else if (bt.equals(RepositoryProperties.Graph)) {
return GraphType.Graph;
} else if (bt.equals(RepositoryProperties.None)) {
return GraphType.None;
}
return null;
}
private EntryType getEntryType(Value rt) {
if (rt.equals(RepositoryProperties.Reference)) {
return EntryType.Reference;
} else if (rt.equals(RepositoryProperties.Link)) {
return EntryType.Link;
} else if (rt.equals(RepositoryProperties.LinkReference)) {
return EntryType.LinkReference;
} else if (rt.equals(RepositoryProperties.Local)) {
return EntryType.Local;
}
return null;
}
public URI getEntryURI() {
return URI.create(entryURI.toString());
}
public IRI getSesameEntryURI() {
return entryURI;
}
public IRI getSesameResourceURI() {
return resURI;
}
public URI getResourceURI() {
return URI.create(resURI.stringValue());
}
public URI getLocalMetadataURI() {
if (localMdURI != null) {
return URI.create(getSesameLocalMetadataURI().stringValue());
}
return null;
}
public IRI getSesameLocalMetadataURI() {
return localMdURI;
}
public URI getExternalMetadataURI() {
if (externalMdURI != null) {
return URI.create(externalMdURI.stringValue());
}
return null;
}
public IRI getSesameExternalMetadataURI() {
return externalMdURI;
}
public URI getCachedExternalMetadataURI() {
if (cachedExternalMdURI != null) {
return URI.create(cachedExternalMdURI.stringValue());
}
return null;
}
public IRI getSesameCachedExternalMetadataURI() {
return cachedExternalMdURI;
}
public Date getExternalMetadataCacheDate() {
if(cachedExternalMdURI == null) {
return null;
}
return cachedAt != null ? cachedAt.toGregorianCalendar().getTime() : null;
}
public URI getCreator() {
if (this.creator != null) {
return URI.create(this.creator.stringValue());
}
return null;
}
public void setCreator(URI userURI) {
if (userURI == null) {
throw new IllegalArgumentException("User URI must not be null");
}
checkAdministerRights();
try {
synchronized (this.repository) {
RepositoryConnection rc = this.repository.getConnection();
rc.begin();
try {
IRI creatorURI = rc.getValueFactory().createIRI(userURI.toString());
rc.remove(rc.getStatements(entryURI, RepositoryProperties.Creator, null, false, entryURI), entryURI);
rc.add(entryURI, RepositoryProperties.Creator, creatorURI, entryURI);
registerEntryModified(rc, this.repository.getValueFactory());
rc.commit();
this.creator = creatorURI;
} catch (Exception e) {
rc.rollback();
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Error in repository connection", e);
} finally {
rc.close();
}
}
} catch (RepositoryException e) {
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Failed to connect to repository", e);
}
}
public Set<URI> getContributors() {
Set<URI> result = new HashSet<URI>();
for (IRI contribURI : this.contributors) {
result.add(URI.create(contribURI.stringValue()));
}
return result;
}
public Date getCreationDate() {
return created != null ? created.toGregorianCalendar().getTime() : null;
}
public Date getModifiedDate() {
return modified != null ? modified.toGregorianCalendar().getTime() : null;
}
public ResourceType getResourceType() {
return repType;
}
public EntryType getEntryType() {
return locType;
}
public Model getGraph() {
//ACL check not necessary as the prerequisite for accessing the MetaMetadata object at all is
//AccessProperty.readMetadata rights. It is supposed that the object is not delegated
//to principals with less rights.
RepositoryConnection rc = null;
try {
rc = this.repository.getConnection();
Model graph = Iterations.addAll(rc.getStatements(null, null, null, false, entryURI), new LinkedHashModel());
//TODO following is a fix for backwards compatability where homeContext is set on user object rather than in the entryinfo.
if (this.resource instanceof User && ((User) this.resource).getHomeContext() != null) {
Context context = ((User) this.resource).getHomeContext();
graph.add(this.getSesameResourceURI(), RepositoryProperties.homeContext, ((ContextImpl) context).getSesameURI());
}
//End of fix.
return graph;
} catch (RepositoryException e) {
log.error(e.getMessage(), e);
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
} finally {
try {
rc.close();
} catch (RepositoryException e) {
log.error(e.getMessage());
}
}
}
public Set<URI> getReferringListsInSameContext() {
HashSet<URI> set = new HashSet<URI>();
List<Statement> relations = getRelations();
for (Statement statement : relations) {
if (statement.getPredicate().equals(RepositoryProperties.hasListMember) ||
statement.getPredicate().equals(RepositoryProperties.hasGroupMember)) {
set.add(URI.create(statement.getSubject().toString()));
}
}
return set;
}
protected void addReferringList(ResourceImpl resource, RepositoryConnection rc) throws RepositoryException {
synchronized (this.repository) {
// rc.add(entryURI, RepositoryProperties.referredIn, listResource, entryURI);
// referredIn.add(URI.create(listResource.stringValue()));
ValueFactory vf = this.repository.getValueFactory();
this.addRelationSynchronized(vf.createStatement(resource.resourceURI,
resource instanceof Group ? RepositoryProperties.hasGroupMember : RepositoryProperties.hasListMember, this.getSesameEntryURI()), rc, vf);
}
}
protected void removeReferringList(ResourceImpl resource, RepositoryConnection rc) throws RepositoryException {
synchronized (this.repository) {
// rc.remove(entryURI, RepositoryProperties.referredIn, listResource, entryURI);
// referredIn.remove(URI.create(listResource.stringValue()));
ValueFactory vf = this.repository.getValueFactory();
this.removeRelationSynchronized(vf.createStatement(resource.resourceURI,
resource instanceof Group ? RepositoryProperties.hasGroupMember : RepositoryProperties.hasListMember, this.getSesameEntryURI()), rc, vf);
}
}
public void setEntryType(EntryType entryType) {
checkAdministerRights();
EntryType oldLT = locType;
try {
synchronized (this.repository) {
RepositoryConnection rc = this.repository.getConnection();
rc.setAutoCommit(false);
try {
// we add an MD triple of we convert from Reference to LinkReference
if (EntryType.Reference.equals(locType) && EntryType.LinkReference.equals(entryType)) {
rc.add(entryURI, RepositoryProperties.metadata, this.localMdURI, entryURI);
}
setLocationType(entryType, rc); // this also sets locType, therefore the assignment in the catch clause
registerEntryModified(rc, this.repository.getValueFactory());
rc.commit();
} catch (Exception e) {
rc.rollback();
locType = oldLT;
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
}
} catch (RepositoryException e) {
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
public void setResourceURI(URI resourceURI) {
if (resourceURI.toString().equals(this.resURI.toString())) {
return;
}
checkAdministerRights();
ValueFactory vf = getRepositoryManager().getValueFactory();
IRI oldResourceURI = vf.createIRI(getResourceURI().toString());
IRI newResourceURI = vf.createIRI(resourceURI.toString());
// update entry graph
// Graph entryGraph = getGraph();
// Graph newEntryGraph = new GraphImpl();
// for (Statement statement : entryGraph) {
// if (statement.getSubject().equals(oldResourceURI)) {
// // replace subject URI
// newEntryGraph.add(newResourceURI, statement.getPredicate(), statement.getObject());
// } else if (statement.getObject().equals(oldResourceURI)) {
// // replace object URI
// newEntryGraph.add(statement.getSubject(), statement.getPredicate(), newResourceURI);
// } else {
// // leave everything else untouched
// newEntryGraph.add(statement);
// }
// }
Model entryGraph = getGraph();
Model newEntryGraph = new LinkedHashModel();
for (Statement stmnt : entryGraph) {
if (RepositoryProperties.resource.equals(stmnt.getPredicate())) {
newEntryGraph.add(stmnt.getSubject(), stmnt.getPredicate(), newResourceURI);
} else {
newEntryGraph.add(stmnt);
}
}
// update metadata graph
Model newMetadataGraph = null;
if (getLocalMetadata() != null) {
Model metadataGraph = getLocalMetadata().getGraph();
if (metadataGraph != null && metadataGraph.size() != 0) {
newMetadataGraph = new LinkedHashModel();
for (Statement statement : metadataGraph) {
if (statement.getSubject().equals(oldResourceURI)) {
// replace subject URI
newMetadataGraph.add(newResourceURI, statement.getPredicate(), statement.getObject());
} else {
// leave everything else untouched
newMetadataGraph.add(statement);
}
}
}
}
// update cached external metadata graph
Model newCachedExternalMetadataGraph = null;
if (getCachedExternalMetadata() != null) {
Model metadataGraph = getCachedExternalMetadata().getGraph();
if (metadataGraph != null && metadataGraph.size() != 0) {
newCachedExternalMetadataGraph = new LinkedHashModel();
for (Statement statement : metadataGraph) {
if (statement.getSubject().equals(oldResourceURI)) {
// replace subject URI
newCachedExternalMetadataGraph.add(newResourceURI, statement.getPredicate(), statement.getObject());
} else {
// leave everything else untouched
newCachedExternalMetadataGraph.add(statement);
}
}
}
}
// update resource graph if resource is builtin
Model newResourceGraph = null;
if (!getGraphType().equals(GraphType.None)) {
Model resourceGraph = getResource().getEntry().getGraph();
if (resourceGraph != null && resourceGraph.size() != 0) {
newResourceGraph = new LinkedHashModel();
for (Statement statement : resourceGraph) {
if (statement.getSubject().equals(oldResourceURI)) {
// replace subject URI
newResourceGraph.add(newResourceURI, statement.getPredicate(), statement.getObject());
} else {
// leave everything else untouched
newResourceGraph.add(statement);
}
}
}
}
// update all graphs
setGraphRaw(newEntryGraph);
if (newMetadataGraph != null) {
getLocalMetadata().setGraph(newMetadataGraph);
}
if (newCachedExternalMetadataGraph != null) {
getCachedExternalMetadata().setGraph(newCachedExternalMetadataGraph);
}
if (newResourceGraph != null) {
getResource().getEntry().setGraph(newResourceGraph);
}
// update index of context with new triple
try {
synchronized (this.repository) {
RepositoryConnection rc = this.repository.getConnection();
try {
rc.setAutoCommit(false);
IRI contextURI = vf.createIRI(this.getContext().getEntry().getResourceURI().toString());
IRI entryURI = vf.createIRI(this.getEntryURI().toString());
rc.remove(vf.createStatement(oldResourceURI, RepositoryProperties.resHasEntry, entryURI, contextURI));
rc.add(vf.createStatement(newResourceURI, RepositoryProperties.resHasEntry, entryURI, contextURI));
rc.commit();
} catch (RepositoryException e) {
rc.rollback();
log.error(e.getMessage(), e);
} finally {
if (rc != null) {
rc.close();
}
}
}
} catch (RepositoryException re) {
log.error(re.getMessage(), re);
}
// update local variable with new URI
this.resURI = newResourceURI;
// update index
this.context.updateResource2EntryIndex(
URI.create(oldResourceURI.stringValue()),
URI.create(this.resURI.stringValue()),
URI.create(this.entryURI.stringValue())
);
}
public void setExternalMetadataURI(URI externalMetadataURI) {
if (this.externalMdURI != null && externalMetadataURI.toString().equals(this.externalMdURI.toString())) {
return;
}
checkAdministerRights();
ValueFactory vf = getRepositoryManager().getValueFactory();
IRI oldExternalMetadataURI = vf.createIRI(getExternalMetadataURI().toString());
IRI newExternalMetadataURI = vf.createIRI(externalMetadataURI.toString());
// update entry graph
Model entryGraph = getGraph();
Model newEntryGraph = new LinkedHashModel();
for (Statement statement : entryGraph) {
if (statement.getSubject().equals(oldExternalMetadataURI)) {
// we don't want to take the cached date into the new graph,
// so we don't to anything here
} else if (statement.getObject().equals(oldExternalMetadataURI)) {
// replace object URI
newEntryGraph.add(statement.getSubject(), statement.getPredicate(), newExternalMetadataURI);
} else {
// leave everything else untouched
newEntryGraph.add(statement);
}
}
// set entry graph
setGraphRaw(newEntryGraph);
// update index of context with new triple
try {
synchronized (this.repository) {
RepositoryConnection rc = this.repository.getConnection();
try {
rc.setAutoCommit(false);
IRI contextURI = vf.createIRI(this.getContext().getEntry().getResourceURI().toString());
IRI entryURI = vf.createIRI(this.getEntryURI().toString());
rc.remove(vf.createStatement(oldExternalMetadataURI, RepositoryProperties.mdHasEntry, entryURI, contextURI));
rc.add(vf.createStatement(newExternalMetadataURI, RepositoryProperties.mdHasEntry, entryURI, contextURI));
rc.commit();
} catch (RepositoryException e) {
rc.rollback();
log.error(e.getMessage(), e);
} finally {
if (rc != null) {
rc.close();
}
}
}
} catch (RepositoryException re) {
log.error(re.getMessage(), re);
}
// update local variable with new URI
this.externalMdURI = newExternalMetadataURI;
// update index
this.context.updateExternalMetadata2EntryIndex(
URI.create(oldExternalMetadataURI.stringValue()),
URI.create(this.externalMdURI.stringValue()),
URI.create(this.entryURI.stringValue())
);
}
/**
* Sets a location to the entry. If the the entryType is Local no location is set.
* @param entryType
* @param rc
* @throws RepositoryException
* @throws DatatypeConfigurationException
*/
protected void setLocationType(EntryType entryType, RepositoryConnection rc) throws RepositoryException, DatatypeConfigurationException {
rc.remove(rc.getStatements(entryURI, RDF.TYPE, null,false, entryURI), entryURI);
switch (entryType) {
case Reference:
rc.add(entryURI, RDF.TYPE, RepositoryProperties.Reference, entryURI);
break;
case LinkReference:
rc.add(entryURI, RDF.TYPE, RepositoryProperties.LinkReference, entryURI);
break;
case Link:
rc.add(entryURI, RDF.TYPE, RepositoryProperties.Link, entryURI);
break;
}
locType = entryType;
}
private Set<URI> getCachedAllowedPrincipalsFor(AccessProperty prop) {
switch (prop) {
case Administer:
return administerPrincipals;
case ReadMetadata:
return readMetadataPrincipals;
case WriteMetadata:
return writeMetadataPrincipals;
case ReadResource:
return readResourcePrincipals;
case WriteResource:
return writeResourcePrincipals;
}
return null;
}
private void setCachedAllowedPrincipalsFor(AccessProperty prop, Set<URI> set) {
switch (prop) {
case Administer:
administerPrincipals = set;
break;
case ReadMetadata:
readMetadataPrincipals = set;
break;
case WriteMetadata:
writeMetadataPrincipals = set;
break;
case ReadResource:
readResourcePrincipals = set;
break;
case WriteResource:
writeResourcePrincipals = set;
break;
}
}
public Set<URI> getAllowedPrincipalsFor(AccessProperty prop) {
// No access check since everyone, even guest should have access to read entry information.
Set<URI> set = getCachedAllowedPrincipalsFor(prop);
if (set != null) {
return set;
}
RepositoryConnection rc = null;
try {
rc = this.repository.getConnection();
IRI subject = getAccessSubject(prop);
IRI predicate = getAccessPredicate(prop);
List<Statement> statements = rc.getStatements(subject, predicate, null, false, entryURI).asList();
set = new HashSet<URI>();
for (Statement statement : statements) {
if (statement.getObject() instanceof IRI) {
set.add(URI.create(((IRI) statement.getObject()).stringValue()));
}
}
setCachedAllowedPrincipalsFor(prop, set);
return set;
} catch (RepositoryException e) {
e.printStackTrace();
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
} finally {
try {
rc.close();
} catch (RepositoryException e) {
e.printStackTrace();
}
}
}
public void setAllowedPrincipalsFor(AccessProperty prop, Set<URI> principals) {
checkAdministerRights();
updateAllowedPrincipalsFor(prop, principals, true, false);
}
public void addAllowedPrincipalsFor(AccessProperty prop, URI principal) {
checkAdministerRights();
HashSet<URI> principals = new HashSet<URI>();
principals.add(principal);
updateAllowedPrincipalsFor(prop, principals, false, true);
}
public boolean removeAllowedPrincipalsFor(AccessProperty prop, URI principal) {
checkAdministerRights();
HashSet<URI> principals = new HashSet<URI>();
principals.add(principal);
return updateAllowedPrincipalsFor(prop, principals, false, false);
}
public boolean updateAllowedPrincipalsFor(AccessProperty prop, Set<URI> principals, boolean replace, boolean append) {
this.readOrWrite = null;
try {
synchronized (this.repository) {
RepositoryConnection rc = this.repository.getConnection();
rc.setAutoCommit(false);
try {
IRI subject = getAccessSubject(prop);
IRI predicate = getAccessPredicate(prop);
if (replace) {
rc.remove(subject, predicate, null, entryURI);
}
for (URI principal : principals) {
IRI principalURI = this.repository.getValueFactory().createIRI(principal.toString());
if (replace || append) {
rc.add(subject, predicate, principalURI, entryURI);
} else {
rc.remove(subject, predicate, principalURI, entryURI);
}
}
rc.commit();
if (replace) {
setCachedAllowedPrincipalsFor(prop, principals);
} else {
setCachedAllowedPrincipalsFor(prop, null);
}
} catch (Exception e) {
rc.rollback();
e.printStackTrace();
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
}
} catch (RepositoryException e) {
log.error(e.getMessage(), e);
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
return false;
}
public boolean hasAllowedPrincipals() {
if (this.readOrWrite == null) {
try {
RepositoryConnection rc = this.repository.getConnection();
try {
if (rc.hasStatement(null, RepositoryProperties.Write, null, false, entryURI) ||
rc.hasStatement(null, RepositoryProperties.Read, null, false, entryURI)) {
this.readOrWrite = Boolean.TRUE;
} else {
this.readOrWrite = Boolean.FALSE;
}
} finally {
rc.close();
}
} catch (RepositoryException e) {
log.error(e.getMessage());
}
}
return this.readOrWrite;
}
private IRI getAccessSubject(AccessProperty prop) {
return switch (prop) {
case Administer -> entryURI;
case ReadMetadata, WriteMetadata -> localMdURI;
case ReadResource, WriteResource -> resURI;
};
}
private IRI getAccessPredicate(AccessProperty prop) {
return switch (prop) {
case Administer, WriteMetadata, WriteResource -> RepositoryProperties.Write;
case ReadResource, ReadMetadata -> RepositoryProperties.Read;
};
}
public void setGraphType(GraphType gt) {
checkAdministerRights();
if (this.graphType != gt && this.locType == EntryType.Local) {
throw new org.entrystore.repository.RepositoryException("Cannot change the graph type of a local resource");
}
try {
synchronized (this.repository) {
RepositoryConnection rc = this.repository.getConnection();
rc.setAutoCommit(false);
try {
setGraphType(gt, rc);
registerEntryModified(rc, this.repository.getValueFactory());
rc.commit();
} catch (Exception e) {
rc.rollback();
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
}
} catch (RepositoryException e) {
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
/**
* If this method is called successfully (no Exception thrown), and for some reason
* the transaction is rolled back, than the cached built-in type will be wrong,
* call {@link #refreshFromRepository(RepositoryConnection)} to correct this.
*
* @param gt the new {@link org.entrystore.GraphType}
* @param rc a RepositoryConnection
* @throws RepositoryException
* @throws DatatypeConfigurationException
*/
protected void setGraphType(GraphType gt, RepositoryConnection rc) throws RepositoryException, DatatypeConfigurationException {
List<Statement> statements = rc.getStatements(resURI, RDF.TYPE, null, false, entryURI).asList();
for (Statement statement : statements) {
if (getGraphType(statement.getObject()) != null) {
rc.remove(statement, entryURI);
}
}
switch (gt) {
case Context -> rc.add(resURI, RDF.TYPE, RepositoryProperties.Context, entryURI);
case SystemContext -> rc.add(resURI, RDF.TYPE, RepositoryProperties.SystemContext, entryURI);
case List -> rc.add(resURI, RDF.TYPE, RepositoryProperties.List, entryURI);
case ResultList -> rc.add(resURI, RDF.TYPE, RepositoryProperties.ResultList, entryURI);
case User -> rc.add(resURI, RDF.TYPE, RepositoryProperties.User, entryURI);
case Group -> rc.add(resURI, RDF.TYPE, RepositoryProperties.Group, entryURI);
case Pipeline -> rc.add(resURI, RDF.TYPE, RepositoryProperties.Pipeline, entryURI);
case PipelineResult -> rc.add(resURI, RDF.TYPE, RepositoryProperties.PipelineResult, entryURI);
case String -> rc.add(resURI, RDF.TYPE, RepositoryProperties.String, entryURI);
case Graph -> rc.add(resURI, RDF.TYPE, RepositoryProperties.Graph, entryURI);
}
graphType = gt;
}
public void setResourceType(ResourceType resType) {
checkAdministerRights();
if (this.repType != resType && this.locType == EntryType.Local && (this.graphType != GraphType.None && this.graphType != GraphType.Pipeline && this.graphType != GraphType.PipelineResult)) {
throw new org.entrystore.repository.RepositoryException("Cannot change the resource type of a local and/or built-in resource");
}
try {
synchronized (this.repository) {
RepositoryConnection rc = this.repository.getConnection();
rc.setAutoCommit(false);
try {
setResourceType(resType, rc);
registerEntryModified(rc, this.repository.getValueFactory());
rc.commit();
} catch (Exception e) {
rc.rollback();
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
}
} catch (RepositoryException e) {
log.error(e.getMessage(), e);
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository", e);
}
}
protected void setResourceType(ResourceType resType, RepositoryConnection rc) throws RepositoryException, DatatypeConfigurationException {
List<Statement> statements = rc.getStatements(resURI, RDF.TYPE, null, false, entryURI).asList();
for (Statement statement : statements) {
if (getResourceType(statement.getObject()) != null) {
rc.remove(statement, entryURI);
}
}
switch (resType) {
case ResolvableInformationResource ->
rc.add(resURI, RDF.TYPE, RepositoryProperties.ResolvableInformationResource, entryURI);
case Unknown -> rc.add(resURI, RDF.TYPE, RepositoryProperties.Unknown, entryURI);
case NamedResource -> rc.add(resURI, RDF.TYPE, RepositoryProperties.NamedResource, entryURI);
}
repType = resType;
}
protected void updateModifiedDateSynchronized(RepositoryConnection rc, ValueFactory vf) throws RepositoryException {
synchronized (this.repository) {
registerEntryModified(rc, vf);
}
}
protected void registerEntryModified(RepositoryConnection rc, ValueFactory vf) throws RepositoryException {
try {
modified = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
} catch (DatatypeConfigurationException e) {
log.error(e.getMessage());
}
rc.remove(rc.getStatements(entryURI, RepositoryProperties.Modified, null, false, entryURI), entryURI);
rc.add(entryURI, RepositoryProperties.Modified, vf.createLiteral(modified), entryURI);
//Also adding the one who update using dcterms:contributor
if (this.repositoryManager != null &&
this.repositoryManager.getPrincipalManager() != null &&
this.repositoryManager.getPrincipalManager().getAuthenticatedUserURI() != null) {
URI contrib = this.repositoryManager.getPrincipalManager().getAuthenticatedUserURI();
String contributor = contrib.toString();
IRI contributorURI = vf.createIRI(contributor);
//Do not add if the contributor is the same as the creator
if (contrib != null && !contrib.equals(this.getCreator()) && contributors != null && !contributors.contains(contributorURI)) {
rc.add(this.entryURI,RepositoryProperties.Contributor,contributorURI, this.entryURI);
contributors.add(contributorURI);
}
}
}
public void updateModificationDate() {
try (RepositoryConnection rc = repository.getConnection()) {
this.updateModifiedDateSynchronized(rc, getRepositoryManager().getValueFactory());
}
}
public void updateCachedExternalMetadataDateSynchronized(RepositoryConnection rc, ValueFactory vf) throws RepositoryException, DatatypeConfigurationException {
synchronized (this.repository) {
if (this.getEntryType() == EntryType.Reference || this.getEntryType() == EntryType.LinkReference) {
cachedAt = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
rc.remove(rc.getStatements(cachedExternalMdURI, RepositoryProperties.cached, null, false, entryURI), entryURI);
// TODO: maybe entryUri as context last parameter..
rc.add(cachedExternalMdURI, RepositoryProperties.cached, vf.createLiteral(cachedAt), entryURI);
}
registerEntryModified(rc, vf);
}
}
/**
* WARNING, do not use unless you are very certain that you know what you are doing.
* Replaces the entryinformation without questions asked.
* The new graph should not change anything that affects inverse-relation-cache on other entries, if so, use setGraph instead.
*
* @param metametadata
*/
protected void setGraphRaw(Model metametadata) {
checkAdministerRights();
try {
synchronized (this.repository) {
RepositoryConnection rc = this.repository.getConnection();
ValueFactory vf = this.repository.getValueFactory();
rc.begin();
try {
rc.clear(entryURI);
rc.add(metametadata, entryURI);
registerEntryModified(rc, vf);
rc.commit();
// we reload the internal cache
loadFromStatements(rc.getStatements(null, null, null, false, entryURI).asList());
initMetadataObjects();
getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(this, RepositoryEvent.EntryUpdated));
} catch (Exception e) {
rc.rollback();
// Reset to previous saved values, just in case we saved the types above halfway through.
loadFromStatements(rc.getStatements(null, null, null, false, entryURI).asList());
rc.close();
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
}
} catch (RepositoryException e) {
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
public void setGraph(Model metametadata) {
checkAdministerRights();
Model oldGraph = getGraph();
Iterator<Statement> resourceURIStmnts = metametadata.filter(this.entryURI, RepositoryProperties.resource, null).iterator();
if (resourceURIStmnts.hasNext()) {
Value newResourceURI = resourceURIStmnts.next().getObject();
if (newResourceURI instanceof IRI) {
setResourceURI(URI.create(newResourceURI.toString()));
}
}
Iterator<Statement> externalMdURIStmnts = metametadata.filter(this.entryURI, RepositoryProperties.externalMetadata, null).iterator();
if (externalMdURIStmnts.hasNext()) {
Value newResourceURI = externalMdURIStmnts.next().getObject();
if (newResourceURI instanceof IRI) {
setExternalMetadataURI(URI.create(newResourceURI.toString()));
}
}
String originalList = this.getOriginalList();
try {
synchronized (this.repository) {
ValueFactory vf = this.repository.getValueFactory();
RepositoryConnection rc = this.repository.getConnection();
rc.begin();
Model minimalProvenanceGraph = null;
if (this.provenance != null) {
minimalProvenanceGraph = this.provenance.getMinimalGraph(rc);
}
try {
removeInverseRelations(rc);
rc.clear(entryURI);
for (Statement statement : metametadata) {
IRI predicate = statement.getPredicate();
if (predicate.stringValue().startsWith(RepositoryProperties.NSbase)) {
//Ignore basic structure subgraph, will be added below.
if (!(predicate.equals(RepositoryProperties.resource)
|| predicate.equals(RepositoryProperties.metadata)
|| predicate.equals(RepositoryProperties.externalMetadata)
|| predicate.equals(RepositoryProperties.cachedExternalMetadata)
|| predicate.equals(RepositoryProperties.cached)
|| predicate.equals(RepositoryProperties.relation)
//|| predicate.equals(RepositoryProperties.referredIn)
)) {
rc.add(statement, entryURI);
}
} else if (this.entryURI.equals(statement.getSubject())
&& (predicate.equals(RepositoryProperties.Created)
|| predicate.equals(RepositoryProperties.Modified)
|| predicate.equals(RepositoryProperties.Creator)
|| predicate.equals(RepositoryProperties.Contributor))) {
//In basic structure below.
} else if (predicate.equals(RDF.TYPE)) {
if (this.entryURI.equals(statement.getSubject())) {
EntryType lt = getEntryType(statement.getObject());
if (lt != null && locType == EntryType.Reference && lt == EntryType.LinkReference) { //Only allowed to change from Reference to LinkReference
locType = lt;
localMdURI = vf.createIRI(URISplit.createURI(repositoryManager.getRepositoryURL().toString(), context.id, RepositoryProperties.MD_PATH, this.id).toString());
}
} else {
GraphType gt = getGraphType(statement.getObject());
if (gt != null) {
if (locType != EntryType.Local) { //Only allowed to change builtintype for non local resources.
this.graphType = gt;
}
} else {
ResourceType rt = getResourceType(statement.getObject());
if (rt != null) {
if (locType != EntryType.Local) { //Only allowed to change representationtype for non local resources.
repType = rt;
}
} else { //Some other rdf:type, just add it.
rc.add(statement, entryURI);
}
}
}
} else if (this.provenance != null
&& this.provenance.hasProvenanceCharacter(statement)) {
//Filter out provenance as it will be added back in a controlled manner below
} else {
rc.add(statement, entryURI);
}
}
//----------Start basic structure:
//Since we cleared the previous graph, we set the types again, they might have been updated in the loop above.
setLocationType(this.locType, rc);
setGraphType(this.graphType, rc);
setResourceType(this.repType, rc);
rc.add(entryURI, RepositoryProperties.resource, getSesameResourceURI(), entryURI);
rc.add(entryURI, RepositoryProperties.relation, getSesameRelationURI(), entryURI);
if (localMdURI != null) {
rc.add(entryURI, RepositoryProperties.metadata, localMdURI, entryURI);
}
if (externalMdURI != null) {
rc.add(entryURI, RepositoryProperties.externalMetadata, externalMdURI, entryURI);
}
if (cachedExternalMdURI != null) {
rc.add(entryURI, RepositoryProperties.cachedExternalMetadata, cachedExternalMdURI, entryURI);
if (cachedAt != null) {
rc.add(cachedExternalMdURI, RepositoryProperties.cached, vf.createLiteral(cachedAt), entryURI);
}
}
/* for (URI refIn : this.referredIn) { //Adds the referredIn relations to the graph.
rc.add(entryURI, RepositoryProperties.referredIn, vf.createIRI(refIn.toString()), entryURI);
}*/
if (created != null) {
rc.add(entryURI, RepositoryProperties.Created, vf.createLiteral(created), entryURI);
}
if (creator != null) {
rc.add(entryURI, RepositoryProperties.Creator, creator, entryURI);
}
if (contributors != null && contributors.size()>0){
for (Iterator<IRI> iter = contributors.iterator(); iter.hasNext();) {
IRI contrib = iter.next();
rc.add(entryURI, RepositoryProperties.Contributor, contrib, entryURI);
}
}
if (originalList !=null) {
rc.add(entryURI, RepositoryProperties.originallyCreatedIn, vf.createIRI(originalList), entryURI);
}
modified = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
rc.add(entryURI, RepositoryProperties.Modified, vf.createLiteral(modified), entryURI);
if (minimalProvenanceGraph != null) {
rc.add(minimalProvenanceGraph, entryURI);
}
//------------End basic structure
addInverseRelations(rc, metametadata);
rc.commit();
administerPrincipals = null;
readMetadataPrincipals = null;
writeMetadataPrincipals = null;
readResourcePrincipals = null;
writeResourcePrincipals = null;
readOrWrite = null;
format = null;
status = null;
// we reload the internal cache
loadFromStatements(rc.getStatements(null, null, null, false, entryURI).asList());
initMetadataObjects();
getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(this, RepositoryEvent.EntryUpdated));
if (GraphType.Context.equals(this.getGraphType())) {
if (hasAclChangedForGuest(oldGraph, metametadata)) {
getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(this, RepositoryEvent.EntryAclGuestUpdated, metametadata));
}
if (hasProjectTypeChanged(oldGraph, metametadata)) {
getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(this, RepositoryEvent.EntryProjectTypeUpdated, metametadata));
}
}
} catch (Exception e) {
rc.rollback();
// Reset to previous saved values, just in case we saved the types above halfway through.
loadFromStatements(rc.getStatements(null, null, null, false, entryURI).asList());
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
}
} catch (RepositoryException e) {
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
private boolean hasAclChangedForGuest(Model oldGraph, Model newGraph) {
if (oldGraph == null || newGraph == null) {
throw new IllegalArgumentException("Parameters must not be null");
}
Model oldModel = new LinkedHashModel(oldGraph);
Model newModel = new LinkedHashModel(newGraph);
IRI guestURI = getRepositoryManager().getValueFactory().createIRI(getRepositoryManager().getPrincipalManager().getGuestUser().getURI().toString());
Model oldAcl = new LinkedHashModel();
oldAcl.addAll(oldModel.filter(null, RepositoryProperties.Read, guestURI));
oldAcl.addAll(oldModel.filter(null, RepositoryProperties.Write, guestURI));
Model newAcl = new LinkedHashModel();
newAcl.addAll(newModel.filter(null, RepositoryProperties.Read, guestURI));
newAcl.addAll(newModel.filter(null, RepositoryProperties.Write, guestURI));
return !Models.isomorphic(oldAcl, newAcl);
}
private boolean hasProjectTypeChanged(Model oldGraph, Model newGraph) {
if (oldGraph == null || newGraph == null) {
throw new IllegalArgumentException("Parameters must not be null");
}
IRI projectTypeProperty = iri("http://entryscape.com/terms/projectType");
return !Models.isomorphic(oldGraph.filter(null, projectTypeProperty, null), newGraph.filter(null, projectTypeProperty, null));
}
private boolean isStatementInvRelationCandidate(Statement statement, String base) {
IRI predicate = statement.getPredicate();
if (!predicate.equals(RepositoryProperties.resource)
&& !predicate.equals(RepositoryProperties.metadata)
&& !predicate.equals(RepositoryProperties.externalMetadata)
&& !predicate.equals(RepositoryProperties.cachedExternalMetadata)
&& !predicate.equals(RepositoryProperties.relation)
&& !predicate.equals(RepositoryProperties.cached)
&& !predicate.equals(RepositoryProperties.Creator)
&& !predicate.equals(RepositoryProperties.Contributor)
&& !predicate.equals(RepositoryProperties.Read)
&& !predicate.equals(RepositoryProperties.Write)
// && !predicate.equals(RepositoryProperties.Pipeline)
&& !predicate.equals(RepositoryProperties.originallyCreatedIn)) {
Value obj = statement.getObject();
org.eclipse.rdf4j.model.Resource subj = statement.getSubject();
//Check for relations between this resource and another entry (resourceURI (has to be a repository resource), metadataURI, or entryURI)
if (obj instanceof IRI
&& obj.stringValue().startsWith(base)
&& subj.stringValue().startsWith(base)) {
return true;
}
}
return false;
}
private void removeInverseRelations(RepositoryConnection rc) throws RepositoryException {
if (invRelations) {
RepositoryResult<Statement> rr = rc.getStatements(null, null, null, false, entryURI);
String base = repositoryManager.getRepositoryURL().toString();
while (rr.hasNext()) {
Statement statement = rr.next();
if (isStatementInvRelationCandidate(statement, base)) {
URI entryURI = URI.create(statement.getObject().stringValue());
EntryImpl sourceEntry = (EntryImpl) repositoryManager.getContextManager().getEntry(entryURI);
if (sourceEntry != null && sourceEntry != this) {
sourceEntry.removeRelationSynchronized(statement, rc, repository.getValueFactory());
}
}
}
rr.close();
invRelations = false;
}
}
private void addInverseRelations(RepositoryConnection rc, Model graph) {
String base = repositoryManager.getRepositoryURL().toString();
for (Statement statement : graph) {
if (isStatementInvRelationCandidate(statement, base)) {
URI entryURI = URI.create(statement.getObject().stringValue());
EntryImpl sourceEntry = (EntryImpl) repositoryManager.getContextManager().getEntry(entryURI);
if (sourceEntry != null && sourceEntry != this) {
sourceEntry.addRelationSynchronized(statement, rc, repository.getValueFactory());
}
}
}
}
private void checkAdministerRights() {
PrincipalManager pm = this.getRepositoryManager().getPrincipalManager();
pm.checkAuthenticatedUserAuthorized(this, AccessProperty.Administer);
}
public Context getContext() {
return context;
}
public RepositoryManager getRepositoryManager() {
return repositoryManager;
}
@Override
public Provenance getProvenance() {
return this.provenance;
}
public Resource getResource() {
if(resource == null) {
ContextImpl contextImpl = ((ContextImpl)this.getContext());
try {
contextImpl.initResource(this);
} catch (RepositoryException e) {
log.error(e.getMessage());
}
}
return resource;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Entry) {
return getEntryURI().equals(((Entry)obj).getEntryURI());
}
return false;
}
public boolean isExternalMetadataCached() {
return getExternalMetadataCacheDate() != null;
}
public Metadata getLocalMetadata() {
if (localMetadata == null) {
initMetadataObjects();
}
return localMetadata;
}
public Model getMetadataGraph() {
if (getEntryType().equals(EntryType.Local) || getEntryType().equals(EntryType.Link)) {
if (getLocalMetadata() != null && getLocalMetadata().getGraph() != null) {
return getLocalMetadata().getGraph();
}
} else if (getEntryType().equals(EntryType.Reference)) {
if (getCachedExternalMetadata() != null && getCachedExternalMetadata().getGraph() != null) {
return getCachedExternalMetadata().getGraph();
}
} else if (getEntryType().equals(EntryType.LinkReference)) {
Model mergedMd = new LinkedHashModel();
if (getLocalMetadata() != null && getLocalMetadata().getGraph() != null) {
mergedMd.addAll(getLocalMetadata().getGraph());
}
if (getCachedExternalMetadata() != null && getCachedExternalMetadata().getGraph() != null) {
mergedMd.addAll(getCachedExternalMetadata().getGraph());
}
return mergedMd;
}
return new LinkedHashModel();
}
public void remove(RepositoryConnection rc) throws Exception {
// TODO the handling of removal is non-atomic and should be rewritten to take
// failures (i.e. rollbacks of the ongoing transaction) into consideration
deleted = true;
log.debug("Removing entry " + entryURI);
removeInverseRelations(rc);
rc.clear(entryURI);
if (locType == EntryType.Local || locType == EntryType.Link || locType == EntryType.LinkReference) {
localMetadata.removeGraphSynchronized(rc);
}
if (locType == EntryType.LinkReference || locType == EntryType.Reference) {
if (cachedExternalMetadata instanceof MetadataImpl) {
((MetadataImpl) cachedExternalMetadata).removeGraphSynchronized(rc);
} else {
rc.clear(cachedExternalMdURI);
}
}
localMetadata = null;
cachedExternalMetadata = null;
if (resource != null && resource.isRemovable()) {
resource.remove(rc);
resource = null;
}
}
public String getFilename() {
if (this.filename == null) {
Statement st = getStatement(resURI, RepositoryProperties.filename, null);
if (st != null) {
this.filename = st.getObject().stringValue();
}
}
return this.filename;
}
public IRI getSesameRelationURI() {
return this.relationURI;
}
public URI getRelationURI() {
return URI.create(relationURI.toString());
}
public void setFilename(String name) {
PrincipalManager pm = this.getRepositoryManager().getPrincipalManager();
pm.checkAuthenticatedUserAuthorized(this, AccessProperty.WriteResource);
ValueFactory vf = this.repository.getValueFactory();
if (replaceStatement(resURI, RepositoryProperties.filename, vf.createLiteral(name))) {
this.filename = name;
}
}
public long getFileSize() {
if (this.fileSize > 0 ) {
Statement st = getStatement(resURI, RepositoryProperties.fileSize, null);
if (st != null) {
this.fileSize = ((Literal) st.getObject()).longValue();
}
}
return this.fileSize;
}
public void setFileSize(long size) {
PrincipalManager pm = this.getRepositoryManager().getPrincipalManager();
pm.checkAuthenticatedUserAuthorized(this, AccessProperty.WriteResource);
ValueFactory vf = this.repository.getValueFactory();
if (replaceStatement(resURI, RepositoryProperties.fileSize, vf.createLiteral(size))) {
this.fileSize = size;
}
}
public URI getStatus() {
if (this.status == null) {
// the mime type in the local MD overwrites the mime type in the entry graph
Statement st = getStatement(entryURI, RepositoryProperties.status, null);
if (st != null) {
this.status = URI.create(st.getObject().stringValue());
}
}
return this.status;
}
public void setStatus(URI newStatus) {
checkAdministerRights();
ValueFactory vf = this.repository.getValueFactory();
if (replaceStatement(entryURI, RepositoryProperties.status, vf.createIRI(newStatus.toString()))) {
this.status = newStatus;
}
}
public String getMimetype() {
if (this.format == null) {
// the mime type in the local MD overwrites the mime type in the entry graph
String mtMd = getMimetypeFromMetadata();
if (mtMd != null) {
this.format = mtMd;
return this.format;
}
Statement st = getStatement(resURI, RepositoryProperties.format, null);
if (st != null) {
this.format = st.getObject().stringValue();
}
}
return this.format;
}
public void setMimetype(String mt) {
PrincipalManager pm = this.getRepositoryManager().getPrincipalManager();
pm.checkAuthenticatedUserAuthorized(this, AccessProperty.WriteResource);
ValueFactory vf = this.repository.getValueFactory();
if (replaceStatement(resURI, RepositoryProperties.format, vf.createLiteral(mt))) {
this.format = mt;
}
// if the mime-type is set (overwritten) in the metadata, we take that one instead
String mtMd = getMimetypeFromMetadata();
if (mtMd != null) {
this.format = mtMd;
}
}
private String getMimetypeFromMetadata() {
Statement st = getStatementFromLocalMetadata(resURI, RepositoryProperties.format, null);
if (st != null) {
Value obj = st.getObject();
if (obj.isLiteral()) {
return obj.stringValue();
}
}
return null;
}
public boolean replaceStatementSynchronized(IRI subject, IRI predicate, Value object, RepositoryConnection rc, ValueFactory vf) throws RepositoryException {
rc.remove(subject, predicate, null, entryURI);
rc.add(subject, predicate, object, entryURI);
registerEntryModified(rc, vf);
return true;
}
private boolean replaceStatementSynchronized(IRI subject, IRI predicate, Value object) {
try {
RepositoryConnection rc = this.repository.getConnection();
rc.begin();
try {
boolean result = this.replaceStatementSynchronized(subject, predicate, object, rc, this.repository.getValueFactory());
rc.commit();
getRepositoryManager().fireRepositoryEvent(new RepositoryEventObject(this, RepositoryEvent.EntryUpdated));
return result;
} catch (Exception e) {
rc.rollback();
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
} catch (RepositoryException e) {
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
private boolean replaceStatement(IRI subject, IRI predicate, Value object) {
synchronized (this.repository) {
return this.replaceStatementSynchronized(subject, predicate, object);
}
}
public Statement getStatement(IRI subject, IRI predicate, Value object) {
try {
RepositoryConnection rc = this.repository.getConnection();
try {
RepositoryResult<Statement> matches = rc.getStatements(subject, predicate, object, false, entryURI);
if (matches.hasNext()) {
Statement result = matches.next();
matches.close();
return result;
}
if (!matches.isClosed()) {
matches.close();
}
rc.close();
return null;
} catch (org.eclipse.rdf4j.repository.RepositoryException e) {
rc.close();
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
} finally {
rc.close();
}
} catch (RepositoryException e) {
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
public Statement getStatementFromLocalMetadata(IRI subject, IRI predicate, Value object) {
if (localMdURI == null) {
return null;
}
try {
RepositoryConnection rc = this.repository.getConnection();
try {
RepositoryResult<Statement> matches = rc.getStatements(subject, predicate, object, false, localMdURI);
if (matches.hasNext()) {
Statement result = matches.next();
matches.close();
return result;
}
if (!matches.isClosed()) {
matches.close();
}
rc.close();
return null;
} catch (org.eclipse.rdf4j.repository.RepositoryException e) {
rc.close();
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
} finally {
rc.close();
}
} catch (RepositoryException e) {
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
/**
* @return the original list where the entry was created, null if the creator was the owner of
* the current context or has since added it to another list or removed it from all lists.
*/
public String getOriginalList () {
if (this.originalList == null) {
Statement st = this.getStatement(this.entryURI, RepositoryProperties.originallyCreatedIn, null);
if (st != null && st.getObject() instanceof IRI) {
this.originalList = st.getObject().stringValue();
} else {
this.originalList = "";
}
}
if (this.originalList.equals("")) {
return null;
}
return this.originalList;
}
public void setOriginalListSynchronized(String list, RepositoryConnection rc, ValueFactory vf) throws RepositoryException {
rc.remove(this.entryURI, RepositoryProperties.originallyCreatedIn, null, this.entryURI);
if (list != null) {
rc.add(this.entryURI, RepositoryProperties.originallyCreatedIn, vf.createIRI(list), this.entryURI);
this.originalList = list;
} else {
this.originalList = "";
}
}
public void setOriginalListSynchronized(String list) {
try {
RepositoryConnection rc = this.repository.getConnection();
rc.begin();
try {
rc.remove(this.entryURI, RepositoryProperties.originallyCreatedIn, null, this.entryURI);
if (list != null) {
rc.add(this.entryURI, RepositoryProperties.originallyCreatedIn, this.repository.getValueFactory().createIRI(list), this.entryURI);
this.originalList = list;
} else {
this.originalList = "";
}
rc.commit();
} catch (Exception e) {
rc.rollback();
throw new org.entrystore.repository.RepositoryException("Error in repository connection.", e);
} finally {
rc.close();
}
} catch (RepositoryException e) {
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
}
}
public List<Statement> getRelations() {
if (this.relations == null) {
RepositoryConnection rc = null;
try {
rc = this.repository.getConnection();
return Iterations.asList(rc.getStatements(null, null, null, false, this.relationURI));
} catch (RepositoryException e) {
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Failed to connect to Repository.", e);
} finally {
try {
rc.close();
} catch (RepositoryException e) {
log.error(e.getMessage(), e);
}
}
}
return this.relations;
}
protected void addRelationSynchronized(Statement statement, RepositoryConnection rc, ValueFactory vf) {
synchronized (this) {
addRelation(statement, rc, vf);
}
}
private void addRelation(Statement statement, RepositoryConnection rc, ValueFactory vf) {
try {
rc.add(statement, relationURI);
if (this.relations != null) {
this.relations.add(statement);
}
} catch (RepositoryException e) {
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Failed to connect to repository", e);
}
}
protected void removeRelationSynchronized(Statement statement, RepositoryConnection rc, ValueFactory vf) {
synchronized (this) {
removeRelation(statement, rc, vf);
}
}
private void removeRelation(Statement statement, RepositoryConnection rc, ValueFactory vf) {
try {
rc.remove(statement, relationURI);
if (this.relations != null) {
this.relations.remove(statement);
}
} catch (RepositoryException e) {
log.error(e.getMessage());
throw new org.entrystore.repository.RepositoryException("Failed to connect to repository", e);
}
}
@Override
public String toString() {
return entryURI.toString() + "," + super.toString();
}
}