/*
* Copyright (c) 2007-2009, James Leigh All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the openrdf.org nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.openrdf.repository.object.advisers.helpers;
import info.aduna.iteration.CloseableIteration;
import info.aduna.iteration.ConvertingIteration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.openrdf.repository.object.ObjectConnection;
import org.openrdf.repository.object.exceptions.ObjectPersistException;
import org.openrdf.repository.object.exceptions.ObjectStoreException;
import org.openrdf.repository.object.result.ObjectIterator;
import org.openrdf.repository.object.traits.ManagedRDFObject;
import org.openrdf.repository.object.traits.Refreshable;
/**
* A set for a given getResource(), predicate.
*
* @author James Leigh
*/
public class RemotePropertySet implements PropertySet, Set<Object> {
private final ManagedRDFObject bean;
protected PropertySetModifier property;
public RemotePropertySet(ManagedRDFObject bean, PropertySetModifier property) {
assert bean != null;
assert property != null;
this.bean = bean;
this.property = property;
}
public void refresh() {
// no-op
}
/**
* This method always returns <code>true</code>
*
* @return <code>true</code>
*/
public boolean add(Object o) {
ObjectConnection conn = getObjectConnection();
try {
Value value = getValue(o);
add(conn, getResource(), value);
if (value instanceof Resource) {
refreshEntity();
}
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
refresh();
refresh(o);
return true;
}
public boolean addAll(Collection<?> c) {
ObjectConnection conn = getObjectConnection();
boolean modified = false;
try {
boolean autoCommit = conn.isAutoCommit();
if (autoCommit)
conn.setAutoCommit(false);
try {
for (Object o : c)
if (add(o))
modified = true;
if (autoCommit)
conn.setAutoCommit(true);
} finally {
if (autoCommit && !conn.isAutoCommit()) {
conn.rollback();
conn.setAutoCommit(true);
}
}
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
refresh();
refreshEntity();
return modified;
}
public void clear() {
try {
property.remove(getObjectConnection(), getResource(), null);
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
refresh();
refreshEntity();
}
public boolean contains(Object o) {
ObjectConnection conn = getObjectConnection();
try {
Value val = getValue(o);
return conn.hasStatement(getResource(), getURI(), val);
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
}
public boolean containsAll(Collection<?> c) {
Iterator<?> e = c.iterator();
while (e.hasNext())
if (!contains(e.next()))
return false;
return true;
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!o.getClass().equals(this.getClass()))
return false;
RemotePropertySet p = (RemotePropertySet) o;
if (!getResource().equals(p.getResource()))
return false;
if (!property.equals(p.property))
return false;
if (!getObjectConnection().equals(p.getObjectConnection()))
return false;
return true;
}
public Set<Object> getAll() {
return this;
}
public Object getSingle() {
ObjectIterator<?, Object> iter = getObjectIterator();
try {
if (iter.hasNext())
return iter.next();
return null;
} finally {
iter.close();
}
}
@Override
public int hashCode() {
int hashCode = getResource().hashCode();
hashCode ^= property.hashCode();
return hashCode;
}
public boolean isEmpty() {
ObjectIterator<?, Object> iter = getObjectIterator();
try {
return !iter.hasNext();
} finally {
iter.close();
}
}
/**
* This method always returns <code>true</code>
*
* @return <code>true</code>
*/
public boolean remove(Object o) {
ObjectConnection conn = getObjectConnection();
try {
Value value = getValue(o);
remove(conn, getResource(), value);
if (value instanceof Resource) {
refreshEntity();
}
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
refresh(o);
refresh();
return true;
}
public boolean removeAll(Collection<?> c) {
ObjectConnection conn = getObjectConnection();
boolean modified = false;
try {
boolean autoCommit = conn.isAutoCommit();
if (autoCommit)
conn.setAutoCommit(false);
try {
for (Object o : c)
if (remove(o))
modified = true;
if (autoCommit)
conn.setAutoCommit(true);
} finally {
if (autoCommit && !conn.isAutoCommit()) {
conn.rollback();
conn.setAutoCommit(true);
}
}
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
refresh();
refreshEntity();
return modified;
}
public boolean retainAll(Collection<?> c) {
ObjectConnection conn = getObjectConnection();
boolean modified = false;
try {
boolean autoCommit = conn.isAutoCommit();
if (autoCommit)
conn.setAutoCommit(false);
ObjectIterator<?, Object> e = getObjectIterator();
try {
while (e.hasNext()) {
if (!c.contains(e.next())) {
e.remove();
modified = true;
}
}
} finally {
e.close();
}
if (autoCommit)
conn.setAutoCommit(true);
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
refresh();
refreshEntity();
return modified;
}
public void setAll(Set<?> set) {
if (this == set)
return;
if (set == null) {
clear();
return;
}
Set<Object> c = new HashSet<Object>(set);
ObjectConnection conn = getObjectConnection();
try {
boolean autoCommit = conn.isAutoCommit();
if (autoCommit)
conn.setAutoCommit(false);
try {
clear();
addAll(c);
if (autoCommit)
conn.setAutoCommit(true);
} finally {
if (autoCommit && !conn.isAutoCommit()) {
conn.rollback();
conn.setAutoCommit(true);
}
}
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
}
public void setSingle(Object o) {
if (o == null) {
clear();
} else {
ObjectConnection conn = getObjectConnection();
try {
boolean autoCommit = conn.isAutoCommit();
if (autoCommit)
conn.setAutoCommit(false);
try {
clear();
add(o);
if (autoCommit)
conn.setAutoCommit(true);
} finally {
if (autoCommit && !conn.isAutoCommit()) {
conn.rollback();
conn.setAutoCommit(true);
}
}
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
}
}
}
public int size() {
CloseableIteration<? extends Statement, RepositoryException> iter;
try {
iter = getStatements();
try {
int size;
for (size = 0; iter.hasNext(); size++)
iter.next();
return size;
} finally {
iter.close();
}
} catch (RepositoryException e) {
throw new ObjectStoreException(e);
}
}
public Iterator<Object> iterator() {
return getObjectIterator();
}
public Object[] toArray() {
List<Object> list = new ArrayList<Object>();
ObjectIterator<?, Object> iter = getObjectIterator();
try {
while (iter.hasNext()) {
list.add(iter.next());
}
} finally {
iter.close();
}
return list.toArray();
}
public <T> T[] toArray(T[] a) {
List<Object> list = new ArrayList<Object>();
ObjectIterator<?, Object> iter = getObjectIterator();
try {
while (iter.hasNext()) {
list.add(iter.next());
}
} finally {
iter.close();
}
return list.toArray(a);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
ObjectIterator<?, Object> iter = getObjectIterator();
try {
if (iter.hasNext()) {
sb.append(iter.next().toString());
}
while (iter.hasNext()) {
sb.append(", ");
sb.append(iter.next());
}
} finally {
iter.close();
}
return sb.toString();
}
final ObjectConnection getObjectConnection() {
return bean.getObjectConnection();
}
final Resource getResource() {
return bean.getResource();
}
final URI getURI() {
return property.getPredicate();
}
void add(ObjectConnection conn, Resource subj, Value obj)
throws RepositoryException {
property.add(conn, subj, obj);
}
void remove(ObjectConnection conn, Resource subj, Value obj)
throws RepositoryException {
property.remove(conn, subj, obj);
}
void remove(ObjectConnection conn, Statement stmt)
throws RepositoryException {
assert stmt.getPredicate().equals(getURI());
remove(conn, stmt.getSubject(), stmt.getObject());
}
protected Object createInstance(Value value) throws RepositoryException {
if (value instanceof Resource)
return getObjectConnection().getObject((Resource) value);
return getObjectConnection().getObjectFactory().createObject(
((Literal) value));
}
protected RepositoryResult<Statement> getStatements() throws RepositoryException {
ObjectConnection conn = getObjectConnection();
return conn.getStatements(getResource(), getURI(), null);
}
protected CloseableIteration<Value, RepositoryException> getValues() throws RepositoryException {
return new ConvertingIteration<Statement, Value, RepositoryException>(getStatements()) {
@Override
protected Value convert(Statement st) throws RepositoryException {
return st.getObject();
}
};
}
protected Value getValue(Object instance) throws RepositoryException {
return getObjectConnection().addObject(instance);
}
protected void refresh(Object o) {
if (o instanceof Refreshable) {
((Refreshable) o).refresh();
}
}
protected void refreshEntity() {
refresh(bean);
}
protected CloseableIteration<?, ?> getObjects() throws RepositoryException, QueryEvaluationException {
return new ConvertingIteration<Value, Object, RepositoryException>(getValues()) {
@Override
protected Object convert(Value value) throws RepositoryException {
return createInstance(value);
}
};
}
protected ObjectIterator<?, Object> getObjectIterator() {
try {
return new ObjectIterator<Object, Object>(getObjects()) {
@Override
protected void remove(Object o) {
RemotePropertySet.this.remove(o);
}
};
} catch (RepositoryException e) {
throw new ObjectPersistException(e);
} catch (QueryEvaluationException e) {
throw new ObjectPersistException(e);
}
}
}