fr.inria.atlanmod.neoemf.datastore.estores.impl.DirectWriteHbaseResourceEStoreImpl.java Source code

Java tutorial

Introduction

Here is the source code for fr.inria.atlanmod.neoemf.datastore.estores.impl.DirectWriteHbaseResourceEStoreImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Abel Gmez.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Abel Gmez - initial API and implementation
 ******************************************************************************/
package fr.inria.atlanmod.neoemf.datastore.estores.impl;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import org.apache.commons.lang.ArrayUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Append;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.util.Bytes;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.jboss.util.collection.SoftValueHashMap;

import fr.inria.atlanmod.neoemf.core.NeoEMFEObject;
import fr.inria.atlanmod.neoemf.core.NeoEMFInternalEObject;
import fr.inria.atlanmod.neoemf.core.impl.NeoEMFEObjectAdapterFactoryImpl;
import fr.inria.atlanmod.neoemf.datastore.estores.SearcheableResourceEStore;
import fr.inria.atlanmod.neoemf.logger.Logger;
import fr.inria.atlanmod.neoemf.util.NeoEMFUtil;

public class DirectWriteHbaseResourceEStoreImpl implements SearcheableResourceEStore {

    protected static final byte[] PROPERTY_FAMILY = Bytes.toBytes("p");
    protected static final byte[] TYPE_FAMILY = Bytes.toBytes("t");
    protected static final byte[] METAMODEL_QUALIFIER = Bytes.toBytes("m");
    protected static final byte[] ECLASS_QUALIFIER = Bytes.toBytes("e");
    protected static final byte[] CONTAINMENT_FAMILY = Bytes.toBytes("c");
    protected static final byte[] CONTAINER_QUALIFIER = Bytes.toBytes("n");
    protected static final byte[] CONTAINING_FEATURE_QUALIFIER = Bytes.toBytes("g");

    private static final int ATTEMP_TIMES_DEFAULT = 10;
    private static final long SLEEP_DEFAULT = 1L;

    @SuppressWarnings("unchecked")
    protected Map<Object, NeoEMFInternalEObject> loadedEObjects = new SoftValueHashMap();

    //protected Connection connection;

    protected HTable table;

    protected Resource.Internal resource;

    protected static Configuration conf = HBaseConfiguration.create();

    public DirectWriteHbaseResourceEStoreImpl(Resource.Internal resource) throws IOException {

        this.resource = resource;

        conf.set("hbase.zookeeper.quorum", resource.getURI().host());
        conf.set("hbase.zookeeper.property.clientPort",
                resource.getURI().port() != null ? resource.getURI().port() : "2181");

        TableName tableName = TableName.valueOf(NeoEMFUtil.formatURI(resource.getURI()));
        @SuppressWarnings("resource")
        HBaseAdmin admin = new HBaseAdmin(conf);
        if (!admin.tableExists(tableName)) {
            HTableDescriptor desc = new HTableDescriptor(tableName);
            HColumnDescriptor propertyFamily = new HColumnDescriptor(PROPERTY_FAMILY);
            HColumnDescriptor typeFamily = new HColumnDescriptor(TYPE_FAMILY);
            HColumnDescriptor containmentFamily = new HColumnDescriptor(CONTAINMENT_FAMILY);
            desc.addFamily(propertyFamily);
            desc.addFamily(typeFamily);
            desc.addFamily(containmentFamily);
            admin.createTable(desc);
        }

        table = new HTable(conf, tableName);
    }

    @Override
    public Resource.Internal getResource() {
        return resource;
    }

