/******************************************************************************* * Copyright (c) 2012 IBM Corporation. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v. 1.0 which accompanies this distribution. * * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * * Keith Wells - initial API and implementation * Sam Padgett - initial API and Implementation * Jim Conallen - initial API and implementation * *******************************************************************************/ package org.eclipse.lyo.samples.sharepoint.store; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.lyo.samples.sharepoint.core.IConstants; import org.eclipse.lyo.samples.sharepoint.store.ShareValue.ShareValueType; public class ShareResource { protected String uri; protected String resourceContext; protected List<ShareStatement> statements = new ArrayList<ShareStatement>(); protected Map<String,ShareResource> inlinedResources = new HashMap<String,ShareResource>(); protected ShareResource parentResource; public ShareResource(String uri) throws ShareServerException { this.uri = uri; this.resourceContext = uri; } public ShareResource(String uri, String resourceContext) throws ShareServerException { this.uri = uri; this.resourceContext = resourceContext; } public ShareResource(String uri, List<ShareStatement> statements) { this.uri = uri; this.resourceContext = uri; this.addStatements(statements); } public ShareResource(String uri, String resourceContext, List<ShareStatement> statements) { this.uri = uri; this.resourceContext = resourceContext; this.addStatements(statements); } public String getUri(){ return uri; } /** * * @param uri * @throws ShareServerException */ public void setUri(String uri) throws ShareServerException { // need to re-index everything if( uri == null || uri.isEmpty() ) throw new ShareServerException("Resource URI must be valid or blank node"); try{ if( this.parentResource != null ) { // need to update dad this.parentResource.inlinedResources.remove(this.uri); this.parentResource.inlinedResources.put(uri, this); } else { // this is also a resource context change this.resourceContext = uri; List<ShareStatement> allStatements = this.getStatements(); for (ShareStatement rioStatement : allStatements) { rioStatement.setContext(uri); } } // update immediate properties for( ShareStatement statement : statements ) { statement.setSubject(uri); ShareValue obj = statement.getObject(); if( ( obj.getType() == ShareValueType.BLANK_NODE || obj.getType() == ShareValueType.URI) && uri.equals(obj.stringValue()) ) { ShareValue updatedObj = null; if( uri.startsWith("http://") || uri.startsWith("https://") ) { updatedObj = new ShareValue(ShareValueType.URI, uri); } else { updatedObj = new ShareValue(ShareValueType.BLANK_NODE, uri); } statement.setObject(updatedObj); } } // now recurse into inlined resources, and update objects for(ShareResource rioResource : this.inlinedResources.values() ) { rioResource.reindexProperties(this.uri, uri); } // finally update this uri this.uri = uri; }catch( UnrecognizedValueTypeException e) { throw new ShareServerException(e); } } private void reindexProperties(String oldUri, String updatedUri) throws ShareServerException { try{ for( ShareStatement statement : statements ) { ShareValue obj = statement.getObject(); if( ( obj.getType() == ShareValueType.BLANK_NODE || obj.getType() == ShareValueType.URI) && oldUri.equals(obj.stringValue()) ) { ShareValue updatedObj = null; if( updatedUri.startsWith("http://") || updatedUri.startsWith("https://") ) { updatedObj = new ShareValue(ShareValueType.URI, updatedUri); } else { updatedObj = new ShareValue(ShareValueType.BLANK_NODE, updatedUri); } statement.setObject(updatedObj); } } for(ShareResource resource : this.inlinedResources.values() ) { resource.reindexProperties(oldUri, updatedUri); } }catch( UnrecognizedValueTypeException e) { throw new ShareServerException(e); } } public String getResourceContext(){ return resourceContext; } public void setResourceContext(String resourceContext){ // update all statements! } public void addStatements(List<ShareStatement> statements ) { this.statements.addAll(statements); } public void addStatement(ShareStatement rioStatement) { this.statements.add(rioStatement); } public List<ShareStatement> getStatements(){ List<ShareStatement> allStatements = new ArrayList<ShareStatement>(this.statements); for (ShareResource inlinedResource : this.inlinedResources.values()) { allStatements.addAll( inlinedResource.getStatements()); } return Collections.unmodifiableList(allStatements); } public List<ShareStatement> getStatements(String subject, String predicate, ShareValue value) { ArrayList<ShareStatement> filteredStatements = new ArrayList<ShareStatement>(); for (ShareStatement rioStatement : this.getStatements()) { // be sure to use all child statements too if( subject != null && !subject.equals(rioStatement.getSubject() ) ) continue; if( predicate != null && !predicate.equals(rioStatement.getPredicate() ) ) continue; if( value != null ) { if( value.getType() == rioStatement.getObject().getType() ) { if( !value.toString().equals(rioStatement.getObject().toString()) ) continue; } else { continue; } } filteredStatements.add(rioStatement); } return filteredStatements; } public ShareStatement getFirstStatement(String subject, String predicate, ShareValue value) { for (ShareStatement rioStatement : statements) { if( subject != null && !subject.equals(rioStatement.getSubject() ) ) continue; if( predicate != null && !predicate.equals(rioStatement.getPredicate() ) ) continue; if( value != null ) { if( value.getType() == rioStatement.getObject().getType() ) { if( !value.toString().equals(rioStatement.getObject().toString()) ) continue; } else { continue; } } return rioStatement; } return null; } public ShareValue getFirstPropertyValue(String predicateUri) { ShareStatement statement = getFirstStatement(uri, predicateUri, null); if( statement != null ) { return statement.getObject(); } return null; } public void addRdfType(String rdfTypeUri) throws ShareServerException { addProperty(IConstants.RDF_TYPE, ShareValueType.URI, rdfTypeUri, false); } public boolean isRdfType(String rdfTypeUri) throws ShareServerException { List<ShareStatement> rdftypes = this.getStatements(uri, IConstants.RDF_TYPE, null); for (ShareStatement rioStatement : rdftypes) { ShareValue obj = rioStatement.getObject(); if( rdfTypeUri.equals(obj.stringValue())) return true; } return false; } private void insertInlinedResource( String propertyUri, ShareResource rioResource ) throws ShareServerException { try{ String bn = null; if( this.uri.startsWith("_:") ) { bn = uri + '_' + inlinedResources.size(); } else { bn = "_:bn" + + inlinedResources.size(); } ShareValue blankNode = ShareValue.createBlankNodeValue(bn); ShareStatement statement = new ShareStatement(uri, propertyUri, blankNode, uri); statements.add(statement); rioResource.setUri(bn); rioResource.setResourceContext(this.resourceContext); inlinedResources.put(blankNode.stringValue(),rioResource); rioResource.parentResource = this; } catch ( Exception e ) { throw new ShareServerException(e); } } public ShareResource createInlinedResource( String propertyUri, String typeUri ) throws ShareServerException { try{ String bn = null; if( this.uri.startsWith("_:") ) { bn = uri + '_' + inlinedResources.size(); } else { bn = "_:bn" + + inlinedResources.size(); } ShareValue blankNode = ShareValue.createBlankNodeValue(bn); ShareStatement statement = new ShareStatement(uri, propertyUri, blankNode, uri); statements.add(statement); ShareResource resource = new ShareResource(blankNode.stringValue(), uri); inlinedResources.put(blankNode.stringValue(),resource); if( typeUri != null ) { ShareValue val = ShareValue.createUriValue(typeUri); resource.createProperty(IConstants.RDF_TYPE, val, true); } resource.parentResource = this; return resource; } catch ( Exception e ) { throw new ShareServerException(e); } } public ShareResource getFirstInlinedResource( String propertyUri ) throws ShareServerException { ShareStatement statement = getFirstStatement(uri, propertyUri, null); if( statement != null ) { ShareValue obj = statement.getObject(); if( obj.getType() == ShareValueType.BLANK_NODE ) { return getInlinedResource(obj.toString()); } } return null; } @SuppressWarnings("unchecked") public <T> List<T> getInlinedResources( String propertyUri ) throws ShareServerException { List<T> inlinedResources = new ArrayList<T>(); List<ShareStatement> inlinedStatements = getStatements(uri, propertyUri, null); for (ShareStatement rioStatement : inlinedStatements) { ShareValue obj = rioStatement.getObject(); inlinedResources.add((T) getInlinedResource(obj.toString())); } return inlinedResources; } public ShareResource getInlinedResource( String bnodeID ) throws ShareServerException { return this.inlinedResources.get(bnodeID); } public void removeInlinedResource(String bnodeId) throws ShareServerException { this.inlinedResources.remove(bnodeId); } /** * change owner of the resource to this one * @param propertyUri * @param rioResource * @param typeUri * @throws ShareServerException */ public void setInlinedResource(String propertyUri, ShareResource rioResource) throws ShareServerException { ShareResource oldResource = this.getFirstInlinedResource(propertyUri); if(oldResource != null ) { // remove it String bnode = oldResource.getUri(); this.removeInlinedResource(bnode); } insertInlinedResource(propertyUri, rioResource); } // String public void setStringProperty( String propertyUri, String value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createStringValue(value); this.createProperty(propertyUri, lyoVal, true); } catch (Exception e) { throw new ShareServerException(e); } } public void addStringProperty( String propertyUri, String value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createStringValue(value); this.createProperty(propertyUri, lyoVal, false); } catch (Exception e) { throw new ShareServerException(e); } } public boolean hasStringProperty(String propertyUri ) { return hasPropertyOfType(propertyUri, ShareValueType.STRING); } public String getFirstStringProperty(String propertyUri ) { List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.STRING)) { return val.stringValue(); } } return null; } public Collection<String> getStringProperties(String propertyUri ) { List<String> propertyValues = new ArrayList<String>(); List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.STRING)) { propertyValues.add(val.stringValue()); } } return propertyValues; } // Integer public void setIntegerProperty( String propertyUri, int value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createIntegerValue(value); this.createProperty(propertyUri, lyoVal, true); } catch (Exception e) { throw new ShareServerException(e); } } public void addIntegerProperty( String propertyUri, int value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createIntegerValue(value); this.createProperty(propertyUri, lyoVal, false); } catch (Exception e) { throw new ShareServerException(e); } } public boolean hasIntegerProperty(String propertyUri ) { return hasPropertyOfType(propertyUri, ShareValueType.INTEGER); } public Integer getFirstIntegerProperty(String propertyUri ) throws ShareServerException { List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.INTEGER)) { try { return val.intValue(); } catch (IncompatibleValueException e) { throw new ShareServerException(e); } } } return null; } public Collection<Integer> getIntegerProperties(String propertyUri ) { List<Integer> propertyValues = new ArrayList<Integer>(); List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.INTEGER)) { try { propertyValues.add(val.intValue()); } catch (IncompatibleValueException e) { // log this? don't abort since the client probably interested only in the ints that are working } } } return propertyValues; } // Decimal public void setDecimalProperty( String propertyUri, double value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createDecimalValue(value); this.createProperty(propertyUri, lyoVal, true); } catch (Exception e) { throw new ShareServerException(e); } } public void addDecimalProperty( String propertyUri, double value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createDecimalValue(value); this.createProperty(propertyUri, lyoVal, false); } catch (Exception e) { throw new ShareServerException(e); } } public boolean hasDecimalProperty(String propertyUri ) { return hasPropertyOfType(propertyUri, ShareValueType.DECIMAL); } public Double getFirstDecimalProperty(String propertyUri ) throws ShareServerException { List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.DECIMAL)) { try { return val.doubleValue(); } catch (IncompatibleValueException e) { throw new ShareServerException(e); } } } return null; } public Collection<Double> getDecimalProperties(String propertyUri ) { List<Double> propertyValues = new ArrayList<Double>(); List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.DECIMAL)) { try { propertyValues.add(val.doubleValue()); } catch (IncompatibleValueException e) { // log this? don't abort since the client probably interested only in the ints that are working } } } return propertyValues; } // Date public void setDateProperty( String propertyUri, Date value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createCalendarValue(value); this.createProperty(propertyUri, lyoVal, true); } catch (Exception e) { throw new ShareServerException(e); } } public void addDateProperty( String propertyUri, Date value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createCalendarValue(value); this.createProperty(propertyUri, lyoVal, false); } catch (Exception e) { throw new ShareServerException(e); } } public boolean hasDateProperty(String propertyUri ) { return hasPropertyOfType(propertyUri, ShareValueType.CALENDAR); } public Date getFirstDateProperty(String propertyUri ) throws ShareServerException { List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.CALENDAR)) { try { return val.dateValue(); } catch (IncompatibleValueException e) { throw new ShareServerException(e); } } } return null; } public Collection<Date> getDateProperties(String propertyUri ) { List<Date> propertyValues = new ArrayList<Date>(); List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.CALENDAR)) { try { propertyValues.add(val.dateValue()); } catch (IncompatibleValueException e) { // log this? don't abort since the client probably interested only in the ints that are working } } } return propertyValues; } // URI public void setUriProperty( String propertyUri, String value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createUriValue(value); this.createProperty(propertyUri, lyoVal, true); } catch (Exception e) { throw new ShareServerException(e); } } public void addUriProperty( String propertyUri, String value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createUriValue(value); this.createProperty(propertyUri, lyoVal, false); } catch (Exception e) { throw new ShareServerException(e); } } public void removeUriProperty( String propertyUri, String uri) throws ShareServerException { try { ShareValue value = ShareValue.createUriValue(uri); ShareStatement stmt = this.getFirstStatement(getUri(), propertyUri, value); if( stmt != null ) { statements.remove(stmt); } } catch (Exception e) { throw new ShareServerException(e); } } public boolean hasUriProperty(String propertyUri ) { return hasPropertyOfType(propertyUri, ShareValueType.URI); } public String getFirstUriProperty(String propertyUri ) { List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.URI)) { return val.stringValue(); } } return null; } public List<String> getUriProperties(String propertyUri ) { List<String> propertyValues = new ArrayList<String>(); List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.URI)) { propertyValues.add(val.stringValue()); } } return propertyValues; } // Boolean public void setBooleanProperty( String propertyUri, boolean value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createBooleanValue(value); this.createProperty(propertyUri, lyoVal, true); } catch (Exception e) { throw new ShareServerException(e); } } public void addBooleanProperty( String propertyUri, boolean value) throws ShareServerException { try { ShareValue lyoVal = ShareValue.createBooleanValue(value); this.createProperty(propertyUri, lyoVal, false); } catch (Exception e) { throw new ShareServerException(e); } } public boolean hasBooleanProperty(String propertyUri ) { return hasPropertyOfType(propertyUri, ShareValueType.BOOLEAN); } public boolean getFirstBooleanProperty(String propertyUri, boolean defaultValue ) { List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.BOOLEAN)) { try { return val.booleanValue(); } catch (IncompatibleValueException e) { // log this? it should never happen } } } return defaultValue; } public Collection<Boolean> getBooleanProperties(String propertyUri ) { List<Boolean> propertyValues = new ArrayList<Boolean>(); List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(ShareValueType.BOOLEAN)) { try { propertyValues.add(val.booleanValue()); } catch (IncompatibleValueException e) { // log this? it should never happen } } } return propertyValues; } // Common property methods protected void addProperty(String propertyUri, ShareValueType valType, Object value, boolean exclusive) throws ShareServerException { createProperty(this.uri, propertyUri, valType, value, exclusive); } protected void createProperty(String subjectUri, String propertyUri, ShareValueType valType, Object value, boolean exclusive) throws ShareServerException { ShareValue rioValue = null; try { rioValue = new ShareValue(valType, value); } catch (UnrecognizedValueTypeException e) { // should NEVER happen throw new ShareServerException(e); } createProperty(subjectUri, propertyUri, rioValue, exclusive); } protected void createProperty(String propertyUri, ShareValue value, boolean exclusive) throws ShareServerException { createProperty(this.uri, propertyUri, value, exclusive); } protected void createProperty(String subjectUri, String propertyUri, ShareValue value, boolean exclusive) throws ShareServerException { List<ShareStatement> statements = this.getStatements(subjectUri, propertyUri, null); if ((exclusive || value == null)) { for (ShareStatement rioStatement : statements) { this.statements.remove(rioStatement); } } if (value == null || value.getValue() == null) return; // our work is finished ShareStatement statement = new ShareStatement(subjectUri, propertyUri, value, resourceContext); this.statements.add(statement); } public boolean hasPropertyOfType( String propertyUri, ShareValueType type) { List<ShareStatement> strStatements = this.getStatements(this.uri, propertyUri, null); for (ShareStatement rioStatement : strStatements) { ShareValue val = rioStatement.getObject(); if( val.getType().equals(type)) { return true; } } return false; } // // Ordered list methods (rdf sequences) // public void appendToSeq(String propertyUri, ShareValue value) throws ShareServerException { if (value == null) return; // our work is finished String propName = extractLastSegment(propertyUri); ShareStatement statement = null; List<ShareStatement> statements = this.getStatements(null, propertyUri, null); if (statements.size() == 0) { // create it try { ShareValue bnVal = new ShareValue(ShareValueType.BLANK_NODE, propName); statement = new ShareStatement(uri, propertyUri, bnVal, resourceContext); this.addStatement(statement); ShareValue rdfSeqVal = new ShareValue(ShareValueType.URI, IConstants.RDF_SEQ); ShareStatement collTypeStatement = new ShareStatement(propName, IConstants.RDF_TYPE, rdfSeqVal, resourceContext); this.addStatement(collTypeStatement); } catch (Exception e) { throw new ShareServerException(e); } } else { statement = statements.get(0); } // now that we have the blank node String bNodeId = statement.getObject().stringValue(); // get all other elements in this collection statements = this.getStatements(bNodeId, null, null); int count = statements.size() - 1; // -1 to subtract the rdf:type from the list statement = new ShareStatement(bNodeId, IConstants.RDF_NAMESPACE + "_" + (count + 1), value, uri); this.statements.add(statement); } public List<ShareValue> getSeq(String propertyUri) throws ShareServerException { List<ShareValue> seqValues = new ArrayList<ShareValue>(); String propName = extractLastSegment(propertyUri); List<ShareStatement> statements = this .getStatements(propName, null, null); // TODO: sort them by predicate for (ShareStatement rioStatement : statements) { ShareValue obj = rioStatement.getObject(); String pred = rioStatement.getPredicate(); if (pred.startsWith("http://www.w3.org/1999/02/22-rdf-syntax-ns#_")) { seqValues.add(obj); } } return seqValues; } public void removeSeq(String propertyUri) throws ShareServerException { List<ShareStatement> statements = this.getStatements(null, propertyUri, null); for (ShareStatement rioStatement : statements) { List<ShareStatement> childStatements = this.getStatements( rioStatement.getObject().stringValue(), null, null); this.statements.removeAll(childStatements); } this.statements.removeAll(statements); } protected String extractLastSegment(String uri) { int pos = uri.lastIndexOf('#'); if( pos > 0 ) { return uri.substring(pos + 1); } pos = uri.lastIndexOf('/'); return uri.substring(pos + 1); } public String dumpNTriples(){ StringBuffer sb = new StringBuffer(); List<ShareStatement> allStatements = this.getStatements(); for (ShareStatement rioStatement : allStatements) { sb.append( rioStatement.toString() + " .\n"); } return sb.toString(); } }