package org.neo4j.util; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.index.IndexService; import org.neo4j.index.lucene.LuceneIndexService; /** * Manages the life cycle of a {@link GraphDatabaseService} as well as other components. * Removes the tedious work of having to think about shutting down components * and the {@link GraphDatabaseService} when the JVM exists, in the right order as well. */ public class GraphDatabaseLifecycle { /** * Field not final since it's nulled in the shutdown process (to be able * to support multiple calls to shutdown). */ private GraphDatabaseService graphDb; private IndexService indexService; private Thread shutdownHook; /** * Constructs a new {@link GraphDatabaseLifecycle} instance with {@code graphDb} * as the {@link GraphDatabaseService}. Other components can be instantiated using * methods, f.ex. {@link #addIndexService(IndexService)}. * * @param graphDb the {@link GraphDatabaseService} instance to manage. */ public GraphDatabaseLifecycle( GraphDatabaseService graphDb ) { this.graphDb = graphDb; this.shutdownHook = new Thread() { @Override public void run() { runJvmShutdownHook(); } }; Runtime.getRuntime().addShutdownHook( this.shutdownHook ); } /** * Runs the shutdown process manually instead of waiting for it to happen * just before the JVM exists, see {@link #runJvmShutdownHook()}. Normally * this method isn't necessary to call, but can be good to have for special * cases. */ public void manualShutdown() { runShutdown(); if ( this.shutdownHook != null ) { try { Runtime.getRuntime().removeShutdownHook( this.shutdownHook ); this.shutdownHook = null; } catch ( IllegalStateException ise ) { // already shutting down, so to late to remove hook } } } /** * Runs the shutdown process of all started services. Supports multiple * calls to it (if such would accidentally be done). */ protected void runShutdown() { if ( this.indexService != null ) { this.indexService.shutdown(); this.indexService = null; } if ( this.graphDb != null ) { this.graphDb.shutdown(); this.graphDb = null; } } /** * Called right before the JVM exists. It's called from a thread registered * with {@link Runtime#addShutdownHook(Thread)}. */ protected void runJvmShutdownHook() { runShutdown(); } /** * Convenience method for adding a {@link LuceneIndexService} as the * {@link IndexService}. See {@link #addIndexService(IndexService)}. * * @return the created {@link LuceneIndexService} instance. */ public IndexService addLuceneIndexService() { assertIndexServiceNotInstantiated(); return addIndexService( new LuceneIndexService( this.graphDb ) ); } /** * Adds an {@link IndexService} to list of components to manage (which * means the shutdown of it will be managed automatically). * Currently only one {@link IndexService} instance is supported so if * you try to instantiate more than one instance a * {@link UnsupportedOperationException} will be thrown. There are * convenience methods for creating common index services, * {@link #addLuceneIndexService()}. * * @param indexService the {@link IndexService} to add to the list if * managed components by this life cycle object. * @return the created {@link IndexService} instance. */ public IndexService addIndexService( IndexService indexService ) { assertIndexServiceNotInstantiated(); this.indexService = indexService; return indexService; } /** * @return the {@link GraphDatabaseService} instance passed in to the constructor, */ public GraphDatabaseService graphDb() { return this.graphDb; } /** * @return the {@link IndexService} instance managed by this life cycle * object or {@code null} if no {@link IndexService} has been instantiated. * See {@link #addIndexService(IndexService)}. */ public IndexService indexService() { return this.indexService; } private void assertIndexServiceNotInstantiated() { if ( this.indexService != null ) { throw new UnsupportedOperationException( "This utility class " + "only supports zero or one IndexService, there's already a " + this.indexService + " instantiated" ); } } }