/*
* 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.clerezza.rdf.enrichment;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.clerezza.rdf.core.BNode;
import org.apache.clerezza.rdf.core.LiteralFactory;
import org.apache.clerezza.rdf.core.NonLiteral;
import org.apache.clerezza.rdf.core.Resource;
import org.apache.clerezza.rdf.core.Triple;
import org.apache.clerezza.rdf.core.TripleCollection;
import org.apache.clerezza.rdf.core.UriRef;
import org.apache.clerezza.rdf.core.impl.TripleImpl;
import org.apache.clerezza.rdf.ontologies.RDF;
import org.apache.clerezza.utils.IteratorMerger;
/**
* add a a weather property pointing to the weather expressed a a bnode with
* current temperature and humidity (fake values)
*
* @author reto
*/
public class CityWeatherEnricher extends Enricher {
//ontology part
static UriRef classCity = new UriRef("http://example.org/ontology#City");
static UriRef weatherProperty = new UriRef("http://example.org/ontology#weather");
static UriRef temperatureProperty = new UriRef("http://example.org/ontology#temperature");
static UriRef humidityProperty = new UriRef("http://example.org/ontology#humidity");
final private static UriRef xsdDouble =
new UriRef("http://www.w3.org/2001/XMLSchema#double");
private final ResourceFilter classCityFilter = getFilterForSubjectsWith(RDF.type, classCity);
private final Map<NonLiteral, WeakReference<BNode>> cityWeatherMap = new HashMap<NonLiteral, WeakReference<BNode>>();
/*
* we might be able to tell more about things that are a City and about
* the Weather-Bnode we created
*/
@Override
public ResourceFilter getSubjectFilter() {
return new OrConnector(
classCityFilter, getLocalBNodeFilter());
}
@Override
public ResourceFilter getPredicateFilter() {
return getExtensionalFilter(weatherProperty, temperatureProperty, humidityProperty);
}
@Override
public ResourceFilter getObjectFilter() {
return new OrConnector(getLocalBNodeFilter(), getDataTypeFilter(xsdDouble));
}
@Override
public Iterator<Triple> filter(final NonLiteral subject,
final UriRef predicate, final Resource object,
final TripleCollection base) {
if (subject == null) {
Iterator<Triple> iteratorCitySubjects = new IteratorMerger(
new Iterator<Iterator<Triple>>() {
Iterator<Resource> subjectIterator =
classCityFilter.getAcceptable(base).iterator();
@Override
public boolean hasNext() {
return subjectIterator.hasNext();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public Iterator<Triple> next() {
return CityWeatherEnricher.this.filterSubjectNonNull(
(NonLiteral)subjectIterator.next(),
predicate, object, base);
}
});
//TODO add with bnode subjects
return iteratorCitySubjects;
} else {
return filterSubjectNonNull(subject, predicate, object, base);
}
}
private Iterator<Triple> filterSubjectNonNull(final NonLiteral subject,
final UriRef predicate, final Resource object,
final TripleCollection base) {
Set<Triple> resultSet = new HashSet<Triple>();
if (classCityFilter.accept(subject, base)) {
if (predicate.equals(weatherProperty)) {
BNode weatherNode = getWeatherNode(subject);
resultSet.add(new TripleImpl(subject, predicate, weatherNode));
}
} else {
NonLiteral city = null;
Collection<NonLiteral> obsoleteCities = new ArrayList<NonLiteral>();
for (Map.Entry<NonLiteral, WeakReference<BNode>> entry : cityWeatherMap.entrySet()) {
BNode node = entry.getValue().get();
if (node == null) {
obsoleteCities.add(entry.getKey());
}
if (node.equals(subject)) {
city = entry.getKey();
break;
}
}
for (NonLiteral nonLiteral : obsoleteCities) {
cityWeatherMap.remove(nonLiteral);
}
if (predicate.equals(temperatureProperty) || (predicate == null)) {
resultSet.add(new TripleImpl(subject,
temperatureProperty, LiteralFactory.getInstance().createTypedLiteral((double)city.toString().length())));
}
if (predicate.equals(humidityProperty) || (predicate == null)) {
resultSet.add(new TripleImpl(subject,
humidityProperty, LiteralFactory.getInstance().createTypedLiteral(0.51)));
}
}
return resultSet.iterator();
}
/**
* for every city the is one weather node
*
* @param subject
* @return
*/
private synchronized BNode getWeatherNode(NonLiteral city) {
WeakReference<BNode> nodeRef = cityWeatherMap.get(city);
if (nodeRef != null) {
BNode node = nodeRef.get();
if (node != null) {
return node;
}
}
BNode newNode = createLocalBNode();
cityWeatherMap.put(city, new WeakReference<BNode>(newNode));
return newNode;
}
@Override
public int providedTriplesCount(TripleCollection base) {
int count = 0;
for (Iterator<Triple> bas = base.filter(null, RDF.type, classCity); bas.hasNext();) {
bas.next();
count++;
}
return count * 4;
}
}