/* Copyright 2014 The Johns Hopkins University Applied Physics Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.jhuapl.tinkerpop.tables.core; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import org.apache.accumulo.core.client.BatchWriter; import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.Scanner; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Range; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.iterators.user.RegExFilter; import org.apache.hadoop.io.Text; import com.tinkerpop.blueprints.Element; import com.tinkerpop.blueprints.util.StringFactory; import edu.jhuapl.tinkerpop.AccumuloByteSerializer; import edu.jhuapl.tinkerpop.Constants; import edu.jhuapl.tinkerpop.GlobalInstances; import edu.jhuapl.tinkerpop.mutator.property.ClearPropertyMutator; import edu.jhuapl.tinkerpop.mutator.property.WritePropertyMutator; import edu.jhuapl.tinkerpop.mutator.Mutators; import edu.jhuapl.tinkerpop.parser.PropertyParser; import edu.jhuapl.tinkerpop.tables.BaseTableWrapper; /** * Wrapper around tables with operations * common to {@link Element}s. */ public abstract class ElementTableWrapper extends BaseTableWrapper { private BatchWriter writer; public ElementTableWrapper(GlobalInstances globals, String tableName) { super(globals, tableName); writer = super.getWriter(); } /** * Give a single instance of the writer for this table. */ @Override protected BatchWriter getWriter() { return writer; } /** * Read the given property from the backing table * for the given element id. * @param id * @param key * @return */ public <V> V readProperty(Element element, String key) { Scanner s = getScanner(); s.setRange(new Range(element.getId().toString())); Text colf = StringFactory.LABEL.equals(key) ? new Text(Constants.LABEL) : new Text(key); s.fetchColumnFamily(colf); V value = null; Iterator<Entry<Key, Value>> iter = s.iterator(); if (iter.hasNext()) { value = AccumuloByteSerializer.deserialize(iter.next().getValue().get()); } s.close(); return value; } /** * Read all properties for the given element * from the backing table. * If the element has no properties, return an empty Map. * If the element does not exist, return null. * @param element * @return */ public Map<String, Object> readAllProperties(Element element) { return readProperties(element, null); } /** * Read the given properties for the given element. * If propertyKeys is null, read all properties. * If the element has no properties, return an empty Map. * If the element does not exist, return null. * @param id * @param propertyKeys * @return */ public Map<String, Object> readProperties(Element element, String[] propertyKeys) { Scanner s = getScanner(); s.setRange(Range.exact((String) element.getId())); // If propertyKeys is null, we read everything. // Otherwise, limit to the given attributes. if (propertyKeys != null) { s.fetchColumnFamily(new Text(Constants.LABEL)); for (String key : propertyKeys) { s.fetchColumnFamily(new Text(key)); } } Map<String, Object> props = new PropertyParser().parse(s); s.close(); return props; } /** * Return true if the element with given id exists. * @param id * @return */ public boolean elementExists(String id) { Scanner scan = null; try { scan = getScanner(); scan.setRange(Range.exact(id)); scan.fetchColumnFamily(new Text(Constants.LABEL)); return new PropertyParser().parse(scan) != null; } finally { if (scan != null) { scan.close(); } } } /** * Get all property keys for the given element id. * @param id * @return */ public Set<String> readPropertyKeys(Element element) { Scanner s = getScanner(); s.setRange(new Range(element.getId().toString())); Set<String> keys = new HashSet<String>(); for (Entry<Key, Value> entry : s) { String cf = entry.getKey().getColumnFamily().toString(); keys.add(cf); } s.close(); // Remove some special keys. keys.remove(Constants.IN_EDGE); keys.remove(Constants.LABEL); keys.remove(Constants.OUT_EDGE); return keys; } /** * Delete the property entry from property table. * @param id * @param key */ public void clearProperty(Element element, String key) { Mutators.apply(getWriter(), new ClearPropertyMutator(element.getId().toString(), key)); globals.checkedFlush(); } /** * Write the given property to the property table. * @param id * @param key * @param value */ public void writeProperty(Element element, String key, Object value) { Mutators.apply(getWriter(), new WritePropertyMutator(element.getId().toString(), key, value)); globals.checkedFlush(); } /** * Add custom iterator to the given scanner so that * it will only return keys with value corresponding to an edge. * @param scan * @param labels */ protected void applyEdgeLabelValueFilter(Scanner scan, String... labels) { StringBuilder regex = new StringBuilder(); for (String lab : labels) { if (regex.length() != 0) regex.append("|"); regex.append(".*"+Constants.ID_DELIM+"\\Q").append(lab).append("\\E$"); } IteratorSetting is = new IteratorSetting(10, "edgeValueFilter", RegExFilter.class); RegExFilter.setRegexs(is, null, null, null, regex.toString(), false); scan.addScanIterator(is); } public void close() { // TODO? } }