updates for page management as well as updates to new URI maker and individual dao jena to handle creation of new URI (old code was returning duplicate when maximum number of attempts was exhausted in NewURIMakerVitro b/c IndividualDaoJena kept returning the same URI since Random instance was set with system time seed and possibly the calls to the method were occurring close together in time and nextInt kept returning the same number).

This commit is contained in:
hjkhjk54 2012-06-21 20:44:42 +00:00
parent 98e5dc93f6
commit f6b2387a3e
9 changed files with 219 additions and 94 deletions

View file

@ -5,13 +5,18 @@ import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl;
import edu.cornell.mannlib.vitro.webapp.dao.jena.IndividualDaoJena;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.NewURIMaker;
public class NewURIMakerVitro implements NewURIMaker {
private static final Log log = LogFactory.getLog(NewURIMakerVitro.class.getName());
private static final int MAX_ATTEMPTS = 10;
private static final int MAX_ATTEMPTS = 20;
WebappDaoFactory wdf;
Set<String> madeURIs = new HashSet<String>();
static Random random = new Random();
@ -27,24 +32,38 @@ public class NewURIMakerVitro implements NewURIMaker {
String newURI = null;
int attempts = 0;
boolean goodNewURI = false;
log.debug("Before starting : Made URIs contains " + madeURIs.toString());
while( ! goodNewURI && attempts < MAX_ATTEMPTS ){
attempts++;
if( attempts > 2 && prefixURI != null && !prefixURI.isEmpty() )
if( attempts > 2 && prefixURI != null && !prefixURI.isEmpty() )
{
log.debug("Attempts: " + attempts + " and prefix not null and prefix not empty " + prefixURI);
ind.setURI(prefixURI + random.nextInt() );
else
}
else {
log.debug("Attempts:" + attempts + " and setting uri to " + prefixURI);
ind.setURI( prefixURI );
}
newURI = wdf.getIndividualDao().getUnusedURI( ind );
log.debug("Created new uri " + newURI + " and does madeURIs contain it?" + madeURIs.contains(newURI));
if( newURI != null && ! newURI.isEmpty() && ! madeURIs.contains( newURI) ){
log.debug("new URI is not null and new URI is empty and madeURIs does not containt new URI");
goodNewURI = true;
madeURIs.add( newURI );
}
}
log.debug("Made URIs contains " + madeURIs.toString());
}
if( newURI != null && !newURI.isEmpty())
if(goodNewURI && newURI != null && !newURI.isEmpty()) {
log.debug("Decided on this URI " + newURI);
return newURI;
else
throw new InsertException("Could not get a new URI for the prefix " + prefixURI );
}
else {
log.error("An error occurred and URI could not be created for prefix " + prefixURI);
throw new InsertException("Could not get a new URI for the prefix " + prefixURI );
}
}
}

View file

