Populate the new bean from the base property. Handle policy restrictions.

This commit is contained in:
Jim Blake 2014-11-06 10:28:40 -05:00
parent ec6f166f54
commit daac8c3c4f
9 changed files with 203 additions and 90 deletions

View file

@ -79,6 +79,7 @@ public class BaseResourceBean implements ResourceBean {
return shorthand;
}
// Never returns null.
public static RoleLevel getRoleByUri(String uri2) {
if (uri2 == null)
return RoleLevel.values()[0];

View file

@ -214,7 +214,8 @@ public class FauxProperty extends BaseResourceBean implements ResourceBean,
return "FauxProperty[domainURI=" + domainURI + ", baseUri=" + getURI()
+ ", rangeURI=" + rangeURI + ", rangeLabel=" + rangeLabel
+ ", domainLabel=" + domainLabel + ", pickListName="
+ getPickListName() + ", groupURI=" + groupURI
+ getPickListName() + ", contextUri=" + contextUri
+ ", configUri=" + configUri + ", groupURI=" + groupURI
+ "publicDescription=" + publicDescription + ", displayTier="
+ displayTier + ", displayLimit=" + displayLimit
+ ", collateBySubclass=" + collateBySubclass

View file

@ -31,12 +31,14 @@ import edu.cornell.mannlib.vedit.validator.impl.RequiredFieldValidator;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.SimplePermission;
import edu.cornell.mannlib.vitro.webapp.auth.policy.bean.PropertyRestrictionListener;
import edu.cornell.mannlib.vitro.webapp.beans.FauxProperty;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.beans.Property;
import edu.cornell.mannlib.vitro.webapp.beans.PropertyGroup;
import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.edit.utils.RoleLevelOptionsSetup;
import edu.cornell.mannlib.vitro.webapp.dao.FauxPropertyDao;
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
@ -141,7 +143,7 @@ public class FauxPropertyRetryController extends BaseEditController {
String domainUri = req.getParameter("domainUri");
if (epo.getAction().equals("insert")) {
return new FauxProperty(null, baseUri, null);
return newFauxProperty(baseUri);
}
FauxProperty bean = fpDao.getFauxPropertyByUris(domainUri, baseUri,
@ -155,6 +157,22 @@ public class FauxPropertyRetryController extends BaseEditController {
return bean;
}
/**
* Create a new FauxProperty object and let it inherit some values from its base property.
*/
private FauxProperty newFauxProperty(String baseUri) {
FauxProperty fp = new FauxProperty(null, baseUri, null);
ObjectPropertyDao opDao = wadf.getObjectPropertyDao();
ObjectProperty base = opDao.getObjectPropertyByURI(baseUri);
fp.setGroupURI(base.getGroupURI());
fp.setRangeURI(base.getRangeVClassURI());
fp.setDomainURI(base.getDomainVClassURI());
fp.setHiddenFromDisplayBelowRoleLevel(base.getHiddenFromDisplayBelowRoleLevel());
fp.setHiddenFromPublishBelowRoleLevel(base.getHiddenFromPublishBelowRoleLevel());
fp.setProhibitedFromUpdateBelowRoleLevel(base.getProhibitedFromUpdateBelowRoleLevel());
return fp;
}
private void setFieldValidators() {
epo.getValidatorMap()
.put("RangeURI",

View file

@ -180,7 +180,7 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
@Override
public void insertFauxProperty(FauxProperty fp) {
if ((fp.getContextUri() != null) || (fp.getConfigUri() == null)) {
if ((fp.getContextUri() != null) || (fp.getConfigUri() != null)) {
throw new IllegalStateException(
"ContextUri and ConfigUri must be null on insert: " + fp);
}
@ -193,31 +193,28 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
"FauxProperty with these qualifiers already exists: " + fp);
}
try {
fp.setContextUri(getUnusedURI());
fp.setConfigUri(getUnusedURI());
} catch (InsertException e) {
throw new RuntimeException(e);
}
try (LockedOntModel displayModel = models.getDisplayModel().write()) {
fp.setContextUri(getUnusedURI());
OntResource context = displayModel.createOntResource(fp
.getContextUri());
addPropertyResourceValue(context, RDF.type, CONFIG_CONTEXT);
addPropertyResourceURIValue(context, HAS_CONFIGURATION,
fp.getConfigUri());
addPropertyResourceURIValue(context, CONFIG_CONTEXT_FOR,
fp.getBaseURI());
addPropertyResourceURIValue(context, QUALIFIED_BY_RANGE,
fp.getRangeURI());
addPropertyResourceURIValue(context, QUALIFIED_BY_DOMAIN,
addPropertyResourceURINotEmpty(context, QUALIFIED_BY_DOMAIN,
fp.getDomainURI());
fp.setConfigUri(getUnusedURI());
addPropertyResourceURIValue(context, HAS_CONFIGURATION,
fp.getConfigUri());
OntResource config = displayModel.createOntResource(fp
.getConfigUri());
addPropertyResourceValue(config, RDF.type,
OBJECT_PROPERTY_DISPLAY_CONFIG);
addPropertyResourceURIValue(config, PROPERTY_GROUP,
addPropertyResourceURINotEmpty(config, PROPERTY_GROUP,
fp.getGroupURI());
addPropertyStringValue(config, DISPLAY_NAME, fp.getDisplayName(),
displayModel);
@ -237,6 +234,26 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
fp.getCustomEntryForm(), displayModel);
addPropertyStringValue(config, LIST_VIEW_FILE,
fp.getCustomListView(), displayModel);
updatePropertyResourceURIValue(config,
HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT, fp
.getHiddenFromDisplayBelowRoleLevel().getURI());
updatePropertyResourceURIValue(config,
HIDDEN_FROM_PUBLISH_BELOW_ROLE_LEVEL_ANNOT, fp
.getHiddenFromPublishBelowRoleLevel().getURI());
updatePropertyResourceURIValue(config,
PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT, fp
.getProhibitedFromUpdateBelowRoleLevel().getURI());
} catch (InsertException e) {
throw new RuntimeException(e);
}
}
private void addPropertyResourceURINotEmpty(OntResource context,
ObjectProperty prop, String uri) {
if (uri != null && !uri.isEmpty()) {
addPropertyResourceURIValue(context, prop, uri);
}
}
@ -302,6 +319,16 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
fp.getCustomEntryForm(), displayModel);
updatePropertyStringValue(config, LIST_VIEW_FILE,
fp.getCustomListView(), displayModel);
updatePropertyResourceURIValue(config,
HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT, fp
.getHiddenFromDisplayBelowRoleLevel().getURI());
updatePropertyResourceURIValue(config,
HIDDEN_FROM_PUBLISH_BELOW_ROLE_LEVEL_ANNOT, fp
.getHiddenFromPublishBelowRoleLevel().getURI());
updatePropertyResourceURIValue(config,
PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT, fp
.getProhibitedFromUpdateBelowRoleLevel().getURI());
}
}
@ -388,14 +415,24 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
fp.setDisplayTier(getPropertyIntValue(config,
DISPLAY_RANK_ANNOT));
fp.setDisplayLimit(getPropertyIntValue(config, DISPLAY_LIMIT));
fp.setCollateBySubclass(getPropertyBooleanValue(config,
PROPERTY_COLLATEBYSUBCLASSANNOT));
fp.setSelectFromExisting(getPropertyBooleanValue(config,
PROPERTY_SELECTFROMEXISTINGANNOT));
fp.setOfferCreateNewOption(getPropertyBooleanValue(config,
PROPERTY_OFFERCREATENEWOPTIONANNOT));
fp.setCollateBySubclass(Boolean.TRUE
.equals(getPropertyBooleanValue(config,
PROPERTY_COLLATEBYSUBCLASSANNOT)));
fp.setSelectFromExisting(Boolean.TRUE
.equals(getPropertyBooleanValue(config,
PROPERTY_SELECTFROMEXISTINGANNOT)));
fp.setOfferCreateNewOption(Boolean.TRUE
.equals(getPropertyBooleanValue(config,
PROPERTY_OFFERCREATENEWOPTIONANNOT)));
fp.setCustomEntryForm(getPropertyStringValue(config,
PROPERTY_CUSTOMENTRYFORMANNOT));
fp.setHiddenFromDisplayBelowRoleLevel(getMostRestrictiveRoleLevel(
config, HIDDEN_FROM_DISPLAY_BELOW_ROLE_LEVEL_ANNOT));
fp.setHiddenFromPublishBelowRoleLevel(getMostRestrictiveRoleLevel(
config, HIDDEN_FROM_PUBLISH_BELOW_ROLE_LEVEL_ANNOT));
fp.setProhibitedFromUpdateBelowRoleLevel(getMostRestrictiveRoleLevel(
config, PROHIBITED_FROM_UPDATE_BELOW_ROLE_LEVEL_ANNOT));
}
}
}
@ -444,7 +481,7 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
private static final String QUERY_LOCATE_CONFIG_CONTEXT_WITH_NO_DOMAIN = "" //
+ "PREFIX : <http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationConfiguration#> \n" //
+ "\n" //
+ "SELECT DISTINCT ?context \n" //
+ "SELECT DISTINCT ?context ?config \n" //
+ "WHERE { \n" //
+ " ?context a :ConfigContext ; \n" //
+ " :configContextFor ?baseUri ; \n" //
@ -493,7 +530,7 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
String baseUri, String rangeUri) {
try (LockedOntModel displayModel = lockableDisplayModel.read()) {
String queryString;
if (domainUri == null) {
if (domainUri == null || domainUri.trim().isEmpty()) {
queryString = bindValues(
QUERY_LOCATE_CONFIG_CONTEXT_WITH_NO_DOMAIN,
uriValue("baseUri", baseUri),
@ -505,11 +542,19 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
uriValue("rangeUri", rangeUri),
uriValue("domainUri", domainUri));
}
if (log.isDebugEnabled()) {
log.debug("domainUri=" + domainUri + ", baseUri=" + baseUri
+ ", rangeUri=" + rangeUri + ", queryString="
+ queryString);
}
ParserLocateConfigContext parser = new ParserLocateConfigContext(
domainUri, baseUri, rangeUri);
return new SparqlQueryRunner(displayModel).executeSelect(
parser, queryString);
Set<ConfigContext> contexts = new SparqlQueryRunner(
displayModel).executeSelect(parser, queryString);
log.debug("found " + contexts.size() + " contexts: " + contexts);
return contexts;
}
}
@ -548,6 +593,13 @@ public class FauxPropertyDaoJena extends JenaBaseDao implements FauxPropertyDao
return rangeUri;
}
@Override
public String toString() {
return "ConfigContext[contextUri=" + contextUri + ", configUri="
+ configUri + ", domainUri=" + domainUri + ", baseUri="
+ baseUri + ", rangeUri=" + rangeUri + "]";
}
}
}

