/* * Copyright (c) 2007, 2010, 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 net.enilink.komma.em.internal.behaviours; import java.util.AbstractList; import java.util.HashSet; import net.enilink.commons.iterator.ConvertingIterator; import net.enilink.commons.iterator.IExtendedIterator; import net.enilink.composition.annotations.Iri; import net.enilink.composition.annotations.Precedes; 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.IReference; import net.enilink.komma.core.IStatement; import net.enilink.komma.core.IValue; import net.enilink.komma.core.KommaException; import net.enilink.komma.core.Statement; import net.enilink.komma.core.URI; import net.enilink.komma.em.concepts.ResourceSupport; import net.enilink.vocab.rdf.RDF; /** * This behaviour provides a java.util.List interface for RDF containers. * */ @Iri("http://www.w3.org/2000/01/rdf-schema#Container") @Precedes(ResourceSupport.class) public abstract class RDFSContainer extends AbstractList<Object> implements java.util.List<Object>, Refreshable, Mergeable, IEntity, Behaviour<IEntity> { private static final int UNKNOWN = -1; private int _size = UNKNOWN; @Override public void add(int index, Object obj) { boolean active = getEntityManager().getTransaction().isActive(); try { if (!active) { getEntityManager().getTransaction().begin(); } for (int i = size() - 1; i >= index; i--) { replace(i + 1, get(i)); } replace(index, obj); if (_size > UNKNOWN) _size++; if (!active) { getEntityManager().getTransaction().commit(); } } catch (KommaException e) { if (!active) { getEntityManager().getTransaction().rollback(); } throw e; } } private void assign(int index, Object o) { URI pred = getMemberPredicate(index); getEntityManager().add(new Statement(getBehaviourDelegate(), pred, o)); } @Override public Object get(int index) { URI pred = getMemberPredicate(index); IExtendedIterator<IValue> stmts = getStatements(pred); try { if (stmts.hasNext()) { IValue next = stmts.next(); return getEntityManager().toInstance(next); } return null; } finally { stmts.close(); } } private IValue getAndSet(int index, Object o) { URI pred = getMemberPredicate(index); IExtendedIterator<IValue> stmts = getStatements(pred); try { IValue newValue = getEntityManager().toValue(o); IValue oldValue = null; while (stmts.hasNext()) { oldValue = stmts.next(); if (newValue == null || !newValue.equals(oldValue)) { stmts.remove(); } } if (newValue != null && !newValue.equals(oldValue)) { getEntityManager().add( new Statement(getBehaviourDelegate(), pred, newValue)); } return oldValue; } finally { stmts.close(); } } private URI getMemberPredicate(int index) { return RDF.NAMESPACE_URI.appendFragment("_" + (index + 1)); } private int getSize() { try { HashSet<IReference> set = new HashSet<IReference>(); IExtendedIterator<IStatement> result = getEntityManager().match( getBehaviourDelegate(), null, null); try { while (result.hasNext()) { set.add(result.next().getPredicate()); } } finally { result.close(); } int index = 0; while (set.contains(getMemberPredicate(index))) index++; return index; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new KommaException(e); } } private IExtendedIterator<IValue> getStatements(URI pred) { return new ConvertingIterator<IStatement, IValue>(getEntityManager() .match(getBehaviourDelegate(), pred, null)) { IStatement currentStmt; protected IValue convert(IStatement stmt) { currentStmt = stmt; return (IValue) stmt.getObject(); } @Override public void remove() { if (currentStmt != null) { getEntityManager().remove(currentStmt); currentStmt = null; } } }; } public void merge(Object source) { if (source instanceof java.util.List<?>) { boolean active = getEntityManager().getTransaction().isActive(); try { if (!active) { getEntityManager().getTransaction().begin(); } java.util.List<?> list = (java.util.List<?>) source; int size = list.size(); for (int i = 0, n = size; i < n; i++) { assign(i, list.get(i)); } if (_size > UNKNOWN && _size < size) _size = size; if (!active) { getEntityManager().getTransaction().commit(); } } catch (KommaException e) { if (!active) { getEntityManager().getTransaction().rollback(); } throw e; } } } public void refresh() { _size = UNKNOWN; } @Override public Object remove(int index) { boolean active = getEntityManager().getTransaction().isActive(); try { if (!active) { getEntityManager().getTransaction().begin(); } Object obj = get(index); int size = size(); for (int i = index; i < size - 1; i++) { replace(i, get(i + 1)); } URI pred = getMemberPredicate(size - 1); IExtendedIterator<IValue> stmts = getStatements(pred); try { while (stmts.hasNext()) { stmts.next(); stmts.remove(); } } finally { stmts.close(); } if (_size > UNKNOWN) _size--; if (!active) { getEntityManager().getTransaction().commit(); } return obj; } catch (KommaException e) { if (!active) { getEntityManager().getTransaction().rollback(); } throw e; } } private void replace(int index, Object o) { URI pred = getMemberPredicate(index); boolean active = getEntityManager().getTransaction().isActive(); try { if (!active) { getEntityManager().getTransaction().begin(); } getEntityManager().remove( new Statement(getBehaviourDelegate(), pred, null)); getEntityManager().add( new Statement(getBehaviourDelegate(), pred, o)); if (!active) { getEntityManager().getTransaction().commit(); } } catch (KommaException e) { if (!active) { getEntityManager().getTransaction().rollback(); } throw e; } } @Override public Object set(int index, Object obj) { boolean active = getEntityManager().getTransaction().isActive(); try { if (!active) { getEntityManager().getTransaction().begin(); } IValue value = getAndSet(index, obj); Object old = getEntityManager().toInstance(value); if (!active) { getEntityManager().getTransaction().commit(); } return old; } catch (KommaException e) { if (!active) { getEntityManager().getTransaction().rollback(); } throw e; } } @Override public int size() { if (_size < 0) { synchronized (this) { if (_size < 0) { int index = getSize(); _size = index; } } } return _size; } @Override public String toString() { return super.toString(); } }