Package com.google.dataconnector.client

Source Code of com.google.dataconnector.client.Client

/* Copyright 2008 Google Inc.
*
* Licensed 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.
*
* $Id: Client.java 555 2011-06-06 18:50:31Z jacob13moon $
*/
package com.google.dataconnector.client;

import com.google.dataconnector.util.ClientGuiceModule;
import com.google.dataconnector.util.ConnectionException;
import com.google.dataconnector.util.FileUtil;
import com.google.dataconnector.util.LocalConf;
import com.google.dataconnector.util.LocalConfException;
import com.google.dataconnector.util.LocalConfValidator;
import com.google.dataconnector.util.ShutdownManager;
import com.google.feedserver.util.BeanCliHelper;
import com.google.feedserver.util.ConfigurationBeanException;
import com.google.gdata.util.common.util.Base64;
import com.google.inject.Inject;
import com.google.inject.Injector;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import java.io.IOException;
import java.util.Properties;

/**
* Entry point class for starting the Secure Data Connector.  There are three components to the
* Secure Data Connector:
*
* 1) The "secure data connection" to the server which provides the transport from the server
* side back to the client.  see {@link SdcConnection}
* 2) The Socks 5 proxy which provides the network firewall to incoming network connections through
* the secure data transport. see {@link JsocksStarter}
* 3) The HTTP(S) proxy which provides the http firewall filtering for incoming http requests.
*
* @author rayc@google.com (Ray Colline)
*/
public class Client {

  // Logging instance
  private static final Logger LOG = Logger.getLogger(Client.class);

  // Constants
  private static final long MAX_BACKOFF_TIME = 5 * 60 * 1000; // 5 minutes

  /* Dependencies */
  private final LocalConf localConf;
  private final SdcConnection secureDataConnection;
  private final JsocksStarter jsocksStarter;
  private final ShutdownManager shutdownManager;

  /* Local fields */
  private static long unsuccessfulAttempts = 0;


  /**
   * Creates a new client from the populated client configuration object.
   */
  @Inject
  public Client(final LocalConf localConf, final SdcConnection secureDataConnection,
      final JsocksStarter jsocksStarter,
      final ShutdownManager shutdownManager) {
    this.localConf = localConf;
    this.secureDataConnection = secureDataConnection;
    this.jsocksStarter = jsocksStarter;
    this.shutdownManager = shutdownManager;
  }

  /**
   * Reads flags and config files, validates configuration and starts agent.
   */
  public void parseFlagsValidateAndConnect(final String[] args) {
    LOG.info("****************************************************************");
    LOG.info("Agent handshake version = " + SdcConnection.INITIAL_HANDSHAKE_MSG);

    // validate the localConf.xml file and the input args
    try {
      BeanCliHelper beanCliHelper = new BeanCliHelper();
      beanCliHelper.register(localConf);
      beanCliHelper.parse(args);
      new LocalConfValidator().validate(localConf);
    } catch (LocalConfException e) {
      LOG.fatal("Configuration error", e);
      return;
    } catch (ConfigurationBeanException e) {
      LOG.fatal("Configuration error", e);
      return;
    }

    // Set log4j properties.  We do not expect this file to change often so we do not use the
    // cooler, yet more resource intensive, "configureAndWatch".
    PropertyConfigurator.configure(localConf.getLog4jPropertiesFile());
    if (localConf.getDebug()) {
      Logger.getRootLogger().setLevel(Level.DEBUG);
    }

    // Connect
    try {
      // If the password file is specified, then read its contents and override
      // the password property with the contents read.  At this point the file
      // is readable since the check has already been performed during validation.
      if (localConf.getPasswordFile() != null) {
        String password = new FileUtil().readFile(localConf.getPasswordFile());
        localConf.setPassword(password);
      }
      // start jsocks thread
      jsocksStarter.startJsocksProxy();
      // start main processing thread - to initiate connection/registration with the SDC server
      secureDataConnection.connect();
    } catch (IOException e ) {
      LOG.fatal("Cannot read password file.", e);
    } catch (ConnectionException e) {
      LOG.fatal("Connection failed.", e);
    } finally {
      shutdownManager.shutdownAll();
    }

    // Check whether connection was successful or not.
    if (secureDataConnection.hasConnectedSuccessfully()) {
      unsuccessfulAttempts = 0;
    } else if (localConf.getStartOnce()) {
      LOG.info("Configured only to start once. Quitting!");
      unsuccessfulAttempts = -1; // Sentinel value meaning we should quit.
    } else { // Failed connection
      unsuccessfulAttempts++;
    }
  }

  /**
   * Entry point for the Secure Data Connector binary.  Sets up logging, parses flags and
   * creates ClientConf.
   *
   * @param args
   */
  public static void main(final String[] args) {
    // Bootstrap logging system
    PropertyConfigurator.configure(getBootstrapLoggingProperties());

    final Injector injector = ClientGuiceModule.getInjector();
    final ShutdownManager shutdownManager = injector.getInstance(ShutdownManager.class);
    // Add shutdown hook to call shutdown if control c or OS SIGTERM is received.
    Runtime.getRuntime().addShutdownHook(new Thread() {
      @Override
      public void run() {
        shutdownManager.shutdownAll();
      }
    });

    // Starts the client in a loop that exponentially backs off.
    while (true) {
      try {
        // Only try to back-off if we have unsuccessful connections.
        if (unsuccessfulAttempts > 0) {
          long backOffTime = (long) Math.min(
              MAX_BACKOFF_TIME, Math.pow(2, unsuccessfulAttempts) * 1000L);
          try {
            // Sleep for the amount of time needed.
            Thread.sleep(backOffTime);
          } catch (InterruptedException e) {
            LOG.error("Interrupted while trying to exponentially back off. Exiting.");
            break;
          }
          LOG.info("Starting agent after " + unsuccessfulAttempts + " unsuccessful attempts." +
              " Next connect in " + backOffTime + " milliseconds.");
        } else if (unsuccessfulAttempts == -1) {
          // We are being told to quit probably because we were only configured to start once.
          break;
        }
        injector.getInstance(Client.class).parseFlagsValidateAndConnect(args);
      } catch (Exception e) { // This is an outside server loop. Catch everything.
        LOG.error("Agent died.", e);
        shutdownManager.shutdownAll();
      }
    }
  }

  /**
   * Returns a base set of logging properties so we can log fatal errors before config parsing is
   * done.
   *
   * @return Properties a basic console logging setup.
   */
  public static Properties getBootstrapLoggingProperties() {
    final Properties props = new Properties();
    props.setProperty("log4j.rootLogger","info, A");
    props.setProperty("log4j.appender.A", "org.apache.log4j.ConsoleAppender");
    props.setProperty("log4j.appender.Ant d.layout", "org.apache.log4j.PatternLayout");
    props.setProperty("log4j.appender.A.layout.ConversionPattern", "%d [%t] %-5p %c %x - %m%n");
    return props;
  }
}
TOP

Related Classes of com.google.dataconnector.client.Client

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.