public InternalNode(Settings preparedSettings, boolean loadConfigSettings)
      throws ElasticsearchException {
    final Settings pSettings =
        settingsBuilder()
            .put(preparedSettings)
            .put(Client.CLIENT_TYPE_SETTING, CLIENT_TYPE)
            .build();
    Tuple<Settings, Environment> tuple =
        InternalSettingsPreparer.prepareSettings(pSettings, loadConfigSettings);
    tuple = new Tuple<>(TribeService.processSettings(tuple.v1()), tuple.v2());

    // The only place we can actually fake the version a node is running on:
    Version version = pSettings.getAsVersion("tests.mock.version", Version.CURRENT);

    ESLogger logger = Loggers.getLogger(Node.class, tuple.v1().get("name"));
    logger.info(
        "version[{}], pid[{}], build[{}/{}]",
        version,
        JvmInfo.jvmInfo().pid(),
        Build.CURRENT.hashShort(),
        Build.CURRENT.timestamp());

    logger.info("initializing ...");

    if (logger.isDebugEnabled()) {
      Environment env = tuple.v2();
      logger.debug(
          "using home [{}], config [{}], data [{}], logs [{}], work [{}], plugins [{}]",
          env.homeFile(),
          env.configFile(),
          Arrays.toString(env.dataFiles()),
          env.logsFile(),
          env.workFile(),
          env.pluginsFile());
    }

    this.pluginsService = new PluginsService(tuple.v1(), tuple.v2());
    this.settings = pluginsService.updatedSettings();
    // create the environment based on the finalized (processed) view of the settings
    this.environment = new Environment(this.settings());

    CompressorFactory.configure(settings);
    final NodeEnvironment nodeEnvironment;
    try {
      nodeEnvironment = new NodeEnvironment(this.settings, this.environment);
    } catch (IOException ex) {
      throw new ElasticsearchIllegalStateException("Failed to created node environment", ex);
    }

    boolean success = false;
    try {
      ModulesBuilder modules = new ModulesBuilder();
      modules.add(new Version.Module(version));
      modules.add(new PageCacheRecyclerModule(settings));
      modules.add(new CircuitBreakerModule(settings));
      modules.add(new BigArraysModule(settings));
      modules.add(new PluginsModule(settings, pluginsService));
      modules.add(new SettingsModule(settings));
      modules.add(new NodeModule(this));
      modules.add(new NetworkModule());
      modules.add(new ScriptModule(settings));
      modules.add(new EnvironmentModule(environment));
      modules.add(new NodeEnvironmentModule(nodeEnvironment));
      modules.add(new ClusterNameModule(settings));
      modules.add(new ThreadPoolModule(settings));
      modules.add(new DiscoveryModule(settings));
      modules.add(new ClusterModule(settings));
      modules.add(new RestModule(settings));
      modules.add(new TransportModule(settings));
      if (settings.getAsBoolean(HTTP_ENABLED, true)) {
        modules.add(new HttpServerModule(settings));
      }
      modules.add(new RiversModule(settings));
      modules.add(new IndicesModule(settings));
      modules.add(new SearchModule());
      modules.add(new ActionModule(false));
      modules.add(new MonitorModule(settings));
      modules.add(new GatewayModule(settings));
      modules.add(new NodeClientModule());
      modules.add(new ShapeModule());
      modules.add(new PercolatorModule());
      modules.add(new ResourceWatcherModule());
      modules.add(new RepositoriesModule());
      modules.add(new TribeModule());
      modules.add(new BenchmarkModule(settings));

      injector = modules.createInjector();

      client = injector.getInstance(Client.class);
      success = true;
    } finally {
      if (!success) {
        nodeEnvironment.close();
      }
    }

    logger.info("initialized");
  }
  private void loadPluginsIntoClassLoader() {
    File pluginsFile = environment.pluginsFile();
    if (!pluginsFile.exists()) {
      return;
    }
    if (!pluginsFile.isDirectory()) {
      return;
    }

    ClassLoader classLoader = settings.getClassLoader();
    Class classLoaderClass = classLoader.getClass();
    Method addURL = null;
    while (!classLoaderClass.equals(Object.class)) {
      try {
        addURL = classLoaderClass.getDeclaredMethod("addURL", URL.class);
        addURL.setAccessible(true);
        break;
      } catch (NoSuchMethodException e) {
        // no method, try the parent
        classLoaderClass = classLoaderClass.getSuperclass();
      }
    }
    if (addURL == null) {
      logger.debug(
          "Failed to find addURL method on classLoader [" + classLoader + "] to add methods");
      return;
    }

    File[] pluginsFiles = pluginsFile.listFiles();
    for (File pluginFile : pluginsFiles) {
      if (!pluginFile.getName().endsWith(".zip")) {
        continue;
      }
      if (logger.isTraceEnabled()) {
        logger.trace("Processing [{}]", pluginFile);
      }

      String pluginNameNoExtension =
          pluginFile.getName().substring(0, pluginFile.getName().lastIndexOf('.'));
      File extractedPluginDir =
          new File(new File(environment.workFile(), "plugins"), pluginNameNoExtension);
      extractedPluginDir.mkdirs();

      File stampsDir = new File(new File(environment.workFile(), "plugins"), "_stamps");
      stampsDir.mkdirs();

      boolean extractPlugin = true;
      File stampFile = new File(stampsDir, pluginNameNoExtension + ".stamp");
      if (stampFile.exists()) {
        // read it, and check if its the same size as the pluginFile
        RandomAccessFile raf = null;
        try {
          raf = new RandomAccessFile(stampFile, "r");
          long size = raf.readLong();
          if (size == pluginFile.length()) {
            extractPlugin = false;
            if (logger.isTraceEnabled()) {
              logger.trace("--- No need to extract plugin, same size [" + size + "]");
            }
          }
        } catch (Exception e) {
          // ignore and extract the plugin
        } finally {
          if (raf != null) {
            try {
              raf.close();
            } catch (IOException e) {
              // ignore
            }
          }
        }
      }

      if (extractPlugin) {
        if (logger.isTraceEnabled()) {
          logger.trace("--- Extracting plugin to [" + extractedPluginDir + "]");
        }
        deleteRecursively(extractedPluginDir, false);

        ZipFile zipFile = null;
        try {
          zipFile = new ZipFile(pluginFile);
          Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
          while (zipEntries.hasMoreElements()) {
            ZipEntry zipEntry = zipEntries.nextElement();
            if (!(zipEntry.getName().endsWith(".jar") || zipEntry.getName().endsWith(".zip"))) {
              continue;
            }
            String name = zipEntry.getName().replace('\\', '/');
            File target = new File(extractedPluginDir, name);
            Streams.copy(zipFile.getInputStream(zipEntry), new FileOutputStream(target));
          }
        } catch (Exception e) {
          logger.warn("Failed to extract plugin [" + pluginFile + "], ignoring...", e);
          continue;
        } finally {
          if (zipFile != null) {
            try {
              zipFile.close();
            } catch (IOException e) {
              // ignore
            }
          }
        }

        try {
          RandomAccessFile raf = new RandomAccessFile(stampFile, "rw");
          raf.writeLong(pluginFile.length());
          raf.close();
        } catch (Exception e) {
          // ignore
        }
      }

      try {
        for (File jarToAdd : extractedPluginDir.listFiles()) {
          if (!(jarToAdd.getName().endsWith(".jar") || jarToAdd.getName().endsWith(".zip"))) {
            continue;
          }
          addURL.invoke(classLoader, jarToAdd.toURI().toURL());
        }
      } catch (Exception e) {
        logger.warn("Failed to add plugin [" + pluginFile + "]", e);
      }
    }
  }