Package org.neo4j.neoclipse.graphdb

Source Code of org.neo4j.neoclipse.graphdb.GraphDbServiceManager$DisplayRunnable

/**
* Licensed to Neo Technology under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Neo Technology licenses this file to you 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.neo4j.neoclipse.graphdb;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.preference.IPreferenceStore;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.neoclipse.Activator;
import org.neo4j.neoclipse.connection.Alias;
import org.neo4j.neoclipse.connection.ConnectionMode;
import org.neo4j.neoclipse.editor.CypherResultSet;
import org.neo4j.neoclipse.editor.NodeWrapper;
import org.neo4j.neoclipse.preference.Preferences;
import org.neo4j.neoclipse.util.ApplicationUtil;
import org.neo4j.neoclipse.view.UiHelper;
import org.neo4j.rest.graphdb.RestGraphDatabase;
import org.neo4j.rest.graphdb.query.RestCypherQueryEngine;


/**
* This manager controls the neo4j service.
*
* @author Peter Hänsgen
* @author Anders Nawroth
* @author Radhakrishan Kalyan
*/
public class GraphDbServiceManager
{
    private static final String FIND_REFERENCE_NODE_WITH_RELS_STATEMENT = "START n=node(*) MATCH n--() RETURN id(n) as id LIMIT 1";
    private static final String FIND_REFERENCE_NODE_STATEMENT = "START n=node(*) RETURN id(n) as id LIMIT 1";
    private static final String NEOCLIPSE_PACKAGE = "org.neo4j.neoclipse.";
    private static Logger logger = Logger.getLogger( GraphDbServiceManager.class.getName() );
    private Alias currentAlias;

    {
        logger.setUseParentHandlers( false );
        logger.setLevel( Level.INFO );
        ConsoleHandler handler = new ConsoleHandler();
        handler.setLevel( Level.INFO );
        logger.addHandler( handler );
    }

    private class Tasks
    {
        final Runnable START = new Runnable()
        {
            @Override
            public void run()
            {
                if ( lifecycle != null )
                {
                    throw new IllegalStateException(
                            "Can't start new database: There is already a serice running or isn't properly shutdown." );
                }
                logInfo( "trying to start/connect ..." );
                GraphDatabaseService graphDb = null;
                ConnectionMode connectionMode = currentAlias.getConnectionMode();

                switch ( connectionMode )
                {
                case REMOTE:
                {
                    graphDb = new RestGraphDatabase( currentAlias.getUri(), currentAlias.getUserName(),
                            currentAlias.getPassword() );
                    logInfo( "connected to remote neo4j using neo4j rest api." );
                    break;

                }
                case LOCAL:
                {
                    GraphDatabaseBuilder databaseBuilder = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder( currentAlias
                            .getUri() );
                    Boolean allowStoreUpgrade = Boolean.parseBoolean( currentAlias
                            .getConfigurationByKey( GraphDatabaseSettings.allow_store_upgrade.name() ) );
                    graphDb = databaseBuilder.setConfig( GraphDatabaseSettings.read_only, Boolean.toString( isReadOnlyMode() ) )
                            .setConfig( GraphDatabaseSettings.allow_store_upgrade, allowStoreUpgrade.toString() )
                            .newGraphDatabase();
                    logInfo( isReadOnlyMode() ? "connected to embedded read-only neo4j" : "connected to embedded neo4j" );
                    break;
                }
                default:
                {
                    throw new UnsupportedOperationException( "Connection mode is required" );
                }

                }

                lifecycle = new GraphDbLifecycle( graphDb );
                if ( !isReadOnlyMode() )
                {
                    logFine( "starting tx" );
                    tx = graphDb.beginTx();
                }
                fireServiceChangedEvent( GraphDbServiceStatus.STARTED );
            }
        };

        final Runnable STOP = new Runnable()
        {
            @Override
            public void run()
            {
                logInfo( "stopping/disconnecting ..." );
                if ( lifecycle == null )
                {
                    throw new IllegalStateException( "Can not stop the database: there is no running database." );
                }
                fireServiceChangedEvent( GraphDbServiceStatus.STOPPING );
                // TODO give the UI some time to deal with it here?
                try
                {
                    if ( !isReadOnlyMode() )
                    {
                        tx.failure();
                        tx.finish();
                    }
                }
                catch ( Exception e )
                {
                    e.printStackTrace();
                }
                try
                {
                    lifecycle.manualShutdown();
                    logInfo( "stopped/disconnected" );
                }
                catch ( Exception e )
                {
                    throw new RuntimeException( "Can not stop the database. The reason is not known." );
                }
                finally
                {
                    lifecycle = null;
                    fireServiceChangedEvent( GraphDbServiceStatus.STOPPED );
                }
            }
        };

