# MemoryEventStoreService.java

    /*
     * Copyright (c) 2011, Rickard Öberg. All Rights Reserved.
     *
     * 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.library.eventsourcing.domain.source.memory;

    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.ListIterator;
    import org.qi4j.api.activation.Activators;
    import org.qi4j.api.mixin.Mixins;
    import org.qi4j.api.service.ServiceComposite;
    import org.qi4j.io.Input;
    import org.qi4j.io.Output;
    import org.qi4j.io.Receiver;
    import org.qi4j.io.Sender;
    import org.qi4j.library.eventsourcing.domain.api.UnitOfWorkDomainEventsValue;
    import org.qi4j.library.eventsourcing.domain.source.AbstractEventStoreMixin;
    import org.qi4j.library.eventsourcing.domain.source.EventSource;
    import org.qi4j.library.eventsourcing.domain.source.EventStore;
    import org.qi4j.library.eventsourcing.domain.source.EventStoreActivation;
    import org.qi4j.library.eventsourcing.domain.source.EventStream;

    /**
     * In-Memory EventStore. Mainly used for testing.
     */
    @Mixins(MemoryEventStoreService.MemoryEventStoreMixin.class)
    @Activators( EventStoreActivation.Activator.class )
    public interface MemoryEventStoreService
            extends EventSource, EventStore, EventStream, EventStoreActivation, ServiceComposite
    {
        abstract class MemoryEventStoreMixin
                extends AbstractEventStoreMixin
                implements EventSource, EventStoreActivation
        {
            // This list holds all transactions
            private LinkedList<UnitOfWorkDomainEventsValue> store = new LinkedList<UnitOfWorkDomainEventsValue>();

            private long currentCount = 0;

            public Input<UnitOfWorkDomainEventsValue, IOException> events( final long offset, final long limit )
            {
                if (offset < 0 || offset > count())
                    throw new IllegalArgumentException( "Offset must be between 0 and current number of events in the store" );

                if (limit <= 0 )
                    throw new IllegalArgumentException( "Limit must be above 0" );

                return new Input<UnitOfWorkDomainEventsValue, IOException>()
                {
                    @Override
                    public <ReceiverThrowableType extends Throwable> void transferTo( Output<? super UnitOfWorkDomainEventsValue, ReceiverThrowableType> output ) throws IOException, ReceiverThrowableType
                    {
                        // Lock store first
                        lock.lock();
                        try
                        {
                            output.receiveFrom( new Sender<UnitOfWorkDomainEventsValue, IOException>()
                            {
                                @Override
                                public <ReceiverThrowableType extends Throwable> void sendTo( Receiver<? super UnitOfWorkDomainEventsValue, ReceiverThrowableType> receiver ) throws ReceiverThrowableType, IOException
                                {
                                    ListIterator<UnitOfWorkDomainEventsValue> iterator = store.listIterator( (int) offset );

                                    long count = 0;

                                    while( iterator.hasNext() && count < limit )
                                    {
                                        UnitOfWorkDomainEventsValue next = iterator.next();
                                        receiver.receive( next );
                                        count++;
                                    }
                                }
                            } );
                        } finally
                        {
                            lock.unlock();
                        }
                    }
                };
            }

            @Override
            public long count()
            {
                return currentCount;
            }

            @Override
            protected Output<UnitOfWorkDomainEventsValue, IOException> storeEvents0()
            {
                return new Output<UnitOfWorkDomainEventsValue, IOException>()
                {
                    @Override
                    public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends UnitOfWorkDomainEventsValue, SenderThrowableType> sender ) throws IOException, SenderThrowableType
                    {
                        final List<UnitOfWorkDomainEventsValue> newEvents = new ArrayList<UnitOfWorkDomainEventsValue>(  );
                        sender.sendTo( new Receiver<UnitOfWorkDomainEventsValue, IOException>()
                        {
                            @Override
                            public void receive( UnitOfWorkDomainEventsValue item ) throws IOException
                            {
                                newEvents.add( item );
                            }
                        });
                        store.addAll( newEvents );
                        currentCount += newEvents.size();
                    }
                };
            }
        }
    }