View file

@ -48,6 +48,7 @@ import com.hp.hpl.jena.util.iterator.ClosableIterator;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
public class JenaBaseDao extends JenaBaseDaoCon {
@ -573,6 +574,20 @@ public class JenaBaseDao extends JenaBaseDaoCon {
return list;
}
protected RoleLevel getMostRestrictiveRoleLevel(Resource res, Property prop) {
RoleLevel level = RoleLevel.getRoleByUri(null);
for (Statement stmt : res.listProperties(prop).toList()) {
if (stmt.getObject().isURIResource()) {
RoleLevel roleFromModel = RoleLevel.getRoleByUri(stmt
.getObject().as(Resource.class).getURI());
if (roleFromModel.compareTo(level) > 0) {
level = roleFromModel;
}
}
}
return level;
}
/**
* convenience method for use with functional object properties
*/

View file

@ -2,19 +2,21 @@
package edu.cornell.mannlib.vitro.webapp.utils.configuration;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.*;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.vocabulary.RDF;
import edu.cornell.mannlib.vitro.webapp.utils.jena.Critical;
import edu.cornell.mannlib.vitro.webapp.utils.jena.Critical.LockableModel;
import edu.cornell.mannlib.vitro.webapp.utils.jena.Critical.LockedModel;
/**
* Load one or more Configuration beans from a specified model.
@ -48,7 +50,7 @@ public class ConfigurationBeanLoader {
// ----------------------------------------------------------------------
/** Must not be null. */
private final Model model;
private final LockableModel model;
/**
* May be null, but the loader will be unable to satisfy instances of
@ -82,7 +84,7 @@ public class ConfigurationBeanLoader {
throw new NullPointerException("model may not be null.");
}
this.model = model;
this.model = new LockableModel(model);
this.req = req;
this.ctx = ctx;
}
@ -120,9 +122,9 @@ public class ConfigurationBeanLoader {
public <T> Set<T> loadAll(Class<T> resultClass)
throws ConfigurationBeanLoaderException {
Set<String> uris = new HashSet<>();
try (Critical.Section section = Critical.Section.read(model)) {
List<Resource> resources = model.listResourcesWithProperty(
RDF.type, createResource(toJavaUri(resultClass))).toList();
try (LockedModel m = model.read()) {
List<Resource> resources = m.listResourcesWithProperty(RDF.type,
createResource(toJavaUri(resultClass))).toList();
for (Resource r : resources) {
if (r.isURIResource()) {
uris.add(r.getURI());

View file

@ -13,7 +13,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Selector;
@ -23,15 +22,17 @@ import com.hp.hpl.jena.vocabulary.RDF;
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyStatement;
import edu.cornell.mannlib.vitro.webapp.utils.configuration.PropertyType.PropertyTypeException;
import edu.cornell.mannlib.vitro.webapp.utils.jena.Critical;
import edu.cornell.mannlib.vitro.webapp.utils.jena.Critical.LockableModel;
import edu.cornell.mannlib.vitro.webapp.utils.jena.Critical.LockedModel;
/**
* Parse the RDF for a single individual in the model to create a
* ConfigurationRdf object.
*/
public class ConfigurationRdfParser {
public static <T> ConfigurationRdf<T> parse(Model model, String uri,
Class<T> resultClass) throws InvalidConfigurationRdfException {
public static <T> ConfigurationRdf<T> parse(LockableModel model,
String uri, Class<T> resultClass)
throws InvalidConfigurationRdfException {
if (model == null) {
throw new NullPointerException("model may not be null.");
}
@ -54,36 +55,36 @@ public class ConfigurationRdfParser {
return new ConfigurationRdf<T>(concreteClass, properties);
}
private static void confirmExistenceInModel(Model model, String uri)
private static void confirmExistenceInModel(LockableModel model, String uri)
throws InvalidConfigurationRdfException {
Selector s = new SimpleSelector(createResource(uri), null,
(RDFNode) null);
try (Critical.Section section = Critical.Section.read(model)) {
if (model.listStatements(s).toList().isEmpty()) {
try (LockedModel m = model.read()) {
if (m.listStatements(s).toList().isEmpty()) {
throw individualDoesNotAppearInModel(uri);
}
}
}
private static void confirmEligibilityForResultClass(Model model,
private static void confirmEligibilityForResultClass(LockableModel model,
String uri, Class<?> resultClass)
throws InvalidConfigurationRdfException {
Statement s = createStatement(createResource(uri), RDF.type,
createResource(toJavaUri(resultClass)));
try (Critical.Section section = Critical.Section.read(model)) {
if (!model.contains(s)) {
try (LockedModel m = model.read()) {
if (!m.contains(s)) {
throw noTypeStatementForResultClass(s);
}
}
}
private static Set<PropertyStatement> loadProperties(Model model, String uri)
throws InvalidConfigurationRdfException {
private static Set<PropertyStatement> loadProperties(LockableModel model,
String uri) throws InvalidConfigurationRdfException {
Set<PropertyStatement> set = new HashSet<>();
try (Critical.Section section = Critical.Section.read(model)) {
List<Statement> rawStatements = model.listStatements(
model.getResource(uri), (Property) null, (RDFNode) null)
try (LockedModel m = model.read()) {
List<Statement> rawStatements = m.listStatements(
m.getResource(uri), (Property) null, (RDFNode) null)
.toList();
if (rawStatements.isEmpty()) {
throw noRdfStatements(uri);
@ -106,14 +107,14 @@ public class ConfigurationRdfParser {
}
}
private static <T> Class<? extends T> determineConcreteClass(Model model,
String uri, Class<T> resultClass)
private static <T> Class<? extends T> determineConcreteClass(
LockableModel model, String uri, Class<T> resultClass)
throws InvalidConfigurationRdfException {
Set<Class<? extends T>> concreteClasses = new HashSet<>();
try (Critical.Section section = Critical.Section.read(model)) {
for (RDFNode node : model.listObjectsOfProperty(
createResource(uri), RDF.type).toSet()) {
try (LockedModel m = model.read()) {
for (RDFNode node : m.listObjectsOfProperty(createResource(uri),
RDF.type).toSet()) {
if (!node.isURIResource()) {
throw typeMustBeUriResource(node);
}

View file

@ -2,52 +2,25 @@
package edu.cornell.mannlib.vitro.webapp.utils.jena;
import static com.hp.hpl.jena.shared.Lock.READ;
import static com.hp.hpl.jena.shared.Lock.WRITE;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.shared.Lock;
import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector;
import edu.cornell.mannlib.vitro.webapp.rdfservice.adapters.AbstractModelDecorator;
import edu.cornell.mannlib.vitro.webapp.rdfservice.adapters.AbstractOntModelDecorator;
/**
* AutoCloseable helper classes for using models in a try-with-resources block.
*
* TODO - create separate classes in criticalsection package
* Locked<? extends Model>
* LockerFor<? extends Model>
* Add to develop.
* Remove Critical and convert configurationBeanLoader
* Merge to faux.
*/
public abstract class Critical {
/**
* Use this when you have a bare model, and you want to control a critical
* section.
*
* <pre>
* try (Critical.Section section = Critical.Section.read(model)) {
* ...
* }
* </pre>
*/
public static class Section implements AutoCloseable {
public static Section read(Model model) {
return new Section(model, READ);
}
public static Section write(Model model) {
return new Section(model, WRITE);
}
private final Model model;
private Section(Model model, boolean readLockRequested) {
this.model = model;
this.model.enterCriticalSection(readLockRequested);
}
@Override
public void close() {
this.model.leaveCriticalSection();
}
}
/**
* Use this when you have a bare OntModelSelector. It returns
* LockableOntModels, which can then be locked in a critical section.
@ -74,7 +47,7 @@ public abstract class Critical {
/**
* Returned by the LockingOntModelSelector, or it can be wrapped around a
* bare OntModel.
* bare OntModel. Cannot be used without locking.
*
* <pre>
* try (LockedOntModel m = lockingOms.getDisplayModel.read()) {
@ -104,7 +77,7 @@ public abstract class Critical {
* A simple OntModel, except that it can only be created by locking a
* LockableOntModel. It is AutoCloseable, but the close method has been
* hijacked to simply release the lock, and not to actually close the
* wrapped model.
* wrapped model.
*/
public static class LockedOntModel extends AbstractOntModelDecorator
implements AutoCloseable {
@ -123,4 +96,54 @@ public abstract class Critical {
}
}
/**
* Can be wrapped around a bare OntModel. Cannot be used without locking.
*
* <pre>
* try (LockedModel m = lockableModel.read()) {
* ...
* }
* </pre>
*/
public static class LockableModel {
private final Model model;
public LockableModel(Model model) {
this.model = model;
}
public LockedModel read() {
model.enterCriticalSection(Lock.READ);
return new LockedModel(model);
}
public LockedModel write() {
model.enterCriticalSection(Lock.WRITE);
return new LockedModel(model);
}
}
/**
* A simple Model, except that it can only be created by locking a
* LockableModel. It is AutoCloseable, but the close method has been
* hijacked to simply release the lock, and not to actually close the
* wrapped model.
*/
public static class LockedModel extends AbstractModelDecorator
implements AutoCloseable {
private LockedModel(Model m) {
super(m);
}
/**
* Just unlocks the model. Doesn't actually close it, because we may
* want to use it again.
*/
@Override
public void close() {
super.leaveCriticalSection();
}
}
}

View file

@ -6,7 +6,7 @@
<tr class="editformcell">
<td valign="top" colspan="2">
<b>Base property</b><br/>
<input type="text" class="fullWidthInput" name="Base property" value="<form:value name="BaseUri"/>" disabled="disabled" /></br>
<input type="text" class="fullWidthInput" name="Base property" value="<form:value name="BaseURI"/>" disabled="disabled" /></br>
<i>a specification of this property</i></br>
</td>
<td valign="top" colspan="2">