        final Runnable RESTART = new Runnable()
        {
            @Override
            public void run()
            {
                STOP.run();
                START.run();
            }
        };

        final Runnable SHUTDOWN = new Runnable()
        {
            @Override
            public void run()
            {
                if ( lifecycle != null )
                {
                    fireServiceChangedEvent( GraphDbServiceStatus.SHUTTING_DOWN );
                    STOP.run();
                }
            }
        };

        final Runnable COMMIT = new Runnable()
        {
            @Override
            public void run()
            {
                if ( serviceMode == GraphDbServiceMode.READ_WRITE_EMBEDDED )
                {
                    tx.success();
                }
                else
                {
                    logFine( "Committing while not in write mode." );
                }
                if ( !isReadOnlyMode() )
                {
                    tx.finish();
                    tx = lifecycle.graphDb().beginTx();
                    fireServiceChangedEvent( GraphDbServiceStatus.COMMIT );
                }
            }
        };

        final Runnable ROLLBACK = new Runnable()
        {
            @Override
            public void run()
            {
                if ( !isReadOnlyMode() )
                {
                    tx.finish();
                    tx = lifecycle.graphDb().beginTx();
                    fireServiceChangedEvent( GraphDbServiceStatus.ROLLBACK );
                }
            }
        };
    }

    private class TaskWrapper<T> implements Callable<T>
    {
        private final GraphCallable<T> callable;

        public TaskWrapper( final GraphCallable<T> callable )
        {
            this.callable = callable;
        }

        @Override
        public T call() throws Exception
        {
            GraphDatabaseService graphDb = null;
            if ( lifecycle != null )
            {
                graphDb = lifecycle.graphDb();
            }
            return callable.call( graphDb );
        }
    }

    private class RunnableWrapper implements Runnable
    {
        private final GraphRunnable runnable;
        private final String name;

        public RunnableWrapper( final GraphRunnable runnable, final String name )
        {
            this.runnable = runnable;
            this.name = name;
        }

        @Override
        public void run()
        {
            GraphDatabaseService graphDb = null;
            if ( lifecycle != null )
            {
                graphDb = lifecycle.graphDb();
            }
            logFine( "running: " + name );
            runnable.run( graphDb );
            logFine( "finished running: " + name );
        }
    }

    private class DisplayRunnable implements Runnable
    {
        private final Runnable runnable;
        private final String name;

        public DisplayRunnable( final Runnable runnable, final String name )
        {
            this.runnable = runnable;
            this.name = name;
        }

        @Override
        public void run()
        {
            logFine( "sending display task: " + name );
            UiHelper.asyncExec( runnable );
        }
    }

    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private final Tasks tasks = new Tasks();

    /**
     * The service instance.
     */
    private GraphDbServiceMode serviceMode;
    private GraphDbLifecycle lifecycle = null;

    /**
     * The registered service change listeners.
     */
    private final ListenerList listeners = new ListenerList();
    private Transaction tx;
    private final IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();

    /**
     * The constructor.
     */
    public GraphDbServiceManager()
    {
        serviceMode = GraphDbServiceMode.valueOf( preferenceStore.getString( Preferences.CONNECTION_MODE ) );
        logInfo( "Starting " + this.getClass().getSimpleName() );
    }

    private void logFine( final String message )
    {
        logger.fine( message );
    }

    private void logInfo( final String message )
    {
        logger.info( message );
    }

    private Tasks tasks()
    {
        return tasks;
    }

    private void printTask( final Object task, final String type, final String info )
    {
        String name = task.getClass().getName();
        if ( name.startsWith( NEOCLIPSE_PACKAGE ) )
        {
            name = name.substring( NEOCLIPSE_PACKAGE.length() );
        }
        logFine( type + " -> " + name + ":\n" + info );
    }

    public <T> Future<T> submitTask( final Callable<T> task, final String info )
    {
        printTask( task, "C", info );
        return executor.submit( task );
    }

    public <T> Future<T> submitTask( final GraphCallable<T> callable, final String info )
    {
        printTask( callable, "GC", info );
        TaskWrapper<T> wrapped = new TaskWrapper<T>( callable );
        return executor.submit( wrapped );
    }

    public Future<?> submitTask( final Runnable runnable, final String info )
    {
        printTask( runnable, "R", info );
        return executor.submit( runnable );
    }

