/*
* Created on Mar 16, 2005
*/
package edu.mit.simile.fresnel.selection;
import java.util.HashSet;
import java.util.Set;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
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 fr.inria.jfresnel.fsl.FSLPath;
import edu.mit.simile.fresnel.FresnelCoreTypes;
import edu.mit.simile.fresnel.FresnelResource;
import edu.mit.simile.fresnel.configuration.Configuration;
import edu.mit.simile.fresnel.purpose.Purpose;
import edu.mit.simile.fresnel.util.RDFList;
import edu.mit.simile.vocabularies.FresnelCore;
/**
* Java representation of the Fresnel owl:Class :Lens.
* As per the schema, a Lens specifies what parts of a model
* to select via the :lensDomain (resources encompassed by the
* ISelector) and which properties of matching resources to
* display via the :showProperties set.
*
* @author ryanlee
*/
public class Lens extends FresnelResource {
/**
* Context for determining FSL first location step type.
*/
protected final static short _fslContext = FSLPath.NODE_STEP;
/**
* Resource identifying this lens.
*/
protected Resource _identifier;
/**
* Match the domain to a model to choose resources for display.
*/
protected Set<ISelector> _domains;
/**
* Specify the purpose of the lens.
*/
protected Set<Purpose> _purposes;
/**
* The set of properties to display for each matching resource.
*/
protected PropertySet _show;
/**
* The set of properties to display for each matching resource.
*/
protected PropertySet _hide;
/**
* Resource defined in the schema.
*/
protected static final Resource _schemaResource = FresnelCore.Lens;
/**
* Is not an instance lens by default.
*/
private static final boolean IS_INSTANCE = false;
/**
* Empty constructor.
*/
public Lens() {
this._purposes = new HashSet<Purpose>();
this._show = new PropertySet();
this._hide = new PropertySet();
this._domains = new HashSet<ISelector>();
}
/**
* Parses a lens from a model into a <code>Lens</code> object.
*
* @param in The configuration source <code>Grap</code>
* @param selected The <code>Resource</code> defining the lens
* @param conf The <code>Configuration</code> that's parsing out this lens
* @throws ParsingException If semantic errors in use of Fresnel vocabulary exist
* @throws UnresolvableException If cardinality constraints on certain properties are violated
*/
public Lens(Repository in, Resource selected, Configuration conf)
throws ParsingException, UnresolvableException {
this(selected);
try {
// Parse domain
parseDomain(in, selected, conf);
RepositoryConnection conn = in.getConnection();
// Set of purposes
RepositoryResult<Statement> purposesI = conn.getStatements(selected, FresnelCore.purpose, (Value) null, false);
try {
while (purposesI.hasNext()) {
Value purposeNode = purposesI.next().getObject();
if (purposeNode instanceof Resource) {
Resource purposeRes = (Resource) purposeNode;
addPurpose(new Purpose(purposeRes));
} else {
throw new ParsingException(purposeNode.toString() + "could not be used as a :Purpose");
}
}
} finally {
purposesI.close();
}
// Parse the property selections
RepositoryResult<Statement> showI = conn.getStatements(selected, FresnelCore.showProperties, (Value) null, false);
try {
if (showI.hasNext()) {
Statement showStmt = showI.next();
Value showsNode = showStmt.getObject();
if (showI.hasNext()) throw new UnresolvableException("More than one :showProperties value available");
if (showsNode instanceof Resource && RDFList.isRDFList(in, (Resource) showsNode)) {
RDFList showsRDFList = new RDFList(in, (Resource) showsNode);
if (showsRDFList.isValid()) {
setShowProperties(PropertySet.showParse(this, in, showsRDFList, conf));
} else {
throw new ParsingException(showsNode.toString() + "is not a valid rdf:List");
}
} else {
addShowProperty(PropertySet.showPropertyParse(this, in, showsNode, conf));
}
}
} finally {
showI.close();
}
// Parse the property hiding selections
RepositoryResult<Statement> hideI = conn.getStatements(selected, FresnelCore.hideProperties, (Value) null, false);
try {
if (hideI.hasNext()) {
Statement hideStmt = (Statement) hideI.next();
Value hidesNode = hideStmt.getObject();
if (hideI.hasNext()) throw new UnresolvableException("More than one :hideProperties value available");
if (hidesNode instanceof Resource && RDFList.isRDFList(in, (Resource) hidesNode)) {
RDFList hidesRDFList = new RDFList(in, (Resource) hidesNode);
if (hidesRDFList.isValid()) {
setHideProperties(PropertySet.hideParse(this, in, hidesRDFList, conf));
} else {
throw new ParsingException(hidesNode.toString() + "is not a valid rdf:List");
}
} else {
addHideProperty(PropertySet.hidePropertyParse(this, in, hidesNode, conf));
}
}
} finally {
hideI.close();
}
conn.close();
} catch (RepositoryException e) {
throw new UnresolvableException("Problem connecting to repository: " + e.getLocalizedMessage());
}
}
/**
* Construct lens based on identifier.
*
* @param id A <code>Resource</code>
*/
public Lens(Resource id) {
this();
setIdentifier(id);
}
/**
* Construct lens based on lensDomain.
*
* @param domains A <code>DomainSet</code>
*/
public Lens(Set<ISelector> domains) {
this();
setDomainSet(domains);
}
/**
* Returns the resource identifying the lens.
*
* @return A <code>Resource</code>
*/
public Resource getIdentifier() {
return this._identifier;
}
/**
* Returns the lens domain.
*
* @return A <code>ISelector</code>
*/
public Set<ISelector> getDomainSet() {
return this._domains;
}
/**
* Returns the purpose of the lens.
*
* @return A <code>Purpose</code>
*/
public Set<Purpose> getPurposes() {
return this._purposes;
}
/**
* Returns the set of properties used for display.
*
* @return A <code>PropertySet</code> of displayed predicates and values
*/
public PropertySet getShowProperties() {
return this._show;
}
/**
* Returns the set of properties used for hiding things in display.
*
* @return A <code>PropertySet</code> of hidden predicates and values
*/
public PropertySet getHideProperties() {
return this._hide;
}
/**
* Sets the resource identifying this lens.
*
* @param identifier A unique <code>Resource</code>
*/
protected void setIdentifier(Resource identifier) {
this._identifier = identifier;
}
/**
* Sets the lens domain.
*
* @param domains A <code>Set</code> of <code>ISelector</code>s
*/
protected void setDomainSet(Set<ISelector> domains) {
this._domains = domains;
}
/**
* Sets the set of properties to display.
*
* @param show A <code>PropertySet</code>
*/
protected void setShowProperties(PropertySet show) {
this._show = show;
}
/**
* Sets the set of properties to hide.
*
* @param hide A <code>PropertySet</code>
*/
protected void setHideProperties(PropertySet hide) {
this._hide = hide;
}
/**
* Adds a lens domain
*
* @param domain An <code>ISelector</code>
*/
protected void addDomain(ISelector domain) {
this._domains.add(domain);
}
/**
* Adds a lens purpose.
*
* @param purpose A <code>Purpose</code>
*/
protected void addPurpose(Purpose purpose) {
this._purposes.add(purpose);
}
/**
* Add a property to be shown.
*
* @param show An <code>ISelector</code>
*/
protected void addShowProperty(ISelector show) {
this._show.add(show);
}
/**
* Add a property to be hidden.
*
* @param hide An <code>ISelector</code>
*/
protected void addHideProperty(ISelector hide) {
this._hide.add(hide);
}
/**
* Check if this lens has a particular purpose.
*
* @param check A <code>Purpose</code> to check against
* @return A <code>boolean</code> indicator
*/
public boolean hasPurpose(Purpose check) {
for (Purpose purpose : this._purposes) {
if (purpose.equals(check)) {
return true;
}
}
return false;
}
/**
* Check if this lens has a default purpose.
*
* @return A <code>boolean</code> indicator
*/
public boolean isDefault() {
Purpose defaultP = new Purpose(FresnelCore.defaultLens);
return hasPurpose(defaultP);
}
/**
* Check if this lens is an instance lens.
*
* @return False if not an instance domain lens, true if so.
*/
public boolean isInstance() {
return IS_INSTANCE;
}
/**
* Parse out domain information (depends on the kind of lens) and add to the lens.
*
* @param in The <code>Repository</code> containing configuration information
* @param selected The <code>Resource</code> identifying the lens
* @param conf The <code>Configuration</code> parsing this lens
*/
protected void parseDomain(Repository in, Resource selected, Configuration conf) throws RepositoryException {
RepositoryConnection conn = in.getConnection();
RepositoryResult<Statement> domainsI = conn.getStatements(selected, FresnelCore.classLensDomain, (Value) null, false);
try {
while (domainsI.hasNext()) {
ISelector domain = null;
Value domainNode = domainsI.next().getObject();
if (domainNode instanceof Resource) {
// This is a type selector
domain = new TypeSelector((Resource) domainNode);
} else if (domainNode instanceof Literal) {
Literal domainL = (Literal) domainNode;
// TODO: catch bad expressions? throw exceptions?
if (domainL.getDatatype().equals(FresnelCoreTypes.fslSelector)) {
domain = new FSESelector(domainL.getLabel(), _fslContext, conf.getNamespaceMap());
} else if (domainL.getDatatype().equals(FresnelCoreTypes.sparqlSelector)) {
domain = new SPARQLSelector(domainL.getLabel(), conf.getNamespaces());
}
}
addDomain(domain);
}
} finally {
domainsI.close();
}
conn.close();
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
String state = " [Lens " + super.toString() + "]\n";
state += " " + this._identifier + "\n";
state += "\n Domain(s):\n";
state += this._domains;
state += "\n Purpose(s):\n";
state += this._purposes;
state += "\n Show Properties:\n";
state += this._show;
state += "\n Hide Properties:\n";
state += this._hide;
state += "\n ====== [end lens] \n";
return state;
}
}