/* * Created on Apr 11, 2005 */ package edu.mit.simile.fresnel.selection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; 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.repository.Repository; import org.openrdf.repository.RepositoryConnection; import org.openrdf.repository.RepositoryException; import org.openrdf.repository.RepositoryResult; import edu.mit.simile.fresnel.FresnelCoreTypes; import edu.mit.simile.fresnel.FresnelResource; import edu.mit.simile.fresnel.configuration.Configuration; import edu.mit.simile.fresnel.configuration.Group; import edu.mit.simile.fresnel.format.Format; import edu.mit.simile.vocabularies.FresnelCore; import fr.inria.jfresnel.fsl.FSLPath; /** * Used for describing more about how a property is selected * in a lens; core terms involve the sublens and which style * should directly be used. * * @author ryanlee */ public class PropertyDescription extends FresnelResource implements ISelector { /** * Resource of schema class */ protected static final Resource _schemaResource = FresnelCore.PropertyDescription; /** * Identifier for a PropertyDescription instance. */ private Resource _id; /** * The selector for the property the description describes. */ private ISelector _propertySelector; /** * The set of sublenses that should be used with the property's objects. */ private Set<Lens> _sublenses; /** * The maximum recursion depth the sublens application can reach. */ private int _depth; /** * Default maximum recursion depth. */ private static final int DEFAULT_MAX_DEPTH = 3; /** * The group of styles that should be used with this description. */ private Group _groupUse; /** * The single lens that should be used with this description. */ private Format _formatUse; /** * This selector class can return statements. */ private boolean _statements = true; /** * This selector class cannot return resources. */ private boolean _resources = false; /** * This selector class cannot return nodes. */ private boolean _nodes = false; /** * Context for determining FSL first location step type. */ protected final static short _fslContext = FSLPath.ARC_STEP; /** * Constructor taking an identifier for the property description. * * @param identifier A unique <code>Resource</code> */ public PropertyDescription(Resource identifier) { setIdentifier(identifier); this._sublenses = new HashSet<Lens>(); } /** * Returns the instance identifier. * * @return A <code>Resource</code> identifier. */ public Resource getIdentifier() { return this._id; } /** * Returns the property selector being described. * * @return A property <code>ISelector</code> */ public ISelector getProperty() { return this._propertySelector; } /** * Returns the maximum recursion depth that can be attained in sublensing. * * @return An <code>int</code> depth. */ public int getDepth() { return this._depth; } /** * Returns the set of sublenses associated with this description. * * @return A <code>LensSet</code> of sublenses. */ public Set<Lens> getSublenses() { return this._sublenses; } /** * Return an iterator over sublenses. * * @return A <code>LensIterator</code> */ public Iterator<Lens> getSublensesIterator() { return this._sublenses.iterator(); } /** * Return the style usage for the property. * * @return An <code>Object</code> * @see edu.mit.simile.fresnel.selection.PropertyDescription#isGroupUse() */ public Object getUse() { return (null != this._groupUse) ? (Object) this._groupUse : (Object) this._formatUse; } /** * Returns whether or not the usage is a group or a single style. * * @return A <code>boolean</code> */ public boolean isGroupUse() { return (null != this._groupUse); } /** * Returns whether or not there is a usage associated with this description. * * @return A <code>boolean</code> */ public boolean hasUse() { return (null != this._groupUse || null != this._formatUse); } /** * Returns whether or not there are sublenses associated with this description. * * @return A <code>boolean</code> */ public boolean hasSublens() { return (null != this._sublenses); } /** * Sets the identifier for the instance of a description. * * @param id A unique <code>Resource</code> */ protected void setIdentifier(Resource id) { this._id = id; } /** * Sets the property selector this instance describes * * @param prop A property <code>ISelector</code> */ public void setProperty(ISelector propertySelector) { this._propertySelector = propertySelector; } /** * Sets the maximum recursion depth. * * @param depth An <code>int</code> */ public void setDepth(int depth) { this._depth = depth; } /** * Sets the sublens set used in this description. * * @param sub A <code>LensSet</code> */ public void setSublenses(Set<Lens> sub) { this._sublenses = sub; } /** * Appends a sublens to the set of sublenses. * * @param sub A <code>Lens</code> */ public void addSublens(Lens sub) { this._sublenses.add(sub); } /** * Sets the style group to use with the property description. * * @param use A <code>Group</code> with styles */ public void setGroupUse(Group use) { this._groupUse = use; } /** * Sets the format to use with the property description. * * @param use A <code>Format</code> */ public void setFormatUse(Format use) { this._formatUse = use; } /** * Parses a fresnel:PropertyDescription. * * @param lens A <code>Lens</code> (the lens being parsed) * @param in The <code>Repository</code> containing the configuration * @param selected The <code>Resource</code> that is a property description * @param conf The <code>Configuration</code>, for lookups of existing resources * @return A <code>PropertyDescription</code> * @throws UnresolvableException When too many predicates are used beyond their * OWL cardinality restriction * @throws ParsingException When an improper model form is used in configuration */ public static PropertyDescription parse(Lens lens, Repository in, Resource selected, Configuration conf) throws UnresolvableException, ParsingException, ResourceNotFoundException { PropertyDescription out = new PropertyDescription(selected); try { RepositoryConnection conn = in.getConnection(); RepositoryResult<Statement> pdSI = conn.getStatements(selected, FresnelCore.property, (Value) null, false); while (pdSI.hasNext()) { Statement stmt = (Statement) pdSI.next(); if (pdSI.hasNext()) throw new UnresolvableException("More than one fresnel:property predicate used."); Value obj = stmt.getObject(); ISelector selector = null; // Evaluate the selector type for a property if (obj instanceof Resource) { // This is a type selector selector = new PropertySelector((URI) obj); out.setProperty(selector); } else if (obj instanceof Literal) { Literal domainL = (Literal) obj; // TODO: catch bad expressions? throw exceptions? if (domainL.getDatatype().equals(FresnelCoreTypes.fslSelector)) { selector = new FSESelector(domainL.getLabel(), _fslContext, conf.getNamespaceMap()); out.setProperty(selector); } if (domainL.getDatatype().equals(FresnelCoreTypes.sparqlSelector)) { selector = new SPARQLSelector(domainL.getLabel(), conf.getNamespaces()); out.setProperty(selector); } } else { throw new ParsingException("Expected but did not find a resource value for fresnel:property"); } } pdSI.close(); pdSI = conn.getStatements(selected, FresnelCore.sublens, (Value) null, false); while (pdSI.hasNext()) { Statement stmt = (Statement) pdSI.next(); Value obj = stmt.getObject(); if (obj instanceof Resource) { Resource objRes = (Resource) obj; Lens sublens = (!objRes.equals(lens.getIdentifier())) ? conf.lensLookup(objRes) : lens; out.addSublens(sublens); } else if (obj instanceof Literal) { // you could implement a fresnel-querying component for finding lenses here // we chose not to } else { throw new ResourceNotFoundException("Expected but did not find a resource value for fresnel:sublens"); } } pdSI.close(); pdSI = conn.getStatements(selected, FresnelCore.depth, (Value) null, false); if (!pdSI.hasNext()) out.setDepth(DEFAULT_MAX_DEPTH); while (pdSI.hasNext()) { Statement stmt = (Statement) pdSI.next(); if (pdSI.hasNext()) throw new UnresolvableException("More than one fresnel:depth predicate used."); Value obj = stmt.getObject(); if (obj instanceof Literal && Integer.parseInt(((Literal) stmt.getObject()).getLabel()) >= 0) { out.setDepth(Integer.parseInt(((Literal) stmt.getObject()).getLabel())); } else { throw new ParsingException("Expected but did not find a non-negative integer value for fresnel:depth"); } } pdSI.close(); pdSI = conn.getStatements(selected, FresnelCore.use, (Value) null, false); while (pdSI.hasNext()) { Statement stmt = (Statement) pdSI.next(); if (pdSI.hasNext()) throw new UnresolvableException("More than one fresnel:use predicate used."); Value obj = stmt.getObject(); if (obj instanceof Resource) { Resource objRes = (Resource) obj; try { Group objGroup = conf.groupLookupOrAdd(objRes); out.setGroupUse(objGroup); } catch (ResourceNotFoundException e) { // if not a group, try a format try { Format objFormat = conf.formatLookup(objRes); out.setFormatUse(objFormat); } catch (ResourceNotFoundException re) { // if not a style, there's nothing to fall back to throw new ParsingException("Failed to find useful description of fresnel:use object: " + ((URI) objRes).toString()); } } } else { throw new ParsingException("Expected but did not find a resource value for fresnel:use"); } } pdSI.close(); conn.close(); } catch (RepositoryException e) { // TODO: how to handle this exception } return out; } /** * @see edu.mit.simile.fresnel.selection.ISelector#selectStatements(Repository, Resource) */ public Iterator<Statement> selectStatements(Repository in, Resource selected) throws InvalidResultSetException { Iterator<Statement> si = _propertySelector.selectStatements(in, selected); return si; } /** * @see edu.mit.simile.fresnel.selection.ISelector#canSelectStatements() */ public boolean canSelectStatements() { return this._statements; } /** * @see edu.mit.simile.fresnel.selection.ISelector#selectResources(Repository) */ public Iterator<Resource> selectResources(Repository in) throws InvalidResultSetException { throw new InvalidResultSetException("PropertyDescription cannot be used to select resources"); } /** * @see edu.mit.simile.fresnel.selection.ISelector#canSelectResources() */ public boolean canSelectResources() { return this._resources; } /** * @see edu.mit.simile.fresnel.selection.ISelector#selectNodes(Repository) */ public Iterator<Value> selectNodes(Repository in) throws InvalidResultSetException { throw new InvalidResultSetException("PropertyDescription cannot be used to select object nodes"); } /** * @see edu.mit.simile.fresnel.selection.ISelector#canSelectNodes() */ public boolean canSelectNodes() { return this._nodes; } /** * @see edu.mit.simile.fresnel.selection.ISelector#canSelect(Repository, Resource, URI) */ public boolean canSelect(Repository in, Resource selected, URI prop) { boolean out = false; out = _propertySelector.canSelect(in, selected, prop); return out; } /** * @see edu.mit.simile.fresnel.selection.ISelector#canSelect(Repository, Resource) */ public boolean canSelect(Repository in, Resource selected) { boolean out = false; out = _propertySelector.canSelect(in, selected); return out; } /** * @see edu.mit.simile.fresnel.selection.ISelector#canSelect(Repository, Value) */ public boolean canSelect(Repository in, Value selected) { return this._nodes; } /** * @see java.lang.Object#toString() */ public String toString() { String state = " [ISelector:PropertyDescription " + super.toString() + "]\n"; state += " " + this._id + "\n"; state += " property_selector: " + this._propertySelector.toString() + "\n"; state += " depth: " + this._depth + "\n"; state += " " + this._sublenses + "\n"; return state; } }