    public Future<?> submitTask( final GraphRunnable runnable, final String info )
    {
        printTask( runnable, "GR", info );
        RunnableWrapper wrapped = new RunnableWrapper( runnable, info );
        return executor.submit( wrapped );
    }

    /**
     * Submit a task that should be performed by the UI thread after the tasks
     * in the execution queue have executed.
     *
     * @param runnable runnable to execute
     * @param info short description of the task
     */
    public void submitDisplayTask( final Runnable runnable, final String info )
    {
        DisplayRunnable wrapped = new DisplayRunnable( runnable, info );
        executor.submit( wrapped );
    }

    public void executeTask( final GraphRunnable runnable, final String info )
    {
        logFine( "starting: " + info );
        runnable.run( lifecycle.graphDb() );
        logFine( "finishing: " + info );
    }

    public <T> T executeTask( final GraphCallable<T> callable, final String info )
    {
        logFine( "calling: " + info );
        return callable.call( lifecycle.graphDb() );
    }

    public void stopExecutingTasks()
    {
        if ( !executor.isShutdown() )
        {
            executor.shutdown();
        }
    }

    public boolean isRunning()
    {
        return lifecycle != null && lifecycle.graphDb() != null;
    }

    public boolean isReadOnlyMode()
    {
        return serviceMode == GraphDbServiceMode.READ_ONLY_EMBEDDED;
    }

    public void setGraphServiceMode( final GraphDbServiceMode gdbServiceMode )
    {
        serviceMode = gdbServiceMode;
    }

    /**
     * Starts the neo4j service.
     *
     * @return
     */
    public Future<?> startGraphDbService( Alias alias )
    {
        if ( alias == null )
        {
            throw new IllegalAccessError( "PLease select the database to start." );
        }
        if ( isRunning() )
        {
            throw new IllegalAccessError( "Database is already running." );
        }
        currentAlias = alias;
        Future<?> submitTask = submitTask( tasks().START, "start db" );
        return submitTask;
    }

    /**
     * Stops the neo4j service.
     *
     * @return
     */
    public Future<?> stopGraphDbService()
    {
        return submitTask( tasks().STOP, "stop db" );
    }

    /**
     * Restarts the neo4j service.
     *
     * @return
     */
    public Future<?> restartGraphDbService() throws Exception
    {
        return submitTask( tasks().RESTART, "restart db" );
    }

    /**
     * Shuts down the Neo4j service if it's running.
     *
     * @return
     */
    public Future<?> shutdownGraphDbService()
    {
        return submitTask( tasks().SHUTDOWN, "shutdown db" );
    }

    /**
     * Commit transaction.
     *
     * @return
     */
    public Future<?> commit()
    {
        return submitTask( tasks().COMMIT, "commit" );
    }

