package edu.mit.simile.fresnel.results;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import org.openrdf.model.BNode;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.sail.memory.MemoryStore;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import edu.mit.simile.fresnel.FresnelUtilities;
import edu.mit.simile.fresnel.configuration.Configuration;
import edu.mit.simile.fresnel.configuration.Group;
import edu.mit.simile.fresnel.configuration.LensMatchSet;
import edu.mit.simile.fresnel.format.Format;
import edu.mit.simile.fresnel.format.FormatDescription;
import edu.mit.simile.fresnel.format.Style;
import edu.mit.simile.fresnel.purpose.Purpose;
import edu.mit.simile.fresnel.selection.AllPropertiesSelector;
import edu.mit.simile.fresnel.selection.FSESelector;
import edu.mit.simile.fresnel.selection.ISelector;
import edu.mit.simile.fresnel.selection.InvalidResultSetException;
import edu.mit.simile.fresnel.selection.Lens;
import edu.mit.simile.fresnel.selection.PropertyDescription;
import edu.mit.simile.fresnel.selection.PropertySelector;
import edu.mit.simile.fresnel.selection.PropertySet;
import edu.mit.simile.vocabularies.FresnelCore;
/**
* The output of lens selection which can then be formatted and finally
* rendered to an XML output.
*
* @author ryanlee
*/
public class Selection implements ResultConstants {
/**
* The configuration that generated this selection
*/
private Configuration _conf;
/**
* The subRepository of data selected in the selection process
*/
private Repository _model;
/**
* A subRepository of data only relating to its types, independent of what is actually selected
*/
private Repository _typesModel;
/**
* Statements expected but not found in results; no way to match selectors but through
* model API...
*/
private Repository _notModel;
/**
* Unused; will specify order of results if ever implemented
*/
//private Vector _order;
/**
* The set of all primary results generated during selection
*/
private List<Result> _results;
/**
* A hash of all results generated in selection keyed by resource
*/
private ResultHashMap<Resource, Result> _resultModelHash;
/**
* A hash of all property results generated in selection keyed by property URI
*/
private ResultHashMap<URI, PropertyResult> _propertyResultModelHash;
/**
* A hash of all value results generated in selection keyed by value
*/
private ResultHashMap<Value, ValueResult> _valueResultModelHash;
/**
* Language preference
*/
private String _langPref;
/**
* Format should apply to a resource
*/
public static final int RESOURCE = 0;
/**
* Format should apply to a property
*/
public static final int PROPERTY = 1;
/**
* Format should apply to a label
*/
public static final int LABEL = 2;
/**
* Format should apply to a value
*/
public static final int VALUE = 3;
/**
* dc:title URI, because it's easier to put it here
*/
public static final String DCTITLE = "http://purl.org/dc/elements/1.1/title";
/**
* Constructor based on a configuration.
*
* @param conf A <code>Configuration</code>
*/
public Selection(Configuration conf) {
this._conf = conf;
this._model = new SailRepository(new MemoryStore());
this._typesModel = new SailRepository(new MemoryStore());
this._notModel = new SailRepository(new MemoryStore());
try {
this._model.initialize();
this._typesModel.initialize();
this._notModel.initialize();
} catch (RepositoryException e) {
System.err.println("Failed to initialize repositories");
}
//this._order = new Vector();
this._results = new LinkedList<Result>();
this._resultModelHash = new ResultHashMap<Resource, Result>();
this._propertyResultModelHash = new ResultHashMap<URI, PropertyResult>();
this._valueResultModelHash = new ResultHashMap<Value, ValueResult>();
this._langPref = "en";
}
/**
* Retrieves a subRepository created to reflect all the things which were requested in the
* configuration and found in the data source.
*
* @return A <code>Repository</code>
*/
public Repository getModel() {
return this._model;
}
/**
* Retrieves a subRepository created to reflect all the things which were requested
* in configuration but not actually found in the data source.
*
* @return A <code>Repository</code>
*/
public Repository getNotModel() {
return this._notModel;
}
/**
* Retrieves a subRepository with just typing information.
*
* @return A <code>Repository</code> consisting solely of rdf:type statements
*/
public Repository getTypesModel() {
return this._typesModel;
}
/**
* Retrieves the hash of all results generated during selection.
*
* @return A <code>ResultHashMap</code>
*/
public ResultHashMap<Resource, Result> getResourceHash() {
return this._resultModelHash;
}
/**
* Retrieves the hash of all property results generated during selection
*
* @return A <code>ResultHashMap</code>
*/
public ResultHashMap<URI, PropertyResult> getPropertyHash() {
return this._propertyResultModelHash;
}
/**
* Retrieves the hash of all value results generated during selection
*
* @return A <code>ResultHashMap</code>
*/
public ResultHashMap<Value, ValueResult> getValueHash() {
return this._valueResultModelHash;
}
/*
*
* @param params
*/
/*
public void reorder(Object[] params) {
// TODO write this with input on how to do ordering selection
this._order.clear();
}
*/
/**
* Add to the list of primary results
*
* @param r A <code>Result</code>
*/
public void addPrimary(Result r) {
this._results.add(r);
}
/**
* Sets preferred language for labels
* @param langPref
*/
public void setLangPref(String langPref) {
this._langPref = langPref;
}
/**
* Select data using a lens.
*
* @param group The <code>Group</code> to work with
* @param in Data source <code>Repository</code>
* @param lens The <code>Lens</code> to select with
* @param focus Subject <code>Resource</code>
* @param current Present recursion depth, an <code>int</code>
* @param max Maximum recursion depth, an <code>int</code>
* @return A selection <code>Result</code>
*/
public Result applyLens(Group group, Repository in, Lens lens, Resource focus, int current, int max) {
Result r = new Result(FresnelUtilities.dupResource(focus), group, lens, in);
try {
Iterator<Statement> it = r.getTypesStatements();
RepositoryConnection conn = this._typesModel.getConnection();
conn.setAutoCommit(false);
while(it.hasNext()) {
Statement s = it.next();
conn.add(s.getSubject(), s.getPredicate(), s.getObject(), s.getContext());
}
conn.commit();
conn.setAutoCommit(true);
conn.close();
} catch (RepositoryException sue) {
System.err.println("Could not add to repository: " + sue);
return null;
}
PropertySet finalProperties = resolvePropertySet(lens, in, focus);
Iterator<ISelector> focusPSI = finalProperties.iterator();
r.setTitle(resolveLabel(in, focus));
this._resultModelHash.putResult(FresnelUtilities.dupResource(focus), r);
while (focusPSI.hasNext()) {
ISelector selector = focusPSI.next();
if (selector.canSelectStatements()) {
try {
Iterator<Statement> selects = selector.selectStatements(in, focus);
if (!selects.hasNext() &&
(selector instanceof PropertySelector || selector instanceof PropertyDescription)) {
if (selector instanceof PropertySelector) {
URI predicate = ((PropertySelector) selector).getProperty();
PropertyResult pr = r.getProperties().lookup(predicate);
if (null == pr) {
NoSuchPropertyResult nspr = new NoSuchPropertyResult(FresnelUtilities.dupURI(predicate), selector, r);
nspr.setTitle(resolveLabel(in, predicate));
r.addProperty(nspr);
this._propertyResultModelHash.putResult(FresnelUtilities.dupURI(predicate), nspr);
RepositoryConnection nconn = this._notModel.getConnection();
nconn.add(FresnelUtilities.dupResource(focus), FresnelUtilities.dupURI(predicate), new LiteralImpl("empty"));
nconn.close();
} // if it's not null, there's nothing to do
} else {
Iterator<Statement> pi = ((PropertyDescription) selector).getProperty().selectStatements(in, focus);
if (pi.hasNext()) {
URI predicate = pi.next().getPredicate();
PropertyResult pr = r.getProperties().lookup(predicate);
if (null == pr) {
NoSuchPropertyResult nspr = new NoSuchPropertyResult(FresnelUtilities.dupURI(predicate), selector, r);
nspr.setTitle(resolveLabel(in, predicate));
r.addProperty(nspr);
this._propertyResultModelHash.putResult(FresnelUtilities.dupURI(predicate), nspr);
RepositoryConnection nconn = this._notModel.getConnection();
nconn.add(FresnelUtilities.dupResource(focus), FresnelUtilities.dupURI(predicate), new LiteralImpl("empty"));
nconn.close();
} // if it's not null, there's nothing to do
}
}
}
while (selects.hasNext()) {
Statement selected = selects.next();
RepositoryConnection mconn = this._model.getConnection();
mconn.add(selected.getSubject(), selected.getPredicate(), selected.getObject(), selected.getContext());
mconn.commit();
mconn.close();
URI predicate;
boolean inverse = !selected.getSubject().equals(focus);
Value object = inverse ? selected.getSubject() : selected.getObject();
if (selector instanceof PropertyDescription && ((PropertyDescription)selector).getProperty() instanceof FSESelector) {
predicate = new URIImpl("fsl://" + ((FSESelector)((PropertyDescription)selector).getProperty()).get_fse());
}
else
predicate = selected.getPredicate();
PropertyResult pr = r.getProperties().lookup(predicate, inverse);
if (null == pr) {
pr = new PropertyResult(FresnelUtilities.dupURI(predicate), selector, r, inverse);
pr.setTitle(resolveLabel(in, predicate));
r.addProperty(pr);
// this._propertyResultModelHash.putResult(FresnelUtilities.dupURI(predicate), pr);
} else {
// if somehow this property was already marked as NoSuchProperty, then
// replace it with a real result
if (!pr.isInModel()) {
r.getProperties().removePropertyResult(pr);
pr = new PropertyResult(FresnelUtilities.dupURI(predicate), selector, r);
pr.setTitle(resolveLabel(in, predicate));
r.addProperty(pr);
// this._propertyResultModelHash.putResult(FresnelUtilities.dupURI(predicate), pr);
}
}
// cb
this._propertyResultModelHash.putResult(FresnelUtilities.dupURI(predicate), pr);
if (object instanceof Resource) {
Resource objResource = (Resource) object;
Result subr = new Result(FresnelUtilities.dupResource(objResource), group, lens, in);
Iterator<Statement> types = r.getTypesStatements();
RepositoryConnection tmconn = this._typesModel.getConnection();
tmconn.setAutoCommit(false);
while(types.hasNext()) {
Statement s = types.next();
tmconn.add(s.getSubject(), s.getPredicate(), s.getObject(), s.getContext());
}
tmconn.commit();
tmconn.setAutoCommit(true);
tmconn.close();
if (selector instanceof PropertyDescription) {
PropertyDescription selectorPD = (PropertyDescription) selector;
if (current == max) {
// if we've hit the limit, stop with sublensing
subr.setTitle(resolveLabel(in, objResource));
} else {
// pick a sublens to apply to the resource
int newdepth = (selectorPD.getDepth() + current < max) ? selectorPD.getDepth() + current : max;
Lens sublens = null;
Iterator<Lens> sublensesIt = selectorPD.getSublensesIterator();
boolean match = false;
matched:
while (sublensesIt.hasNext()) {
sublens = sublensesIt.next();
Iterator<ISelector> domainIt = sublens.getDomainSet().iterator();
while (domainIt.hasNext()) {
ISelector subdomain = domainIt.next();
if (subdomain.canSelect(in, objResource)) {
subr = applyLens(group, in, sublens, objResource, current + 1, newdepth);
match = true;
break matched;
}
}
}
if (!match) {
// if none of the specified sublenses fit, check for other matches
LensMatchSet lenses = this._conf.getLensMatches().getMatch(objResource);
if (null != lenses && !lenses.isEmpty()) {
sublens = lenses.topMatch();
subr = applyLens(group, in, sublens, objResource, current + 1, max);
} else {
// or if no lenses fit, turn it into a label
subr.setTitle(resolveLabel(in, objResource));
}
}
}
} else {
subr.setTitle(resolveLabel(in, objResource));
}
this._resultModelHash.putResult(FresnelUtilities.dupResource(objResource), subr);
ValueResult vr = new ValueResult(subr, pr, selected.getContext());
this._valueResultModelHash.putResult(FresnelUtilities.dupResource(objResource), vr);
pr.addValue(vr,in);
} /* instanceof Resource */
else {
Literal objLiteral = (Literal) object;
ValueResult vr = new ValueResult(objLiteral.getLabel(), pr, selected.getContext());
this._valueResultModelHash.putResult((Literal) FresnelUtilities.dupValue(objLiteral), vr);
pr.addValue(vr);
}
}
} catch (InvalidResultSetException e) {
//
} catch (RepositoryException sue) {
System.err.println("Could not add to repository: " + sue);
return null;
}
}
}
return r;
}
/**
* Dispatching method to apply a format depending which type is being formatted
*
* @param group The <code>Group</code> to work with
* @param format The <code>Format</code> to use
* @param focus The <code>Object</code> to format
* @param type The <code>int</code> type as specified by the class constants
* @return Success or failure
*/
public boolean applyFormat(Group group, Format format, Object focus, int type, Repository in) {
// by contrast, do not use a formatting if it's not in the right group
boolean success = true;
switch(type) {
case RESOURCE:
applyFormat(group, format, (Resource) focus);
break;
case PROPERTY:
applyFormat(group, format, (URI) focus, in);
break;
case LABEL:
applyLabelFormat(group, format, (PropertyResult) focus);
break;
case VALUE:
applyValueFormat(group, format, (PropertyResult) focus);
break;
default:
success = false;
break;
}
return success;
}
/**
* Applies a label lens to get a result in return.
*
* @param lens The label <code>Lens</code>
* @param in Data source <code>Repository</code>
* @param focus The selected <code>Resource</code>
* @param current The current recursion depth, an <code>int</code>
* @param max The maximum recursion depth, an <code>int</code>
* @return An appropriate <code>Result</code> that can be rendered as a label
*/
public Result applyLabelLens(Lens lens, Repository in, Resource focus, int current, int max) {
Result r = new Result(FresnelUtilities.dupResource(focus), null, lens, in);
try {
Iterator<Statement> it = r.getTypesStatements();
RepositoryConnection conn = this._typesModel.getConnection();
conn.setAutoCommit(false);
while (it.hasNext()) {
Statement s = it.next();
conn.add(s.getSubject(), s.getPredicate(), s.getObject(), s.getContext());
}
conn.commit();
conn.setAutoCommit(true);
conn.close();
} catch (RepositoryException sue) {
System.err.println("Could not add to repository: " + sue);
return null;
}
PropertySet finalProperties = resolvePropertySet(lens, in, focus);
Iterator<ISelector> focusPSI = finalProperties.iterator();
this._resultModelHash.putResult(FresnelUtilities.dupResource(focus), r);
while (focusPSI.hasNext()) {
ISelector selector = focusPSI.next();
if (selector.canSelectStatements()) {
try {
Iterator<Statement> selects = selector.selectStatements(in, focus);
while (selects.hasNext()) {
Statement selected = selects.next();
RepositoryConnection mconn = this._model.getConnection();
mconn.add(FresnelUtilities.dupResource(selected.getSubject()),
FresnelUtilities.dupURI(selected.getPredicate()),
FresnelUtilities.dupValue(selected.getObject()));
mconn.commit();
mconn.close();
URI prop = FresnelUtilities.dupURI(selected.getPredicate());
Value object = selected.getObject();
PropertyResult pr = r.getProperties().lookup(prop);
if (null == pr) {
pr = new PropertyResult(prop, selector, r);
r.addProperty(pr);
}
if (object instanceof Resource) {
Resource objResource = (Resource) object;
if (selector instanceof PropertyDescription) {
PropertyDescription selectorPD = (PropertyDescription) selector;
if (current == max) {
ValueResult vr = new ValueResult(resolveLabel(in, objResource, false).getString(), pr, selected.getContext());
pr.addValue(vr);
this._propertyResultModelHash.putResult(prop, pr);
} else {
// pick a sublens to apply to the resource
int newdepth = (selectorPD.getDepth() + current < max) ? selectorPD.getDepth() : max;
Lens sublens = null;
Iterator<Lens> sublensesIt = selectorPD.getSublensesIterator();
boolean matched = false;
matching:
while (sublensesIt.hasNext()) {
sublens = sublensesIt.next();
Iterator<ISelector> domainIt = sublens.getDomainSet().iterator();
while (domainIt.hasNext()) {
ISelector subdomain = domainIt.next();
if (subdomain.canSelect(in, objResource)) {
Result subr = applyLabelLens(sublens, in, objResource, current + 1, newdepth);
ValueResult vr = new ValueResult(subr, pr, selected.getContext());
pr.addValue(vr);
this._propertyResultModelHash.putResult(prop, pr);
matched = true;
break matching;
}
}
}
if (!matched) {
// if none of the specified sublenses fit, check for other matches
LensMatchSet lenses = this._conf.getLensMatches().getMatch(objResource);
if (null != lenses) {
sublens = lenses.topMatch();
Result subr = applyLabelLens(sublens, in, objResource, current + 1, max);
ValueResult vr = new ValueResult(subr, pr, selected.getContext());
pr.addValue(vr);
this._propertyResultModelHash.putResult(prop, pr);
} else {
// or if no lenses fit, turn it into a label
ValueResult vr = new ValueResult(resolveLabel(in, objResource, false).getString(), pr, selected.getContext());
pr.addValue(vr);
this._propertyResultModelHash.putResult(prop, pr);
}
}
}
} else {
// if not a sublens situation, check for other matches
LensMatchSet lenses = this._conf.getLensMatches().getMatch(objResource);
if (null != lenses) {
Result subr = applyLabelLens(lenses.topMatch(), in, objResource, current + 1, max);
ValueResult vr = new ValueResult(subr, pr, selected.getContext());
pr.addValue(vr);
this._propertyResultModelHash.putResult(prop, pr);
} else {
// or if no lenses fit, turn it into a label
ValueResult vr = new ValueResult(resolveLabel(in, objResource, false).getString(), pr, selected.getContext());
pr.addValue(vr);
this._propertyResultModelHash.putResult(prop, pr);
}
}
} else {
Literal objLiteral = (Literal) object;
ValueResult vr = new ValueResult(objLiteral.getLabel(), pr, selected.getContext());
pr.addValue(vr);
this._propertyResultModelHash.putResult(prop, pr);
}
}
} catch (InvalidResultSetException e) {
//
} catch (RepositoryException sue) {
System.err.println("Could not add to repository: " + sue);
return null;
}
}
}
return r;
}
/**
* Look in the source and ontologies model for a resource's label.
*
* @param in Data source <code>Repository</code>
* @param focus The <code>Resource</code> whose label is being sought
* @param lens If the algorithm should look into lenses for labelling information or not
* @return A <code>Title</code> label for the resource
*/
protected Title resolveLabel(Repository in, Resource focus, boolean lens, String label) {
if (null != label) return new Title(label);
Resource focusType = (Resource) FresnelUtilities.getType(in, focus);
// this is ugly, but to not waste resources, it really needs the 'return' statements to
// return ASAP
LensMatchSet lenses = this._conf.getLensMatches().getMatch(focus);
LensMatchSet instanceLenses = this._conf.getInstanceLensMatches().getMatch(focus);
LensMatchSet classLenses = this._conf.getClassLensMatches().getMatch(focusType);
if (lens) {
if (null != lenses) {
// find label lens for resource
Iterator<Lens> instancesIt = lenses.getInstanceLenses().iterator();
while (instancesIt.hasNext()) {
Lens check = instancesIt.next();
if (check.hasPurpose(new Purpose(FresnelCore.labelLens))) {
AggregateLabel labels = new AggregateLabel(applyLabelLens(check, in, focus, 0, MAXIMUM_LENS_DEPTH));
if (labels.getString().trim().equals(""))
continue;
else
return new Title(labels);
}
}
// find label lens for resource's type
Iterator<Lens> classesIt = lenses.getClassLenses().iterator();
while (classesIt.hasNext()) {
Lens check = classesIt.next();
if (check.hasPurpose(new Purpose(FresnelCore.labelLens))) {
AggregateLabel labels = new AggregateLabel(applyLabelLens(check, in, focus, 0, MAXIMUM_LENS_DEPTH));
if (labels.getString().trim().equals(""))
continue;
else
return new Title(labels);
}
}
}
if (null != instanceLenses) {
// find label lens for resource
Iterator<Lens> instancesIt = instanceLenses.getInstanceLenses().iterator();
while (instancesIt.hasNext()) {
Lens check = instancesIt.next();
if (check.hasPurpose(new Purpose(FresnelCore.labelLens))) {
AggregateLabel labels = new AggregateLabel(applyLabelLens(check, in, focus, 0, MAXIMUM_LENS_DEPTH));
if (labels.getString().trim().equals(""))
continue;
else
return new Title(labels);
}
}
}
if (null != classLenses) {
// find label lens for resource
Iterator<Lens> classesIt = classLenses.getClassLenses().iterator();
while (classesIt.hasNext()) {
Lens check = classesIt.next();
if (check.hasPurpose(new Purpose(FresnelCore.labelLens))) {
AggregateLabel labels = new AggregateLabel(applyLabelLens(check, in, focus, 0, MAXIMUM_LENS_DEPTH));
if (labels.getString().trim().equals(""))
continue;
else
return new Title(labels);
}
}
}
}
Iterator<Statement> labelIt = this._conf.getOntologyLabels(focus, RDFS.LABEL);
while (labelIt.hasNext()) {
Statement labelSt = labelIt.next();
if (((Literal) labelSt.getObject()).getLabel().trim().equals(""))
continue;
else {
return new Title(((Literal) labelSt.getObject()).getLabel());
}
}
labelIt = this._conf.getOntologyLabels(focus, new URIImpl(DCTITLE));
while (labelIt.hasNext()) {
Statement labelSt = labelIt.next();
if (((Literal) labelSt.getObject()).getLabel().trim().equals(""))
continue;
else {
return new Title(((Literal) labelSt.getObject()).getLabel());
}
}
/* Get labels from the input repository */
try {
String resLabel = null;
boolean matchesPreferredLanguage = false;
String[] knownLabels = {
"http://xmlns.com/foaf/0.1/name",
"http://www.w3.org/2000/01/rdf-schema#label",
"http://purl.org/dc/elements/1.1/title",
"http://usefulinc.com/ns/doap#name",
"http://www.geonames.org/ontology#name"
};
RepositoryConnection conn = in.getConnection();
for (String labelPredicate : knownLabels) {
RepositoryResult<Statement> it = conn.getStatements(focus, new URIImpl(labelPredicate), (Value) null, true);
while (!matchesPreferredLanguage && it.hasNext()) {
Statement st = it.next();
if (st != null && st.getObject() instanceof Literal) {
Literal lit = ((Literal)st.getObject());
if (lit.getLanguage() != null && lit.getLanguage().equals(_langPref))
matchesPreferredLanguage = true;
/* Take the first label, or the first one in the preferred language */
if (resLabel == null || matchesPreferredLanguage)
resLabel = lit.getLabel();
}
}
it.close();
if (matchesPreferredLanguage)
break;
}
conn.close();
if (resLabel != null)
return new Title(resLabel);
}
catch (RepositoryException e) {
e.printStackTrace();
}
if (!(focus instanceof BNode)) {
// try to truncate the URI?
return new Title(((URI) focus).toString(), true);
} else
return new Title(((BNode)focus).getID(), true); //return new Title("(anonymous node)", true);
}
/**
* Default behavior for label resolution is to look into label lenses.
*
* @param in Data source <code>Repository</code>
* @param focus The <code>Resource</code> whose label is being sought
* @param lens <code>boolean</code> indicator of whether to use lenses or not.
* @return A <code>Title</code> label for the resource
*/
protected Title resolveLabel(Repository in, Resource focus, boolean lens) {
return resolveLabel(in, focus, lens, null);
}
/**
* Default behavior for label resolution is to look into label lenses.
*
* @param in The data <code>Repository</code>
* @param focus The <code>Resource</code> whose label is being sought
* @return A <code>Title</code> label for the resource
*/
protected Title resolveLabel(Repository in, Resource focus) {
return resolveLabel(in, focus, true, null);
}
/**
* Resolve the property sets to a final ordered list of what will show up.
*
* @param lens The <code>Lens</code> with selection information
* @param in The <code>Repository</code> with all the data
* @param focus The <code>Resource</code> to resolve
* @return A <code>PropertySet</code> of properties to select.
*/
protected PropertySet resolvePropertySet(Lens lens, Repository in, Resource focus) {
PropertySet properties = new PropertySet();
PropertySet hide = lens.getHideProperties();
PropertySet show = lens.getShowProperties();
if (show.seenAllProperties()) {
try {
RepositoryConnection conn = in.getConnection();
RepositoryResult<Statement> focusProperties = conn.getStatements(focus, (URI) null, (Value) null, true);
RepositoryResult<Statement> focusPropertiesInverse = conn.getStatements(null, (URI) null, focus, true);
Iterator<ISelector> showPSI = show.iterator();
while (showPSI.hasNext()) {
ISelector selector = showPSI.next();
if (AllPropertiesSelector.isAllProperties(selector)) {
// get all properties and check if in hidden properties
while (focusProperties.hasNext() || focusPropertiesInverse.hasNext()) {
Statement st = (focusProperties.hasNext() ? focusProperties.next() : focusPropertiesInverse.next());
URI maybeAdd = FresnelUtilities.dupURI(st.getPredicate());
PropertySelector maybeAddSelector = new PropertySelector(maybeAdd);
if (hide.size() > 0) {
if (!hide.containsSelector(maybeAddSelector)
&& !properties.containsSelector(maybeAddSelector)) {
properties.addSelector(maybeAddSelector);
}
} else {
if (!properties.containsSelector(maybeAddSelector)) {
properties.addSelector(maybeAddSelector);
}
}
}
} else {
if (selector instanceof PropertySelector) {
if (!properties.containsSelector((PropertySelector) selector)) {
properties.addSelector(selector);
}
} else {
properties.addSelector(selector);
}
}
}
focusProperties.close();
focusPropertiesInverse.close();
conn.close();
} catch (RepositoryException e) {
// TODO: how to handle this exception
}
} else {
properties = show;
}
return properties;
}
/**
* Apply formatting to a resource.
*
* @param grouping Use from this <code>Group</code>
* @param format Use this <code>Format</coe>
* @param focus On this <code>Resource</code>
*/
protected void applyFormat(Group grouping, Format format, Resource focus) {
// lookup the results that use this resource focus and apply this to all of them
Iterator<Result> it = this._resultModelHash.getResultIterator(focus);
while (it.hasNext()) {
Result r = (Result) it.next();
// get any group-scope styling
if (grouping.getResourceStyle().size() > 0) {
Iterator<Style> sit = grouping.getResourceStyle().iterator();
String classes = "";
while(sit.hasNext()) {
// N.B.: if styles were ever expanded to be more than strings, here would
// be a good place to make that adaptation
classes += sit.next().getString();
}
r.setStyles(classes.trim());
}
// get any group-scope content
if (grouping.getResourceFormat().size() > 0) {
// there should only be one FormatDescription...
Iterator<FormatDescription> fdit = grouping.getResourceFormat().iterator();
if (fdit.hasNext()) {
r.setContents(fdit.next().getContentSet());
}
}
// process format argument for style
if (format.getResourceStyle().size() > 0) {
Iterator<Style> sit = format.getResourceStyle().iterator();
String classes = r.getStyles() + " ";
while(sit.hasNext()) {
// N.B.: if styles were ever expanded to be more than strings, here would
// be a good place to make that adaptation
classes += sit.next().getString();
}
r.setStyles(classes.trim());
}
// process format argument for content
if (format.getResourceFormat().size() > 0) {
// there should only be one FormatDescription...
Iterator<FormatDescription> fdit = format.getResourceFormat().iterator();
if (fdit.hasNext()) {
r.setContents(fdit.next().getContentSet());
}
}
}
}
/**
* Apply formatting to a property result.
*
* @param grouping Use from this <code>Group</code>
* @param format Use this <code>Format</code>
* @param focus Apply to this property <code>URI</code>
*/
protected void applyFormat(Group grouping, Format format, URI focus, Repository in) {
Iterator<PropertyResult> it = this._propertyResultModelHash.getResultIterator(focus);
while (it.hasNext()) {
PropertyResult r = (PropertyResult) it.next();
// get any group-global styling
if (grouping.getPropertyStyle().size() > 0) {
Iterator<Style> sit = grouping.getPropertyStyle().iterator();
String classes = "";
while(sit.hasNext()) {
// N.B.: if styles were ever expanded to be more than strings, here would
// be a good place to make that adaptation
classes += sit.next().getString() + " ";
}
r.setStyles(classes.trim());
}
// get any group-scope content
if (grouping.getPropertyFormat().size() > 0) {
// there should only be one FormatDescription...
Iterator<FormatDescription> fdit = grouping.getPropertyFormat().iterator();
if (fdit.hasNext()) {
r.setContents(fdit.next().getContentSet());
}
}
// get any lens-specified (property description) formatting, use instead of
// passed in format if necessary
Lens parent = r.getParent().getLens();
Iterator<ISelector> psi = parent.getShowProperties().iterator();
while (psi.hasNext()) {
ISelector check = psi.next();
if (check.canSelect(in, r.getParent().getOrigin(), r.getOrigin())) {
if (check instanceof PropertyDescription) {
PropertyDescription pd = (PropertyDescription) check;
if (pd.isGroupUse()) {
// pick which format to use...
Group groupFormats = (Group) pd.getUse();
Iterator<Format> fi = groupFormats.getFormats().iterator();
while (fi.hasNext()) {
Format potential = fi.next();
for (Iterator<ISelector> di = potential.getDomainSet().iterator(); di.hasNext(); ) {
ISelector potentialCheck = di.next();
if (potentialCheck.canSelect(getModel(), r.getParent().getOrigin(), r.getOrigin())) {
format = potential;
break;
}
}
}
} else {
if (null != pd.getUse()) {
format = (Format) pd.getUse();
break;
}
}
}
}
}
// process format argument for style
if (null != format.getPropertyStyle()) {
Iterator<Style> sit = format.getPropertyStyle().iterator();
String classes = (r.getStyles() != null) ? r.getStyles() + " " : "";
while(sit.hasNext()) {
// N.B.: if styles were ever expanded to be more than strings, here would
// be a good place to make that adaptation
classes += sit.next().getString() + " ";
}
r.setStyles(classes.trim());
}
// process format argument for content
if (null != format.getPropertyFormat()) {
// there should only be one FormatDescription...
Iterator<FormatDescription> fdit = format.getPropertyFormat().iterator();
if (fdit.hasNext()) {
r.setContents(fdit.next().getContentSet());
}
}
// call label and value format using the right format
applyFormat(grouping, format, r, LABEL, in);
applyFormat(grouping, format, r, VALUE, in);
}
}
/**
* Apply formatting to property labels.
*
* @param grouping Use those found in this <code>Group</code>
* @param format Use this <code>Format</code>
* @param pr Associated with this <code>PropertyResult</code>
*/
protected void applyLabelFormat(Group grouping, Format format, PropertyResult pr) {
// get any group-global styling
if (grouping.getLabelStyle().size() > 0) {
Iterator<Style> it = grouping.getLabelStyle().iterator();
String classes = "";
while(it.hasNext()) {
// N.B.: if styles were ever expanded to be more than strings, here would
// be a good place to make that adaptation
classes += it.next().getString() + " ";
}
pr.setLabelStyles(classes.trim());
}
// get any group-scope content
if (grouping.getLabelFormat().size() > 0) {
// there should only be one FormatDescription...
Iterator<FormatDescription> fdit = grouping.getLabelFormat().iterator();
if (fdit.hasNext()) {
pr.setLabelContents(fdit.next().getContentSet());
}
}
// process format argument for style
if (null != format.getLabelStyle()) {
Iterator<Style> sit = format.getLabelStyle().iterator();
String classes = (pr.getLabelStyles() != null) ? pr.getLabelStyles() + " " : "";
while(sit.hasNext()) {
// N.B.: if styles were ever expanded to be more than strings, here would
// be a good place to make that adaptation
classes += sit.next().getString() + " ";
}
pr.setLabelStyles(classes.trim());
}
// process format argument for content
if (null != format.getLabelFormat()) {
// there should only be one FormatDescription...
Iterator<FormatDescription> fdit = format.getLabelFormat().iterator();
if (fdit.hasNext()) {
pr.setContents(fdit.next().getContentSet());
}
}
// change the label depending on fresnel:label settings
if (!format.getLabel().isShown()) {
pr.setShowLabel(false);
} else if (format.getLabel().isShown() && format.getLabel().isString()) {
pr.setTitle(new Title(format.getLabel().getString()));
}
//handle missing label title
if ((null == pr.getTitle() || pr.getTitle().getString().trim().equals(""))
&& (null != pr.getContents().getReplacement()
&& !pr.getContents().getReplacement().trim().equals(""))) {
pr.setTitle(new Title(pr.getContents().getReplacement()));
}
}
/**
* Apply formatting to a set of values.
*
* @param grouping Use those found in this <code>Group</code>
* @param format Use this <code>Format</code>
* @param pr Start from this <code>PropertyResult</code>
*/
protected void applyValueFormat(Group grouping, Format format, PropertyResult pr) {
String classes = "";
// get any group-global styling
if (grouping.getValueStyle().size() > 0) {
Iterator<Style> it = grouping.getValueStyle().iterator();
while(it.hasNext()) {
// N.B.: if styles were ever expanded to be more than strings, here would
// be a good place to make that adaptation
classes += it.next().getString();
}
classes = classes.trim();
Iterator<ValueResult> vrit = pr.getValues().valueResultIterator();
while (vrit.hasNext()) {
vrit.next().setStyles(classes);
}
}
// get any group-scope content
if (grouping.getValueFormat().size() > 0) {
// there should only be one FormatDescription...
Iterator<FormatDescription> fdit = grouping.getValueFormat().iterator();
if (fdit.hasNext()) {
pr.getValues().setContents(fdit.next().getContentSet());
}
}
// process format argument for style
if (null != format.getValueStyle()) {
Iterator<Style> sit = format.getValueStyle().iterator();
classes += " ";
while(sit.hasNext()) {
// N.B.: if styles were ever expanded to be more than strings, here would
// be a good place to make that adaptation
classes += sit.next().getString();
}
Iterator<ValueResult> vrit = pr.getValues().valueResultIterator();
while (vrit.hasNext()) {
vrit.next().setStyles(classes.trim());
}
}
// process format argument for content
if (null != format.getValueFormat()) {
// there should only be one FormatDescription...
Iterator<FormatDescription> fdit = format.getValueFormat().iterator();
if (fdit.hasNext()) {
pr.getValues().setContents(fdit.next().getContentSet());
}
}
// indicate what type the value is based on fresnel:value
String kind = null;
if (format.getValueType().isImage()) {
kind = "image";
} else if (format.getValueType().isURI()) {
kind = "uri";
} else if (format.getValueType().isLink()) {
kind = "link";
}
Iterator<ValueResult> vrit = pr.getValues().valueResultIterator();
while (vrit.hasNext()) {
vrit.next().setOutputType(kind);
}
}
/**
* Renders the entire selection to the Fresnel XML tree output as DOM.
*
* @return A <code>Document</code>, e.g.: <results> ... </results>
*/
public Document render() throws ParserConfigurationException {
// TODO: ordering
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document out = db.newDocument();
Element root = out.createElementNS(INTERMEDIATE_NS, "results");
for(Iterator<Result> it = this._results.iterator(); it.hasNext(); ) {
root.appendChild(it.next().render(out));
}
out.appendChild(root);
return out;
}
// Ideally this would simply generate events without bothering to render the document
// to a DOM model first. Ideally.
/**
* Renders the entire selection into a SAX stream of events conforming to the
* Fresnel output XML Schema.
*
* @param handler For handling SAX events
* @throws SAXException
*/
public void events(ContentHandler handler) throws SAXException {
try {
Document d = render();
DOMSource in = new DOMSource(d);
SAXResult res = new SAXResult(handler);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serial = tf.newTransformer();
serial.setOutputProperty(OutputKeys.INDENT, "yes");
serial.transform(in, res);
} catch (Exception e) {
throw new SAXException(e);
}
}
}