Package com.saasovation.collaboration.port.adapter.event

Source Code of com.saasovation.collaboration.port.adapter.event.FollowStoreEventDispatcher

//   Copyright 2012,2013 Vaughn Vernon
//
//   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 com.saasovation.collaboration.port.adapter.event;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import com.saasovation.collaboration.port.adapter.persistence.EventStoreProvider;
import com.saasovation.common.domain.model.DomainEventPublisher;
import com.saasovation.common.event.sourcing.DispatchableDomainEvent;
import com.saasovation.common.event.sourcing.EventDispatcher;
import com.saasovation.common.event.sourcing.EventNotifiable;
import com.saasovation.common.port.adapter.persistence.ConnectionProvider;

public class FollowStoreEventDispatcher implements EventDispatcher, EventNotifiable {

    private DataSource collaborationDataSource;
    private long lastDispatchedEventId;
    private List<EventDispatcher> registeredDispatchers;

    public FollowStoreEventDispatcher(DataSource aDataSource) {
        super();

        this.setCollaborationDataSource(aDataSource);
        this.setRegisteredDispatchers(new ArrayList<EventDispatcher>());

        EventStoreProvider
            .instance()
            .eventStore().registerEventNotifiable(this);

        this.setLastDispatchedEventId(this.queryLastDispatchedEventId());

        this.notifyDispatchableEvents();
    }

    @Override
    public void dispatch(DispatchableDomainEvent aDispatchableDomainEvent) {
        DomainEventPublisher.instance().publish(aDispatchableDomainEvent.domainEvent());

        for (EventDispatcher eventDispatcher : this.registeredDispatchers()) {
           eventDispatcher.dispatch(aDispatchableDomainEvent);
        }
    }

    @Override
    public void notifyDispatchableEvents() {

        // this could be multi-threaded from here,
        // but is not for simplicity

        // child EventDispatchers should use only
        // ConnectionProvider.connection() and
        // not commit. i will commit and close the
        // connection here

        Connection connection =
                ConnectionProvider
                    .connection(this.collaborationDataSource());

        try {
            List<DispatchableDomainEvent> undispatchedEvents =
                    EventStoreProvider
                        .instance()
                        .eventStore()
                        .eventsSince(this.lastDispatchedEventId());

            if (!undispatchedEvents.isEmpty()) {

                for (DispatchableDomainEvent event : undispatchedEvents) {
                    this.dispatch(event);
                }

                DispatchableDomainEvent withLastEventId =
                        undispatchedEvents.get(undispatchedEvents.size() - 1);

                long lastDispatchedEventId = withLastEventId.eventId();

                this.setLastDispatchedEventId(lastDispatchedEventId);

                this.saveLastDispatchedEventId(connection, lastDispatchedEventId);
            }

            connection.commit();

        } catch (Throwable t) {
            throw new IllegalStateException("Cannot dispatch events because: " + t.getMessage(), t);
        } finally {
            ConnectionProvider.closeConnection();
        }
    }

    @Override
    public void registerEventDispatcher(EventDispatcher anEventDispatcher) {
        this.registeredDispatchers().add(anEventDispatcher);
    }

    @Override
    public boolean understands(DispatchableDomainEvent aDispatchableDomainEvent) {
        return true;
    }

    private void close(Statement aStatement, ResultSet aResultSet) {
        this.closeStatement(aStatement);

        this.closeResultSet(aResultSet);

        ConnectionProvider.closeConnection();
    }

    private void closeResultSet(ResultSet aResultSet) {
        if (aResultSet != null) {
            try {
                aResultSet.close();
            } catch (Exception e) {
                // ignore
            }
        }
    }

    private void closeStatement(Statement aStatement) {
        if (aStatement != null) {
            try {
                aStatement.close();
            } catch (Exception e) {
                // ignore
            }
        }
    }

    private DataSource collaborationDataSource() {
        return this.collaborationDataSource;
    }

    private void setCollaborationDataSource(DataSource aDataSource) {
        this.collaborationDataSource = aDataSource;
    }

    private Connection connection() {
        Connection connection = null;

        try {
            connection =
                    ConnectionProvider
                        .connection(this.collaborationDataSource());
        } catch (Throwable t) {
            throw new IllegalStateException(
                    "Cannot acquire database connection because: "
                            + t.getMessage(),
                    t);
        }

        return connection;
    }

    private long lastDispatchedEventId() {
        return this.lastDispatchedEventId;
    }

    private void setLastDispatchedEventId(long aLastDispatchedEventId) {
        this.lastDispatchedEventId = aLastDispatchedEventId;
    }

    private long queryLastDispatchedEventId() {

        long lastHandledEventId = 0;

        Connection connection = this.connection();
        ResultSet result = null;
        PreparedStatement statement = null;

        try {
            statement =
                    connection.prepareStatement(
                            "select max(event_id) from tbl_dispatcher_last_event");

            result = statement.executeQuery();

            if (result.next()) {
                lastHandledEventId = result.getLong(1);
            } else {
                this.saveLastDispatchedEventId(connection, 0);
            }

            connection.commit();

        } catch (Exception e) {
            throw new IllegalStateException(
                    "Cannot query last dispatched event because: "
                        + e.getMessage(),
                    e);
        } finally {
            this.close(statement, result);
        }

        return lastHandledEventId;
    }

    private void saveLastDispatchedEventId(
            Connection aConnection,
            long aLastDispatchedEventId)
    throws Exception {

        int updated = 0;

        PreparedStatement statement = null;

        try {
            statement = aConnection.prepareStatement(
                    "update tbl_dispatcher_last_event set event_id=?");
            statement.setLong(1, aLastDispatchedEventId);
            updated = statement.executeUpdate();

        } catch (Exception e) {
            throw new IllegalStateException("Cannot update dispatcher last event.");
        } finally {
            this.closeStatement(statement);
        }

        if (updated == 0) {

            try {
                statement = aConnection.prepareStatement(
                        "insert into tbl_dispatcher_last_event values(?)");
                statement.setLong(1, aLastDispatchedEventId);
                statement.executeUpdate();

            } catch (Exception e) {
                throw new IllegalStateException("Cannot insert dispatcher last event.");
            } finally {
                this.closeStatement(statement);
            }
        }
    }

    private List<EventDispatcher> registeredDispatchers() {
        return this.registeredDispatchers;
    }

    private void setRegisteredDispatchers(List<EventDispatcher> aDispatchers) {
        this.registeredDispatchers = aDispatchers;
    }
}
TOP

Related Classes of com.saasovation.collaboration.port.adapter.event.FollowStoreEventDispatcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.