/**
* OpenSpotLight - Open Source IT Governance Platform
*
* Copyright (c) 2009, CARAVELATECH CONSULTORIA E TECNOLOGIA EM INFORMATICA LTDA
* or third-party contributors as indicated by the @author tags or express
* copyright attribution statements applied by the authors. All third-party
* contributions are distributed under license by CARAVELATECH CONSULTORIA E
* TECNOLOGIA EM INFORMATICA LTDA.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
***********************************************************************
* OpenSpotLight - Plataforma de Governança de TI de Código Aberto
*
* Direitos Autorais Reservados (c) 2009, CARAVELATECH CONSULTORIA E TECNOLOGIA
* EM INFORMATICA LTDA ou como contribuidores terceiros indicados pela etiqueta
* @author ou por expressa atribuição de direito autoral declarada e atribuída pelo autor.
* Todas as contribuições de terceiros estão distribuídas sob licença da
* CARAVELATECH CONSULTORIA E TECNOLOGIA EM INFORMATICA LTDA.
*
* Este programa é software livre; você pode redistribuí-lo e/ou modificá-lo sob os
* termos da Licença Pública Geral Menor do GNU conforme publicada pela Free Software
* Foundation.
*
* Este programa é distribuído na expectativa de que seja útil, porém, SEM NENHUMA
* GARANTIA; nem mesmo a garantia implícita de COMERCIABILIDADE OU ADEQUAÇÃO A UMA
* FINALIDADE ESPECÍFICA. Consulte a Licença Pública Geral Menor do GNU para mais detalhes.
*
* Você deve ter recebido uma cópia da Licença Pública Geral Menor do GNU junto com este
* programa; se não, escreva para:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.openspotlight.storage;
import static com.google.common.collect.Lists.newLinkedList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newLinkedHashSet;
import static org.openspotlight.common.Pair.newPair;
import static org.openspotlight.common.util.Assertions.checkNotEmpty;
import static org.openspotlight.common.util.Assertions.checkNotNull;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openspotlight.common.Pair;
import org.openspotlight.common.util.SLCollections;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaBuilder;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem.CompositeKeyCriteriaItem;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem.NodeKeyCriteriaItem;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem.PropertyContainsString;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem.PropertyCriteriaItem;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem.PropertyEndsWithString;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem.PropertyStartsWithString;
import org.openspotlight.storage.NodeCriteriaImpl.CriteriaBuilderImpl;
import org.openspotlight.storage.domain.NodeFactory;
import org.openspotlight.storage.domain.NodeFactory.NodeBuilder;
import org.openspotlight.storage.domain.Property;
import org.openspotlight.storage.domain.PropertyContainer;
import org.openspotlight.storage.domain.StorageLink;
import org.openspotlight.storage.domain.StorageLinkImpl;
import org.openspotlight.storage.domain.StorageNode;
import org.openspotlight.storage.domain.StorageNodeImpl;
import org.openspotlight.storage.domain.key.NodeKey;
import org.openspotlight.storage.domain.key.NodeKey.CompositeKey.SimpleKey;
import org.openspotlight.storage.domain.key.NodeKeyImpl;
import org.openspotlight.storage.domain.key.NodeKeyImpl.CompositeKeyImpl;
import org.openspotlight.storage.domain.key.NodeKeyImpl.CompositeKeyImpl.SimpleKeyImpl;
import org.openspotlight.storage.engine.StorageEngineBind;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
/**
* Internal (default) implementation of {@link StorageSession}.
*
* @author feuteston
* @author porcelli
* @param <RN> storage engine specific type that represents a node
* @param <RL> storage engine specific type that represents a link
*/
public class StorageSessionImpl<RN, RL> implements StorageSession {
/**
* Internal (default) implementation of {@link NodeFactory.NodeBuilder}.
*
* @author feuteston
* @author porcelli
*/
private final class NodeBuilderImpl implements NodeBuilder {
private final Set<String> keyNames = newHashSet();
private final Set<SimpleKey> keys = newHashSet();
private String parentKey = null;
private final Partition partition;
private final String type;
private NodeBuilderImpl(final String type, final Partition partition) {
this.type = type;
this.partition = partition;
}
/**
* {@inheritDoc}
*/
@Override
public StorageNode andCreate()
throws RuntimeException {
final CompositeKeyImpl localKey = new CompositeKeyImpl(keys, type);
final NodeKeyImpl uniqueKey = new NodeKeyImpl(localKey, parentKey, partition);
final StorageNodeImpl result = new StorageNodeImpl(uniqueKey, false);
if (getFlushMode().equals(FlushMode.AUTO)) {
StorageSessionImpl.this.persistNode(result);
} else {
final RN ref = storageEngine.createNodeReference(result);
final Pair<StorageNode, RN> pair = newPair((StorageNode) result, ref);
StorageSessionImpl.this.newNodes.add(pair);
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public NodeFactory.NodeBuilder withParent(final StorageNode parent)
throws IllegalArgumentException, IllegalStateException {
checkNotNull("parent", parent);
return withParent(parent.getKeyAsString());
}
/**
* {@inheritDoc}
*/
@Override
public NodeBuilder withParent(final String key) {
checkNotEmpty("key", key);
if (this.parentKey != null) { throw new IllegalStateException(); }
this.parentKey = key;
return this;
}
/**
* {@inheritDoc}
*/
@Override
public NodeFactory.NodeBuilder withSimpleKey(final String name, final String value)
throws IllegalArgumentException, IllegalStateException {
checkNotEmpty("name", name);
checkNotEmpty("value", value);
if (keyNames.contains(name)) { throw new IllegalStateException("key name already inserted"); }
this.keys.add(new SimpleKeyImpl(name, value));
this.keyNames.add(name);
return this;
}
}
/**
* Internal (default) implementation of {@link PartitionMethods}.
*
* @author feuteston
* @author porcelli
*/
public class PartitionMethodsImpl implements PartitionMethods {
private final Partition partition;
private PartitionMethodsImpl(final Partition partition) {
this.partition = partition;
}
/**
* {@inheritDoc}
*/
@Override
public NodeCriteriaBuilder createCriteria() {
return new CriteriaBuilderImpl(partition);
}
/**
* {@inheritDoc}
*/
@Override
public StorageNode createNewSimpleNode(final String... nodeTypes)
throws RuntimeException, IllegalStateException {
checkNotEmpty("nodeTypes", nodeTypes);
StorageNode parent = null;
NodeKey parentKey = null;
for (final String nodeType: nodeTypes) {
parentKey =
new NodeKeyImpl(new CompositeKeyImpl(Collections.<SimpleKey>emptySet(), nodeType),
parentKey != null ? parentKey.getKeyAsString() : null,
partition);
parent = new StorageNodeImpl(parentKey, false);
persistNode(parent);
}
return parent;
}
/**
* {@inheritDoc}
*/
@Override
public NodeKeyBuilder createNodeKeyWithType(final String nodeType)
throws IllegalArgumentException {
checkNotEmpty("nodeType", nodeType);
return new NodeKeyBuilderImpl(nodeType, partition);
}
/**
* {@inheritDoc}
*/
@Override
public NodeFactory.NodeBuilder createNodeWithType(final String type)
throws IllegalArgumentException {
checkNotEmpty("type", type);
return this.createWithType(StorageSessionImpl.this, type);
}
/**
* {@inheritDoc}
*/
@Override
public NodeFactory.NodeBuilder createWithType(final StorageSession session, final String type)
throws IllegalArgumentException {
checkNotNull("session", session);
checkNotEmpty("type", type);
return new NodeBuilderImpl(type, partition);
}
/**
* {@inheritDoc}
*/
@Override
public Iterable<String> getAllNodeTypes()
throws RuntimeException {
try {
return storageEngine.getAllNodeTypes(partition);
} catch (final Exception e) {
handleException(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public Iterable<StorageNode> getNodes(final String type)
throws RuntimeException, IllegalArgumentException {
checkNotEmpty("type", type);
try {
return storageEngine.getNodes(partition, type);
} catch (final Exception e) {
handleException(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public Iterable<StorageNode> search(final NodeCriteria criteria)
throws RuntimeException, IllegalArgumentException, IllegalStateException {
checkNotNull("criteria", criteria);
try {
if (!criteria.getPartition().equals(partition)) { throw new IllegalStateException(); }
boolean hasGlobal = false;
boolean hasOther = false;
for (final NodeCriteriaItem item: criteria.getCriteriaItems()) {
if (item instanceof PropertyCriteriaItem) {
hasOther = true;
} else if (item instanceof CompositeKeyCriteriaItem) {
hasOther = true;
} else if (item instanceof PropertyContainsString) {
hasOther = true;
} else if (item instanceof PropertyStartsWithString) {
hasOther = true;
} else if (item instanceof PropertyEndsWithString) {
hasOther = true;
} else if (item instanceof NodeKeyCriteriaItem) {
hasGlobal = true;
}
if (hasOther && hasGlobal) { throw new IllegalStateException(); }
}
return storageEngine.search(criteria);
} catch (final Exception e) {
handleException(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public StorageNode searchUnique(final NodeCriteria criteria)
throws RuntimeException, IllegalArgumentException, IllegalStateException {
checkNotNull("criteria", criteria);
try {
final Iterable<StorageNode> result = search(criteria);
if (result == null) { return null; }
final Iterator<StorageNode> it = result.iterator();
if (!it.hasNext()) { return null; }
return it.next();
} catch (final Exception e) {
handleException(e);
return null;
}
}
}
private final FlushMode flushMode;
private final PartitionFactory partitionFactory;
private final StorageEngineBind<RN, RL> storageEngine;
private final Map<Partition, PartitionMethods> partitionMethods = newHashMap();
private final Multimap<StorageNode, Property> dirtyNodeProperties = ArrayListMultimap.create();
private final Multimap<StorageLink, Property> dirtyLinkProperties = ArrayListMultimap.create();
private final Set<Pair<StorageLink, RL>> newLinks = newLinkedHashSet();
private final Set<Pair<StorageNode, RN>> newNodes = newLinkedHashSet();
private final Set<StorageLink> removedLinks = newLinkedHashSet();
private final Set<StorageNode> removedNodes = newLinkedHashSet();
@Inject
public StorageSessionImpl(final FlushMode flushMode, final PartitionFactory partitionFactory,
final StorageEngineBind<RN, RL> storageEngine) {
if (flushMode == null) { throw new NullPointerException(); }
if (partitionFactory == null) { throw new NullPointerException(); }
this.flushMode = flushMode;
this.partitionFactory = partitionFactory;
this.storageEngine = storageEngine;
}
/**
* Utility method that trows the input as a {@link RuntimeException}. If input is not an instance of {@link RuntimeException}
* it wraps the input into a new one.
*
* @param e parameter exception
* @throws RuntimeException always throwed
*/
private void handleException(final Exception e)
throws RuntimeException {
if (e instanceof RuntimeException) { throw (RuntimeException) e; }
throw new RuntimeException(e);
}
/**
* Serializes the property invoking storage engine {@link StorageEngineBind#setNodeProperty(Object, Property)} operation.
*
* @param reference the engine specific representation of the node
* @param property the property to be serialized
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if property param is null
*/
private void serializeNodeProperty(final RN reference, final Property property)
throws RuntimeException, IllegalArgumentException {
try {
checkNotNull("property", property);
storageEngine.setNodeProperty(reference, property);
} catch (final Exception e) {
handleException(e);
}
}
/**
* Serializes the property invoking storage engine {@link StorageEngineBind#setLinkProperty(Object, Property)} operation.
*
* @param reference the engine specific representation of the link
* @param property the property to be serialized
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if property param is null
*/
private void serializeLinkProperty(final RL reference, final Property property)
throws RuntimeException, IllegalArgumentException {
checkNotNull("property", property);
try {
storageEngine.setLinkProperty(reference, property);
} catch (final Exception e) {
handleException(e);
}
}
/**
* Persists the input node.<br>
* If this session operates in {@link FlushMode#AUTO} mode, it persists the node directly into storage engine, otherwise it
* keep it in memory.
*
* @param node the node to be persisted
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if input param is null
*/
private void persistNode(final StorageNode node)
throws RuntimeException, IllegalArgumentException {
checkNotNull("node", node);
try {
RN reference;
switch (getFlushMode()) {
case AUTO:
reference = storageEngine.createNodeReference(node);
storageEngine.persistNode(reference, node);
break;
case EXPLICIT:
reference = storageEngine.createNodeReference(node);
newNodes.add(newPair(node, reference));
break;
}
} catch (final Exception e) {
handleException(e);
}
}
/**
* Deletes the input node.<br>
* If this session operates in {@link FlushMode#AUTO} mode, it deletes the node directly from storage engine, otherwise it
* keep this operation to be executed later (on {@link #flushTransient()}).
*
* @param node the node to be deleted
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if input param is null
*/
private void deleteNode(final StorageNode node)
throws RuntimeException, IllegalArgumentException {
checkNotNull("node", node);
try {
switch (getFlushMode()) {
case AUTO:
storageEngine.deleteNode(node);
break;
case EXPLICIT:
removedNodes.add(node);
break;
}
} catch (final Exception e) {
handleException(e);
}
}
/**
* Collects children from input node and store into parameter list.
*
* @param node the node to collect its children
* @param collectedChildrenList list that all collected children references will be added
* @throws IllegalArgumentException if any input param is null
*/
private void collectChildren(final StorageNode node, final List<StorageNode> collectedChildrenList)
throws IllegalArgumentException {
checkNotNull("node", node);
checkNotNull("removedItems", collectedChildrenList);
collectedChildrenList.add(node);
for (final Partition p: partitionFactory.getValues()) {
final Iterable<StorageNode> children = node.getChildren(p, this);
for (final StorageNode e: children) {
collectChildren(e, collectedChildrenList);
}
}
}
/**
* Creates a new {@link NodeBuilder} based on input params.
*
* @param partition the partition where node should be stored
* @param parent the parent node
* @param type the node type to be created
* @return a node builder filled with input params
* @throws IllegalArgumentException if any input param is null or empty
*/
public NodeBuilder createNode(final Partition partition, final StorageNode parent, final String type)
throws IllegalArgumentException {
checkNotNull("partition", partition);
checkNotNull("parent", parent);
checkNotEmpty("type", type);
return withPartition(partition).createWithType(StorageSessionImpl.this, type).withParent(parent);
}
/**
* Query storage engine and returns an iterable of children nodes of the input node stored into specific partition.
*
* @param partition the partion to lookup for children nodes
* @param node the node to get its children
* @return an iterable of children nodes, or empty if not found
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if any input param is null
*/
public Iterable<StorageNode> getChildren(final Partition partition, final StorageNode node)
throws RuntimeException, IllegalArgumentException {
checkNotNull("partition", partition);
checkNotNull("node", node);
try {
return storageEngine.getChildren(partition, node);
} catch (final Exception e) {
handleException(e);
}
return null;
}
/**
* Query storage engine and returns an iterable of children nodes of the input node restricted by a given type and stored into
* specific partition.
*
* @param partition the partion to lookup for children nodes
* @param node the node to get its children
* @param type the node type filter
* @return an iterable of children nodes, or empty if not found
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if any input param is null or empty
*/
public Iterable<StorageNode> getChildren(final Partition partition, final StorageNode node, final String type)
throws RuntimeException, IllegalArgumentException {
checkNotNull("partition", partition);
checkNotNull("node", node);
checkNotEmpty("type", type);
try {
return storageEngine.getChildren(partition, node, type);
} catch (final Exception e) {
handleException(e);
}
return null;
}
/**
* Query storage engine and returns the parent node of the input.
*
* @param node the input node to get parent from
* @return parent node, or null if there is no parent
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if input param is null
*/
public StorageNode getParent(final StorageNode node)
throws RuntimeException, IllegalArgumentException {
checkNotNull("node", node);
try {
return storageEngine.getParent(node);
} catch (final Exception e) {
handleException(e);
}
return null;
}
/**
* Query storage engine and returns all existing properties, or an empty {@link Set}, of the input element. <br>
*
* @param element element to get properties from
* @return all properties of the input element
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if input param is null
*/
public Set<Property> getProperties(final PropertyContainer element)
throws RuntimeException, IllegalArgumentException {
checkNotNull("element", element);
try {
return storageEngine.getProperties(element);
} catch (final Exception e) {
handleException(e);
}
return null;
}
/**
* Query storage engine to return the property value as byte array.
*
* @param property the input property to get value from
* @return the value as byte array
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if input param is null
*/
public byte[] getPropertyValue(final Property property)
throws RuntimeException {
checkNotNull("property", property);
try {
return storageEngine.getPropertyValue(property);
} catch (final Exception e) {
handleException(e);
}
return null;
}
/**
* Sets the property value. <br>
* If this session operates in {@link FlushMode#AUTO} mode, it stores the value directly into storage engine, otherwise it
* keep the value in memory.
*
* @param property property to be setted
* @param value the value to be stored
* @throws RuntimeException if there is any exception on storage engine during this operation
* @throws IllegalArgumentException if property param is null
*/
public void setPropertyValue(final Property property, final byte[] value)
throws RuntimeException, IllegalArgumentException {
checkNotNull("property", property);
if (property.getParent() instanceof StorageNode) {
if (flushMode.equals(FlushMode.AUTO)) {
serializeNodeProperty(null, property);
} else {
dirtyNodeProperties.put((StorageNode) property.getParent(), property);
}
} else if (property.getParent() instanceof StorageLink) {
if (flushMode.equals(FlushMode.AUTO)) {
serializeLinkProperty(null, property);
} else {
dirtyLinkProperties.put((StorageLink) property.getParent(), property);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public StorageLink addLink(final StorageNode source, final StorageNode target, final String type)
throws RuntimeException, IllegalArgumentException {
checkNotNull("source", source);
checkNotNull("target", target);
checkNotEmpty("type", type);
final StorageLink link = new StorageLinkImpl(type, source, target, true);
if (getFlushMode().equals(FlushMode.AUTO)) {
try {
storageEngine.persistLink(link);
} catch (final Exception e) {
handleException(e);
}
} else {
final RL ref = storageEngine.createLinkReference(link);
final Pair<StorageLink, RL> pair = newPair(link, ref);
StorageSessionImpl.this.newLinks.add(pair);
}
return link;
}
/**
* {@inheritDoc}
*/
@Override
public void discardTransient() {
this.newNodes.clear();
this.removedNodes.clear();
this.dirtyNodeProperties.clear();
this.dirtyLinkProperties.clear();
}
/**
* {@inheritDoc}
*/
@Override
public void flushTransient()
throws RuntimeException {
if (getFlushMode() == FlushMode.AUTO) { return; }
final Set<Partition> partitions = newHashSet();
final Map<StorageNode, RN> referenceNodeMap = newHashMap();
final Map<StorageLink, RL> referenceLinkMap = newHashMap();
for (final Pair<StorageNode, RN> newNode: newNodes) {
try {
partitions.add(newNode.getK1().getKey().getPartition());
storageEngine.persistNode(newNode.getK2(), newNode.getK1());
referenceNodeMap.put(newNode.getK1(), newNode.getK2());
} catch (final Exception e) {
handleException(e);
}
}
for (final Pair<StorageLink, RL> link: this.newLinks) {
try {
storageEngine.persistLink(link.getK1());
referenceLinkMap.put(link.getK1(), link.getK2());
} catch (final Exception e) {
handleException(e);
}
}
for (final StorageNode node: dirtyNodeProperties.keySet()) {
partitions.add(node.getPartition());
RN reference = referenceNodeMap.get(node);
for (final Property data: dirtyNodeProperties.get(node)) {
try {
serializeNodeProperty(reference, data);
} catch (final Exception e) {
handleException(e);
}
}
}
for (final StorageLink link: dirtyLinkProperties.keySet()) {
partitions.add(link.getPartition());
RL reference = referenceLinkMap.get(link);
for (final Property data: dirtyLinkProperties.get(link)) {
try {
serializeLinkProperty(reference, data);
} catch (final Exception e) {
handleException(e);
}
}
}
for (final StorageNode removedNode: removedNodes) {
try {
partitions.add(removedNode.getKey().getPartition());
storageEngine.deleteNode(removedNode);
} catch (final Exception e) {
handleException(e);
}
}
for (final StorageLink link: this.removedLinks) {
try {
storageEngine.deleteLink(link);
} catch (final Exception e) {
handleException(e);
}
}
try {
storageEngine.save(partitions.toArray(new Partition[partitions.size()]));
} catch (final Exception e) {
handleException(e);
}
discardTransient();
}
/**
* {@inheritDoc}
*/
@Override
public FlushMode getFlushMode() {
return flushMode;
}
/**
* {@inheritDoc}
*/
@Override
public StorageLink getLink(final StorageNode source, final StorageNode target, final String type)
throws RuntimeException, IllegalArgumentException {
checkNotNull("source", source);
checkNotNull("target", target);
checkNotEmpty("type", type);
try {
return SLCollections.firstOf(storageEngine.getLinks(source, target, type));
} catch (final Exception e) {
handleException(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public Iterable<StorageLink> getLinks(final StorageNode source)
throws RuntimeException, IllegalArgumentException {
checkNotNull("source", source);
try {
return storageEngine.getLinks(source, null, null);
} catch (final Exception e) {
handleException(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public Iterable<StorageLink> getLinks(final StorageNode source, final StorageNode target)
throws RuntimeException, IllegalArgumentException {
checkNotNull("source", source);
checkNotNull("target", target);
try {
return storageEngine.getLinks(source, target, null);
} catch (final Exception e) {
handleException(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public Iterable<StorageLink> getLinks(final StorageNode source, final String type)
throws RuntimeException, IllegalArgumentException {
checkNotNull("source", source);
checkNotEmpty("type", type);
try {
return storageEngine.getLinks(source, null, type);
} catch (final Exception e) {
handleException(e);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public StorageNode getNode(final String key)
throws RuntimeException, IllegalArgumentException {
checkNotEmpty("key", key);
final Partition partition = partitionFactory.getPartition(StringKeysSupport.getPartitionName(key));
return withPartition(partition).createCriteria().withUniqueKeyAsString(key).buildCriteria().andSearchUnique(this);
}
/**
* {@inheritDoc}
*/
@Override
public void removeLink(final StorageLink link)
throws RuntimeException, IllegalArgumentException {
checkNotNull("link", link);
try {
switch (getFlushMode()) {
case AUTO:
storageEngine.deleteLink(link);
break;
case EXPLICIT:
removedLinks.add(link);
break;
}
} catch (final Exception e) {
handleException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public void removeLink(final StorageNode source, final StorageNode target, final String type)
throws RuntimeException, IllegalArgumentException {
checkNotNull("source", source);
checkNotNull("target", target);
checkNotNull("type", type);
removeLink(new StorageLinkImpl(type, source, target, false));
}
/**
* {@inheritDoc}
*/
@Override
public void removeNode(final StorageNode node)
throws RuntimeException, IllegalArgumentException {
checkNotNull("node", node);
final List<StorageNode> removedItems = newLinkedList();
collectChildren(node, removedItems);
Collections.reverse(removedItems);
for (final StorageNode r: removedItems) {
deleteNode(r);
}
}
/**
* {@inheritDoc}
*/
@Override
public PartitionMethods withPartition(final Partition partition)
throws IllegalArgumentException {
checkNotNull("partition", partition);
PartitionMethods result = partitionMethods.get(partition);
if (result == null) {
result = new PartitionMethodsImpl(partition);
partitionMethods.put(partition, result);
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public void closeResources() {
storageEngine.closeResources();
}
}