    @Override
    public Object get(InternalEObject object, EStructuralFeature feature, int index) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        if (feature instanceof EAttribute) {
            return get(neoEMFEObject, (EAttribute) feature, index);
        } else if (feature instanceof EReference) {
            return ((EReference) feature).isContainer() ? getContainer(object)
                    : get(neoEMFEObject, (EReference) feature, index);
        } else {
            throw new IllegalArgumentException(feature.toString());
        }
    }

    protected Object get(NeoEMFEObject object, EAttribute eAttribute, int index) {
        Object value = getFromTable(object, eAttribute);
        if (!eAttribute.isMany()) {
            return parseValue(eAttribute, (String) value);
        } else {
            String[] array = (String[]) value;
            return parseValue(eAttribute, array[index]);
        }
    }

    protected Object get(NeoEMFEObject object, EReference eReference, int index) {
        Object value = getFromTable(object, eReference);
        if (!eReference.isMany()) {
            return getEObject((String) value);
        } else {
            String[] array = (String[]) value;
            return getEObject(array[index]);
        }
    }

    @Override
    public Object set(InternalEObject object, EStructuralFeature feature, int index, Object value) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        if (feature instanceof EAttribute) {
            return set(neoEMFEObject, (EAttribute) feature, index, value);
        } else if (feature instanceof EReference) {
            NeoEMFInternalEObject referencedEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(value,
                    NeoEMFInternalEObject.class);
            return set(neoEMFEObject, (EReference) feature, index, referencedEObject);
        } else {
            throw new IllegalArgumentException(feature.toString());
        }
    }

    protected Object set(NeoEMFEObject object, EAttribute eAttribute, int index, Object value) {
        Object oldValue = isSet((InternalEObject) object, eAttribute) ? get(object, eAttribute, index) : null;
        try {
            if (!eAttribute.isMany()) {
                Put put = new Put(Bytes.toBytes(object.neoemfId()));
                put.add(PROPERTY_FAMILY, Bytes.toBytes(eAttribute.getName()),
                        Bytes.toBytes(serializeValue(eAttribute, value)));
                table.put(put);
            } else {
                try {
                    String[] array;
                    boolean passed = false;
                    int attemp = 0;

                    do {
                        array = (String[]) getFromTable(object, eAttribute);
                        //array = (String[]) ArrayUtils.add(array, index, serializeValue(eAttribute, value));
                        Put put = new Put(Bytes.toBytes(object.neoemfId())).add(PROPERTY_FAMILY,
                                Bytes.toBytes(eAttribute.getName()),
                                NeoEMFUtil.EncoderUtil.toBytes((String[]) ArrayUtils.add(array, index,
                                        serializeValue(eAttribute, value))));
                        passed = table.checkAndPut(Bytes.toBytes(object.neoemfId()), PROPERTY_FAMILY,
                                Bytes.toBytes(eAttribute.getName()),
                                array == null ? null : NeoEMFUtil.EncoderUtil.toBytes(array), put);
                        if (!passed) {
                            if (attemp > ATTEMP_TIMES_DEFAULT)
                                throw new TimeoutException();
                            Thread.sleep((++attemp) * SLEEP_DEFAULT);
                        }

                    } while (!passed);

                } catch (IOException e) {
                    Logger.log(Logger.SEVERITY_ERROR,
                            MessageFormat.format("Unable to set ''{0}'' to ''{1}'' for element ''{2}''", value,
                                    eAttribute.getName(), object));
                } catch (TimeoutException e) {
                    Logger.log(Logger.SEVERITY_ERROR,
                            MessageFormat.format(
                                    "Unable to set ''{0}'' to ''{1}'' for element ''{2}'' after ''{3}'' times",
                                    value, eAttribute.getName(), object, ATTEMP_TIMES_DEFAULT));
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    Logger.log(Logger.SEVERITY_ERROR, MessageFormat.format(
                            "InterruptedException while updating element ''{0}''.\n{1}", object, e.getMessage()));
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to set information for element ''{0}''", object));
        }
        return oldValue;
    }

    protected Object set(NeoEMFEObject object, EReference eReference, int index,
            NeoEMFInternalEObject referencedObject) {
        Object oldValue = isSet((InternalEObject) object, eReference) ? get(object, eReference, index) : null;
        updateLoadedEObjects(referencedObject);
        updateContainment(object, eReference, referencedObject);
        updateInstanceOf(referencedObject);

        try {
            if (!eReference.isMany()) {
                Put put = new Put(Bytes.toBytes(object.neoemfId()));
                put.add(PROPERTY_FAMILY, Bytes.toBytes(eReference.getName()),
                        Bytes.toBytes(referencedObject.neoemfId()));
                table.put(put);
            } else {
                String[] array = (String[]) getFromTable(object, eReference);
                array[index] = referencedObject.neoemfId();
                Put put = new Put(Bytes.toBytes(object.neoemfId()));
                put.add(PROPERTY_FAMILY, Bytes.toBytes(eReference.getName()),
                        NeoEMFUtil.EncoderUtil.toBytesReferences(array));
                table.put(put);
            }
        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to set information for element ''{0}''", object));
        }
        return oldValue;
    }

    @Override
    public boolean isSet(InternalEObject object, EStructuralFeature feature) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        try {
            Result result = table.get(new Get(Bytes.toBytes(neoEMFEObject.neoemfId())));
            byte[] value = result.getValue(PROPERTY_FAMILY, Bytes.toBytes(feature.getName()));
            return value != null;
        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to get information for element ''{0}''", neoEMFEObject));
        }
        return false;
    }

    @Override
    public void add(InternalEObject object, EStructuralFeature feature, int index, Object value) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        if (feature instanceof EAttribute) {
            add(neoEMFEObject, (EAttribute) feature, index, value);
        } else if (feature instanceof EReference) {
            NeoEMFInternalEObject referencedEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(value,
                    NeoEMFInternalEObject.class);
            add(neoEMFEObject, (EReference) feature, index, referencedEObject);
        } else {
            throw new IllegalArgumentException(feature.toString());
        }
    }

    protected void add(NeoEMFEObject object, EAttribute eAttribute, int index, Object value) {
        try {
            String[] array;
            boolean passed = false;
            int attemp = 0;

            do {
                array = (String[]) getFromTable(object, eAttribute);
                //array = (String[]) ArrayUtils.add(array, index, serializeValue(eAttribute, value));
                Put put = new Put(Bytes.toBytes(object.neoemfId()))
                        .add(PROPERTY_FAMILY, Bytes.toBytes(eAttribute.getName()),
                                NeoEMFUtil.EncoderUtil.toBytes(index < 0
                                        ? (String[]) ArrayUtils.add(array, serializeValue(eAttribute, value))
                                        : (String[]) ArrayUtils.add(array, serializeValue(eAttribute, value))));
                passed = table.checkAndPut(Bytes.toBytes(object.neoemfId()), PROPERTY_FAMILY,
                        Bytes.toBytes(eAttribute.getName()),
                        array == null ? null : NeoEMFUtil.EncoderUtil.toBytes(array), put);
                if (!passed) {
                    if (attemp > ATTEMP_TIMES_DEFAULT)
                        throw new TimeoutException();
                    Thread.sleep((++attemp) * SLEEP_DEFAULT);
                }

            } while (!passed);

        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR, MessageFormat.format(
                    "Unable to add ''{0}'' to ''{1}'' for element ''{2}''", value, eAttribute.getName(), object));
        } catch (TimeoutException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to add ''{0}'' to ''{1}'' for element ''{2}'' after ''{3}'' times",
                            value, eAttribute.getName(), object, ATTEMP_TIMES_DEFAULT));
            e.printStackTrace();
        } catch (InterruptedException e) {
            Logger.log(Logger.SEVERITY_ERROR, MessageFormat
                    .format("InterruptedException while updating element ''{0}''.\n{1}", object, e.getMessage()));
            e.printStackTrace();
        }
    }

    protected void add(NeoEMFEObject object, EReference eReference, int index,
            NeoEMFInternalEObject referencedObject) {
        try {

            // as long as the element is not attached to the resource, the containment and type  information 
            // are not stored.
            updateLoadedEObjects(referencedObject);
            updateContainment(object, eReference, referencedObject);
            updateInstanceOf(referencedObject);

            if (index == NO_INDEX) {
                addAsAppend(object, eReference, index == NO_INDEX, referencedObject);
            } else {

                String[] array;
                boolean passed = false;
                int attemp = 0;

                do {
                    array = (String[]) getFromTable(object, eReference);
                    //array = (String[]) ArrayUtils.add(array, index, referencedObject.neoemfId());
                    Put put = new Put(Bytes.toBytes(object.neoemfId())).add(PROPERTY_FAMILY,
                            Bytes.toBytes(eReference.getName()), NeoEMFUtil.EncoderUtil.toBytesReferences(
                                    (String[]) ArrayUtils.add(array, index, referencedObject.neoemfId())));

                    passed = table.checkAndPut(Bytes.toBytes(object.neoemfId()), PROPERTY_FAMILY,
                            Bytes.toBytes(eReference.getName()),
                            array == null ? null : NeoEMFUtil.EncoderUtil.toBytesReferences(array), put);
                    if (!passed) {
                        if (attemp > ATTEMP_TIMES_DEFAULT)
                            throw new TimeoutException();
                        Thread.sleep((++attemp) * SLEEP_DEFAULT);
                    }

                } while (!passed);
            }

        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to add ''{0}'' to ''{1}'' for element ''{2}''", referencedObject,
                            eReference.getName(), object));
        } catch (TimeoutException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to add ''{0}'' to ''{1}'' for element ''{2}'' after ''{3}'' times",
                            referencedObject, eReference.getName(), object, ATTEMP_TIMES_DEFAULT));
            e.printStackTrace();
        } catch (InterruptedException e) {
            Logger.log(Logger.SEVERITY_ERROR, MessageFormat
                    .format("InterruptedException while updating element ''{0}''.\n{1}", object, e.getMessage()));
            e.printStackTrace();
        }

    }

    protected void addAsAppend(NeoEMFEObject object, EReference eReference, boolean atEnd,
            NeoEMFInternalEObject referencedObject) throws IOException {

        Append append = new Append(Bytes.toBytes(object.neoemfId()));
        append.add(PROPERTY_FAMILY, Bytes.toBytes(eReference.getName()), atEnd
                ? Bytes.toBytes(NeoEMFUtil.EncoderUtil.VALUE_SEPERATOR_DEFAULT + referencedObject.neoemfId())
                : Bytes.toBytes(referencedObject.neoemfId() + NeoEMFUtil.EncoderUtil.VALUE_SEPERATOR_DEFAULT));

        table.append(append);
    }

    @Override
    public Object remove(InternalEObject object, EStructuralFeature feature, int index) {
        // TODO nothing guarantees that the index is still the same 
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        if (feature instanceof EAttribute) {
            return remove(neoEMFEObject, (EAttribute) feature, index);
        } else if (feature instanceof EReference) {
            return remove(neoEMFEObject, (EReference) feature, index);
        } else {
            throw new IllegalArgumentException(feature.toString());
        }
    }

    protected Object remove(NeoEMFEObject object, EAttribute eAttribute, int index) {
        Object oldValue = get(object, eAttribute, index);
        try {

            String[] array;
            boolean passed = false;
            int attemp = 0;

            do {
                array = (String[]) getFromTable(object, eAttribute);
                //array = (String[]) ArrayUtils.add(array, index, serializeValue(eAttribute, value));
                Put put = new Put(Bytes.toBytes(object.neoemfId())).add(PROPERTY_FAMILY,
                        Bytes.toBytes(eAttribute.getName()),
                        NeoEMFUtil.EncoderUtil.toBytes((String[]) ArrayUtils.remove(array, index)));
                passed = table.checkAndPut(Bytes.toBytes(object.neoemfId()), PROPERTY_FAMILY,
                        Bytes.toBytes(eAttribute.getName()),
                        array == null ? null : NeoEMFUtil.EncoderUtil.toBytes(array), put);
                if (!passed) {
                    if (attemp > ATTEMP_TIMES_DEFAULT)
                        throw new TimeoutException();
                    Thread.sleep((++attemp) * SLEEP_DEFAULT);
                    oldValue = get(object, eAttribute, index);
                }

            } while (!passed);

        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to delete ''{0}'' to ''{1}'' for element ''{2}''", oldValue,
                            eAttribute.getName(), object));
        } catch (TimeoutException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format(
                            "Unable to delete ''{0}'' to ''{1}'' for element ''{2}'' after ''{3}'' times", oldValue,
                            eAttribute.getName(), object, ATTEMP_TIMES_DEFAULT));
            e.printStackTrace();
        } catch (InterruptedException e) {
            Logger.log(Logger.SEVERITY_ERROR, MessageFormat
                    .format("InterruptedException while updating element ''{0}''.\n{1}", object, e.getMessage()));
            e.printStackTrace();
        }

        return oldValue;
    }

    protected Object remove(NeoEMFEObject object, EReference eReference, int index) {

        Object oldValue = get(object, eReference, index);

        try {

            String[] array;
            boolean passed = false;
            int attemp = 0;

            do {
                array = (String[]) getFromTable(object, eReference);
                //array = (String[]) ArrayUtils.add(array, index, referencedObject.neoemfId());
                Put put = new Put(Bytes.toBytes(object.neoemfId())).add(PROPERTY_FAMILY,
                        Bytes.toBytes(eReference.getName()),
                        NeoEMFUtil.EncoderUtil.toBytesReferences((String[]) ArrayUtils.remove(array, index)));

                passed = table.checkAndPut(Bytes.toBytes(object.neoemfId()), PROPERTY_FAMILY,
                        Bytes.toBytes(eReference.getName()),
                        array == null ? null : NeoEMFUtil.EncoderUtil.toBytesReferences(array), put);

                if (!passed) {
                    if (attemp > ATTEMP_TIMES_DEFAULT)
                        throw new TimeoutException();

                    Thread.sleep((++attemp) * SLEEP_DEFAULT);
                }

            } while (!passed);

        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR, MessageFormat.format(
                    "Unable to delete ''{0}[{1}''] for element ''{2}''", eReference.getName(), index, object));
        } catch (TimeoutException e) {
            Logger.log(Logger.SEVERITY_ERROR, MessageFormat.format(
                    "Unable to delete ''{0}[{1}''] for element ''{2}''", eReference.getName(), index, object));
            e.printStackTrace();
        } catch (InterruptedException e) {
            Logger.log(Logger.SEVERITY_ERROR, MessageFormat
                    .format("InterruptedException while updating element ''{0}''.\n{1}", object, e.getMessage()));
            e.printStackTrace();
        }

        return oldValue;
    }

    @Override
    public Object move(InternalEObject object, EStructuralFeature feature, int targetIndex, int sourceIndex) {
        Object movedElement = remove(object, feature, sourceIndex);
        add(object, feature, targetIndex, movedElement);
        return movedElement;
    }

    @Override
    public void unset(InternalEObject object, EStructuralFeature feature) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        try {
            Delete delete = new Delete(Bytes.toBytes(neoEMFEObject.neoemfId()));
            delete.deleteColumn(PROPERTY_FAMILY, Bytes.toBytes(feature.toString()));
            table.delete(delete);
        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to get containment information for {0}", neoEMFEObject));
        }
    }

    @Override
    public boolean isEmpty(InternalEObject object, EStructuralFeature feature) {
        return size(object, feature) == 0;
    }

    @Override
    public int size(InternalEObject object, EStructuralFeature feature) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        String[] array = (String[]) getFromTable(neoEMFEObject, feature);
        return array != null ? array.length : 0;
    }

    @Override
    public boolean contains(InternalEObject object, EStructuralFeature feature, Object value) {
        return false;
        //return indexOf(object, feature, value) != -1;
    }

    @Override
    public int indexOf(InternalEObject object, EStructuralFeature feature, Object value) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        String[] array = (String[]) getFromTable(neoEMFEObject, feature);
        if (array == null) {
            return -1;
        }
        if (feature instanceof EAttribute) {
            return ArrayUtils.indexOf(array, serializeValue((EAttribute) feature, value));
        } else {
            NeoEMFEObject childEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(value, NeoEMFEObject.class);
            return ArrayUtils.indexOf(array, childEObject.neoemfId());
        }
    }

    @Override
    public int lastIndexOf(InternalEObject object, EStructuralFeature feature, Object value) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        String[] array = (String[]) getFromTable(neoEMFEObject, feature);
        if (array == null) {
            return -1;
        }
        if (feature instanceof EAttribute) {
            return ArrayUtils.lastIndexOf(array, serializeValue((EAttribute) feature, value));
        } else {
            NeoEMFEObject childEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(value, NeoEMFEObject.class);
            return ArrayUtils.lastIndexOf(array, childEObject.neoemfId());
        }
    }

    @Override
    public void clear(InternalEObject object, EStructuralFeature feature) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);
        try {
            Put put = new Put(Bytes.toBytes(neoEMFEObject.neoemfId()));
            put.add(PROPERTY_FAMILY, Bytes.toBytes(feature.toString()),
                    NeoEMFUtil.EncoderUtil.toBytes(new String[] {}));
            table.put(put);
        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to get containment information for {0}", neoEMFEObject));
        }
    }

    @Override
    public Object[] toArray(InternalEObject object, EStructuralFeature feature) {
        int size = size(object, feature);
        Object[] result = new Object[size];
        for (int index = 0; index < size; index++) {
            result[index] = get(object, feature, index);
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T[] toArray(InternalEObject object, EStructuralFeature feature, T[] array) {
        int size = size(object, feature);
        T[] result = null;
        if (array.length < size) {
            result = Arrays.copyOf(array, size);
        } else {
            result = array;
        }
        for (int index = 0; index < size; index++) {
            result[index] = (T) get(object, feature, index);
        }
        return result;
    }

    @Override
    public int hashCode(InternalEObject object, EStructuralFeature feature) {
        return toArray(object, feature).hashCode();
    }

    @Override
    public InternalEObject getContainer(InternalEObject object) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);

        try {
            Result result = table.get(new Get(Bytes.toBytes(neoEMFEObject.neoemfId())));
            String containerId = Bytes.toString(result.getValue(CONTAINMENT_FAMILY, CONTAINER_QUALIFIER));
            String containingFeatureName = Bytes
                    .toString(result.getValue(CONTAINMENT_FAMILY, CONTAINING_FEATURE_QUALIFIER));

            if (containerId != null && containingFeatureName != null) {
                return (InternalEObject) getEObject(containerId);
            }

        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to get containment information for {0}", neoEMFEObject));
        }
        return null;
    }

    @Override
    public EStructuralFeature getContainingFeature(InternalEObject object) {
        NeoEMFEObject neoEMFEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(object, NeoEMFEObject.class);

        try {
            Result result = table.get(new Get(Bytes.toBytes(neoEMFEObject.neoemfId())));
            String containerId = Bytes.toString(result.getValue(CONTAINMENT_FAMILY, CONTAINER_QUALIFIER));
            String containingFeatureName = Bytes
                    .toString(result.getValue(CONTAINMENT_FAMILY, CONTAINING_FEATURE_QUALIFIER));

            if (containerId != null && containingFeatureName != null) {
                EObject container = getEObject(containerId);
                return container.eClass().getEStructuralFeature(containingFeatureName);
            }

        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to get containment information for {0}", neoEMFEObject));
        }
        return null;
    }

    @Override
    public EObject create(EClass eClass) {
        // This should not be called
        throw new UnsupportedOperationException();
    }

    @Override
    public EObject getEObject(String id) {
        if (id == null) {
            return null;
        }
        NeoEMFInternalEObject neoemfEObject = loadedEObjects.get(id);
        if (neoemfEObject == null) {
            EClass eClass = resolveInstanceOf(id);
            if (eClass != null) {
                EObject eObject = EcoreUtil.create(eClass);
                if (eObject instanceof NeoEMFInternalEObject) {
                    neoemfEObject = (NeoEMFInternalEObject) eObject;
                } else {
                    neoemfEObject = NeoEMFEObjectAdapterFactoryImpl.getAdapter(eObject,
                            NeoEMFInternalEObject.class);
                }
                neoemfEObject.neoemfSetId(id.toString());
            } else {
                Logger.log(Logger.SEVERITY_ERROR,
                        MessageFormat.format("Element {0} does not have an associated EClass", id));
            }
            loadedEObjects.put(id, neoemfEObject);
        }
        if (neoemfEObject == null) {
            MessageFormat.format("Element {0} does not exist", id);
            return null;
        }
        if (neoemfEObject.neoemfResource() != getResource()) {
            neoemfEObject.neoemfSetResource(getResource());
        }
        return neoemfEObject;
    }

    protected EClass resolveInstanceOf(String id) {
        try {
            Result result = table.get(new Get(Bytes.toBytes(id)));
            String nsURI = Bytes.toString(result.getValue(TYPE_FAMILY, METAMODEL_QUALIFIER));
            String className = Bytes.toString(result.getValue(TYPE_FAMILY, ECLASS_QUALIFIER));
            if (nsURI != null && className != null) {
                EClass eClass = (EClass) Registry.INSTANCE.getEPackage(nsURI).getEClassifier(className);
                return eClass;
            }
        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to get instance of information for {0}", id));
        }
        return null;
    }

    protected void updateLoadedEObjects(NeoEMFInternalEObject eObject) {
        loadedEObjects.put(eObject.neoemfId(), eObject);
    }

    protected void updateContainment(NeoEMFEObject object, EReference eReference, NeoEMFEObject referencedObject) {
        if (eReference.isContainment()) {

            // remove from root 

            try {
                Put put = new Put(Bytes.toBytes(referencedObject.neoemfId()));
                put.add(CONTAINMENT_FAMILY, CONTAINER_QUALIFIER, Bytes.toBytes(object.neoemfId()));
                put.add(CONTAINMENT_FAMILY, CONTAINING_FEATURE_QUALIFIER, Bytes.toBytes(eReference.getName()));
                //                  no need to use the CAS mech   
                //                  table.checkAndPut(
                //                  Bytes.toBytes(referencedObject.neoemfId()), CONTAINMENT_FAMILY, CONTAINER_QUALIFIER, CompareOp.NOT_EQUAL,
                //                  Bytes.toBytes(object.neoemfId()), put);
                table.put(put);

            } catch (IOException e) {
                Logger.log(Logger.SEVERITY_ERROR,
                        MessageFormat.format("Unable to update containment information for {0}", object));
            }
        }
    }

    protected void updateInstanceOf(NeoEMFEObject object) {

        try {
            Put put = new Put(Bytes.toBytes(object.neoemfId()));
            put.add(TYPE_FAMILY, METAMODEL_QUALIFIER, Bytes.toBytes(object.eClass().getEPackage().getNsURI()));
            put.add(TYPE_FAMILY, ECLASS_QUALIFIER, Bytes.toBytes(object.eClass().getName()));
            table.checkAndPut(Bytes.toBytes(object.neoemfId()), TYPE_FAMILY, ECLASS_QUALIFIER, null, put);

        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to update containment information for {0}", object));
        }
    }

    protected static Object parseValue(EAttribute eAttribute, String value) {
        return value != null ? EcoreUtil.createFromString(eAttribute.getEAttributeType(), value) : null;
    }

    protected static String serializeValue(EAttribute eAttribute, Object value) {
        return value != null ? EcoreUtil.convertToString(eAttribute.getEAttributeType(), value) : null;
    }

    /**
     * Gets the {@link EStructuralFeature} {@code feature} from the
     * {@link Table} for the {@link NeoEMFEObject} {@code object}
     * 
     * @param object
     * @param feature
     * @return The value of the {@code feature}. It can be a {@link String} for
     *         single-valued {@link EStructuralFeature}s or a {@link String}[]
     *         for many-valued {@link EStructuralFeature}s
     */
    protected Object getFromTable(NeoEMFEObject object, EStructuralFeature feature) {
        try {
            Result result = table.get(new Get(Bytes.toBytes(object.neoemfId())));
            byte[] value = result.getValue(PROPERTY_FAMILY, Bytes.toBytes(feature.getName()));
            if (!feature.isMany()) {
                return Bytes.toString(value);
            } else {
                if (feature instanceof EAttribute)
                    return NeoEMFUtil.EncoderUtil.toStrings(value);
                return NeoEMFUtil.EncoderUtil.toStringsReferences(value);
            }
        } catch (IOException e) {
            Logger.log(Logger.SEVERITY_ERROR,
                    MessageFormat.format("Unable to get property ''{0}'' for ''{1}''", feature.getName(), object));
        }
        return null;
    }

}