/**
* 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.redis;
import static com.google.common.collect.Lists.newLinkedList;
import static com.google.common.collect.Sets.newHashSet;
import static org.jredis.ri.alphazero.support.DefaultCodec.toStr;
import static org.openspotlight.common.util.Assertions.checkNotNull;
import static org.openspotlight.common.util.Assertions.checkNotEmpty;
import static org.openspotlight.storage.StringKeysSupport.getNodeType;
import static org.openspotlight.storage.StringKeysSupport.getPartition;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.jredis.JRedis;
import org.openspotlight.common.CustomizedFormat;
import org.openspotlight.common.collection.IteratorBuilder;
import org.openspotlight.common.collection.IteratorBuilder.Converter;
import org.openspotlight.storage.NodeCriteria;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem.CompositeKeyCriteriaItem;
import org.openspotlight.storage.NodeCriteria.NodeCriteriaItem.NodeKeyAsStringCriteriaItem;
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.NodeKeyBuilder;
import org.openspotlight.storage.NodeKeyBuilderImpl;
import org.openspotlight.storage.Partition;
import org.openspotlight.storage.PartitionFactory;
import org.openspotlight.storage.StringKeysSupport;
import org.openspotlight.storage.domain.Property;
import org.openspotlight.storage.domain.PropertyContainer;
import org.openspotlight.storage.domain.PropertyImpl;
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.engine.StorageEngineBind;
import org.openspotlight.storage.redis.JRedisStorageSessionImpl.Nothing;
import org.openspotlight.storage.redis.guice.JRedisFactory;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
/**
* Created by User: feu - Date: Mar 23, 2010 - Time: 4:46:25 PM
*/
public class JRedisStorageSessionImpl implements StorageEngineBind<Nothing, Nothing> {
public enum Nothing {
NOTHING
}
private class JRedisLoggedExecution {
private final JRedis jredis;
private final String usedKeys;
private final String uuid;
private JRedisLoggedExecution(final String uuid, final JRedis jredis) {
usedKeys = SET_WITH_ALL_DEPENDENT_KEYS.format(uuid);
this.jredis = jredis;
this.uuid = uuid;
}
public void sadd(final String s, final String o)
throws Exception {
jredis.sadd(s, o);
if (!s.contains(uuid)) {
jredis.sadd(usedKeys, s);
}
}
public void set(final String s, final byte[] o)
throws Exception {
jredis.set(s, o);
if (!s.contains(uuid)) {
jredis.sadd(usedKeys, s);
}
}
public void set(final String s, final String o)
throws Exception {
jredis.set(s, o);
if (!s.contains(uuid)) {
jredis.sadd(usedKeys, s);
}
}
// public void sadd(final String s,
// final byte[] o)
// throws Exception {
// jredis.sadd(s, o);
// if (!s.contains(uuid)) {
// jredis.sadd(usedKeys, s);
// }
// }
//
// public void sadd(final String s,
// final Number o)
// throws Exception {
// jredis.sadd(s, o);
// if (!s.contains(uuid)) {
// jredis.sadd(usedKeys, s);
// }
// }
//
// public void sadd(final String s,
// final Serializable o)
// throws Exception {
// jredis.sadd(s, o);
// if (!s.contains(uuid)) {
// jredis.sadd(usedKeys, s);
// }
// }
//
// public void set(final String s,
// final Number o)
// throws Exception {
// jredis.set(s, o);
// if (!s.contains(uuid)) {
// jredis.sadd(usedKeys, s);
// }
// }
//
// public void set(final String s,
// final Serializable o)
// throws Exception {
// jredis.set(s, o);
// if (!s.contains(uuid)) {
// jredis.sadd(usedKeys, s);
// }
// }
}
private static enum PropertyType {
INDEXED(SET_WITH_NODE_PROPERTY_INDEXED_NAMES, true, false),
KEY(SET_WITH_NODE_PROPERTY_KEY_NAMES, true, true),
SIMPLE(SET_WITH_NODE_PROPERTY_SIMPLE_NAMES, false, false);
private final CustomizedFormat f;
private final boolean indexed;
private final boolean key;
private PropertyType(final CustomizedFormat f, final boolean indexed,
final boolean key) {
this.f = f;
this.key = key;
this.indexed = indexed;
}
public PropertyImpl createProperty(final String name, final PropertyContainer parent) {
if (isKey()) { return PropertyImpl.createKey(name, parent); }
if (isIndexed()) { return PropertyImpl.createIndexed(name, parent); }
return PropertyImpl.createSimple(name, parent);
}
public String getSetName(final String uniqueId) {
return f.format(uniqueId);
}
public boolean isIndexed() {
return indexed;
}
public boolean isKey() {
return key;
}
}
private static enum SearchType {
EQUAL,
STRING_CONTAINS,
STRING_ENDS_WITH,
STRING_STARTS_WITH
}
private static final String SET_WITH_ALL_KEY_NAMES = "names";
private static final String SET_WITH_ALL_KEYS = "uids";
private static final CustomizedFormat KEY_WITH_PARENT_UNIQUE_ID = new CustomizedFormat("nuid: :prt-uid");
private static final CustomizedFormat KEY_WITH_PROPERTY_VALUE = new CustomizedFormat("nuid: :pname: :value");
private static final CustomizedFormat SET_WITH_ALL_DEPENDENT_KEYS = new CustomizedFormat("nuid: :dependent-keys");
private static final CustomizedFormat SET_WITH_ALL_LINKS_FOR_SOURCE = new CustomizedFormat("lorigin: :uids");
private static final CustomizedFormat SET_WITH_ALL_LINKS_FOR_TARGET = new CustomizedFormat("ltarget: :uids");
private static final CustomizedFormat SET_WITH_ALL_LINKS_FOR_TYPE = new CustomizedFormat("ltype: :uids");
private static final CustomizedFormat SET_WITH_ALL_LOCAL_KEYS = new CustomizedFormat("lkeys: :uids");
private static final CustomizedFormat SET_WITH_ALL_NODE_KEYS_FOR_TYPE = new CustomizedFormat("type: :uids");
private static final CustomizedFormat SET_WITH_INDEX_ENTRY = new CustomizedFormat("index: :pname: :uid");
private static final CustomizedFormat SET_WITH_NODE_CHILDREN_KEYS = new CustomizedFormat("nuid: :cld-uids");
private static final CustomizedFormat SET_WITH_NODE_CHILDREN_NAMED_KEYS = new CustomizedFormat("nuid: :nname: :cld-uids");
private static final CustomizedFormat SET_WITH_NODE_PROPERTY_INDEXED_NAMES = new CustomizedFormat("nuid: :inames");
private static final CustomizedFormat SET_WITH_NODE_PROPERTY_KEY_NAMES = new CustomizedFormat("nuid: :knames");
private static final CustomizedFormat SET_WITH_NODE_PROPERTY_SIMPLE_NAMES = new CustomizedFormat("nuid: :pnames");
private final JRedisFactory factory;
private final PartitionFactory partitionFactory;
@Inject
public JRedisStorageSessionImpl(final JRedisFactory factory, final PartitionFactory partitionFactory) {
this.factory = factory;
this.partitionFactory = partitionFactory;
}
private static List<String> listBytesToListString(final List<byte[]> ids) {
final List<String> idsAsString = newLinkedList();
if (ids != null) {
for (final byte[] b: ids) {
final String s = toStr(b);
idsAsString.add(s);
}
}
return idsAsString;
}
private void flushRemoved(final PropertyContainer entry, final String entryName)
throws Exception {
final JRedis jredis = factory.getFrom(entry.getPartition());
final String uniqueKey = entry.getKeyAsString();
jredis.srem(SET_WITH_ALL_KEYS, uniqueKey);
if (entryName != null) {
jredis.srem(SET_WITH_ALL_NODE_KEYS_FOR_TYPE.format(entryName), uniqueKey);
}
final String simpleProperties = SET_WITH_NODE_PROPERTY_SIMPLE_NAMES.format(uniqueKey);
final String keyProperties = SET_WITH_NODE_PROPERTY_KEY_NAMES.format(uniqueKey);
final String indexedProperties = SET_WITH_NODE_PROPERTY_INDEXED_NAMES.format(uniqueKey);
final List<String> allPropertyNames = newLinkedList();
allPropertyNames.addAll(listBytesToListString(jredis.smembers(simpleProperties)));
allPropertyNames.addAll(listBytesToListString(jredis.smembers(keyProperties)));
allPropertyNames.addAll(listBytesToListString(jredis.smembers(indexedProperties)));
for (final String s: allPropertyNames) {
jredis.del(SET_WITH_NODE_CHILDREN_NAMED_KEYS.format(uniqueKey, s), KEY_WITH_PROPERTY_VALUE.format(uniqueKey, s));
}
jredis.del(simpleProperties, keyProperties, indexedProperties, SET_WITH_NODE_CHILDREN_KEYS.format(uniqueKey),
KEY_WITH_PARENT_UNIQUE_ID.format(uniqueKey));
final String dependentKeys = SET_WITH_ALL_DEPENDENT_KEYS.format(uniqueKey);
final List<String> keys = listBytesToListString(jredis.smembers(dependentKeys));
for (final String key: keys) {
if (key.contains(uniqueKey)) {
jredis.del(key);
} else {
final List<String> possibleValues = listBytesToListString(jredis.smembers(key));
for (final String possibleValue: possibleValues) {
if (possibleValue.contains(uniqueKey)) {
jredis.srem(key, possibleValue);
}
}
}
}
jredis.del(dependentKeys);
}
private void internalFlushSimplePropertyAndCreateIndex(final JRedisLoggedExecution exec, final Partition partition,
final String propertyName, final byte[] propertyValue,
final String uniqueKey, final PropertyType propertyType)
throws Exception {
final JRedis jredis = factory.getFrom(partition);
final String setName = propertyType.getSetName(uniqueKey);
exec.sadd(setName, propertyName);
final String valueKey = KEY_WITH_PROPERTY_VALUE.format(uniqueKey, propertyName);
if (propertyType.isIndexed()) {
final String stripped = stripString(propertyValue != null ? new String(propertyValue) : null);
if (jredis.exists(valueKey)) {
final String existent = stripString(toStr(jredis.get(valueKey)));
if (!existent.equals(stripped)) {
jredis.srem(SET_WITH_INDEX_ENTRY.format(existent, propertyName), uniqueKey);
exec.sadd(SET_WITH_INDEX_ENTRY.format(stripped, propertyName), uniqueKey);
}
} else {
exec.sadd(SET_WITH_INDEX_ENTRY.format(stripped, propertyName), uniqueKey);
}
}
if (propertyValue != null) {
exec.set(valueKey, propertyValue);
} else {
jredis.del(valueKey);
}
}
private Collection<String> keysFromProperty(final JRedis jredis, final String nodeEntryName, final String propertyName,
final SearchType equal, final String value)
throws Exception {
if (!SearchType.EQUAL.equals(equal)) { throw new UnsupportedOperationException("Finding by " + equal + " isn't supported"); }
final ImmutableList.Builder<String> builder = ImmutableList.builder();
final String transientValueAsString = stripString(value);
final List<String> ids =
listBytesToListString(jredis.smembers(SET_WITH_INDEX_ENTRY.format(transientValueAsString, propertyName)));
for (final String id: ids) {
String propertyValue = toStr(jredis.get(KEY_WITH_PROPERTY_VALUE.format(id, propertyName)));
if (propertyValue == null) {
propertyValue = "null";
}
boolean needsToAdd = false;
switch (equal) {
case EQUAL:
needsToAdd = stripString(propertyValue).equals(transientValueAsString);
break;
}
if (nodeEntryName != null && needsToAdd) {
final String name = getNodeType(id);
if (!nodeEntryName.equals(name)) {
needsToAdd = false;
}
}
if (needsToAdd) {
builder.add(id);
}
}
return builder.build();
}
public StorageNode getNode(final String key)
throws Exception, IllegalStateException {
checkNotEmpty("key", key);
Partition partition = StringKeysSupport.getPartition(key, partitionFactory);
final JRedis jredis = factory.getFrom(partition);
if (!jredis.sismember(SET_WITH_ALL_KEYS, key)) { return null; }
NodeKeyBuilder keyBuilder = new NodeKeyBuilderImpl(getNodeType(key), partition);
final List<String> keyPropertyNames =
listBytesToListString(jredis.smembers(SET_WITH_NODE_PROPERTY_KEY_NAMES.format(key)));
for (final String keyName: keyPropertyNames) {
final String value = toStr(jredis.get(KEY_WITH_PROPERTY_VALUE.format(key, keyName)));
keyBuilder.withSimpleKey(keyName, value);
}
final String parentKey = toStr(jredis.get(KEY_WITH_PARENT_UNIQUE_ID.format(key)));
if (parentKey != null) {
keyBuilder = keyBuilder.withParent(parentKey);
}
final NodeKey uniqueKey = keyBuilder.andCreate();
final StorageNode nodeEntry = createFoundEntryWithKey(uniqueKey);
return nodeEntry;
}
private Property loadProperty(final PropertyContainer node, final String key, final String propertyName,
final PropertyType type)
throws Exception {
final JRedis jredis = factory.getFrom(node.getPartition());
final Property property = type.createProperty(propertyName, node);
if (type.isKey()) {
final String value = toStr(jredis.get(KEY_WITH_PROPERTY_VALUE.format(key, propertyName)));
((PropertyImpl) property).setStringValueOnLoad(value);
}
return property;
}
private String stripString(final String transientValueAsString) {
return transientValueAsString == null ? "null" : transientValueAsString.replaceAll("[ ]|[\n]|[\t]|[\r]", "-");
}
public final StorageNode createFoundEntryWithKey(final NodeKey uniqueKey) {
return new StorageNodeImpl(uniqueKey, true);
}
@Override
public Nothing createLinkReference(final StorageLink link)
throws IllegalStateException {
checkNotNull("link", link);
return Nothing.NOTHING;
}
@Override
public Nothing createNodeReference(final StorageNode node)
throws IllegalStateException {
checkNotNull("node", node);
return Nothing.NOTHING;
}
@Override
public void persistNode(final Nothing reference, final StorageNode node)
throws Exception, IllegalStateException {
checkNotNull("reference", reference);
checkNotNull("node", node);
final String uniqueKey = node.getKey().getKeyAsString();
final JRedis jredis = factory.getFrom(node.getPartition());
final JRedisLoggedExecution jredisExec = new JRedisLoggedExecution(uniqueKey, jredis);
jredisExec.sadd(SET_WITH_ALL_KEYS, uniqueKey);
jredisExec.sadd(SET_WITH_ALL_NODE_KEYS_FOR_TYPE.format(node.getType()), uniqueKey);
jredis.sadd(SET_WITH_ALL_KEY_NAMES, node.getType());
final String parentKeyAsString = node.getKey().getParentKeyAsString();
if (parentKeyAsString != null) {
jredisExec.set(KEY_WITH_PARENT_UNIQUE_ID.format(uniqueKey), parentKeyAsString);
jredisExec.sadd(SET_WITH_NODE_CHILDREN_KEYS.format(parentKeyAsString), uniqueKey);
jredisExec.sadd(SET_WITH_NODE_CHILDREN_NAMED_KEYS.format(parentKeyAsString, node.getType()), uniqueKey);
}
final String localKey = node.getKey().getCompositeKey().getKeyAsString();
jredisExec.sadd(SET_WITH_ALL_LOCAL_KEYS.format(localKey), uniqueKey);
for (final SimpleKey k: node.getKey().getCompositeKey().getKeys()) {
internalFlushSimplePropertyAndCreateIndex(jredisExec, node.getPartition(), k.getKeyName(),
k.getValue() != null ? k.getValue().getBytes() : null, uniqueKey, PropertyType.KEY);
}
}
@Override
public void deleteNode(final StorageNode node)
throws Exception, IllegalArgumentException {
checkNotNull("node", node);
flushRemoved(node, node.getType());
}
@Override
public void deleteLink(final StorageLink link)
throws Exception, IllegalStateException {
checkNotNull("link", link);
final JRedis jredis = factory.getFrom(link.getPartition());
jredis.srem(SET_WITH_ALL_LINKS_FOR_TYPE.format(link.getType()), link.getKeyAsString());
jredis.srem(SET_WITH_ALL_LINKS_FOR_SOURCE.format(link.getSource().getKeyAsString()), link.getKeyAsString());
jredis.srem(SET_WITH_ALL_LINKS_FOR_TARGET.format(link.getTarget().getKeyAsString()), link.getKeyAsString());
flushRemoved(link, null);
}
@Override
public void persistLink(final StorageLink link)
throws Exception, IllegalStateException {
checkNotNull("link", link);
final JRedis jredis = factory.getFrom(link.getSource().getPartition());
jredis.sadd(SET_WITH_ALL_LINKS_FOR_TYPE.format(link.getType()), link.getKeyAsString());
jredis.sadd(SET_WITH_ALL_LINKS_FOR_SOURCE.format(link.getSource().getKeyAsString()), link.getKeyAsString());
jredis.sadd(SET_WITH_ALL_LINKS_FOR_TARGET.format(link.getTarget().getKeyAsString()), link.getKeyAsString());
}
@Override
public Set<StorageNode> search(final NodeCriteria criteria)
throws Exception, IllegalStateException {
checkNotNull("criteria", criteria);
final List<String> propertiesIntersection = newLinkedList();
final List<String> uniqueIdsFromLocalOnes = newLinkedList();
boolean first = true;
final List<String> uniqueIds = newLinkedList();
final JRedis jredis = factory.getFrom(criteria.getPartition());
for (final NodeCriteriaItem c: criteria.getCriteriaItems()) {
if (c instanceof PropertyCriteriaItem) {
final PropertyCriteriaItem p = (PropertyCriteriaItem) c;
if (first) {
propertiesIntersection.addAll(keysFromProperty(jredis, p.getNodeType(), p.getPropertyName(),
SearchType.EQUAL, p.getValue()));
first = false;
} else {
propertiesIntersection.retainAll(keysFromProperty(jredis, p.getNodeType(), p.getPropertyName(),
SearchType.EQUAL, p.getValue()));
}
}
if (c instanceof PropertyContainsString) {
final PropertyContainsString p = (PropertyContainsString) c;
if (first) {
propertiesIntersection.addAll(keysFromProperty(jredis, p.getNodeType(), p.getPropertyName(),
SearchType.STRING_CONTAINS, p.getValue()));
first = false;
} else {
propertiesIntersection.retainAll(keysFromProperty(jredis, p.getNodeType(), p.getPropertyName(),
SearchType.STRING_CONTAINS, p.getValue()));
}
}
if (c instanceof PropertyStartsWithString) {
final PropertyStartsWithString p = (PropertyStartsWithString) c;
if (first) {
propertiesIntersection.addAll(keysFromProperty(jredis, p.getNodeType(), p.getPropertyName(),
SearchType.STRING_STARTS_WITH, p.getValue()));
first = false;
} else {
propertiesIntersection.retainAll(keysFromProperty(jredis, p.getNodeType(), p.getPropertyName(),
SearchType.STRING_STARTS_WITH, p.getValue()));
}
}
if (c instanceof PropertyEndsWithString) {
final PropertyEndsWithString p = (PropertyEndsWithString) c;
if (first) {
propertiesIntersection.addAll(keysFromProperty(jredis, p.getNodeType(), p.getPropertyName(),
SearchType.STRING_ENDS_WITH, p.getValue()));
first = false;
} else {
propertiesIntersection.retainAll(keysFromProperty(jredis, p.getNodeType(), p.getPropertyName(),
SearchType.STRING_ENDS_WITH, p.getValue()));
}
}
if (c instanceof NodeKeyCriteriaItem) {
final NodeKeyCriteriaItem uniqueCriteria = (NodeKeyCriteriaItem) c;
uniqueIds.add(uniqueCriteria.getValue().getKeyAsString());
}
if (c instanceof NodeKeyAsStringCriteriaItem) {
final NodeKeyAsStringCriteriaItem uniqueCriteria = (NodeKeyAsStringCriteriaItem) c;
uniqueIds.add(uniqueCriteria.getKeyAsString());
}
if (c instanceof CompositeKeyCriteriaItem) {
final CompositeKeyCriteriaItem uniqueCriteria = (CompositeKeyCriteriaItem) c;
final String localHash = uniqueCriteria.getValue().getKeyAsString();
uniqueIdsFromLocalOnes.addAll(listBytesToListString(jredis.smembers(SET_WITH_ALL_LOCAL_KEYS.format(localHash))));
}
}
if (criteria.getCriteriaItems().size() == 0) {
final List<String> keys =
listBytesToListString(jredis.smembers(SET_WITH_ALL_NODE_KEYS_FOR_TYPE.format(criteria.getNodeType())));
uniqueIds.addAll(keys);
}
if (!uniqueIds.isEmpty() && !propertiesIntersection.isEmpty()) { throw new IllegalArgumentException(
"criteria with unique ids can't be used with other criteria types"); }
List<String> ids;
if (uniqueIds.isEmpty()) {
ids = propertiesIntersection;
if (!uniqueIdsFromLocalOnes.isEmpty()) {
if (ids.isEmpty()) {
ids = uniqueIdsFromLocalOnes;
} else {
ids.retainAll(uniqueIdsFromLocalOnes);
}
}
} else {
ids = uniqueIds;
}
final Set<StorageNode> nodeEntries = newHashSet();
for (final String id: ids) {
final StorageNode nodeEntry = getNode(id);
if (nodeEntry != null) {
nodeEntries.add(nodeEntry);
}
}
return ImmutableSet.copyOf(nodeEntries);
}
@Override
public Set<StorageNode> getNodes(final Partition partition, final String type)
throws Exception, IllegalStateException {
checkNotNull("partition", partition);
checkNotEmpty("type", type);
final JRedis jRedis = factory.getFrom(partition);
final List<String> ids = listBytesToListString(jRedis.smembers(SET_WITH_ALL_NODE_KEYS_FOR_TYPE.format(type)));
final ImmutableSet.Builder<StorageNode> builder = ImmutableSet.<StorageNode>builder();
for (final String id: ids) {
final StorageNode loadedNode = getNode(id);
if (loadedNode != null) {
builder.add(loadedNode);
}
}
return builder.build();
}
@SuppressWarnings("unchecked")
@Override
public Iterable<StorageLink> getLinks(final StorageNode source, final StorageNode target, final String type)
throws Exception, IllegalStateException {
checkNotNull("source", source);
final JRedis jredis = factory.getFrom(source.getPartition());
final List<String> linkIds =
listBytesToListString(jredis.smembers(SET_WITH_ALL_LINKS_FOR_SOURCE.format(source.getKeyAsString())));
if (target != null) {
final List<String> newIds =
listBytesToListString(jredis.smembers(SET_WITH_ALL_LINKS_FOR_TARGET.format(target.getKeyAsString())));
linkIds.retainAll(newIds);
}
if (type != null) {
final List<String> newIds = listBytesToListString(jredis.smembers(SET_WITH_ALL_LINKS_FOR_TYPE.format(type)));
linkIds.retainAll(newIds);
}
if (linkIds.size() == 0) { return Collections.emptyList(); }
return IteratorBuilder.<StorageLink, String>createIteratorBuilder().withItems(linkIds)
.withConverter(new Converter<StorageLink, String>() {
@Override
public StorageLink convert(final String o)
throws Exception {
final StorageNode originNode =
JRedisStorageSessionImpl.this.getNode(StringKeysSupport.getOriginKeyAsStringFromLinkKey(o));
final String targetId = StringKeysSupport.getTargeyKeyAsStringFromLinkKey(o);
final StorageNode targetNode = JRedisStorageSessionImpl.this.getNode(targetId);
return new StorageLinkImpl(StringKeysSupport.getLinkTypeFromLinkKey(o), originNode, targetNode, true);
}
}).andBuild();
}
@Override
public void setNodeProperty(Nothing reference, Property property)
throws Exception, IllegalStateException {
flushSimpleProperty(reference, property);
}
@Override
public void setLinkProperty(Nothing reference, Property property)
throws Exception, IllegalStateException {
flushSimpleProperty(reference, property);
}
private void flushSimpleProperty(final Nothing reference, final Property property)
throws Exception, IllegalStateException {
checkNotNull("property", property);
final JRedis jredis = factory.getFrom(property.getParent().getPartition());
final String uniqueKey = property.getParent().getKeyAsString();
final JRedisLoggedExecution jredisExecution = new JRedisLoggedExecution(uniqueKey, jredis);
final PropertyType type =
property.isKey() ? PropertyType.KEY : (property.isIndexed() ? PropertyType.INDEXED : PropertyType.SIMPLE);
internalFlushSimplePropertyAndCreateIndex(jredisExecution, property.getParent().getPartition(),
property.getPropertyName(), ((PropertyImpl) property).getTransientValueAsBytes(), uniqueKey, type);
}
@Override
public Iterable<String> getAllNodeTypes(final Partition partition)
throws Exception, IllegalStateException {
checkNotNull("partition", partition);
final JRedis jredis = factory.getFrom(partition);
return listBytesToListString(jredis.smembers(SET_WITH_ALL_KEY_NAMES));
}
@Override
public Set<StorageNode> getChildren(final Partition partition, final StorageNode node)
throws Exception, IllegalStateException {
checkNotNull("partition", partition);
checkNotNull("node", node);
return internalGetChildren(partition, node, null);
}
@Override
public Set<StorageNode> getChildren(final Partition partition, final StorageNode node, final String type)
throws Exception, IllegalStateException {
checkNotNull("partition", partition);
checkNotNull("node", node);
checkNotEmpty("type", type);
return internalGetChildren(partition, node, type);
}
private Set<StorageNode> internalGetChildren(final Partition partition, final StorageNode node, final String type)
throws Exception {
final JRedis jredis = factory.getFrom(partition);
final String parentKey = node.getKey().getKeyAsString();
final String keyName =
type == null ? SET_WITH_NODE_CHILDREN_KEYS.format(parentKey) : SET_WITH_NODE_CHILDREN_NAMED_KEYS.format(parentKey,
type);
final List<String> childrenKeys = listBytesToListString(jredis.smembers(keyName));
final ImmutableSet.Builder<StorageNode> builder = ImmutableSet.builder();
for (final String id: childrenKeys) {
final Partition childPartition = getPartition(id, partitionFactory);
if (partition.equals(childPartition)) {
final StorageNode loadedNode = getNode(id);
if (loadedNode != null) {
builder.add(loadedNode);
}
}
}
return builder.build();
}
@Override
public StorageNode getParent(final StorageNode node)
throws Exception, IllegalStateException {
checkNotNull("node", node);
final String parentKeyAsString = node.getKey().getParentKeyAsString();
if (parentKeyAsString == null) { return null; }
return getNode(parentKeyAsString);
}
@Override
public Set<Property> getProperties(final PropertyContainer element)
throws Exception, IllegalStateException {
checkNotNull("element", element);
final JRedis jredis = factory.getFrom(element.getPartition());
final Set<Property> result = newHashSet();
final String parentKey = element.getKeyAsString();
for (final PropertyType type: PropertyType.values()) {
final String properties = type.getSetName(parentKey);
if (jredis.exists(properties)) {
final List<String> propertyNames = listBytesToListString(jredis.smembers(properties));
for (final String propertyName: propertyNames) {
final Property property = loadProperty(element, parentKey, propertyName, type);
if (property != null) {
result.add(property);
}
}
}
}
return result;
}
@Override
public byte[] getPropertyValue(final Property property)
throws Exception, IllegalStateException {
checkNotNull("property", property);
final JRedis jredis = factory.getFrom(property.getParent().getPartition());
final String uniqueKey = property.getParent().getKeyAsString();
final byte[] propertyValue = jredis.get(KEY_WITH_PROPERTY_VALUE.format(uniqueKey, property.getPropertyName()));
return propertyValue;
}
@Override
public void save(final Partition... partitions)
throws Exception {
for (final Partition p: partitions) {
factory.getFrom(p).save();
}
}
@Override
public void closeResources() {
factory.closeResources();
}
}