All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.objectfabric.Logger Maven / Gradle / Ivy

There is a newer version: 0.9.1
Show newest version
/**
 * This file is part of ObjectFabric (http://objectfabric.org).
 *
 * ObjectFabric is licensed under the Apache License, Version 2.0, the terms
 * of which may be found at http://www.apache.org/licenses/LICENSE-2.0.html.
 * 
 * Copyright ObjectFabric Inc.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

package org.objectfabric;

import java.io.Closeable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;

import org.objectfabric.Actor.Flush;
import org.objectfabric.TObject.Transaction;
import org.objectfabric.ThreadAssert.AllowSharedRead;
import org.objectfabric.ThreadAssert.SingleThreaded;
import org.objectfabric.Workspace.Granularity;

@SingleThreaded
public class Logger extends Dispatcher implements Closeable {

    @AllowSharedRead
    private final Run _run;

    private Transaction _committed, _previous;

    public Logger(Workspace workspace) {
        this(workspace, workspace.callbackExecutor());
    }

    public Logger(Workspace workspace, Executor executor) {
        super(workspace, false);

        _run = new Run(executor);

        init(true, false);
        workspace.register(this, _run);

        if (Debug.THREADS)
            ThreadAssert.exchangeGive(_run, this);

        _run.onStarted();
    }

    /**
     * Block the current thread until all events which occurred up to now have been
     * logged.
     */
    public void flush() {
        flush(false);
    }

    public Future flushAsync(AsyncCallback callback) {
        return flushAsync(callback, false);
    }

    @Override
    public void close() {
        flush(true);
    }

    public Future closeAsync(AsyncCallback callback) {
        return flushAsync(callback, true);
    }

    private final void flush(boolean stop) {
        @SuppressWarnings("unchecked")
        Future future = flushAsync(FutureWithCallback.NOP_CALLBACK, stop);

        try {
            future.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private final Future flushAsync(AsyncCallback callback, final boolean stop) {
        final FutureWithCallback future = new FutureWithCallback(callback, workspace().callbackExecutor());

        _run.addAndRun(new Flush() {

            @Override
            void onSuccess() {
                if (Debug.ENABLED)
                    ThreadAssert.resume(_run);

                if (stop) {
                    workspace().unregister(Logger.this, _run, null);

                    if (Debug.THREADS)
                        ThreadAssert.removePrivate(Logger.this);
                }

                future.set(null);

                if (Debug.ENABLED)
                    ThreadAssert.suspend(_run);
            }

            @Override
            void onException(Exception e) {
                future.setException(e);
            }
        });

        return future;
    }

    //

    @Override
    protected Action onVisitingMap(int mapIndex) {
        Action action = super.onVisitingMap(mapIndex);

        if (action == Action.VISIT && workspace().granularity() == Granularity.ALL) {
            VersionMap map = snapshot().getVersionMaps()[mapIndex];

            if (Debug.ENABLED) {
                Debug.assertion(map.getTransaction().getVersionMap() == map);
                Debug.assertion(map.getTransaction().getSnapshot().last() == map);
            }

            _committed = map.getTransaction();
            _previous = workspace().transaction();
            workspace().setTransaction(_committed);
        }

        return action;
    }

    @Override
    protected void releaseSnapshot(int start, int end) {
        if (workspace().granularity() == Granularity.ALL) {
            VersionMap map = snapshot().getVersionMaps()[start];

            if (Debug.ENABLED) {
                Debug.assertion(_committed == map.getTransaction());
                Debug.assertion(workspace().transaction() == _committed);
            }

            workspace().setTransaction(_previous);
            _committed = null;
            _previous = null;
        }

        super.releaseSnapshot(start, end);
    }

    //

    protected void onChange(TObject object, String change) {
        String a = Utils.padRight(workspace().toString() + ", ", 30);

        if (Debug.ENABLED)
            Helper.instance().disableEqualsOrHashCheck();

        String b = Utils.padRight(object.toString() + ", ", 60);

        if (Debug.ENABLED)
            Helper.instance().enableEqualsOrHashCheck();

        Log.write(a + b + change);
    }

    /*
     * Indexed.
     */

    @Override
    protected void onIndexedRead(TObject object, int index) {
    }

    @Override
    protected void onIndexedWrite(TObject object, int index) {
        String message;

        if (object instanceof TGenerated) {
            TGenerated generated = (TGenerated) object;
            message = generated.getFieldName(index);

            if (workspace().granularity() == Granularity.ALL) {
                String before = writeField(generated.getOldField(index, _committed));
                String after = writeField(generated.getField(index));
                message += ": " + before + " -> " + after;
            } else
                message += " = " + writeField(generated.getField(index));
        } else
            message = "Field " + index + " changed";

        onChange(object, message);
    }

    private String writeField(Object value) {
        if (value != null) {
            if (Debug.ENABLED)
                Helper.instance().disableEqualsOrHashCheck();

            String result = value.toString();

            if (Debug.ENABLED)
                Helper.instance().enableEqualsOrHashCheck();

            return result;
        }

        return "null";
    }

    /*
     * TKeyed.
     */

    @Override
    protected void onKeyedRead(TObject object, Object key) {
        // TODO
    }

    @Override
    protected void onKeyedPut(TObject object, Object key, Object value) {
        onChange(object, "Put " + key + ", " + value);
    }

    @Override
    protected void onKeyedRemoval(TObject object, Object key) {
        onChange(object, "Removal " + key);
    }

    @Override
    protected void onKeyedClear(TObject object) {
        onChange(object, "Clear");
    }

    // TODO counter

    @SuppressWarnings("serial")
    private final class Run extends Actor implements Runnable {

        private final Executor _executor;

        Run(Executor executor) {
            _executor = executor;
        }

        @Override
        protected void enqueue() {
            _executor.execute(this);
        }

        @Override
        public void run() {
            if (Debug.ENABLED)
                ThreadAssert.resume(this, false);

            onRunStarting();
            runMessages();
            walk();

            if (Debug.ENABLED)
                ThreadAssert.suspend(this);

            onRunEnded();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy