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);
/**
* Checks a URI String for two things: well-formedness and, optionally,
* uniqueness in the model. Ill-formed strings or those matching URIs
* already in use will cause an error message to be returned.
* Checks a URI String to see whether it is suitable for use on a new editable entity.
* It must be well-formed, and it must not be declared in the model as a Thing, Class,
* 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
*/
public String checkURI(String uriStr, boolean checkUniqueness);
public String checkURIForEditableEntity(String uriStr);
/**
* Check if a given URI string exists in the system:

View file

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

View file

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

View file

@ -534,7 +534,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp
ontModel.enterCriticalSection(Lock.WRITE);
try {
getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),true));
String errMsgStr = getWebappDaoFactory().checkURI(prop.getURI());
String errMsgStr = getWebappDaoFactory().checkURIForEditableEntity(prop.getURI());
if (errMsgStr != null) {
throw new InsertException(errMsgStr);
}
@ -542,7 +542,7 @@ public class ObjectPropertyDaoJena extends PropertyDaoJena implements ObjectProp
com.hp.hpl.jena.ontology.ObjectProperty inv = null;
if (hasInverse(prop)) {
log.debug("non-null inverse URI: " +prop.getURIInverse());
errMsgStr = getWebappDaoFactory().checkURI(prop.getURIInverse());
errMsgStr = getWebappDaoFactory().checkURIForEditableEntity(prop.getURIInverse());
if (errMsgStr != null) {
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);
getOntModel().getBaseModel().notifyEvent(new EditEvent(getWebappDaoFactory().getUserURI(),true));
try {
String errMsgStr = getWebappDaoFactory().checkURI(cls.getURI());
String errMsgStr = getWebappDaoFactory().checkURIForEditableEntity(cls.getURI());
if (errMsgStr != null) {
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.ModelFactory;
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.util.iterator.ClosableIterator;
@ -176,31 +178,52 @@ public class WebappDaoFactoryJena implements WebappDaoFactory {
@Override
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
public String checkURI(String uriStr, boolean checkUniqueness) {
public String checkURIForEditableEntity(String uriStr) {
String errorMessage = checkURIForValidity(uriStr);
if (errorMessage != null) {
return errorMessage;
}
if(hasEditableEntity(uriStr)) {
return "URI is already in use. Please enter another URI. ";
}
return null;
}
private String checkURIForValidity(String uriStr) {
uriStr = (uriStr == null) ? " " : uriStr;
String errorMsg = "";
String duplicateMsg = "URI is already in use. " +
"Please enter another URI. ";
IRIFactory factory = IRIFactory.jenaImplementation();
IRI iri = factory.create( uriStr );
if (iri.hasViolation(false) ) {
errorMsg += (iri.violations(false).next())
.getShortMessage() + " ";
} else if (checkUniqueness) {
boolean existingURI = this.hasExistingURI(uriStr);
if(existingURI) {
errorMsg+="Not a valid URI. Please enter another URI. ";
errorMsg+=duplicateMsg;
}
}
return (errorMsg.length()>0) ? errorMsg : null;
IRI iri = IRIFactory.jenaImplementation().create(uriStr);
if (iri.hasViolation(false)) {
return (iri.violations(false).next()).getShortMessage() + " ";
}
try {
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
@ -209,6 +232,11 @@ public class WebappDaoFactoryJena implements WebappDaoFactory {
return URIUtils.hasExistingURI(uriStr, ontModel);
}
private boolean hasEditableEntity(String uriStr) {
OntModel ontModel = ontModelSelector.getFullModel();
return URIUtils.hasEditableEntity(uriStr, ontModel);
}
@Override
public WebappDaoFactory getUserAwareDaoFactory(String userURI) {
return new WebappDaoFactoryJena(this, userURI);

View file

@ -2,59 +2,67 @@
package edu.cornell.mannlib.vitro.webapp.utils.jena;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createProperty;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Property;
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.rdf.model.StmtIterator;
import com.hp.hpl.jena.shared.Lock;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
public class URIUtils {
private static final Log log = LogFactory.getLog(URIUtils.class.getName());
public static boolean hasExistingURI(String uriStr, OntModel ontModel) {
boolean existingURI = false;
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;
if (anyStatements(ontModel, createResource(uriStr), null, null)) {
return true;
}
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;
if (anyStatements(ontModel, null, createProperty(uriStr), null)) {
return true;
}
if (anyStatements(ontModel, null, null, createResource(uriStr))) {
return true;
}
return false;
} finally {
ontModel.leaveCriticalSection();
}
return existingURI;
}
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,7 +71,8 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
this.objectPropertyDao = objectPropertyDao;
}
public void setObjectPropertyStatementDao(ObjectPropertyStatementDao objectPropertyStatementDao) {
public void setObjectPropertyStatementDao(
ObjectPropertyStatementDao objectPropertyStatementDao) {
this.objectPropertyStatementDao = objectPropertyStatementDao;
}
@ -161,9 +162,9 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
}
@Override
public String checkURI(String uriStr, boolean checkUniqueness) {
public String checkURIForEditableEntity(String uriStr) {
throw new RuntimeException(
"WebappDaoFactory.checkURI() not implemented.");
"WebappDaoFactory.checkURIForNewEditableEntity() not implemented.");
}
@Override