VIVO-925 When creating class or properties, permit URIs that are already in use...

...as long as they aren't already declared as things, classes or properties
This commit is contained in:
Jim Blake 2015-02-25 15:42:07 -05:00
parent 837d2afdad
commit 5c1944f508
8 changed files with 129 additions and 90 deletions

View file

@ -21,12 +21,13 @@ public interface WebappDaoFactory {
public String checkURI(String uriStr); public String checkURI(String uriStr);
/** /**
* Checks a URI String for two things: well-formedness and, optionally, * Checks a URI String to see whether it is suitable for use on a new editable entity.
* uniqueness in the model. Ill-formed strings or those matching URIs * It must be well-formed, and it must not be declared in the model as a Thing, Class,
* already in use will cause an error message to be returned. * ObjectProperty or DataProperty. Ill-formed strings or those so declared will
* cause an error message to be returned.
* @return error message String if invalid; otherwise null * @return error message String if invalid; otherwise null
*/ */
public String checkURI(String uriStr, boolean checkUniqueness); public String checkURIForEditableEntity(String uriStr);
/** /**
* Check if a given URI string exists in the system: * Check if a given URI string exists in the system:

View file

@ -88,11 +88,12 @@ public class WebappDaoFactoryFiltering implements WebappDaoFactory {
return innerWebappDaoFactory.checkURI(uriStr); return innerWebappDaoFactory.checkURI(uriStr);
} }
public String checkURI(String uriStr, boolean checkUniqueness) { @Override
return innerWebappDaoFactory.checkURI(uriStr, checkUniqueness); public String checkURIForEditableEntity(String uriStr) {
} return innerWebappDaoFactory.checkURIForEditableEntity(uriStr);
}
public boolean hasExistingURI(String uriStr) {
public boolean hasExistingURI(String uriStr) {
return innerWebappDaoFactory.hasExistingURI(uriStr); return innerWebappDaoFactory.hasExistingURI(uriStr);
} }

View file

@ -487,7 +487,7 @@ public class DataPropertyDaoJena extends PropertyDaoJena implements
ontModel.enterCriticalSection(Lock.WRITE); ontModel.enterCriticalSection(Lock.WRITE);
try { try {
getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),true)); getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),true));
String errMsgStr = getWebappDaoFactory().checkURI(dtp.getURI()); String errMsgStr = getWebappDaoFactory().checkURIForEditableEntity(dtp.getURI());
if (errMsgStr != null) { if (errMsgStr != null) {
throw new InsertException(errMsgStr); throw new InsertException(errMsgStr);
} }

View file

@ -534,7 +534,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp
ontModel.enterCriticalSection(Lock.WRITE); ontModel.enterCriticalSection(Lock.WRITE);
try { try {
getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),true)); getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),true));
String errMsgStr = getWebappDaoFactory().checkURI(prop.getURI()); String errMsgStr = getWebappDaoFactory().checkURIForEditableEntity(prop.getURI());
if (errMsgStr != null) { if (errMsgStr != null) {
throw new InsertException(errMsgStr); throw new InsertException(errMsgStr);
} }
@ -542,7 +542,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp
com.hp.hpl.jena.ontology.ObjectProperty inv = null; com.hp.hpl.jena.ontology.ObjectProperty inv = null;
if (hasInverse(prop)) { if (hasInverse(prop)) {
log.debug("non-null inverse URI: " +prop.getURIInverse()); log.debug("non-null inverse URI: " +prop.getURIInverse());
errMsgStr = getWebappDaoFactory().checkURI(prop.getURIInverse()); errMsgStr = getWebappDaoFactory().checkURIForEditableEntity(prop.getURIInverse());
if (errMsgStr != null) { if (errMsgStr != null) {
throw new InsertException("Unusable URI for inverse property: "+errMsgStr); throw new InsertException("Unusable URI for inverse property: "+errMsgStr);
} }

View file

@ -934,7 +934,7 @@ public class VClassDaoJena extends JenaBaseDao implements VClassDao {
ontModel.enterCriticalSection(Lock.WRITE); ontModel.enterCriticalSection(Lock.WRITE);
getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),true)); getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),true));
try { try {
String errMsgStr = getWebappDaoFactory().checkURI(cls.getURI()); String errMsgStr = getWebappDaoFactory().checkURIForEditableEntity(cls.getURI());
if (errMsgStr != null) { if (errMsgStr != null) {
throw new InsertException(errMsgStr); throw new InsertException(errMsgStr);
} }

View file

@ -23,6 +23,8 @@ import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.shared.Lock;
import com.hp.hpl.jena.util.iterator.ClosableIterator; import com.hp.hpl.jena.util.iterator.ClosableIterator;
@ -174,41 +176,67 @@ public class WebappDaoFactoryJena implements WebappDaoFactory {
return this.properties; return this.properties;
} }
@Override @Override
public String checkURI(String uriStr) { public String checkURI(String uriStr) {
return checkURI(uriStr, true); String errorMessage = checkURIForValidity(uriStr);
} if (errorMessage != null) {
return errorMessage;
}
if (this.hasExistingURI(uriStr)) {
return "URI is already in use. Please enter another URI. ";
}
return null;
}
@Override @Override
public String checkURI(String uriStr, boolean checkUniqueness) { public String checkURIForEditableEntity(String uriStr) {
uriStr = (uriStr == null) ? " " : uriStr; String errorMessage = checkURIForValidity(uriStr);
String errorMsg = ""; if (errorMessage != null) {
String duplicateMsg = "URI is already in use. " + return errorMessage;
"Please enter another URI. "; }
IRIFactory factory = IRIFactory.jenaImplementation();
IRI iri = factory.create( uriStr ); if(hasEditableEntity(uriStr)) {
if (iri.hasViolation(false) ) { return "URI is already in use. Please enter another URI. ";
errorMsg += (iri.violations(false).next()) }
.getShortMessage() + " ";
} else if (checkUniqueness) { return null;
boolean existingURI = this.hasExistingURI(uriStr); }
if(existingURI) {
errorMsg+="Not a valid URI. Please enter another URI. "; private String checkURIForValidity(String uriStr) {
errorMsg+=duplicateMsg; uriStr = (uriStr == null) ? " " : uriStr;
}
} IRI iri = IRIFactory.jenaImplementation().create(uriStr);
return (errorMsg.length()>0) ? errorMsg : null; if (iri.hasViolation(false)) {
} return (iri.violations(false).next()).getShortMessage() + " ";
}
try {
//Check if URI already in use or not either as resource OR as property Resource res = ResourceFactory.createResource(uriStr);
if (res.getLocalName().matches("\\d+")) {
return "Localname must contain at least one non-numeric "
+ "character. Please enter another URI. ";
}
} catch (Exception e) {
return "Not a valid URI. Please enter another URI. ";
}
return null;
}
//Check if URI already in use or not either as resource OR as property
@Override @Override
public boolean hasExistingURI(String uriStr) { public boolean hasExistingURI(String uriStr) {
OntModel ontModel = ontModelSelector.getFullModel(); OntModel ontModel = ontModelSelector.getFullModel();
return URIUtils.hasExistingURI(uriStr, ontModel); return URIUtils.hasExistingURI(uriStr, ontModel);
} }
private boolean hasEditableEntity(String uriStr) {
OntModel ontModel = ontModelSelector.getFullModel();
return URIUtils.hasEditableEntity(uriStr, ontModel);
}
@Override @Override
public WebappDaoFactory getUserAwareDaoFactory(String userURI) { public WebappDaoFactory getUserAwareDaoFactory(String userURI) {
return new WebappDaoFactoryJena(this, userURI); return new WebappDaoFactoryJena(this, userURI);

View file

@ -2,59 +2,67 @@
package edu.cornell.mannlib.vitro.webapp.utils.jena; package edu.cornell.mannlib.vitro.webapp.utils.jena;
import org.apache.commons.logging.Log; import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty;
import org.apache.commons.logging.LogFactory; import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.shared.Lock;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
public class URIUtils { public class URIUtils {
public static boolean hasExistingURI(String uriStr, OntModel ontModel) {
private static final Log log = LogFactory.getLog(URIUtils.class.getName()); ontModel.enterCriticalSection(Lock.READ);
try {
public static boolean hasExistingURI(String uriStr, OntModel ontModel) { if (anyStatements(ontModel, createResource(uriStr), null, null)) {
boolean existingURI = false; return true;
ontModel.enterCriticalSection(Lock.READ);
try {
boolean validPropertyURI = true;
String localName = uriStr.substring(uriStr.lastIndexOf("/") + 1);
//if local name is only numbers, this is not a valid uri for a property
if(localName.matches("\\d+")) {
validPropertyURI = false;
}
Resource newURIAsRes = ResourceFactory.createResource(uriStr);
StmtIterator closeIt = ontModel.listStatements(
newURIAsRes, null, (RDFNode)null);
if (closeIt.hasNext()) {
existingURI = true;
}
//if not in the subject position, check in object position
if (!existingURI) {
closeIt = ontModel.listStatements(null, null, newURIAsRes);
if (closeIt.hasNext()) {
existingURI= true;
}
}
//Check for property
if (validPropertyURI && !existingURI) {
Property newURIAsProp = ResourceFactory.createProperty(uriStr);
closeIt = ontModel.listStatements(
null, newURIAsProp, (RDFNode)null);
if (closeIt.hasNext()) {
existingURI = true;
}
}
} finally {
ontModel.leaveCriticalSection();
} }
if (anyStatements(ontModel, null, createProperty(uriStr), null)) {
return existingURI; return true;
} }
if (anyStatements(ontModel, null, null, createResource(uriStr))) {
return true;
}
return false;
} finally {
ontModel.leaveCriticalSection();
}
}
public static boolean hasEditableEntity(String uriStr, OntModel ontModel) {
ontModel.enterCriticalSection(Lock.READ);
try {
Resource res = createResource(uriStr);
if (anyStatements(ontModel, res, RDF.type, OWL.Thing)) {
return true;
}
if (anyStatements(ontModel, res, RDF.type, OWL.Class)) {
return true;
}
if (anyStatements(ontModel, res, RDF.type, OWL.DatatypeProperty)) {
return true;
}
if (anyStatements(ontModel, res, RDF.type, OWL.ObjectProperty)) {
return true;
}
return false;
} finally {
ontModel.leaveCriticalSection();
}
}
private static boolean anyStatements(OntModel m, Resource s, Property p,
RDFNode o) {
StmtIterator stmts = m.listStatements(s, p, o);
try {
return stmts.hasNext();
} finally {
stmts.close();
}
}
} }

View file

@ -71,10 +71,11 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
this.objectPropertyDao = objectPropertyDao; this.objectPropertyDao = objectPropertyDao;
} }
public void setObjectPropertyStatementDao(ObjectPropertyStatementDao objectPropertyStatementDao) { public void setObjectPropertyStatementDao(
ObjectPropertyStatementDao objectPropertyStatementDao) {
this.objectPropertyStatementDao = objectPropertyStatementDao; this.objectPropertyStatementDao = objectPropertyStatementDao;
} }
public void setFauxPropertyDao(FauxPropertyDao fauxPropertyDao) { public void setFauxPropertyDao(FauxPropertyDao fauxPropertyDao) {
this.fauxPropertyDao = fauxPropertyDao; this.fauxPropertyDao = fauxPropertyDao;
} }
@ -86,7 +87,7 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
public void setUserAccountsDao(UserAccountsDao userAccountsDao) { public void setUserAccountsDao(UserAccountsDao userAccountsDao) {
this.userAccountsDao = userAccountsDao; this.userAccountsDao = userAccountsDao;
} }
public void setVClassDao(VClassDao vClassDao) { public void setVClassDao(VClassDao vClassDao) {
this.vClassDao = vClassDao; this.vClassDao = vClassDao;
} }
@ -161,11 +162,11 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
} }
@Override @Override
public String checkURI(String uriStr, boolean checkUniqueness) { public String checkURIForEditableEntity(String uriStr) {
throw new RuntimeException( throw new RuntimeException(
"WebappDaoFactory.checkURI() not implemented."); "WebappDaoFactory.checkURIForNewEditableEntity() not implemented.");
} }
@Override @Override
public boolean hasExistingURI(String uriStr) { public boolean hasExistingURI(String uriStr) {
throw new RuntimeException( throw new RuntimeException(