/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.stanbol.entityhub.model.clerezza; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.apache.clerezza.commons.rdf.Literal; import org.apache.clerezza.rdf.core.NoConvertorException; import org.apache.clerezza.commons.rdf.RDFTerm; import org.apache.clerezza.commons.rdf.Graph; import org.apache.clerezza.commons.rdf.IRI; import org.apache.clerezza.rdf.utils.GraphNode; import org.apache.stanbol.entityhub.servicesapi.util.AdaptingIterator; import org.apache.stanbol.entityhub.servicesapi.util.FilteringIterator; import org.apache.stanbol.entityhub.servicesapi.util.TypeSafeIterator; import org.apache.stanbol.entityhub.model.clerezza.impl.Literal2TextAdapter; import org.apache.stanbol.entityhub.model.clerezza.impl.LiteralAdapter; import org.apache.stanbol.entityhub.model.clerezza.impl.NaturalTextFilter; import org.apache.stanbol.entityhub.model.clerezza.impl.Resource2ValueAdapter; import org.apache.stanbol.entityhub.model.clerezza.impl.IRI2ReferenceAdapter; import org.apache.stanbol.entityhub.model.clerezza.impl.IRIAdapter; import org.apache.stanbol.entityhub.model.clerezza.utils.Resource2StringAdapter; import org.apache.stanbol.entityhub.servicesapi.model.Reference; import org.apache.stanbol.entityhub.servicesapi.model.Representation; import org.apache.stanbol.entityhub.servicesapi.model.Text; import org.apache.stanbol.entityhub.servicesapi.model.UnsupportedTypeException; import org.apache.stanbol.entityhub.servicesapi.util.ModelUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RdfRepresentation implements Representation{ private static final Logger log = LoggerFactory.getLogger(RdfRepresentation.class); private final RdfValueFactory valueFactory = RdfValueFactory.getInstance(); private final GraphNode graphNode; protected final GraphNode getGraphNode() { return graphNode; } protected RdfRepresentation(IRI resource, Graph graph) { this.graphNode = new GraphNode(resource, graph); } /** * Getter for the read only view onto the RDF data of this representation. * * @return The RDF graph of this Representation */ public Graph getRdfGraph(){ return graphNode.getGraph(); } // protected IRI getRepresentationType(){ // Iterator<IRI> it = this.graphNode.getIRIObjects(REPRESENTATION_TYPE_PROPERTY); // return it.hasNext()?it.next():null; // } @Override public void add(String field, Object value) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } if(value == null){ throw new IllegalArgumentException("NULL values are not supported by Representations"); } IRI fieldIRI = new IRI(field); Collection<Object> values = new ArrayList<Object>(); //process the parsed value with the Utility Method -> // this converts Objects as defined in the specification ModelUtils.checkValues(valueFactory, value, values); //We still need to implement support for specific types supported by this implementation for (Object current : values){ if (current instanceof RDFTerm){ //native support for Clerezza types! graphNode.addProperty(fieldIRI, (RDFTerm)current); } else if (current instanceof RdfReference){ //treat RDF Implementations special to avoid creating new instances graphNode.addProperty(fieldIRI, ((RdfReference) current).getIRI()); } else if (current instanceof Reference){ graphNode.addProperty(fieldIRI, new IRI(((Reference) current).getReference())); } else if (current instanceof RdfText){ //treat RDF Implementations special to avoid creating new instances graphNode.addProperty(fieldIRI,((RdfText) current).getLiteral()); } else if (current instanceof Text){ addNaturalText(fieldIRI, ((Text)current).getText(), ((Text)current).getLanguage()); } else { //else add an typed Literal! addTypedLiteral(fieldIRI, current); } } } private void addTypedLiteral(IRI field, Object literalValue){ Literal literal; try { literal = RdfResourceUtils.createLiteral(literalValue); } catch (NoConvertorException e){ log.info("No Converter for value type "+literalValue.getClass() +" (parsed for field "+field+") use toString() to get String representation"); literal = RdfResourceUtils.createLiteral(literalValue.toString(), null); } graphNode.addProperty(field, literal); } @Override public void addReference(String field, String reference) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } if(reference == null){ throw new IllegalArgumentException("NULL values are not supported by Representations"); } else if (reference.isEmpty()) { throw new IllegalArgumentException("References MUST NOT be empty!"); } graphNode.addProperty(new IRI(field), new IRI(reference)); } @Override public void addNaturalText(String field, String text, String...languages) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } if(text == null){ throw new IllegalArgumentException("NULL values are not supported by Representations"); } this.addNaturalText(new IRI(field), text, languages); } private void addNaturalText(IRI field, String text, String...languages) { if(languages == null || languages.length == 0){ languages = new String []{null}; } for(String language : languages){ graphNode.addProperty(field, RdfResourceUtils.createLiteral(text, language)); } } @SuppressWarnings("unchecked") @Override public <T> Iterator<T> get(String field, final Class<T> type) throws UnsupportedTypeException { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } IRI fieldIRI = new IRI(field); if(RDFTerm.class.isAssignableFrom(type)){ //native support for Clerezza types return new TypeSafeIterator<T>(graphNode.getObjects(fieldIRI), type); // NOTE: (Rupert Westenthaler 12.01.2011) // Converting everything to String is not an intended functionality. When // someone parsed String.class he rather assumes that he gets only string // values and not also string representations for Dates, Integer ... // // } else if(type.equals(String.class)){ //support to convert anything to String // return (Iterator<T>) new AdaptingIterator<RDFTerm,String>( // graphNode.getObjects(fieldIRI), // new Resource2StringAdapter<RDFTerm>(), // String.class); } else if(type.equals(URI.class) || type.equals(URL.class)){ //support for References return new AdaptingIterator<IRI, T>( graphNode.getIRIObjects(fieldIRI), new IRIAdapter<T>(), type); } else if(Reference.class.isAssignableFrom(type)){ return (Iterator<T>) new AdaptingIterator<IRI,Reference>( graphNode.getIRIObjects(fieldIRI), new IRI2ReferenceAdapter(),Reference.class); } else if(Text.class.isAssignableFrom(type)){ return (Iterator<T>)new AdaptingIterator<Literal, Text>( graphNode.getLiterals(fieldIRI), new Literal2TextAdapter<Literal>(), Text.class); } else { //support for Literals -> Type conversions return new AdaptingIterator<Literal, T>( graphNode.getLiterals(fieldIRI), new LiteralAdapter<Literal, T>(), type); } } @Override public Iterator<Reference> getReferences(String field) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } return new AdaptingIterator<IRI,Reference>( graphNode.getIRIObjects(new IRI(field)), new IRI2ReferenceAdapter(),Reference.class); } @Override public Iterator<Text> getText(String field) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } return new AdaptingIterator<Literal, Text>( graphNode.getLiterals(new IRI(field)), new Literal2TextAdapter<Literal>(), Text.class); } @Override public Iterator<Object> get(String field) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } return new AdaptingIterator<RDFTerm, Object>(graphNode.getObjects(new IRI(field)), new Resource2ValueAdapter<RDFTerm>(),Object.class); } @Override public Iterator<Text> get(String field, String...languages) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } return new AdaptingIterator<Literal, Text>( graphNode.getLiterals(new IRI(field)), new Literal2TextAdapter<Literal>(languages), Text.class); } @Override public Iterator<String> getFieldNames() { return new AdaptingIterator<IRI, String>(graphNode.getProperties(), new Resource2StringAdapter<IRI>(), String.class); } @Override public <T> T getFirst(String field, Class<T> type) throws UnsupportedTypeException { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } Iterator<T> it = get(field,type); if(it.hasNext()){ return it.next(); } else { return null; } } @Override public Object getFirst(String field) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } Iterator<Object> it = get(field); if(it.hasNext()){ return it.next(); } else { return null; } } @Override public Reference getFirstReference(String field) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } Iterator<Reference> it = getReferences(field); return it.hasNext()?it.next():null; } @Override public Text getFirst(String field, String...languages) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } if(languages == null){ log.debug("NULL parsed as languages -> replacing with \"new String []{null}\"" + " -> assuming a missing explicit cast to (String) in the var arg"); languages = new String []{null}; } Iterator<Text> it = get(field,languages); if(it.hasNext()){ return it.next(); } else { return null; } } @Override public String getId() { return getNode().getUnicodeString(); } /** * Getter for the IRI representing the ID of this Representation. * @return The IRI representing the ID of this Representation. */ public IRI getNode(){ return (IRI)graphNode.getNode(); } @Override public void remove(String field, Object parsedValue) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } if(parsedValue == null){ log.warn("NULL parsed as value in remove method for symbol "+getId() +" and field "+field+" -> call ignored"); return; } IRI fieldIRI = new IRI(field); Collection<Object> removeValues = new ArrayList<Object>(); ModelUtils.checkValues(valueFactory, parsedValue, removeValues); //We still need to implement support for specific types supported by this implementation for (Object current : removeValues){ if (current instanceof RDFTerm){ //native support for Clerezza types! graphNode.deleteProperty(fieldIRI, (RDFTerm)current); } else if (current instanceof RdfReference){ //treat RDF Implementations special to avoid creating new instances graphNode.deleteProperty(fieldIRI, ((RdfReference) current).getIRI()); } else if (current instanceof Reference){ graphNode.deleteProperty(fieldIRI, new IRI(((Reference) current).getReference())); } else if (current instanceof RdfText){ //treat RDF Implementations special to avoid creating new instances graphNode.deleteProperty(fieldIRI,((RdfText) current).getLiteral()); } else if (current instanceof Text){ removeNaturalText(field,((Text)current).getText(),((Text)current).getLanguage()); } else { //else add an typed Literal! removeTypedLiteral(fieldIRI, current); } } } @Override public void removeReference(String field, String reference) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } if(reference == null){ log.warn("NULL parsed as value in remove method for symbol "+getId()+" and field "+field+" -> call ignored"); } graphNode.deleteProperty(new IRI(field), new IRI(reference)); } protected void removeTypedLiteral(IRI field, Object object){ Literal literal; try{ literal = RdfResourceUtils.createLiteral(object); } catch (NoConvertorException e){ log.info("No Converter for value type "+object.getClass() +" (parsed for field "+field+") use toString() Method to get String representation"); literal = RdfResourceUtils.createLiteral(object.toString(), null); } graphNode.deleteProperty(field,literal); } @Override public void removeNaturalText(String field, String value, String... languages) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } if(value == null){ log.warn("NULL parsed as value in remove method for symbol "+getId()+" and field "+field+" -> call ignored"); } if(languages == null || languages.length == 0){ //null or no language //need to be interpreted as default language languages = new String []{null}; } IRI fieldIRI = new IRI(field); for(String language : languages){ graphNode.deleteProperty(fieldIRI,RdfResourceUtils.createLiteral(value, language)); if(language == null){ //if the language is null //we need also try to remove a typed Literal with the data type //xsd:string and the parsed value! graphNode.deleteProperty(fieldIRI,RdfResourceUtils.createLiteral(value)); } } } @Override public void removeAll(String field) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } graphNode.deleteProperties(new IRI(field)); } @Override public void removeAllNaturalText(String field, String... languages) { if(field == null){ throw new IllegalArgumentException("The parsed field MUST NOT be NULL"); } else if(field.isEmpty()){ throw new IllegalArgumentException("The parsed field MUST NOT be Empty"); } // if(languages == null || languages.length == 0){ // languages = new String []{null}; // } IRI fieldIRI = new IRI(field); //get all the affected Literals Collection<Literal> toRemove = new ArrayList<Literal>(); Iterator<Literal> it = new FilteringIterator<Literal>( graphNode.getLiterals(fieldIRI), new NaturalTextFilter(languages),Literal.class); while(it.hasNext()){ toRemove.add(it.next()); } for(Literal l : toRemove){ graphNode.deleteProperty(fieldIRI, l); } } @Override public void set(String field, Object value) { removeAll(field); if(value != null){ add(field,value); } } @Override public void setReference(String field, String reference) { removeAll(field); if(reference != null){ addReference(field, reference); } } @Override public void setNaturalText(String field, String text, String...languages) { removeAllNaturalText(field, languages); if(text != null){ addNaturalText(field, text, languages); } } @Override public String toString() { return RdfRepresentation.class.getSimpleName()+getId(); } @Override public int hashCode() { return getId().hashCode(); } @Override public boolean equals(Object obj) { return obj instanceof Representation && ((Representation)obj).getId().equals(getId()); } }