    /**
     * ExecuteCypher query.
     *
     * @param cypherSql
     * @return CypherResultSet
     * @throws Exception
     */
    public CypherResultSet executeCypher( final String cypherSql ) throws Exception
    {
        return submitTask( new GraphCallable<CypherResultSet>()
        {
            @Override
            public CypherResultSet call( GraphDatabaseService graphDb )
            {
                if ( !isRunning() )
                {
                    throw new RuntimeException( "Please start the graphdb." );
                }
                final String cypherQuery = cypherSql.replace( '\"', '\'' ).replace( '\n', ' ' );
                String message = null;
                Iterator<Map<String, Object>> iterator = null;
                List<String> columns = new ArrayList<String>();
                //
                if ( currentAlias.getConnectionMode() != ConnectionMode.REMOTE )
                {
                    ExecutionEngine engine = new ExecutionEngine( graphDb );
                    ExecutionResult result = engine.execute( cypherQuery );
                    // message = result.toString().substring( result.toString().lastIndexOf( "+" ) + 1 ).trim();
                    columns = result.columns();
                    iterator = result.iterator();
                }
                else if ( currentAlias.getConnectionMode() == ConnectionMode.REMOTE )
                {
                    Iterable<Map<String, Object>> execute = new RestCypherQueryEngine(( (RestGraphDatabase) graphDb ).getRestAPI()).query(cypherQuery,
                            new HashMap<String, Object>() );
                    iterator = execute.iterator();
                }

                final LinkedList<Map<String, Object>> resultList = new LinkedList<Map<String, Object>>();
                while ( iterator.hasNext() )
                {
                    Map<String, Object> resultMap = iterator.next();
                    LinkedHashMap<String, Object> newMap = new LinkedHashMap<String, Object>();
                    Set<Entry<String, Object>> entrySet = resultMap.entrySet();
                    for ( Entry<String, Object> entry : entrySet )
                    {
                        if ( !columns.contains( entry.getKey() ) )
                        {
                            columns.add( entry.getKey() );
                        }
                        Object objectNode = entry.getValue();
                        if ( objectNode == null )
                        {
                            continue;
                        }

                        Object obj = null;
                        if ( objectNode instanceof Node )
                        {
                            Node node = (Node) objectNode;
                            NodeWrapper oMap = ApplicationUtil.extractToNodeWrapper( node, true );
                            obj = oMap;
                        }
                        else
                        {
                            obj = objectNode;
                        }
                        newMap.put( entry.getKey(), obj );
                    }
                    resultList.add( newMap );
                }
                return new CypherResultSet( resultList, columns, message );
            }

            private List<String> getColumns( String cypherQuery )
            {
                int indexOf = cypherQuery.toLowerCase().indexOf( "return" );
                String[] columns = cypherQuery.substring( indexOf + 7 ).split( "," );
                return Arrays.asList( columns );
            }

        }, "execute cypher query" ).get();
    }

   
    /**
     * getAllNodes
     *
     * @return List<Map<String, Object>>
     * @throws Exception
     */
    public List<NodeWrapper> getAllNodes() throws Exception
    {
        return submitTask( new GraphCallable<List<NodeWrapper>>()
        {
            @Override
            public List<NodeWrapper> call( GraphDatabaseService graphDb )
            {
                final LinkedList<NodeWrapper> list = new LinkedList<NodeWrapper>();
                Iterable<Node> iterable =  graphDb.getAllNodes();
                for ( Node node : iterable )
                {
                    NodeWrapper nodeWrapper = ApplicationUtil.extractToNodeWrapper( node, true );
                    list.add( nodeWrapper );
                }
                return list;
            }

        }, "get all nodes" ).get();
    }

    /**
     * Roll back transaction.
     *
     * @return
     */
    public Future<?> rollback()
    {
        return submitTask( tasks().ROLLBACK, "rollback" );
    }

    /**
     * Registers a service listener.
     */
    public void addServiceEventListener( final GraphDbServiceEventListener listener )
    {
        listeners.add( listener );
    }

    /**
     * Unregisters a service listener.
     */
    public void removeServiceEventListener( final GraphDbServiceEventListener listener )
    {
        listeners.remove( listener );
    }

    /**
     * Notifies all registered listeners about the new service status. Actually
     * just queues up the task so running tasks can finish first.
     */
    public void fireServiceChangedEvent( final GraphDbServiceStatus status )
    {
        submitTask( new Runnable()
        {
            @Override
            public void run()
            {
                fireTheServiceChangedEvent( status );
            }
        }, "fire changed event" );
    }

    private void fireTheServiceChangedEvent( final GraphDbServiceStatus status )
    {
        Object[] changeListeners = listeners.getListeners();
        if ( changeListeners.length > 0 )
        {
            final GraphDbServiceEvent e = new GraphDbServiceEvent( this, status );
            for ( Object changeListener : changeListeners )
            {
                final GraphDbServiceEventListener l = (GraphDbServiceEventListener) changeListener;
                l.serviceChanged( e );
            }
        }
    }

    public Alias getCurrentAlias()
    {
        return currentAlias;
    }

    public Node getAnyReferenceNode() throws Exception
    {
        List<Map<String, Object>> result = executeCypher( FIND_REFERENCE_NODE_WITH_RELS_STATEMENT ).getIterator();
        if ( result.isEmpty() ) {
            result = executeCypher( FIND_REFERENCE_NODE_STATEMENT ).getIterator();
        }
        if ( result.isEmpty() ) {
            return null;
        }
        final long id = ((Number) result.get( 0 ).get( "id" )).longValue();
        return getNodeById( id );
    }

    public Node getNodeById( final long id )
    {
        return executeTask( new GraphCallable<Node>()
        {

            @Override
            public Node call( GraphDatabaseService graphDb )
            {
                Transaction tx = graphDb.beginTx();
                Node nodeById = graphDb.getNodeById( id );
                tx.success();
                return nodeById;
            }
        }, "retrieving node with id "+id );
    }

    public boolean isRemote()
    {
        return currentAlias.getConnectionMode() == ConnectionMode.REMOTE;
    }
}
TOP

Related Classes of org.neo4j.neoclipse.graphdb.GraphDbServiceManager$DisplayRunnable

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.