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  import java.net.URI;
    24  import java.net.URISyntaxException;
    25  import java.util.ArrayList;
    26  import java.util.Collection;
    27  import java.util.List;
    28  import java.util.Map;
    29
    30  import org.apache.commons.configuration.Configuration;
    31  import org.neo4j.server.configuration.Configurator;
    32  import org.neo4j.server.configuration.PropertyFileConfigurator;
    33  import org.neo4j.server.configuration.validation.DatabaseLocationMustBeSpecifiedRule;
    34  import org.neo4j.server.configuration.validation.Validator;
    35  import org.neo4j.server.database.Database;
    36  import org.neo4j.server.database.GraphDatabaseFactory;
    37  import org.neo4j.server.logging.Logger;
    38  import org.neo4j.server.modules.PluginInitializer;
    39  import org.neo4j.server.modules.RESTApiModule;
    40  import org.neo4j.server.modules.ServerModule;
    41  import org.neo4j.server.plugins.Injectable;
    42  import org.neo4j.server.plugins.PluginManager;
    43  import org.neo4j.server.startup.healthcheck.StartupHealthCheck;
    44  import org.neo4j.server.startup.healthcheck.StartupHealthCheckFailedException;
    45  import org.neo4j.server.web.WebServer;
    46
    47  public class NeoServerWithEmbeddedWebServer implements NeoServer {
    48
    49      public static final Logger log = Logger.getLogger(NeoServerWithEmbeddedWebServer.class);
    50
    51      private final File configFile;
    52      private Configurator configurator;
    53      private Database database;
    54      private final WebServer webServer;
    55      private final StartupHealthCheck startupHealthCheck;
    56
    57      private final AddressResolver addressResolver;
    58
    59      private final List<ServerModule> serverModules = new ArrayList<ServerModule>();
    60      private PluginInitializer pluginInitializer;
    61      // Perhaps this shouldn't reference (an instance of) the Bootstrapper class,
    62      // but we need to provide configuration parameters to load the appropriate
    63      // GraphDatabaseFactory implementation
    64      private final Bootstrapper bootstrapper;
    65
    66      public NeoServerWithEmbeddedWebServer( Bootstrapper bootstrapper, AddressResolver addressResolver,
    67              StartupHealthCheck startupHealthCheck, File configFile, WebServer webServer,
    68              Iterable<Class<? extends ServerModule>> moduleClasses )
    69      {
    70          this.bootstrapper = bootstrapper;
    71          this.addressResolver = addressResolver;
    72          this.startupHealthCheck = startupHealthCheck;
    73          this.configFile = configFile;
    74          this.webServer = webServer;
    75          webServer.setNeoServer( this );
    76          for ( Class<? extends ServerModule> moduleClass : moduleClasses )
    77          {
    78              registerModule( moduleClass );
    79          }
    80      }
    81
    82      public NeoServerWithEmbeddedWebServer( Bootstrapper bootstrapper, StartupHealthCheck startupHealthCheck,
    83              File configFile, WebServer ws, Iterable<Class<? extends ServerModule>> mc )
    84      {
    85          this( bootstrapper, new AddressResolver(), startupHealthCheck, configFile, ws, mc );
    86      }
    87
    88      @Override
    89      public void start() {
    90          // Start at the bottom of the stack and work upwards to the Web container
    91          startupHealthCheck();
    92          validateConfiguration();
    93
    94          startDatabase();
    95
    96          startExtensionInitialization();
    97
    98          startModules();
    99
    100         startWebServer();
    101     }
    102
    103     /**
    104      *  Initializes individual plugins using the mechanism provided via @{see PluginInitializer} and the java service locator
    105      */
    106     protected void startExtensionInitialization()
    107     {
    108         pluginInitializer = new PluginInitializer( this );
    109     }
    110
    111     /**
    112      * Use this method to register server modules from subclasses
    113      * @param clazz
    114      */
    115     protected final void registerModule(Class<? extends ServerModule> clazz) {
    116         try {
    117             serverModules.add(clazz.newInstance());
    118         } catch (Exception e) {
    119             log.warn( "Failed to instantiate server module [%s], reason: %s", clazz.getName(), e.getMessage() );
    120         }
    121     }
    122
    123     private void startModules() {
    124         for(ServerModule module : serverModules) {
    125             module.start(this);
    126         }
    127     }
    128
    129     private void stopModules() {
    130         for(ServerModule module : serverModules) {
    131
    132             try{
    133                 module.stop();
    134             }
    135             catch(Exception e)
    136             {
    137                log.error( e );
    138             }
    139         }
    140     }
    141
    142     private void startupHealthCheck() {
    143         if (!startupHealthCheck.run()) {
    144             throw new StartupHealthCheckFailedException(startupHealthCheck.failedRule());
    145         }
    146     }
    147
    148     private void validateConfiguration() {
    149         this.configurator = new PropertyFileConfigurator(new Validator(new DatabaseLocationMustBeSpecifiedRule()), configFile);
    150     }
    151
    152     private void startDatabase() {
    153         String dbLocation = new File(configurator.configuration().getString(Configurator.DATABASE_LOCATION_PROPERTY_KEY)).getAbsolutePath();
    154         GraphDatabaseFactory dbFactory = bootstrapper.getGraphDatabaseFactory( configurator.configuration() );
    155         Map<String, String> databaseTuningProperties = configurator.getDatabaseTuningProperties();
    156         if (databaseTuningProperties != null) {
    157             this.database = new Database( dbFactory, dbLocation, databaseTuningProperties );
    158         } else {
    159             this.database = new Database( dbFactory, dbLocation );
    160         }
    161     }
    162
    163     @Override
    164     public Configuration getConfiguration() {
    165         return configurator.configuration();
    166     }
    167
    168     private void startWebServer() {
    169
    170         int webServerPort = getWebServerPort();
    171
    172         log.info("Starting Neo Server on port [%s]", webServerPort);
    173         webServer.setPort(webServerPort);
    174
    175
    176         try {
    177             webServer.start();
    178         } catch (Exception e) {
    179             e.printStackTrace();
    180             log.error("Failed to start Neo Server on port [%d], reason [%s]", getWebServerPort(), e.getMessage());
    181         }
    182     }
    183
    184     protected int getWebServerPort() {
    185         return configurator.configuration().getInt(Configurator.WEBSERVER_PORT_PROPERTY_KEY, Configurator.DEFAULT_WEBSERVER_PORT);
    186     }
    187
    188     @Override
    189     public void stop() {
    190         try {
    191             stopModules();
    192             stopExtensionInitializers();
    193             stopDatabase();
    194             stopWebServer();
    195             log.info("Successfully shutdown Neo Server on port [%d], database [%s]", getWebServerPort(), getDatabase().getLocation());
    196         } catch (Exception e) {
    197             log.warn("Failed to cleanly shutdown Neo Server on port [%d], database [%s]. Reason: %s", getWebServerPort(), getDatabase().getLocation(),
    198                     e.getMessage());
    199         }
    200     }
    201
    202     /**
    203      * shuts down initializers of individual plugins
    204      */
    205     private void stopExtensionInitializers()
    206     {
    207         pluginInitializer.stop(  );
    208     }
    209
    210     private void stopWebServer() {
    211         if (webServer != null) {
    212             webServer.stop();
    213         }
    214     }
    215
    216     private void stopDatabase() {
    217         if (database != null) {
    218             database.shutdown();
    219         }
    220     }
    221
    222     @Override
    223     public Database getDatabase() {
    224         return database;
    225     }
    226
    227
    228     public URI baseUri() {
    229         StringBuilder sb = new StringBuilder();
    230         sb.append("http");
    231         int webServerPort = getWebServerPort();
    232         if (webServerPort == 443) {
    233             sb.append("s");
    234
    235         }
    236         sb.append("://");
    237         sb.append(addressResolver.getHostname());
    238
    239         if (webServerPort != 80) {
    240             sb.append(":");
    241             sb.append(webServerPort);
    242         }
    243         sb.append("/");
    244
    245         try {
    246             return new URI(sb.toString());
    247         } catch (URISyntaxException e) {
    248             throw new RuntimeException(e);
    249         }
    250     }
    251
    252     public WebServer getWebServer() {
    253         return webServer;
    254     }
    255
    256     @Override
    257     public Configurator getConfigurator() {
    258         return configurator;
    259     }
    260
    261     @Override
    262     public PluginManager getExtensionManager() {
    263         if(hasModule(RESTApiModule.class)) {
    264             return getModule(RESTApiModule.class).getPlugins();
    265         } else {
    266             return null;
    267         }
    268     }
    269
    270     @Override
    271     public Collection<Injectable<?>> getInjectables( List<String> packageNames )
    272     {
    273         return pluginInitializer.intitializePackages( packageNames );
    274     }
    275
    276     private boolean hasModule(Class<? extends ServerModule> clazz) {
    277         for(ServerModule sm : serverModules) {
    278             if(sm.getClass() == clazz) {
    279                 return true;
    280             }
    281         }
    282         return false;
    283     }
    284
    285     @SuppressWarnings("unchecked")
    286     private <T extends ServerModule> T getModule(Class<T> clazz) {
    287         for(ServerModule sm : serverModules) {
    288             if(sm.getClass() == clazz) {
    289                 return (T) sm;
    290             }
    291         }
    292
    293         return null;
    294     }
    295
    296 }