polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From paulmer...@apache.org
Subject [06/18] zest-sandbox git commit: Move Qi4j related projects in a `qi4j/` subfolder
Date Tue, 21 Apr 2015 11:50:18 GMT
http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-s3/src/main/java/org/qi4j/entitystore/s3/S3SerializationStoreMixin.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-s3/src/main/java/org/qi4j/entitystore/s3/S3SerializationStoreMixin.java b/qi4j/extensions/entitystore-s3/src/main/java/org/qi4j/entitystore/s3/S3SerializationStoreMixin.java
new file mode 100644
index 0000000..82640bb
--- /dev/null
+++ b/qi4j/extensions/entitystore-s3/src/main/java/org/qi4j/entitystore/s3/S3SerializationStoreMixin.java
@@ -0,0 +1,109 @@
+/*  Copyright 2008 Rickard �berg.
+ *
+ * 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 org.qi4j.entitystore.s3;
+
+import org.jets3t.service.S3Service;
+import org.jets3t.service.impl.rest.httpclient.RestS3Service;
+import org.jets3t.service.model.S3Bucket;
+import org.jets3t.service.security.AWSCredentials;
+import org.qi4j.api.configuration.Configuration;
+import org.qi4j.api.entity.EntityReference;
+import org.qi4j.api.injection.scope.This;
+import org.qi4j.io.Input;
+import org.qi4j.io.Output;
+import org.qi4j.spi.entitystore.EntityStoreException;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.qi4j.api.service.ServiceActivation;
+import org.qi4j.spi.entitystore.helpers.MapEntityStore;
+
+/**
+ * Amazon S3 implementation of SerializationStore.
+ * <p/>
+ * To use this you must supply your own access key and secret key for your Amazon S3 account.
+ */
+public class S3SerializationStoreMixin
+    implements ServiceActivation, MapEntityStore
+{
+
+    @This
+    private Configuration<S3Configuration> configuration;
+
+    private S3Service s3Service;
+    private S3Bucket entityBucket;
+
+    // Activatable implementation
+    public void activateService()
+        throws Exception
+    {
+        String awsAccessKey = configuration.get().accessKey().get();
+        String awsSecretKey = configuration.get().secretKey().get();
+
+        if( awsAccessKey == null || awsSecretKey == null )
+        {
+            throw new IllegalStateException( "No S3 keys configured" );
+        }
+
+        AWSCredentials awsCredentials =
+            new AWSCredentials( awsAccessKey, awsSecretKey );
+        s3Service = new RestS3Service( awsCredentials );
+
+        S3Bucket[] s3Buckets = s3Service.listAllBuckets();
+        System.out.println( "How many buckets do I have in S3? " + s3Buckets.length );
+
+        if( s3Buckets.length == 0 )
+        {
+            entityBucket = s3Service.createBucket( "entity-bucket" );
+            System.out.println( "Created entity bucket: " + entityBucket.getName() );
+        }
+        else
+        {
+            entityBucket = s3Buckets[ 0 ];
+        }
+    }
+
+    public void passivateService()
+        throws Exception
+    {
+    }
+
+    public Reader get( EntityReference entityReference )
+        throws EntityStoreException
+    {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public Input<Reader, IOException> entityStates()
+    {
+        return new Input<Reader, IOException>()
+        {
+            public <ReceiverThrowableType extends Throwable> void transferTo( Output<? super Reader, ReceiverThrowableType> output )
+                throws IOException, ReceiverThrowableType
+            {
+                // TODO Implement this
+                throw new UnsupportedOperationException( "Not supported yet." );
+            }
+        };
+    }
+
+    public void applyChanges( MapChanges changes )
+        throws IOException
+    {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-s3/src/test/java/org/qi4j/entitystore/s3/S3EntityStoreTest.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-s3/src/test/java/org/qi4j/entitystore/s3/S3EntityStoreTest.java b/qi4j/extensions/entitystore-s3/src/test/java/org/qi4j/entitystore/s3/S3EntityStoreTest.java
new file mode 100644
index 0000000..7afe3ec
--- /dev/null
+++ b/qi4j/extensions/entitystore-s3/src/test/java/org/qi4j/entitystore/s3/S3EntityStoreTest.java
@@ -0,0 +1,47 @@
+/*  Copyright 2008 Rickard Öberg.
+ *
+ * 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 org.qi4j.entitystore.s3;
+
+import org.junit.Test;
+import org.qi4j.api.common.Visibility;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.entitystore.memory.MemoryEntityStoreService;
+import org.qi4j.test.entity.AbstractEntityStoreTest;
+
+/**
+ * Amazon S3 EntityStore test
+ */
+public abstract class S3EntityStoreTest
+    extends AbstractEntityStoreTest
+{
+    public void assemble( ModuleAssembly module ) throws AssemblyException
+    {
+        super.assemble( module );
+        module.addServices( S3EntityStoreService.class ).instantiateOnStartup();
+
+        ModuleAssembly config = module.layer().module( "config" );
+        config.entities( S3Configuration.class ).visibleIn( Visibility.layer );
+        config.services( MemoryEntityStoreService.class );
+    }
+
+    @Test
+    public void dummyTest()
+    {
+        // All tests are disabled since by default the S3 store doesn't work due to missing account keys!
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-s3/src/test/resources/org/qi4j/entitystore/s3/S3EntityStoreComposite.properties
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-s3/src/test/resources/org/qi4j/entitystore/s3/S3EntityStoreComposite.properties b/qi4j/extensions/entitystore-s3/src/test/resources/org/qi4j/entitystore/s3/S3EntityStoreComposite.properties
new file mode 100644
index 0000000..66d19ff
--- /dev/null
+++ b/qi4j/extensions/entitystore-s3/src/test/resources/org/qi4j/entitystore/s3/S3EntityStoreComposite.properties
@@ -0,0 +1,2 @@
+accessKey=yourkey
+secretKey=yoursecretkey

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/osgi.bundle
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/osgi.bundle b/qi4j/extensions/entitystore-swift/osgi.bundle
new file mode 100644
index 0000000..6571e76
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/osgi.bundle
@@ -0,0 +1,33 @@
+Bundle-Activator:
+
+Private-Package:
+
+Ignore-Package: com_cenqua_clover
+
+Import-Package: org.qi4j.api.composite, \
+                org.qi4j.api.common, \
+                org.qi4j.api.concern, \
+                org.qi4j.api.configuration, \
+                org.qi4j.api.entity, \
+                org.qi4j.api.injection.scope, \
+                org.qi4j.api.io, \
+                org.qi4j.api.mixin, \
+                org.qi4j.api.property, \
+                org.qi4j.api.sideeffect, \
+                org.qi4j.api.service, \
+                org.qi4j.api.structure, \
+                org.qi4j.bootstrap, \
+                org.qi4j.entitystore.memory, \
+                org.qi4j.entitystore.map, \
+                org.qi4j.library.locking, \
+                org.qi4j.spi, \
+                org.qi4j.spi.composite, \
+                org.qi4j.spi.entity, \
+                org.qi4j.spi.entity.helpers, \
+                org.qi4j.spi.entitystore, \
+                org.qi4j.spi.query, \
+                org.qi4j.spi.service, \
+                org.qi4j.spi.uuid, \
+                org.qi4j.spi.serialization
+
+Export-Package: org.qi4j.entitystore.swift

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/pom.xml
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/pom.xml b/qi4j/extensions/entitystore-swift/pom.xml
new file mode 100644
index 0000000..95a6cbf
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/pom.xml
@@ -0,0 +1,48 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+   <parent>
+      <groupId>org.qi4j.sandbox</groupId>
+      <artifactId>qi4j-sandbox-extensions</artifactId>
+      <version>0-SNAPSHOT</version>
+   </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.qi4j.extension</groupId>
+  <artifactId>qi4j-entitystore-swift</artifactId>
+  <name>Qi4j Extension - EntityStore - Swift</name>
+  <packaging>jar</packaging>
+
+  <properties>
+    <version.qi4j-tests>1.3</version.qi4j-tests>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.spi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.bootstrap</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.testsupport</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.library</groupId>
+      <artifactId>org.qi4j.library.locking</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.runtime</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.test</groupId>
+      <artifactId>org.qi4j.test.performance</artifactId>
+      <version>1.3.0.RC1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/BucketManager.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/BucketManager.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/BucketManager.java
new file mode 100644
index 0000000..82eb3aa
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/BucketManager.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import org.qi4j.spi.entitystore.EntityStoreException;
+
+public class BucketManager
+    implements Runnable
+{
+    private HashMap<Integer, LruEntry> cache;
+    private File bucketdir;
+    private Thread cleanUpThread;
+    private boolean running;
+
+    public BucketManager( File bucketdir )
+    {
+        cache = new HashMap<Integer, LruEntry>();
+        this.bucketdir = bucketdir;
+        bucketdir.mkdirs();
+        cleanUpThread = new Thread( this, "SwiftEntityStore-cleanup" );
+        cleanUpThread.start();
+    }
+
+    synchronized RandomAccessFile get( int hash )
+        throws IOException
+    {
+        LruEntry entry = cache.get( hash );
+        if( entry != null )
+        {
+            return entry.file;
+        }
+        File bucketFile = new File( bucketdir, Integer.toHexString( hash ) );
+        RandomAccessFile bucket = new RandomAccessFile( bucketFile, "rw" );
+        entry = new LruEntry( bucket, hash );
+        cache.put( hash, entry );
+        return bucket;
+    }
+
+    synchronized void close()
+        throws IOException
+    {
+        running = false;
+        cleanUpThread.interrupt();
+        for( LruEntry entry : cache.values() )
+        {
+            entry.file.close();
+        }
+    }
+
+    private void cleanUp()
+        throws IOException
+    {
+        if( cache.size() < 30 )
+        {
+            return;
+        }
+        LinkedList<LruEntry> sorting = new LinkedList<LruEntry>();
+        sorting.addAll( cache.values() );
+        Collections.sort( sorting, new Comparator<LruEntry>()
+        {
+            public int compare( LruEntry lruEntry1, LruEntry lruEntry2 )
+            {
+                if( lruEntry1.created == lruEntry2.created )
+                {
+                    return 0;
+                }
+                if( lruEntry1.created > lruEntry2.created )
+                {
+                    return 1;
+                }
+
+                return -1;
+            }
+        } );
+        while( cache.size() > 20 )
+        {
+            LruEntry entry = sorting.removeFirst(); // Check if this is at the right end;
+            entry.file.close();
+            cache.remove( entry.hash );
+        }
+    }
+
+    public void run()
+    {
+        running = true;
+        try
+        {
+            while( running )
+            {
+                synchronized( this )
+                {
+                    wait( 15000 );
+                    cleanUp();
+                }
+            }
+        }
+        catch( InterruptedException e )
+        {
+            // ignore, normal shutdown
+        }
+        catch( IOException e )
+        {
+            throw new EntityStoreException( "What the hell!!!???", e );
+        }
+    }
+
+    private static class LruEntry
+    {
+        private long created;
+        private RandomAccessFile file;
+        private int hash;
+
+        public LruEntry( RandomAccessFile bucket, int hash )
+        {
+            this.file = bucket;
+            this.hash = hash;
+            created = System.currentTimeMillis();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/DataBlock.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/DataBlock.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/DataBlock.java
new file mode 100644
index 0000000..fee55d4
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/DataBlock.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.spi.entity.QualifiedIdentity;
+import org.qi4j.api.entity.EntityReference;
+
+import java.util.Arrays;
+
+class DataBlock
+{
+    EntityReference reference;
+    byte[] data;
+    long instanceVersion;
+    int schemaVersion;
+
+    public DataBlock( EntityReference reference, byte[] data, long instanceVersion, int schemaVersion )
+    {
+        this.reference = reference;
+        this.data = data;
+        this.instanceVersion = instanceVersion;
+        this.schemaVersion = schemaVersion;
+    }
+
+    public boolean equals( Object o )
+    {
+        if( this == o )
+        {
+            return true;
+        }
+        if( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        DataBlock dataBlock = (DataBlock) o;
+
+        if( instanceVersion != dataBlock.instanceVersion )
+        {
+            return false;
+        }
+        if( schemaVersion != dataBlock.schemaVersion )
+        {
+            return false;
+        }
+        if( !Arrays.equals( data, dataBlock.data ) )
+        {
+            return false;
+        }
+        if( !reference.equals( dataBlock.reference ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    public int hashCode()
+    {
+        int result;
+        result = reference.hashCode();
+        result = 31 * result + Arrays.hashCode( data );
+        result = 31 * result + (int) ( instanceVersion ^ ( instanceVersion >>> 32 ) );
+        result = 31 * result + schemaVersion;
+        return result;
+    }
+
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append( schemaVersion );
+        buf.append( '[' );
+        buf.append( reference );
+        buf.append( ':' );
+        buf.append( instanceVersion );
+        buf.append( '{' );
+        boolean first = true;
+        for( byte b : data )
+        {
+            if( !first )
+            {
+                buf.append( ',' );
+            }
+            first = false;
+            buf.append( toHex( b ) );
+        }
+        buf.append( '}' );
+        buf.append( ']' );
+        return buf.toString();
+    }
+
+    private String toHex( byte b )
+    {
+        int data = b;
+
+        if( data < 0 )
+        {
+            data = data + 256;
+        }
+        if( data < 16 )
+        {
+            return "0" + Integer.toHexString( data );
+        }
+        return Integer.toHexString( data );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/DataStore.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/DataStore.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/DataStore.java
new file mode 100644
index 0000000..8364c2e
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/DataStore.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.api.entity.EntityReference;
+import org.qi4j.io.Input;
+import org.qi4j.io.Output;
+import org.qi4j.io.Receiver;
+import org.qi4j.io.Sender;
+import org.qi4j.spi.entitystore.EntityStoreException;
+
+import java.io.*;
+
+/**
+ * This class handles the Heap Data file.
+ * The format of the file is as follows;
+ * <p/>
+ * <code><pre>
+ * At OFFSET = 0
+ * [cleanShutDown]  1 byte
+ * [formatVersion]  4 bytes
+ * [noOfEntries]    4 bytes
+ * [noOfIDentries]  4 bytes
+ * <p/>
+ * At OFFSET 256
+ * [blockSize]     4 bytes
+ * [usage]         1 byte    (0=Unused, 1=prime, 2=mirror, 3=primeChanged, 4=mirrorChanged)
+ * [instanceVersion] 8 bytes
+ * [schemaVersion] 4 bytes
+ * [identitySize]  1 byte
+ * [identity]      IDENTITY_MAX_LENGTH bytes
+ * [mirrorPointer] 8 bytes
+ * [primeDataLength] 4 bytes
+ * [primeData]     n bytes
+ * [mirrorDataLength] 4 bytes
+ * [mirrorData]    n bytes
+ * <p/>
+ * At OFFSET 256 + [blockSize]
+ * same as above, repeat until [blockSize] == -1 marking end of DataArea.
+ * </pre></code>
+ * The <b>mirrorPointer</b> points to the mirrorData block.
+ */
+public class DataStore
+{
+    static final long DATA_AREA_OFFSET = 256;
+    private static final int BLOCK_OVERHEAD = 26;
+    private static final int CURRENT_VERSION = 1;
+    private static final String HEAP_DATA_FILENAME = "heap.data";
+
+    private static final int USAGE_UNUSED = 0;
+    private static final int USAGE_PRIME = 1;
+    private static final int USAGE_MIRROR = 2;
+    private static final int USAGE_PRIMECHANGE = 3;
+    private static final int USAGE_MIRRORCHANGE = 4;
+
+    private RandomAccessFile dataFile;
+    private IdentityFile identityFile;
+    private int identityMaxLength;
+    private UndoManager undoManager;
+    private int entries;
+    private File dataDir;
+
+    public DataStore( File dataDirectory, UndoManager undoManager )
+        throws IOException
+    {
+        this.undoManager = undoManager;
+        identityMaxLength = 128; // Default value...
+        this.dataDir = dataDirectory.getAbsoluteFile();
+        dataDir.mkdirs();
+        File file = new File( dataDir, HEAP_DATA_FILENAME );
+        if (!file.exists())
+        {
+            file.createNewFile();
+        }
+        dataFile = new RandomAccessFile( file, "rw" );
+        boolean cleanShutDown;
+        if (file.length() > 0)
+        {
+            dataFile.seek( 0 );
+            cleanShutDown = dataFile.readBoolean();
+            dataFile.seek( 0 );
+            dataFile.writeBoolean( false );
+            dataFile.writeInt( CURRENT_VERSION );  // Write Version.
+            entries = dataFile.readInt();
+            identityMaxLength = dataFile.readInt();
+        } else
+        {
+            cleanShutDown = false;
+            dataFile.writeBoolean( false );
+            entries = 0;
+            dataFile.writeInt( CURRENT_VERSION );  // Write Version.
+            dataFile.writeInt( entries );
+            dataFile.writeInt( identityMaxLength );
+            dataFile.seek( DATA_AREA_OFFSET - 1 );
+            dataFile.writeByte( 0 );
+            dataFile.seek( DATA_AREA_OFFSET );
+            dataFile.writeInt( -1 );  // EOF marker
+        }
+        // Ensure full flush, then reopen...
+        dataFile.close();
+
+        dataFile = new RandomAccessFile( file, "rw" );
+
+        if (!cleanShutDown)
+        {
+            reIndex();
+        } else
+        {
+            File idDir = new File( dataDir, "idx" );
+            try
+            {
+                identityFile = IdentityFile.use( idDir );
+            }
+            catch (MalformedIdentityDirectoryException e)
+            {
+                reIndex();
+            }
+        }
+        if (identityFile.entries() < entries * 2)
+        {
+            reIndex();
+        }
+    }
+
+    RandomAccessFile dataFile()
+    {
+        return dataFile;
+    }
+
+    IdentityFile identityFile()
+    {
+        return identityFile;
+    }
+
+    DataBlock readData( EntityReference reference )
+        throws IOException
+    {
+        long pos = identityFile.find( reference );
+        if (pos < 0)
+        {
+            return null;
+        }
+        dataFile.seek( pos );
+        dataFile.skipBytes( 4 ); // Skip BlockSize
+        return readDataBlock( reference );
+    }
+
+    void putData( DataBlock data )
+        throws IOException
+    {
+        long pos = identityFile.find( data.reference );
+        if (pos < 0)
+        {
+            putNewData( data );
+        } else
+        {
+            dataFile.seek( pos );
+            int blockSize = dataFile.readInt();
+            long usagePointer = dataFile.getFilePointer();
+            byte usage = dataFile.readByte();
+            dataFile.skipBytes( -1 );
+            dataFile.writeByte( usage == USAGE_PRIME ? USAGE_PRIMECHANGE : USAGE_MIRRORCHANGE );
+            int dataAreaSize = (blockSize - BLOCK_OVERHEAD) / 2 - 4;
+            if (dataAreaSize < data.data.length)
+            {
+                putTooLarge( data, pos, usagePointer, usage );
+            } else
+            {
+                putOver( data, pos, usagePointer, usage );
+            }
+        }
+    }
+
+    /* In this case we need to write the new data to the opposite of the current active block. */
+
+    private void putOver( DataBlock data, long pos, long usagePointer, byte usage )
+        throws IOException
+    {
+        dataFile.seek( usagePointer ); // Point to "usage"
+        dataFile.skipBytes( 13 ); // Skip usage, instanceVersion and schemaVersion
+        EntityReference existingReference = readReference();
+        if (!existingReference.equals( data.reference ))
+        {
+            throw new EntityStoreException( "Inconsistent Data Heap: was " + existingReference + ", expected " + data.reference );
+        }
+        long mirror = dataFile.readLong();
+        if (usage == USAGE_PRIME)
+        {
+            dataFile.seek( mirror );
+        }
+        UndoModifyCommand undoModifyCommand = new UndoModifyCommand( pos, usage, data.instanceVersion, data.schemaVersion );
+        undoManager.saveUndoCommand( undoModifyCommand );
+
+        dataFile.writeInt( data.data.length );
+        dataFile.write( data.data );
+        dataFile.seek( usagePointer );
+        dataFile.writeByte( usage == USAGE_PRIME ? USAGE_MIRROR : USAGE_PRIME );
+    }
+
+    /* This case is when the data doesn't fit in the pre-allocated extra space. Write it to the end, and mark the
+       previous block unused.
+     */
+
+    private void putTooLarge( DataBlock data, long pos, long usagePointer, byte usage )
+        throws IOException
+    {
+        long newPosition = addData( data );
+        UndoModifyCommand undoModifyCommand = new UndoModifyCommand( pos, usage, data.instanceVersion, data.schemaVersion );
+        undoManager.saveUndoCommand( undoModifyCommand );
+        dataFile.seek( usagePointer );
+        dataFile.writeByte( USAGE_UNUSED );
+        UndoDropIdentityCommand undoDropIdentityCommand = new UndoDropIdentityCommand( data.reference, pos );
+        undoManager.saveUndoCommand( undoDropIdentityCommand );
+        identityFile.remember( data.reference, newPosition );
+    }
+
+    private void putNewData( DataBlock data )
+        throws IOException
+    {
+        long pos;
+        pos = addData( data );
+        UndoNewIdentityCommand undoNewIdentityCommand = new UndoNewIdentityCommand( data.reference );
+        undoManager.saveUndoCommand( undoNewIdentityCommand );
+        identityFile.remember( data.reference, pos );
+    }
+
+    public void delete( EntityReference reference )
+        throws IOException
+    {
+        long pos = identityFile.find( reference );
+        if (pos < 0)
+        {
+            // Doesn't exist.
+            return;
+        }
+        dataFile.seek( pos );
+        dataFile.skipBytes( 4 ); // Skip BlockSize
+        byte usage = dataFile.readByte();
+        if (usage == USAGE_UNUSED)
+        {
+            // Not used?? Why is the IdentityFile pointing to it then?? Should the following line actually be
+            // executed here.
+            //    identityFile.drop( identity );
+            return;
+        }
+        UndoDropIdentityCommand undoDropIdentityCommand = new UndoDropIdentityCommand( reference, pos );
+        undoManager.saveUndoCommand( undoDropIdentityCommand );
+
+        UndoDeleteCommand undoDeleteCommand = new UndoDeleteCommand( pos, usage );
+        undoManager.saveUndoCommand( undoDeleteCommand );
+
+        identityFile.drop( reference );
+        dataFile.skipBytes( -1 );
+        dataFile.writeByte( USAGE_UNUSED );   // Mark Unused block
+    }
+
+    void flush()
+        throws IOException
+    {
+//        dataFile.getFD().sync();
+    }
+
+    void close()
+        throws IOException
+    {
+        identityFile.close();
+        dataFile.seek( 0 );
+        dataFile.writeBoolean( true );
+        dataFile.writeInt( entries );
+        dataFile.close();
+    }
+
+    private long addData( DataBlock block )
+        throws IOException
+    {
+        dataFile.seek( dataFile.length() - 4 ); // last 4 bytes contain a -1
+        long blockStart = dataFile.getFilePointer();
+
+        // Allow each datablock to grow to twice its size, and provide a primary and mirror allocation.
+        int dataAreaSize = (block.data.length * 2 + 4) * 2;
+        UndoExtendCommand undoExtendCommand = new UndoExtendCommand( blockStart );
+        undoManager.saveUndoCommand( undoExtendCommand );
+
+        int blockSize = dataAreaSize + identityMaxLength + BLOCK_OVERHEAD;
+        dataFile.writeInt( blockSize );
+        long usagePointer = dataFile.getFilePointer();
+        dataFile.writeByte( USAGE_PRIMECHANGE ); // In-progress
+        dataFile.writeLong( block.instanceVersion );
+        dataFile.writeInt( block.schemaVersion );
+        writeIdentity( block.reference );
+
+        long mirrorPosition = blockStart + BLOCK_OVERHEAD + identityMaxLength + dataAreaSize / 2;
+        dataFile.writeLong( mirrorPosition );
+        dataFile.writeInt( block.data.length );
+        dataFile.write( block.data );
+        dataFile.seek( blockStart + blockSize );
+        dataFile.writeInt( -1 ); // Write EOF marker.
+        dataFile.seek( usagePointer );
+        dataFile.write( USAGE_PRIME );
+        return blockStart;
+    }
+
+    private void writeIdentity( EntityReference reference )
+        throws IOException
+    {
+        byte[] idBytes = reference.identity().getBytes( "UTF-8" );
+        if (idBytes.length > identityMaxLength)
+        {
+            throw new EntityStoreException( "Identity is too long. Only " + identityMaxLength + " characters are allowed in this EntityStore." );
+        }
+        byte[] id = new byte[identityMaxLength];
+        System.arraycopy( idBytes, 0, id, 0, idBytes.length );
+        dataFile.writeByte( idBytes.length );
+        dataFile.write( id );
+    }
+
+    private void compact()
+        throws IOException
+    {
+/*
+        File newFileName = new File( dataDir, "heap-compacting.data" );
+        RandomAccessFile newFile = new RandomAccessFile( newFileName, "rw" );
+        File oldFileName = new File( dataDir, "heap.data" );
+        RandomAccessFile oldFile = new RandomAccessFile( oldFileName, "r" );
+
+        oldFile.seek( DATA_AREA_OFFSET ); // Skip initial bytes;
+        newFile.seek( DATA_AREA_OFFSET ); // Skip initial bytes;
+
+        int counter = 0;
+
+        // Move the Records!!
+
+        entries = counter;
+
+        newFile.writeBoolean( false );
+        newFile.writeInt( CURRENT_VERSION );  // Write Version.
+
+        newFile.writeInt( entries );
+        reIndex( dataDir );
+        dataFile.close();
+        newFile.close();
+
+        File standardFilename = new File( dataDir, "heap.data" );
+        newFileName.renameTo( standardFilename );
+        dataFile = new RandomAccessFile( standardFilename, "rw" );
+*/
+    }
+
+    private void reIndex()
+        throws IOException
+    {
+        identityFile = IdentityFile.create( new File( dataDir, "idx" ), identityMaxLength + 16, entries < 5000 ? 10000 : entries * 2 );
+
+        dataFile.seek( DATA_AREA_OFFSET );
+        while (dataFile.getFilePointer() < dataFile.length())
+        {
+            long blockStart = dataFile.getFilePointer();
+            int blockSize = dataFile.readInt();
+            if (blockSize == -1)
+            {
+                break;
+            }
+            byte usage = dataFile.readByte();
+            dataFile.skipBytes( 12 ); // Skip instanceVersion and schemaVersion
+            EntityReference reference = readReference();
+            if (usage != USAGE_UNUSED)
+            {
+                identityFile.remember( reference, blockStart );
+            }
+            dataFile.seek( blockStart + blockSize );
+        }
+    }
+
+    public Input<Reader, IOException> data()
+    {
+        return new Input<Reader, IOException>()
+        {
+            public <ReceiverThrowableType extends Throwable> void transferTo( Output<? super Reader, ReceiverThrowableType> output )
+                throws IOException, ReceiverThrowableType
+            {
+                output.receiveFrom(
+                    new Sender<Reader, IOException>()
+                    {
+                        public <ReceiverThrowableType extends Throwable> void sendTo( Receiver<? super Reader, ReceiverThrowableType> receiver )
+                        throws ReceiverThrowableType, IOException
+                        {
+                            long position = DATA_AREA_OFFSET;
+                            while( position < dataFile.length() )
+                            {
+                                dataFile.seek( position );
+                                int blockSize = dataFile.readInt();
+                                if( blockSize == -1 ) // EOF marker
+                                {
+                                    return;
+                                }
+                                if( blockSize == 0 )
+                                {
+                                    // TODO This is a bug. Why does it occur??
+                                    throw new InternalError();
+                                }
+                                position = position + blockSize;  // position for next round...
+                                DataBlock block = readDataBlock( null );
+                                if( block != null )
+                                {
+                                    receiver.receive( new StringReader( new String( block.data, "UTF-8" ) ) );
+                                }
+                            }
+                        }
+                    }
+                );
+            }
+        };
+    }
+
+    private DataBlock readDataBlock( EntityReference reference )
+        throws IOException
+    {
+        byte usage = dataFile.readByte();
+        if (usage == USAGE_UNUSED)
+        {
+            return null;
+        }
+        long instanceVersion = dataFile.readLong();
+        int schemaVersion = dataFile.readInt();
+        EntityReference existingReference = readReference();
+        if (reference == null)
+        {
+            reference = existingReference;
+        }
+        if (!existingReference.equals( reference ))
+        {
+            throw new EntityStoreException( "Inconsistent Data Heap." );
+        }
+        if (usage == USAGE_MIRROR)
+        {
+            long mirror = dataFile.readLong();
+            dataFile.seek( mirror );
+        } else
+        {
+            dataFile.skipBytes( 8 ); // skip the MirrorPointer
+        }
+        int dataSize = dataFile.readInt();
+        if (dataSize < 0)
+        {
+            throw new InternalError();
+        }
+        byte[] data = new byte[dataSize];
+        dataFile.read( data );
+        return new DataBlock( reference, data, instanceVersion, schemaVersion );
+    }
+
+    private EntityReference readReference()
+        throws IOException
+    {
+        int idSize = dataFile.readByte();
+        if (idSize < 0)
+        {
+            idSize = idSize + 256;  // Fix 2's-complement negative values of bytes into unsigned 8 bit.
+        }
+        byte[] idData = new byte[idSize];
+        dataFile.read( idData );
+        dataFile.skipBytes( identityMaxLength - idSize );
+        return new EntityReference( new String( idData ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/FileUtils.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/FileUtils.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/FileUtils.java
new file mode 100644
index 0000000..14f77f7
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/FileUtils.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import java.io.File;
+
+public class FileUtils
+{
+
+    public static void delete( File file )
+    {
+        if( !file.exists() )
+        {
+            return;
+        }
+        if( file.isDirectory() )
+        {
+            for( File child : file.listFiles() )
+            {
+                delete( child );
+            }
+        }
+        file.delete();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/HeapDump.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/HeapDump.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/HeapDump.java
new file mode 100644
index 0000000..e9fb3f2
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/HeapDump.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2009 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import org.qi4j.api.entity.EntityReference;
+
+public class HeapDump
+{
+    static final long DATA_AREA_OFFSET = 256;
+    private static final String HEAP_DATA_FILENAME = "heap.data";
+
+    private static RandomAccessFile dataFile;
+
+    public static void main( String[] args )
+        throws Exception
+    {
+        File dataDirectory = new File( args[ 0 ] ).getAbsoluteFile();
+        File dataDir = dataDirectory.getAbsoluteFile();
+        File file = new File( dataDir, HEAP_DATA_FILENAME );
+        dataFile = new RandomAccessFile( file, "rw" );
+
+        long position = 256;
+        dataFile.seek( position );  // skip maintenance block.
+        while( dataFile.getFilePointer() < dataFile.length() )
+        {
+            int blockSize = dataFile.readInt();
+            if( blockSize == -1 )
+            {
+                break;
+            }
+            int usage = dataFile.readByte();
+            if( usage != 0 )
+            {
+                long instanceVersion = dataFile.readLong();
+                int schemaVersion = dataFile.readInt();
+                long refPos = dataFile.getFilePointer();
+                String ref = readReference().identity();
+                System.out.print( ref );
+                dataFile.seek( refPos + 129 );
+                long mirror = dataFile.readLong();
+                if( usage == 2 )
+                    dataFile.seek( mirror );
+                if( usage == 3 || usage == 4 )
+                {
+                    System.err.println( "Inconsistent Heap: " + usage + ", pos: " + position  );
+                    System.err.flush();
+                }
+                int dataSize = dataFile.readInt();
+                byte[] data = new byte[ dataSize ];
+                dataFile.read( data, 0, dataSize );
+                System.out.println( new String( data, "UTF-8" ) );
+                System.out.flush();
+            }
+            position = position + blockSize;
+            dataFile.seek( position );
+        }
+    }
+
+    private static EntityReference readReference()
+        throws IOException
+    {
+        int idSize = dataFile.readByte();
+        if( idSize < 0 )
+        {
+            idSize = idSize + 256;  // Fix 2's-complement negative values of bytes into unsigned 8 bit.
+        }
+        byte[] idData = new byte[idSize];
+        dataFile.read( idData );
+        dataFile.skipBytes( 128 - idSize );
+        return new EntityReference( new String( idData ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityFile.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityFile.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityFile.java
new file mode 100644
index 0000000..69af039
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityFile.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import org.qi4j.api.entity.EntityReference;
+
+/**
+ * For Slot 0
+ * [version]     -  4 bytes
+ * [noOfEntries] -  4 bytes
+ * [slotSize]    -  4 bytes
+ *
+ * For Slot 1..n
+ * [isExtended]  -  1 byte
+ * [position]    -  8 bytes
+ * [identity]    -  [slotSize-16] bytes
+ */
+public class IdentityFile
+{
+    private static final int CURRENT_VERSION = 1;
+
+    private RandomAccessFile identityStore;
+    private int entries;
+    private int slotSize;
+    private boolean closed;
+    private BucketManager bucketManager;
+
+    private IdentityFile( RandomAccessFile store, File bucketDir, int slotSize, int entries )
+        throws IOException
+    {
+        this.closed = false;
+        identityStore = store;
+        bucketManager = new BucketManager( bucketDir );
+        this.slotSize = slotSize;
+        this.entries = entries;
+    }
+
+    int entries()
+    {
+        return entries;
+    }
+
+    long find( EntityReference reference )
+        throws IOException
+    {
+        if( closed )
+        {
+            throw new IdentityFileClosedException();
+        }
+        if( reference.identity().length() > slotSize - 16 )
+        {
+            throw new IdentityTooLongException( reference );
+        }
+        final int slot = getSlot( reference );
+        identityStore.seek( slot * slotSize );
+        boolean isExtended = identityStore.readBoolean();
+        if( !isExtended )
+        {
+            long pos = identityStore.readLong();
+            String idString = identityStore.readUTF();
+            if( idString.length() == 0 )
+            {
+                return -1;
+            }
+            EntityReference foundReference = new EntityReference( idString );
+            if( foundReference.equals( reference ) )
+            {
+                return pos;
+            }
+            return -1;
+        }
+        RandomAccessFile buckets = bucketManager.get( slot );
+        int next = 0;
+        while( next * slotSize < buckets.length() )
+        {
+            buckets.seek( next * slotSize );
+            boolean isUsed = buckets.readBoolean();
+            long pos = buckets.readLong();
+            EntityReference foundReference = new EntityReference( buckets.readUTF() );
+            if( isUsed && foundReference.equals( reference ) )
+            {
+                return pos;
+            }
+            next++;
+        }
+        return -1;
+    }
+
+    void remember( EntityReference reference, long pos )
+        throws IOException
+    {
+        if( closed )
+        {
+            throw new IdentityFileClosedException();
+        }
+        if( reference.identity().length() > slotSize - 16 )
+        {
+            throw new IdentityTooLongException( reference );
+        }
+        final int slot = getSlot( reference );
+        identityStore.seek( slot * slotSize );
+        boolean isExtended = identityStore.readBoolean();
+        if( isExtended )
+        {
+            RandomAccessFile bucket = bucketManager.get( slot );
+            bucket.seek( 0 );
+            int next = 0;
+            while( next * slotSize < bucket.length() )
+            {
+                bucket.seek( next * slotSize );
+                boolean isUsed = bucket.readBoolean();
+                if( !isUsed )
+                {
+                    break;
+                }
+                next++;
+            }
+            bucket.seek( next * slotSize );
+            bucket.writeBoolean( true );
+            bucket.writeLong( pos );
+            bucket.writeUTF( reference.identity() );
+            fillExtras( bucket, next, slotSize );
+        }
+        else
+        {
+            long existingPos = identityStore.readLong();
+            if( existingPos == -1 )
+            {
+                // Not used yet.
+                identityStore.seek( slot * slotSize );
+                identityStore.writeBoolean( false );
+                identityStore.writeLong( pos );
+                identityStore.writeUTF( reference.identity() );
+            }
+            else
+            {
+                // Move existing record over to a new bucket.
+                RandomAccessFile bucket = bucketManager.get( slot );
+                bucket.seek( 0 );
+                bucket.writeBoolean( true );
+                bucket.writeLong( existingPos );
+                bucket.writeUTF( identityStore.readUTF() );
+                fillExtras( bucket, 0, slotSize );
+                bucket.seek( slotSize );
+                bucket.writeBoolean( true );
+                bucket.writeLong( pos );
+                bucket.writeUTF( reference.identity() );
+                fillExtras( bucket, 1, slotSize );
+                identityStore.seek( slot * slotSize );
+                identityStore.writeBoolean( true );
+                identityStore.writeLong( -1 );
+                identityStore.writeUTF( "" );
+                fillExtras( identityStore, slot, slotSize );
+            }
+        }
+    }
+
+    void drop( EntityReference reference )
+        throws IOException
+    {
+        if( closed )
+        {
+            throw new IdentityFileClosedException();
+        }
+        if( reference.identity().length() > slotSize - 16 )
+        {
+            throw new IdentityTooLongException( reference );
+        }
+        final int slot = getSlot( reference );
+        identityStore.seek( slot * slotSize );
+        boolean isExtended = identityStore.readBoolean();
+        if( isExtended )
+        {
+            RandomAccessFile buckets = bucketManager.get( slot );
+            int next = 0;
+            while( next * slotSize < buckets.length() )
+            {
+                buckets.seek( next * slotSize );
+                boolean isUsed = buckets.readBoolean();
+                buckets.readLong();  //ignore, should probably be changed to skip(8);
+                EntityReference foundReference = new EntityReference( buckets.readUTF() );
+                if( isUsed && foundReference.equals( reference ) )
+                {
+                    buckets.seek( next * slotSize );
+                    buckets.writeBoolean( false );
+                    return;
+                }
+                next++;
+            }
+        }
+        else
+        {
+            identityStore.readLong(); // ignore the pos
+            EntityReference foundReference = new EntityReference( identityStore.readUTF() );
+            if( reference.equals( foundReference ) )
+            {
+                // found, no erase.
+                identityStore.seek( slot * slotSize );
+                identityStore.writeBoolean( false );
+                identityStore.writeLong( -1 );
+                identityStore.writeUTF( "" );
+                fillExtras( identityStore, slot, slotSize );
+            }
+        }
+    }
+
+    private int getSlot( EntityReference identity )
+    {
+        int hashCode = identity.hashCode();
+        hashCode = hashCode < 0 ? -hashCode : hashCode;
+        return 1 + hashCode % entries;
+    }
+
+    public void close()
+        throws IOException
+    {
+        bucketManager.close();
+        identityStore.close();
+        closed = true;
+    }
+
+    private static void initialize( RandomAccessFile newFile, int entries, int slotSize )
+        throws IOException
+    {
+        for( int i = 1; i <= entries + 1; i++ )
+        {
+            newFile.seek( i * slotSize );
+            newFile.writeBoolean( false );  // Extended
+            newFile.writeLong( -1 );        // Position
+            newFile.writeUTF( "" );         // Identity
+            fillExtras( newFile, i, slotSize );
+        }
+        newFile.seek( 0 );
+        newFile.writeInt( CURRENT_VERSION );
+        newFile.writeInt( entries );
+        newFile.writeInt( slotSize );
+    }
+
+    private static void fillExtras( RandomAccessFile accessFile, int slot, int slotSize )
+        throws IOException
+    {
+        long pointer = accessFile.getFilePointer();
+        long fillTo = ( slot + 1 ) * slotSize - 1;
+        long arraysize = fillTo - pointer;
+        if( arraysize < 0 )
+        {
+            System.err.println( "Negative Array Size detected:" + arraysize );
+        }
+        byte[] extras = new byte[(int) arraysize];
+        accessFile.write( extras );
+    }
+
+    public static IdentityFile use( File identityDir )
+        throws MalformedIdentityDirectoryException, IOException
+    {
+        File idFile = new File( identityDir, "id-hash.data" );
+        if( !idFile.exists() )
+        {
+            throw new MalformedIdentityDirectoryException( identityDir );
+        }
+        File bucketDir = new File( identityDir, "buckets" );
+        if( !bucketDir.exists() )
+        {
+            throw new MalformedIdentityDirectoryException( identityDir );
+        }
+        RandomAccessFile store = new RandomAccessFile( idFile, "rw" );
+        int version = store.readInt(); // Read Version
+        int entries = store.readInt(); // Read entries
+        int slotSize = store.readInt(); // Read slotSize
+        return new IdentityFile( store, bucketDir, slotSize, entries );
+    }
+
+    public static IdentityFile create( File identityDir, int slotSize, int idEntries )
+        throws IOException
+    {
+        FileUtils.delete( identityDir );
+        identityDir.mkdirs();
+        File idFile = new File( identityDir, "id-hash.data" );
+        RandomAccessFile store = new RandomAccessFile( idFile, "rw" );
+        initialize( store, idEntries, slotSize );
+        File bucketDir = new File( identityDir, "buckets" );
+        return new IdentityFile( store, bucketDir, slotSize, idEntries );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityFileClosedException.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityFileClosedException.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityFileClosedException.java
new file mode 100644
index 0000000..4b663b6
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityFileClosedException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.spi.entitystore.EntityStoreException;
+
+public class IdentityFileClosedException extends EntityStoreException
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityTooLongException.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityTooLongException.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityTooLongException.java
new file mode 100644
index 0000000..bb5c4a0
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/IdentityTooLongException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.api.entity.EntityReference;
+import org.qi4j.spi.entitystore.EntityStoreException;
+
+public class IdentityTooLongException extends EntityStoreException
+{
+    public IdentityTooLongException( EntityReference identity )
+    {
+        super( "The identity is too long for the configured store: " + identity.toString().length() + ", " + identity );
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/MalformedIdentityDirectoryException.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/MalformedIdentityDirectoryException.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/MalformedIdentityDirectoryException.java
new file mode 100644
index 0000000..613e35d
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/MalformedIdentityDirectoryException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import java.io.File;
+
+public class MalformedIdentityDirectoryException extends Exception
+{
+    private File idDir;
+
+    public MalformedIdentityDirectoryException( File idDir )
+    {
+        this.idDir = idDir;
+    }
+
+    public File getDirectory()
+    {
+        return idDir;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/RecordManager.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/RecordManager.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/RecordManager.java
new file mode 100644
index 0000000..9bd7efa
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/RecordManager.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.api.entity.EntityReference;
+import org.qi4j.io.Input;
+import org.qi4j.spi.entitystore.EntityStoreException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.Reader;
+import java.util.ArrayList;
+
+public class RecordManager
+    implements UndoManager
+{
+    private static final byte UNDO_DELETE = 2;
+    private static final byte UNDO_MODIFY = 3;
+    private static final byte UNDO_NEW_IDENTITY = 4;
+    private static final byte UNDO_DROP_IDENTITY = 5;
+    private static final byte UNDO_EXTEND = 6;
+
+    private DataStore dataStore;
+    private RandomAccessFile undoJournal;
+    private ArrayList<UndoCommand> commands;
+
+    public RecordManager( File dataDir, boolean recover )
+        throws IOException
+    {
+        File undoFile = new File( dataDir, "undo.data" );
+        dataStore = new DataStore( dataDir, this );
+        commands = new ArrayList<UndoCommand>();
+        if( undoFile.exists() )
+        {
+            undoJournal = new RandomAccessFile( undoFile, "rw" );
+            if( recover && undoJournal.length() > 0 )
+            {
+                recover();
+            }
+        }
+        else
+        {
+            undoFile.createNewFile();
+            undoJournal = new RandomAccessFile( undoFile, "rw" );
+        }
+
+    }
+
+    public void putData( DataBlock data )
+        throws IOException
+    {
+        dataStore.putData( data );
+    }
+
+    public void deleteData( EntityReference reference )
+        throws IOException
+    {
+        dataStore.delete( reference );
+    }
+
+    public DataBlock readData( EntityReference reference )
+        throws IOException
+    {
+        return dataStore.readData( reference );
+    }
+
+    
+    public void commit()
+        throws IOException
+    {
+        dataStore.flush();
+        commands.clear();
+        undoJournal.setLength( 0 );
+    }
+
+    public void discard()
+        throws IOException
+    {
+        for( UndoCommand command : commands )
+        {
+            command.undo( dataStore.dataFile(), dataStore.identityFile() );
+        }
+        commands.clear();
+        undoJournal.setLength( 0 );
+    }
+
+    public void close()
+        throws IOException
+    {
+        dataStore.close();
+    }
+
+    public void saveUndoCommand( UndoCommand command )
+    {
+        commands.add( command );
+        try
+        {
+            if( command instanceof UndoDeleteCommand )
+            {
+                undoJournal.write( UNDO_DELETE );
+                command.save( undoJournal );
+            }
+            else if( command instanceof UndoModifyCommand )
+            {
+                undoJournal.write( UNDO_MODIFY );
+                command.save( undoJournal );
+            }
+            else if( command instanceof UndoDropIdentityCommand )
+            {
+                undoJournal.write( UNDO_DROP_IDENTITY );
+                command.save( undoJournal );
+            }
+            else if( command instanceof UndoNewIdentityCommand )
+            {
+                undoJournal.write( UNDO_NEW_IDENTITY );
+                command.save( undoJournal );
+            }
+            else if( command instanceof UndoExtendCommand )
+            {
+                undoJournal.write( UNDO_EXTEND );
+                command.save( undoJournal );
+            }
+            else
+            {
+                throw new InternalError();
+            }
+        }
+        catch( IOException e )
+        {
+            throw new EntityStoreException( "Undo storage medium is malfunctioning." );
+        }
+    }
+
+    private void recover()
+    {
+        try
+        {
+            undoJournal.seek( 0 );
+            while( undoJournal.getFilePointer() < undoJournal.length() )
+            {
+                byte type = undoJournal.readByte();
+                UndoCommand command;
+                if( type == UNDO_MODIFY )
+                {
+                    command = UndoModifyCommand.load( undoJournal );
+                }
+                else if( type == UNDO_DELETE )
+                {
+                    command = UndoDeleteCommand.load( undoJournal );
+                }
+                else if( type == UNDO_DROP_IDENTITY )
+                {
+                    command = UndoDropIdentityCommand.load( undoJournal );
+                }
+                else if( type == UNDO_EXTEND )
+                {
+                    command = UndoExtendCommand.load( undoJournal );
+                }
+                else if( type == UNDO_NEW_IDENTITY )
+                {
+                    command = UndoNewIdentityCommand.load( undoJournal );
+                }
+                else
+                {
+                    throw new InternalError();
+                }
+                commands.add( command );
+            }
+            discard();
+        }
+        catch( IOException e )
+        {
+            throw new EntityStoreException( "Unable to recover from previous crash." );
+        }
+    }
+
+    public Input<Reader, IOException> data()
+    {
+        return dataStore.data();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/StoreIterator.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/StoreIterator.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/StoreIterator.java
new file mode 100644
index 0000000..69d1fd6
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/StoreIterator.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.api.entity.EntityReference;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Iterator;
+
+class StoreIterator
+    implements Iterator<EntityReference>
+{
+    private boolean isAvailable;
+    private RandomAccessFile store;
+    private EntityReference identity;
+    private long position;
+    private int identityMaxLength;
+
+    StoreIterator( RandomAccessFile store, int identityMaxLength )
+    {
+        this.store = store;
+        this.position = DataStore.DATA_AREA_OFFSET;
+        this.identityMaxLength = identityMaxLength;
+        getNext();
+    }
+
+    public boolean hasNext()
+    {
+        return isAvailable;
+    }
+
+    public EntityReference next()
+    {
+        EntityReference result = identity;
+        getNext();
+        return result;
+    }
+
+    private void getNext()
+    {
+        try
+        {
+            while( store.getFilePointer() < store.length() )
+            {
+                store.seek( position );
+                int blockSize = store.readInt();
+                if( blockSize == 0 )
+                {
+                    // TODO This is a bug. Why does it occur??
+                    isAvailable = false;
+                    return;
+                }
+                position = position + blockSize;  // position for next round...
+                byte usage = store.readByte();
+                if( usage == 1 || usage == 2 )
+                {
+                    store.skipBytes( 12 );
+                    identity = readIdentity();
+                    isAvailable = true;
+                    return;
+                }
+            }
+            isAvailable = false;
+        }
+        catch( IOException e )
+        {
+            identity = null;
+            isAvailable = false;
+        }
+    }
+
+    public void remove()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    private EntityReference readIdentity()
+        throws IOException
+    {
+        int idSize = store.readByte();
+        if( idSize < 0 )
+        {
+            idSize = idSize + 256;  // Fix 2's-complement negative values of bytes into unsigned 8 bit.
+        }
+        byte[] idData = new byte[idSize];
+        store.read( idData );
+        store.skipBytes( identityMaxLength - idSize );
+        return new EntityReference( new String( idData ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftConfiguration.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftConfiguration.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftConfiguration.java
new file mode 100644
index 0000000..b36db15
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftConfiguration.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.api.common.Optional;
+import org.qi4j.api.common.UseDefaults;
+import org.qi4j.api.configuration.ConfigurationComposite;
+import org.qi4j.api.property.Property;
+
+public interface SwiftConfiguration extends ConfigurationComposite
+{
+    Property<String> storageDirectory();
+
+    @Optional @UseDefaults Property<Boolean> turboMode();
+
+    @Optional @UseDefaults Property<Boolean> recover();
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreAssembler.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreAssembler.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreAssembler.java
new file mode 100644
index 0000000..55c217b
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreAssembler.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.api.common.Visibility;
+import org.qi4j.bootstrap.Assembler;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.spi.uuid.UuidIdentityGeneratorService;
+
+public class SwiftEntityStoreAssembler
+    implements Assembler
+{
+    private String configurationModuleName;
+
+    public SwiftEntityStoreAssembler( String configurationModule )
+    {
+        this.configurationModuleName = configurationModule;
+    }
+
+    public void assemble( ModuleAssembly module ) throws AssemblyException
+    {
+        module.services( SwiftEntityStoreService.class, UuidIdentityGeneratorService.class );
+        ModuleAssembly config = module.layer().module( configurationModuleName );
+        config.entities( SwiftConfiguration.class ).visibleIn( Visibility.layer );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreMixin.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreMixin.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreMixin.java
new file mode 100644
index 0000000..89cf3e5
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreMixin.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.api.configuration.Configuration;
+import org.qi4j.api.entity.EntityReference;
+import org.qi4j.api.injection.scope.This;
+import org.qi4j.api.injection.scope.Uses;
+import org.qi4j.api.service.ServiceActivation;
+import org.qi4j.api.service.ServiceDescriptor;
+import org.qi4j.io.Input;
+import org.qi4j.spi.entitystore.EntityNotFoundException;
+import org.qi4j.spi.entitystore.EntityStoreException;
+import org.qi4j.spi.entitystore.helpers.MapEntityStore;
+
+import java.io.*;
+import java.util.concurrent.locks.ReadWriteLock;
+import org.qi4j.api.entity.EntityDescriptor;
+
+public class SwiftEntityStoreMixin
+    implements ServiceActivation, MapEntityStore
+{
+    private @This ReadWriteLock lock;
+    @Uses private ServiceDescriptor descriptor;
+    @This private Configuration<SwiftConfiguration> configuration;
+    private RecordManager recordManager;
+
+    public void activateService()
+        throws Exception
+    {
+        SwiftConfiguration conf = configuration.get();
+        String storage = conf.storageDirectory().get();
+        File storageDir;
+        storageDir = new File( storage );
+        Boolean recover = conf.recover().get();
+        if( recover == null )
+        {
+            recover = Boolean.TRUE;
+        }
+        recordManager = new RecordManager( storageDir, recover );
+    }
+
+    public void passivateService()
+        throws Exception
+    {
+        recordManager.close();
+    }
+
+    public Reader get( EntityReference entityReference )
+        throws EntityStoreException
+    {
+        try
+        {
+            DataBlock dataBlock = recordManager.readData( entityReference );
+            if( dataBlock == null )
+            {
+                throw new EntityNotFoundException( entityReference );
+            }
+            StringReader reader = new StringReader( new String( dataBlock.data, "UTF-8" ) );
+            return reader;
+        }
+        catch( UnsupportedEncodingException e )
+        {
+            // Can not happen.
+            throw new InternalError();
+        }
+        catch( IOException e )
+        {
+            throw new EntityStoreException( "Unable to read '" + entityReference + "' from the store.", e );
+        }
+    }
+
+    public Input<Reader, IOException> entityStates()
+    {
+        return recordManager.data();
+    }
+
+    public void applyChanges( MapChanges changes )
+        throws IOException
+    {
+        try
+        {
+            changes.visitMap( new MapChanger()
+            {
+                public Writer newEntity( final EntityReference ref, EntityDescriptor entityType ) throws IOException
+                {
+                    return new StringWriter( 1000 )
+                    {
+                        @Override public void close() throws IOException
+                        {
+                            super.close();
+
+                            byte[] stateArray = toString().getBytes( "UTF-8" );
+                            DataBlock block = new DataBlock( ref, stateArray, 0, 0 );
+                            recordManager.putData( block );
+                        }
+                    };
+                }
+
+                public Writer updateEntity( final EntityReference ref, EntityDescriptor entityType ) throws IOException
+                {
+                    return new StringWriter( 1000 )
+                    {
+                        @Override public void close() throws IOException
+                        {
+                            super.close();
+                            byte[] stateArray = toString().getBytes( "UTF-8" );
+                            DataBlock block = new DataBlock( ref, stateArray, 0, 0 );
+                            recordManager.putData( block );
+                        }
+                    };
+                }
+
+                public void removeEntity( EntityReference ref, EntityDescriptor entityType ) throws EntityNotFoundException
+                {
+                    try
+                    {
+                        recordManager.deleteData( ref );
+                    }
+                    catch( IOException e )
+                    {
+                        throw new EntityStoreException( e );
+                    }
+                }
+            } );
+            recordManager.commit();
+        }
+        catch( Exception e )
+        {
+            recordManager.discard();
+            if( e instanceof IOException )
+            {
+                throw (IOException) e;
+            }
+            else if( e instanceof EntityStoreException )
+            {
+                throw (EntityStoreException) e;
+            }
+            else
+            {
+                IOException exception = new IOException();
+                exception.initCause( e );
+                throw exception;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreService.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreService.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreService.java
new file mode 100644
index 0000000..3386862
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/SwiftEntityStoreService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import org.qi4j.api.concern.Concerns;
+import org.qi4j.api.mixin.Mixins;
+import org.qi4j.api.service.ServiceActivation;
+import org.qi4j.library.locking.LockingAbstractComposite;
+import org.qi4j.spi.entitystore.ConcurrentModificationCheckConcern;
+import org.qi4j.spi.entitystore.EntityStateVersions;
+import org.qi4j.spi.entitystore.EntityStore;
+import org.qi4j.spi.entitystore.StateChangeNotificationConcern;
+import org.qi4j.spi.entitystore.helpers.MapEntityStoreMixin;
+
+@Concerns( { StateChangeNotificationConcern.class, ConcurrentModificationCheckConcern.class } )
+@Mixins( { MapEntityStoreMixin.class, SwiftEntityStoreMixin.class } )
+public interface SwiftEntityStoreService
+    extends ServiceActivation, EntityStore, EntityStateVersions, LockingAbstractComposite
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoCommand.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoCommand.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoCommand.java
new file mode 100644
index 0000000..8570716
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoCommand.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+public interface UndoCommand
+{
+    void undo( RandomAccessFile dataFile, IdentityFile idFile ) throws IOException;
+
+    void save( RandomAccessFile undoJournal ) throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoDeleteCommand.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoDeleteCommand.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoDeleteCommand.java
new file mode 100644
index 0000000..32eff50
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoDeleteCommand.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Record has been deleted and we want to restore it.
+ *
+ * Block Structure
+ * [blockSize]     4 bytes
+ * [usage]         1 byte    (0=Unused, 1=prime, 2=mirror, 3=primeChanged, 4=mirrorChanged)
+ * [instanceVersion] 8 bytes
+ * [schemaVersion] 4 bytes
+ * [identitySize]  1 byte
+ * [identity]      IDENTITY_MAX_LENGTH bytes
+ * [mirrorPointer] 8 bytes
+ * [primeDataLength] 4 bytes
+ * [primeData]     n bytes
+ * [mirrorDataLength] 4 bytes
+ * [mirrorData]    n bytes
+ */
+public class UndoDeleteCommand
+    implements UndoCommand
+{
+    private long position;
+    private byte usage;
+
+    public UndoDeleteCommand( long position, byte usage )
+    {
+        this.position = position;
+        this.usage = usage;
+    }
+
+    public void undo( RandomAccessFile dataFile, IdentityFile idFile )
+        throws IOException
+    {
+        dataFile.seek( position );
+        dataFile.skipBytes( 4 );
+        dataFile.writeByte( usage );
+    }
+
+    public void save( RandomAccessFile undoJournal ) throws IOException
+    {
+        undoJournal.writeLong( position );
+        undoJournal.writeByte( usage );
+    }
+
+    static UndoDeleteCommand load( RandomAccessFile undoJournal )
+        throws IOException
+    {
+        long position = undoJournal.readLong();
+        byte usage = undoJournal.readByte();
+        return new UndoDeleteCommand( position, usage );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoDropIdentityCommand.java
----------------------------------------------------------------------
diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoDropIdentityCommand.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoDropIdentityCommand.java
new file mode 100644
index 0000000..f0b6f43
--- /dev/null
+++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoDropIdentityCommand.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008 Niclas Hedhman.
+ *
+ * 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 org.qi4j.entitystore.swift;
+
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import org.qi4j.api.entity.EntityReference;
+
+public class UndoDropIdentityCommand
+    implements UndoCommand
+{
+    private EntityReference reference;
+    private long position;
+
+    public UndoDropIdentityCommand( EntityReference reference, long position )
+    {
+        this.reference = reference;
+        this.position = position;
+    }
+
+    public void undo( RandomAccessFile dataFile, IdentityFile idFile ) throws IOException
+    {
+        idFile.remember( reference, position );
+    }
+
+    public void save( RandomAccessFile undoJournal ) throws IOException
+    {
+        undoJournal.writeUTF( reference.identity() );
+        undoJournal.writeLong( position );
+    }
+
+    static UndoDropIdentityCommand load( RandomAccessFile undoJournal )
+        throws IOException
+    {
+        String idString = undoJournal.readUTF();
+        EntityReference ref = new EntityReference( idString );
+        long pos = undoJournal.readLong();
+        return new UndoDropIdentityCommand( ref, pos );
+    }
+}


Mime
View raw message