View Javadoc

1   /**
2    * Copyright (c) 2002-2011 "Neo Technology,"
3    * Network Engine for Objects in Lund AB [http://neotechnology.com]
4    *
5    * This file is part of Neo4j.
6    *
7    * Neo4j is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.neo4j.server;
21  
22  import java.io.File;
23  
24  import org.apache.commons.configuration.Configuration;
25  import org.neo4j.graphdb.TransactionFailureException;
26  import org.neo4j.helpers.Service;
27  import org.neo4j.helpers.collection.IteratorUtil;
28  import org.neo4j.server.configuration.Configurator;
29  import org.neo4j.server.database.GraphDatabaseFactory;
30  import org.neo4j.server.logging.Logger;
31  import org.neo4j.server.modules.ServerModule;
32  import org.neo4j.server.startup.healthcheck.StartupHealthCheck;
33  import org.neo4j.server.startup.healthcheck.StartupHealthCheckRule;
34  import org.neo4j.server.web.Jetty6WebServer;
35  
36  import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J;
37  
38  public abstract class Bootstrapper
39  {
40      public static final Integer OK = 0;
41      public static final Integer WEB_SERVER_STARTUP_ERROR_CODE = 1;
42      public static final Integer GRAPH_DATABASE_STARTUP_ERROR_CODE = 2;
43      public static final String KEY_LOG4J_CONFIG_XML_PATH = "log4j.config.xml.path";
44  
45      private static Logger log = Logger.getLogger( NeoServerBootstrapper.class );
46  
47      private NeoServerWithEmbeddedWebServer server;
48  
49      public void controlEvent( int arg )
50      {
51          // Do nothing, required by the WrapperListener interface
52      }
53  
54      public Integer start()
55      {
56          return start( new String[0] );
57      }
58  
59      public Integer start( String[] args )
60      {
61          try
62          {
63              StartupHealthCheck startupHealthCheck = new StartupHealthCheck( rules() );
64              Jetty6WebServer webServer = new Jetty6WebServer();
65              server = new NeoServerWithEmbeddedWebServer( this, new AddressResolver(),
66                      startupHealthCheck, getConfigFile(), webServer, getServerModules() );
67              server.start();
68              log.info( "Server started on [%s]", server.baseUri() );
69  
70              Runtime.getRuntime().addShutdownHook( new Thread()
71              {
72                  @Override
73                  public void run()
74                  {
75                      log.info( "Neo4j Server shutdown initiated by kill signal" );
76                      if ( server != null )
77                      {
78                          server.stop();
79                      }
80                  }
81              } );
82  
83              return OK;
84          }
85          catch ( TransactionFailureException tfe )
86          {
87              tfe.printStackTrace();
88              log.error( String.format( "Failed to start Neo Server on port [%d], because ", server.getWebServerPort() )
89                         + tfe + ". Another process may be using database location " + server.getDatabase().getLocation() );
90              return GRAPH_DATABASE_STARTUP_ERROR_CODE;
91          }
92          catch ( Exception e )
93          {
94              e.printStackTrace();
95              log.error( "Failed to start Neo Server on port [%s]", server.getWebServerPort() );
96              return WEB_SERVER_STARTUP_ERROR_CODE;
97          }
98      }
99  
100     protected abstract GraphDatabaseFactory getGraphDatabaseFactory( Configuration configuration );
101 
102     private StartupHealthCheckRule[] rules()
103     {
104         return IteratorUtil.asCollection( getHealthCheckRules() ).toArray( new StartupHealthCheckRule[0] );
105     }
106 
107     protected abstract Iterable<StartupHealthCheckRule> getHealthCheckRules();
108 
109     protected abstract Iterable<Class<? extends ServerModule>> getServerModules();
110 
111     public void stop()
112     {
113         stop( 0 );
114     }
115 
116     public int stop( int stopArg )
117     {
118         String location = "unknown location";
119         try
120         {
121             log.info( "Successfully shutdown Neo Server on port [%d], database [%s]", server.getWebServerPort(),
122                     location );
123             return 0;
124         }
125         catch ( Exception e )
126         {
127             log.error( "Failed to cleanly shutdown Neo Server on port [%d], database [%s]. Reason [%s] ",
128                     server.getWebServerPort(), location, e.getMessage() );
129             return 1;
130         }
131     }
132 
133     public NeoServerWithEmbeddedWebServer getServer()
134     {
135         return server;
136     }
137 
138     protected static File getConfigFile()
139     {
140         return new File( System.getProperty( Configurator.NEO_SERVER_CONFIG_FILE_KEY, Configurator.DEFAULT_CONFIG_DIR ) );
141     }
142 
143     public static void main( String[] args )
144     {
145         configureLogging();
146         Bootstrapper bootstrapper = loadMostDerivedBootstrapper();
147         bootstrapper.start( args );
148     }
149 
150     public static Bootstrapper loadMostDerivedBootstrapper()
151     {
152         Bootstrapper winner = new NeoServerBootstrapper();
153         for ( Bootstrapper candidate : Service.load( Bootstrapper.class ) )
154         {
155             if ( candidate.isMoreDerivedThan( winner ) ) winner = candidate;
156         }
157         return winner;
158     }
159 
160     protected boolean isMoreDerivedThan( Bootstrapper other )
161     {
162         // Default implementation just checks if this is a subclass of other
163         return other.getClass().isAssignableFrom( getClass() );
164     }
165 
166     private static void configureLogging()
167     {
168         SysOutOverSLF4J.sendSystemOutAndErrToSLF4J();
169     }
170 }