@ -49,7 +49,9 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.event.IndividualUpdateEvent;
import edu.cornell.mannlib.vitro.webapp.edit.EditLiteral;
public class IndividualDaoJena extends JenaBaseDao implements IndividualDao {
//For random number generation, creating it everytime the method is called lead to nextInt being about the same
//if calls were made close together in time
private Random random = new Random(System.currentTimeMillis());
public IndividualDaoJena(WebappDaoFactoryJena wadf) {
super(wadf);
}
@ -634,6 +636,9 @@ public class IndividualDaoJena extends JenaBaseDao implements IndividualDao {
//we always want local names like n23423 for the default namespace
namespace = DEFAULT_NAMESPACE;
uri = null;
log.debug("Setting namespace to default namespace " + DEFAULT_NAMESPACE + " and uri is null");
log.debug("Individual : " + individual + " - URI: " + individual.getURI() + " - namespace -" +
individual.getNamespace() + "- ");
}else if( individual.getURI() != null ){
errMsg = getWebappDaoFactory().checkURI(individual.getURI());
if( errMsg == null){
@ -642,14 +647,16 @@ public class IndividualDaoJena extends JenaBaseDao implements IndividualDao {
}else{
throw new InsertException(errMsg);
}
log.debug("Individual URI not null " + individual.getURI() + " and uriIsGood is true and uri set to individual uri");
}else{
namespace = individual.getNamespace();
if( namespace == null || namespace.length() == 0 )
namespace = DEFAULT_NAMESPACE;
String localName = individual.getName();
log.debug("Namespace " + namespace + " -localname=" + localName);
/* try to use the specified namespace and local name */
if (localName != null) {
if (localName != null) {
log.debug("Local name not equal to null so replacing characters, etc.");
localName = localName.replaceAll("\\W", "");
localName = localName.replaceAll(":", "");
if (localName.length() > 2) {
@ -661,29 +668,31 @@ public class IndividualDaoJena extends JenaBaseDao implements IndividualDao {
if( errMsg == null)
uriIsGood = true;
else
throw new InsertException(errMsg);
throw new InsertException(errMsg);
log.debug("uriIsGood is true and uri is " + uri);
}
}
/* else try namespace + n2343 */
}
Random random = new Random(System.currentTimeMillis());
int attempts = 0;
while( uriIsGood == false && attempts < 30 ){
while( uriIsGood == false && attempts < 30 ){
log.debug("While loop: Uri is good false, attempt=" + attempts);
String localName = "n" + random.nextInt( Math.min(Integer.MAX_VALUE,(int)Math.pow(2,attempts + 13)) );
uri = namespace + localName;
uri = namespace + localName;
log.debug("Trying URI " + uri);
errMsg = getWebappDaoFactory().checkURI(uri);
if( errMsg != null)
uri = null;
else
uriIsGood = true;
uriIsGood = true;
attempts++;
}
if( uri == null )
throw new InsertException("Could not create URI for individual: " + errMsg);
log.debug("Using URI" + uri);
return uri;
}

View file

@ -307,6 +307,8 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen
//Takes data getter information, packs within JSON object to send back to the form
private void addDataGetterSpecificFormData(String dataGetterURI, ProcessDataGetterN3 pn, OntModel queryModel, JSONArray jsonArray, ServletContext context) {
JSONObject jo = pn.getExistingValuesJSON(dataGetterURI, queryModel, context);
//Add dataGetterURI to jsonObject
jo.element("URI", dataGetterURI);
jsonArray.add(jo);
}

View file

@ -85,42 +85,45 @@ public class ManagePagePreprocessor extends
private void processExistingValues() {
//For all literals that were originally in scope that don't have values on the form
//anymore, replace with blank sentinel value
//anymore, replace with null value
//For those literals, those values will be replaced with form values where overwritten
//And will be deleted where not overwritten which is the behavior we desire
Map<String, List<Literal>> literalsInScope = this.editConfiguration.getLiteralsInScope();
Map<String, List<String>> urisInScope = this.editConfiguration.getUrisInScope();
List<String> literalKeys = new ArrayList<String>(literalsInScope.keySet());
List<String> uriKeys = new ArrayList<String>(urisInScope.keySet());
for(String literalName: literalKeys) {
if(this.editConfiguration.isParamUpdate()) {
Map<String, List<Literal>> literalsInScope = this.editConfiguration.getLiteralsInScope();
Map<String, List<String>> urisInScope = this.editConfiguration.getUrisInScope();
List<String> literalKeys = new ArrayList<String>(literalsInScope.keySet());
//if submission already has value for this, then leave be
//otherwise replace with null which will not be valid N3
//TODO: Replace with better solution for forcing literal deletion
boolean haslv = submission.hasLiteralValue(literalName);
if(!submission.hasLiteralValue(literalName)) {
submission.addLiteralToForm(editConfiguration,
editConfiguration.getField(literalName),
literalName,
(new String[] {null}));
List<String> uriKeys = new ArrayList<String>(urisInScope.keySet());
for(String literalName: literalKeys) {
//if submission already has value for this, then leave be
//otherwise replace with null which will not be valid N3
//TODO: Replace with better solution for forcing literal deletion
boolean haslv = submission.hasLiteralValue(literalName);
if(!submission.hasLiteralValue(literalName)) {
submission.addLiteralToForm(editConfiguration,
editConfiguration.getField(literalName),
literalName,
(new String[] {null}));
}
}
for(String uriName: uriKeys) {
//these values should never be overwritten or deleted
//if(uriName != "page" && uriName != "menuItem" && !uriName.startsWith("dataGetter")) {
if(uriName != "page") {
boolean hasuv = submission.hasUriValue(uriName);
if(!submission.hasUriValue(uriName)) {
submission.addUriToForm(editConfiguration,
uriName,
(new String[] {EditConfigurationConstants.BLANK_SENTINEL}));
}
}
}
}
for(String uriName: uriKeys) {
//these values should never be overwritten or deleted
if(uriName != "page" && uriName != "menuItem" && !uriName.startsWith("dataGetter")) {
boolean hasuv = submission.hasUriValue(uriName);
if(!submission.hasUriValue(uriName)) {
submission.addUriToForm(editConfiguration,
uriName,
(new String[] {EditConfigurationConstants.BLANK_SENTINEL}));
}
}
}
//Other than data getter itself, also get rid of any of the old URIs if any
}
@ -236,35 +239,15 @@ public class ManagePagePreprocessor extends
submission.addUriToForm(editConfiguration, submissionUriName, uriValuesSubmission);
}
//this needs to be different
//Get the literals directly from the processor - which you can get based on counter
//Problem then is we know what the connection is - some way to put that logic within the processor itself?
//It already knows the json object
//--> Get field for this base label, with counter value - that you get from configuration
/*
while(jsonObject.keys().hasNext())
{
//Other than class, all other variables considered a submission value corresponding to field
String key = (String) jsonObject.keys().next();
if(key != "dataGetterClass") {
//not expecting multiple values, so will need to either make this array or
//think about this some more
//TODO: Consider multiple values here
Map<String, String[]> submissionValues = new HashMap<String, String[]>();
submissionValues.put(key, new String[]{jsonObject.getString(key)} );
if(literalLabels.contains(key)) {
submission.addLiteralToForm(editConfiguration.getField(key), field, var, valuesArray)
}
//To get data getter uris, check if editing an existing set and include those as form inputs
if(editConfiguration.isParamUpdate()) {
String URIValue = jsonObject.getString("URI");
if(URIValue != null) {
String dataGetterURISubmissionName = pn.getDataGetterVarName(counter);
submission.addUriToForm(editConfiguration, dataGetterURISubmissionName, new String[]{URIValue});
}
}
List<String> uris = pn.retrieveUrissOnForm(counter);
for(String l:literals) {
//json object should have
submissionValues.put(l, new String[]{jsonObject.getString(l)} );
}*/
}

View file

@ -32,7 +32,12 @@ public abstract class ProcessDataGetterAbstract implements ProcessDataGetterN3 {
//placeholder so need "?" in front of the variable
public String getDataGetterVar(int counter) {
return "?dataGetter" + counter;
return "?" + getDataGetterVarName(counter);
}
//Just the var name, no "?"
public String getDataGetterVarName(int counter) {
return "dataGetter" + counter;
}
public String getPrefixes() {

View file

@ -28,6 +28,7 @@ public interface ProcessDataGetterN3 {
public List<String> getUriVarNamesBase();
public String getVarName(String base, int counter);
public String getDataGetterVar(int counter);
public String getDataGetterVarName(int counter);
public List<String> getNewResources(int counter);
//Get Existing values to put in scope

View file

@ -36,7 +36,6 @@ public class ProcessSparqlDataGetterN3 extends ProcessDataGetterAbstract {
}
//Pass in variable that represents the counter
//TODO: ensure correct model returned
//We shouldn't use the ACTUAL values here but generate the n3 required
public List<String> retrieveN3Required(int counter) {
String dataGetterVar = getDataGetterVar(counter);
@ -54,14 +53,6 @@ public class ProcessSparqlDataGetterN3 extends ProcessDataGetterAbstract {
}
//Need to add method sfor returning the fields, literals on form, and all that
/*
* addLiteralsAndUrisOnForm(pn, counter);
// Add fields
addFields(pn, counter);
//Add input values to submission
addInputsToSubmission(pn, counter);
*/
public List<String> retrieveLiteralsOnForm(int counter) {
List<String> literalsOnForm = new ArrayList<String>();
literalsOnForm.add(getVarName("saveToVar",counter));
@ -81,16 +72,7 @@ public class ProcessSparqlDataGetterN3 extends ProcessDataGetterAbstract {
public List<FieldVTwo> retrieveFields(int counter) {
List<FieldVTwo> fields = new ArrayList<FieldVTwo>();
//An alternative way of doing this
/*
List<String> allFieldsBase = new ArrayList<String>();
allFieldsBase.addAll(getLiteralVarNamesBase());
allFieldsBase.addAll(getUriVarNamesBase());
for(String varName: allFieldsBase) {
fields.add(new FieldVTwo().setName(getVarName(varName, counter)));
} */
//For existing data getters
//fields.add(new FieldVTwo().setName(getVarName("dataGetter", counter)));
fields.add(new FieldVTwo().setName(getVarName("queryModel", counter)));

View file

@ -0,0 +1,111 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.dao;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector;
import edu.cornell.mannlib.vitro.webapp.dao.jena.SimpleOntModelSelector;
import edu.cornell.mannlib.vitro.webapp.dao.jena.WebappDaoFactoryJena;
public class NewURIMakerVitroTest extends AbstractTestClass{
@Test
public void testMultipleNewURIs() {
//Three items needs new URIs assigned in the default namespace
//Var name to namespace, in this case null to denote default namespace
Map<String,String> newResources = new HashMap<String, String>();
newResources.put("page", null);
newResources.put("menuItem", null);
newResources.put("dataGetter", null);
//Setup webappdaofactory
WebappDaoFactoryJena wadf = this.setupWebappDaoFactory();
NewURIMakerVitro nv = new NewURIMakerVitro(wadf);
//Now test for new URI
HashMap<String,String> varToNewURIs = new HashMap<String,String>();
try {
for (String key : newResources.keySet()) {
String prefix = newResources.get(key);
String uri = nv.getUnusedNewURI(prefix);
varToNewURIs.put(key, uri);
}
} catch(Exception ex) {
System.out.println("Error occurred " + ex);
}
//Ensure that URIs are not included more than once
List<String> values = new ArrayList<String>(varToNewURIs.values());
Set<String> valuesSet = new HashSet<String>(varToNewURIs.values());
assertTrue(valuesSet.size() == values.size());
}
@Test
public void testNonNullNamespace() {
//Three items needs new URIs assigned in the default namespace
//Var name to namespace, in this case null to denote default namespace
Map<String,String> newResources = new HashMap<String, String>();
newResources.put("page", "http://displayOntology/test/n12");
//Setup webappdaofactory
WebappDaoFactoryJena wadf = this.setupWebappDaoFactory();
NewURIMakerVitro nv = new NewURIMakerVitro(wadf);
//Now test for new URI
HashMap<String,String> varToNewURIs = new HashMap<String,String>();
try {
for (String key : newResources.keySet()) {
String prefix = newResources.get(key);
String uri = nv.getUnusedNewURI(prefix);
varToNewURIs.put(key, uri);
}
} catch(Exception ex) {
System.out.println("Error occurred " + ex);
}
//Ensure that URIs are not included more than once
List<String> values = new ArrayList<String>(varToNewURIs.values());
Set<String> valuesSet = new HashSet<String>(varToNewURIs.values());
assertTrue(valuesSet.size() == values.size());
}
private WebappDaoFactoryJena setupWebappDaoFactory() {
String defaultNamespace= "http://vivo.mannlib.cornell.edu/individual/";
String testNamespace = "http://displayOntology/test/";
OntModel ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
ontModel.add(
ontModel.createResource(defaultNamespace + "n234"),
RDF.type,
OWL.Thing);
ontModel.add(
ontModel.createResource(testNamespace + "n234"),
RDF.type,
OWL.Thing);
OntModelSelector selector = new SimpleOntModelSelector(ontModel);
//Set up default namespace somewhere?
WebappDaoFactoryConfig config = new WebappDaoFactoryConfig();
config.setDefaultNamespace(defaultNamespace);
//Set up some test uris
WebappDaoFactoryJena wadf = new WebappDaoFactoryJena(selector, config);
return wadf;
}
}

View file

@ -547,6 +547,11 @@ var pageManagementUtils = {
var dataGetterProcessor = pageManagementUtils.dataGetterProcessorMap[dataGetterType];
//the content type specific processor will create the json object to be returned
var jsonObject = dataGetterProcessor.processPageContentSection(pageContentSection);
//if data getter uri included, include that as well
if(pageContentSection.find("input[name='URI']").length > 0) {
var uriValue = pageContentSection.find("input[name='URI']").val();
jsonObject["URI"] = uriValue;
}
return jsonObject;
} else {
//ERROR handling
@ -618,6 +623,8 @@ var pageManagementUtils = {
var $newContentObj = pageManagementUtils.cloneContentAreaForEdit(contentType, contentTypeLabel, additionalLabelText);
//Populate the section with the values
dataGetterProcessorObject.populatePageContentSection(JSONContentObject, $newContentObj);
//Also include a hidden input with data getter URI
pageManagementUtils.includeDataGetterURI(JSONContentObject, $newContentObj);
} else {
//error condition
}
@ -627,6 +634,12 @@ var pageManagementUtils = {
}
},
includeDataGetterURI:function(JSONContentObject, $newContentObj) {
var uri = JSONContentObject["URI"];
if(uri != null) {
$("<input type='hidden' name='URI' value='" + uri + "'>").appendTo($newContentObj);
}
},
//Get the data getter processor
getDataGetterProcessorObject:function(pageContentSection) {
var dataGetterType = pageManagementUtils.processDataGetterUtils.selectDataGetterType(pageContentSection);