/*******************************************************************************
* Copyright (c) 2009, 2010 Fraunhofer IWU and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Fraunhofer IWU - initial API and implementation
*******************************************************************************/
package net.enilink.komma.em.internal.behaviours;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import net.enilink.commons.iterator.ConvertingIterator;
import net.enilink.commons.iterator.IExtendedIterator;
import net.enilink.composition.properties.traits.Mergeable;
import net.enilink.composition.properties.traits.Refreshable;
import net.enilink.composition.traits.Behaviour;
import net.enilink.komma.core.IEntity;
import net.enilink.komma.core.IEntityManager;
import net.enilink.komma.core.IReference;
import net.enilink.komma.core.IStatement;
import net.enilink.komma.core.IValue;
import net.enilink.komma.core.Statement;
import net.enilink.komma.core.URI;
import net.enilink.vocab.komma.KOMMA;
public abstract class AbstractRDFMap extends
java.util.AbstractMap<Object, Object> implements
java.util.Map<Object, Object>, Refreshable, Mergeable, IEntity,
Behaviour<IEntity> {
private class Entry implements Map.Entry<Object, Object> {
private Object key;
private Object value;
public Entry(Object key, Object value) {
this.key = key;
this.value = value;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Map.Entry<?, ?>))
return false;
Map.Entry<?, ?> candidate = (Map.Entry<?, ?>) obj;
if ((this.key.equals(candidate.getKey()))
&& (this.value.equals(candidate.getValue()))) {
return true;
} else {
return false;
}
}
@Override
public Object getKey() {
return key;
}
@Override
public Object getValue() {
return value;
}
@Override
public Object setValue(Object value) {
throw new UnsupportedOperationException();
}
}
private final class EntrySet extends AbstractSet<Map.Entry<Object, Object>> {
public void clear() {
throw new UnsupportedOperationException();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry<?, ?>))
return false;
Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
Map.Entry<?, ?> candidate;
try {
candidate = getEntryAsRDF4JMapEntry(e.getKey());
} catch (Exception e1) {
return false;
}
return candidate != null && candidate.equals(e);
}
public Iterator<Map.Entry<Object, Object>> iterator() {
return new SimpleRDF4JMapIterator();// newEntryIterator();
}
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
public int size() {
throw new UnsupportedOperationException();
}
}
private class SimpleRDF4JMapIterator implements
Iterator<java.util.Map.Entry<Object, Object>> {
private Stack<Entry> elements;
public SimpleRDF4JMapIterator() {
elements = new Stack<Entry>();
IExtendedIterator<IValue> values = match(getBehaviourDelegate(),
KOMMA.PROPERTY_ENTRY, null);
while (values.hasNext()) {
elements.push(createMapEntry(values.next()));
}
}
@Override
public boolean hasNext() {
if (elements.empty())
return false;
else
return true;
}
@Override
public Entry next() {
return elements.pop();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
private int _size = 0;
private transient Set<Map.Entry<Object, Object>> entrySet;
IEntityManager manager;
transient volatile int modCount;
final String SELECT_ENTRY_BY_KEY = "PREFIX komma:<" + KOMMA.NAMESPACE
+ "> " + "SELECT DISTINCT ?entry where {?resource komma:"
+ KOMMA.PROPERTY_ENTRY.localPart() + " ?entry "
+ ". ?entry komma:" + getUri4Key().localPart() + " ?key}";
void addStatement(IReference subj, URI pred, Object obj) {
if (obj == null) {
return;
}
getEntityManager().add(new Statement(subj, pred, obj));
}
@Override
public void clear() {
IExtendedIterator<IValue> values = match(getBehaviourDelegate(),
KOMMA.PROPERTY_ENTRY, null);
while (values.hasNext()) {
removeEntry((IReference) values.next());
}
}
@Override
public boolean containsKey(Object key) {
try {
if (getEntry(key) == null) {
return false;
} else {
return true;
}
} catch (Exception e) {
return false;
}
}
private Entry createMapEntry(IValue v) {
IExtendedIterator<IValue> it = null;
IValue key, value;
try {
it = match((IReference) v, getUri4Value(), null);
value = it.next();
} finally {
it.close();
}
it = match((IReference) v, getUri4Key(), null);
key = it.next();
Entry entry = (Entry) new AbstractRDFMap.Entry(getEntityManager()
.toInstance(key), getEntityManager().toInstance(value));
return entry;
}
@Override
public Set<java.util.Map.Entry<Object, Object>> entrySet() {
Set<Map.Entry<Object, Object>> es = entrySet;
return es != null ? es : (entrySet = new EntrySet());
}
@Override
public Object get(Object key) {
IReference entry = getEntry(key);
if (entry == null) {
return null;
}
IExtendedIterator<IValue> values = match(entry, getUri4Value(), null);
try {
if (values.hasNext()) {
return getEntityManager().toInstance(values.next());
}
} finally {
values.close();
}
return null;
}
private IReference getEntry(Object key) {
IExtendedIterator<IReference> result = null;
try {
result = getEntityManager().createQuery(SELECT_ENTRY_BY_KEY)
.setParameter("resource", getBehaviourDelegate())
.setParameter("key", key)
.evaluateRestricted(IReference.class);
if (result.hasNext()) {
return result.next();
}
} finally {
if (result != null) {
result.close();
}
}
return null;
}
private AbstractRDFMap.Entry getEntryAsRDF4JMapEntry(Object key)
throws Exception {
return createMapEntry(getEntry(key));
}
protected abstract URI getUri4Key();
protected abstract URI getUri4Value();
@Override
public Set<Object> keySet() {
return super.keySet();
}
private IExtendedIterator<IValue> match(IReference subj, URI pred,
IValue obj) {
return new ConvertingIterator<IStatement, IValue>(getEntityManager()
.match(subj, pred, obj)) {
protected IValue convert(IStatement stmt) {
return (IValue) stmt.getObject();
}
};
}
public void merge(Object source) {
if (source instanceof java.util.Map<?, ?>) {
clear();
putAll((java.util.Map<?, ?>) source);
}
}
@Override
public Object put(Object key, Object value) {
Object result = null;
if (containsKey(key)) {
result = get(key);
remove(key);
}
// anonym. Entry anlegen
IEntity mapEntry = manager.create(manager.find(KOMMA.TYPE_MAPENTRY));
// Entry zu Map zuordnen
addStatement(this, KOMMA.PROPERTY_ENTRY, mapEntry);
// Key
addStatement(mapEntry, getUri4Key(), key);
// addProperty(property, obj)
// Value
addStatement(getBehaviourDelegate(), getUri4Value(), value);
_size++;
modCount++;
return result;
}
public void refresh() {
_size = 0;
}
@Override
public Object remove(Object key) {
Object result = get(key);
if (result != null) {
IReference entry = getEntry(key);
removeEntry(entry);
}
return result;
}
private void removeEntry(IReference entry) {
removeStatements(getBehaviourDelegate(), KOMMA.PROPERTY_ENTRY, entry);
removeStatements(entry, getUri4Key(), null);
removeStatements(entry, getUri4Value(), null);
_size--;
}
void removeStatements(IReference subj, URI pred, IValue obj) {
getEntityManager().remove(new Statement(subj, pred, obj));
}
@Override
public int size() {
return _size;
}
@Override
public String toString() {
return super.toString();
}
}