/*
* Created on Mar 16, 2005
*/
package edu.mit.simile.fresnel.selection;
import org.openrdf.model.BNode;
import org.openrdf.model.Literal;
import org.openrdf.model.URI;
import org.openrdf.model.Resource;
import org.openrdf.model.Value;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import fr.inria.jfresnel.fsl.FSLPath;
import edu.mit.simile.fresnel.FresnelCoreTypes;
import edu.mit.simile.fresnel.configuration.Configuration;
import edu.mit.simile.fresnel.util.RDFList;
import edu.mit.simile.fresnel.util.WrappedVector;
import edu.mit.simile.vocabularies.FresnelCore;
import java.util.Iterator;
/**
* Ordered set of selectors describing a set of properties concerning an instance of
* a specific rdf:type.
*
* @author ryanlee
*/
public class PropertySet extends WrappedVector<ISelector> {
/**
* Resource defined by the schema.
*/
protected static final Resource _schemaResource = FresnelCore.PropertySet;
/**
* Context for determining FSL first location step type.
*/
protected final static short _fslContext = FSLPath.ARC_STEP;
/**
* Track fresnel:allProperties usage.
*/
private boolean _seenAllProperties = false;
/**
* Empty constructor.
*/
public PropertySet() {
super();
}
/**
* Retrieves the schema resource defined in this class.
*
* @return A <code>Resource</code>
*/
public static Resource getSchemaResource() {
return _schemaResource;
}
/**
* Add new properties to the set. Though any ISelector can be used, only
* PropertySelectors and their inheritors and property-describing query
* mechanisms should be used.
*
* @param selector An <code>ISelector</code>
*/
public void addSelector(ISelector selector) {
this._base.add(selector);
}
public boolean containsSelector(PropertySelector selector) {
boolean out = false;
for (Iterator<ISelector> psi = iterator(); psi.hasNext(); ) {
ISelector next = psi.next();
if (next instanceof PropertySelector) {
out = out ^ ((PropertySelector) next).getProperty().equals(selector.getProperty());
}
}
return out;
}
/**
* Returns an iterator over the contents of the property set.
*
* @return An <code>Iterator</code>
*/
public Iterator<ISelector> iterator() {
return this._base.iterator();
}
/**
* Retrieves whether or not fresnel:allProperties has been used in this
* property set yet.
*
* @return A <code>boolean</code>
*/
public boolean seenAllProperties() {
return this._seenAllProperties;
}
/**
* Sets the value of whether or not fresnel:allProperties has been used.
*
* @param seen A <code>boolean</code> indicator.
*/
public void setSeenAllProperties(boolean seen) {
this._seenAllProperties = seen;
}
/**
* Parses an rdf:List of selection mechanisms for a showProperties list.
*
* @param lens A <code>Lens</code> (the lens being parsed)
* @param in A <code>Repository</code>
* @param list A <code>RDFList</code>
* @param conf The <code>Configuration</code> that's parsing this list
* @return A new <code>PropertySet</code>
* @throws ParsingException When invalid property lists are presented
*/
public static PropertySet showParse(Lens lens, Repository in, RDFList list, Configuration conf) throws ParsingException, UnresolvableException {
return parse(lens, in, list, true, conf);
}
/**
* Parses an rdf:List of selection mechanisms for a hideProperties list.
*
* @param lens A <code>Lens</code> (the lens being parsed)
* @param in A <code>Repository</code>
* @param list A <code>RDFList</code>
* @param conf The <code>Configuration</code> that's parsing this list
* @return A new <code>PropertySet</code>
* @throws ParsingException When invalid property lists are presented
*/
public static PropertySet hideParse(Lens lens, Repository in, RDFList list, Configuration conf) throws ParsingException, UnresolvableException {
return parse(lens, in, list, false, conf);
}
/**
* Parses an rdf:List of selection mechanisms.
*
* @param lens A <code>Lens</code> (the lens being parsed)
* @param in A <code>Model</code>
* @param list A <code>Repository</code>
* @param allowAllProperties Whether the fresnel:allProperties property set is allowed
* in this list
* @param conf The <code>Configuration</code> that's parsing this list
* @return A new <code>PropertySet</code>
* @throws ParsingException When invalid property lists are presented
*/
private static PropertySet parse(Lens lens, Repository in, RDFList list, boolean allowAllProperties, Configuration conf)
throws ParsingException, UnresolvableException {
PropertySet out = new PropertySet();
for (Iterator listI = list.iterator(); listI.hasNext(); ) {
Value selectorNode = (Value) listI.next();
ISelector selector = propertyParse(lens, in, selectorNode, allowAllProperties, conf);
if (AllPropertiesSelector.isAllProperties(selector)) {
if (out.seenAllProperties()) {
throw new ParsingException("allProperties token used more than once");
} else {
out.add(selector);
out.setSeenAllProperties(true);
}
} else {
out.add(selector);
}
}
return out;
}
/**
* Parses a Repository node into the appropriate selector for a shown property.
*
* @param lens A <code>Lens</code> (the lens being parsed)
* @param in A <code>Repository</code>
* @param selector The node in the Repository acting as a selector
* @param conf The <code>Configuration</code> that's parsing this list
* @return An <code>ISelector</code>
* @throws ParsingException When invalid property lists are presented
*/
public static ISelector showPropertyParse(Lens lens, Repository in, Value selector, Configuration conf)
throws ParsingException, UnresolvableException {
return propertyParse(lens, in, selector, true, conf);
}
/**
* Parses a Repository node into the appropriate selector for a hidden property.
*
* @param lens A <code>Lens</code> (the lens being parsed)
* @param in A <code>Repository</code>
* @param selector The node in the Repository acting as a selector
* @param conf The <code>Configuration</code> that's parsing this list
* @return An <code>ISelector</code>
* @throws ParsingException When invalid property lists are presented
*/
public static ISelector hidePropertyParse(Lens lens, Repository in, Value selector, Configuration conf)
throws ParsingException, UnresolvableException {
return propertyParse(lens, in, selector, false, conf);
}
/**
* Parses a Repository node into the appropriate selector.
*
* @param lens A <code>Lens</code> (the lens being parsed)
* @param in A <code>Repository</code>
* @param selector The node in the Repository acting as a selector
* @param allowAllProperties Whether the fresnel:allProperties property set is allowed
* in this list
* @param conf The <code>Configuration</code> that's parsing this list
* @return An <code>ISelector</code>
* @throws ParsingException When invalid property lists are presented
*/
private static ISelector propertyParse(Lens lens, Repository in, Value selector, boolean allowAllProperties, Configuration conf)
throws UnresolvableException, ParsingException {
ISelector out = null;
if (selector instanceof Resource) {
Resource selectorResource = (Resource) selector;
boolean stmtExists = false;
try {
RepositoryConnection conn = in.getConnection();
stmtExists = conn.hasStatement(selectorResource, FresnelCore.property, (Value) null, false);
conn.close();
} catch (RepositoryException e) {
// TODO: how to handle exception
}
if (selectorResource.equals(AllPropertiesSet.getSchemaResource()) &&
allowAllProperties) {
out = new AllPropertiesSelector();
} else if (selectorResource.equals(AllPropertiesSet.getSchemaResource()) &&
!allowAllProperties) {
throw new ParsingException(selectorResource.toString() +
" cannot use fresnel:allProperties property set");
} else if (selectorResource.equals(FresnelCore.member)) {
out = new ContainerMemberSelector();
} else if (selectorResource instanceof BNode || stmtExists) {
// This is a :PropertyDescription
try {
out = PropertyDescription.parse(lens, in, selectorResource, conf);
} catch (ResourceNotFoundException e) {
// turn into a parsing exception
throw new ParsingException("Cannot find a resource referred to in the PropertyDescription " + selectorResource);
}
} else {
URI selectorProperty = (URI) selectorResource;
out = new PropertySelector(selectorProperty);
}
} else if (selector instanceof Literal) {
// This is a string-based selector
Literal selectorLiteral = (Literal) selector;
if (selectorLiteral.getDatatype().equals(FresnelCoreTypes.fslSelector)) {
out = new FSESelector(selectorLiteral.getLabel(), _fslContext, conf.getNamespaceMap());
} else if (selectorLiteral.getDatatype().equals(FresnelCoreTypes.sparqlSelector)) {
out = new SPARQLSelector(selectorLiteral.getLabel(), conf.getNamespaces());
}
} else {
throw new ParsingException("Could not determine how to parse " + selector);
}
return out;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
String state = " [PropertySet " + super.toString() + "]\n";
Iterator<ISelector> it = this.iterator();
while (it.hasNext()) {
ISelector select = it.next();
state += select;
}
return state;
}
}