Package com.cloud.bridge.service

Source Code of com.cloud.bridge.service.ServiceProvider

/**
* Copyright (C) 2011 Citrix Systems, Inc.  All rights reserved
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.bridge.service;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetAddress;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.axis2.AxisFault;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import org.hibernate.SessionException;

import com.amazon.s3.AmazonS3SkeletonInterface;
import com.amazon.ec2.AmazonEC2SkeletonInterface;
import com.cloud.bridge.model.MHost;
import com.cloud.bridge.model.SHost;
import com.cloud.bridge.model.UserCredentials;
import com.cloud.bridge.persist.PersistContext;
import com.cloud.bridge.persist.PersistException;
import com.cloud.bridge.persist.dao.MHostDao;
import com.cloud.bridge.persist.dao.SHostDao;
import com.cloud.bridge.persist.dao.UserCredentialsDao;
import com.cloud.bridge.service.core.ec2.EC2Engine;
import com.cloud.bridge.service.core.s3.S3BucketPolicy;
import com.cloud.bridge.service.core.s3.S3Engine;
import com.cloud.bridge.service.exception.ConfigurationException;
import com.cloud.bridge.util.ConfigurationHelper;
import com.cloud.bridge.util.DateHelper;
import com.cloud.bridge.util.NetHelper;
import com.cloud.bridge.util.Tuple;

/**
* @author Kelven Yang
*/
public class ServiceProvider {
  protected final static Logger logger = Logger.getLogger(ServiceProvider.class);

  public final static long HEARTBEAT_INTERVAL = 10000;

  private static ServiceProvider instance;

  private Map<Class<?>, Object> serviceMap = new HashMap<Class<?>, Object>();
  private Timer timer = new Timer();
  private MHost mhost;
  private Properties properties;
  private boolean useSubDomain = false;     // use DNS sub domain for bucket name
  private String serviceEndpoint = null;
  private String multipartDir = null;          // illegal bucket name used as a folder for storing multiparts
  private String masterDomain = ".s3.amazonaws.com";
  private S3Engine engine;
  private EC2Engine EC2_engine = null;

  // -> cache Bucket Policies here so we don't have to load from db on every access
  private Map<String,S3BucketPolicy> policyMap = new HashMap<String,S3BucketPolicy>();

  protected ServiceProvider() throws IOException {
    // register service implementation object
    engine = new S3Engine();
    EC2_engine = new EC2Engine();
    serviceMap.put(AmazonS3SkeletonInterface.class, new S3SoapServiceImpl(engine));
    serviceMap.put(AmazonEC2SkeletonInterface.class, new EC2SoapServiceImpl(EC2_engine));
  }

  public synchronized static ServiceProvider getInstance() {
    if(instance == null)
    {
      try {
        instance = new ServiceProvider();
        instance.initialize();
        PersistContext.commitTransaction();
      } catch(Throwable e) {
        logger.error("Unexpected exception " + e.getMessage(), e);
      } finally {
        PersistContext.closeSession();
      }
    }
    return instance;
  }

  public long getManagementHostId() {
    // we want to limit mhost within its own session, id of the value will be returned
    long mhostId = 0;
    if(mhost != null)
      mhostId = mhost.getId() != null ? mhost.getId().longValue() : 0L;
      return mhostId;
  }

  /**
   * We return a tuple to distinguish between two cases:
   * (1) there is no entry in the map for bucketName, and (2) there is a null entry
   * in the map for bucketName.   In case 2, the database was inspected for the
   * bucket policy but it had none so we remember it here to reduce database lookups.
   * @param bucketName
   * @return Integer in the tuple means: -1 if no policy defined for the bucket, 0 if one defined
   *         even if its set at null.
   */
  public Tuple<S3BucketPolicy,Integer> getBucketPolicy(String bucketName) {

    if (policyMap.containsKey( bucketName )) {
      S3BucketPolicy policy = policyMap.get( bucketName );
      return new Tuple<S3BucketPolicy,Integer>( policy, 0 );
    }
    else return new Tuple<S3BucketPolicy,Integer>( null, -1 );
  }

  /**
   * The policy parameter can be set to null, which means that there is no policy
   * for the bucket so a database lookup is not necessary.
   *
   * @param bucketName
   * @param policy
   */
  public void setBucketPolicy(String bucketName, S3BucketPolicy policy) {
    policyMap.put(bucketName, policy);
  }

  public void deleteBucketPolicy(String bucketName) {
    policyMap.remove(bucketName);
  }

  public S3Engine getS3Engine() {
    return engine;
  }

  public EC2Engine getEC2Engine() {
    return EC2_engine;
  }

  public String getMasterDomain() {
    return masterDomain;
  }

  public boolean getUseSubDomain() {
    return useSubDomain;
  }

  public String getServiceEndpoint() {
    return serviceEndpoint;
  }

  public String getMultipartDir() {
    return multipartDir;
  }

  public Properties getStartupProperties() {
    return properties;
  }

  public UserInfo getUserInfo(String accessKey)
      throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
    UserInfo info = new UserInfo();

    UserCredentialsDao credentialDao = new UserCredentialsDao();
    UserCredentials cloudKeys = credentialDao.getByAccessKey( accessKey );
    if ( null == cloudKeys ) {
      logger.debug( accessKey + " is not defined in the S3 service - call SetUserKeys" );
      return null;
    } else {
      info.setAccessKey( accessKey );
      info.setSecretKey( cloudKeys.getSecretKey());
      info.setCanonicalUserId(accessKey);
      info.setDescription( "S3 REST request" );
      return info;
    }
  }

  protected void initialize() {
    if(logger.isInfoEnabled())
      logger.info("Initializing ServiceProvider...");

    File file = ConfigurationHelper.findConfigurationFile("log4j-cloud-bridge.xml");
    if(file != null) {
      System.out.println("Log4j configuration from : " + file.getAbsolutePath());
      DOMConfigurator.configureAndWatch(file.getAbsolutePath(), 10000);
    } else {
      System.out.println("Configure log4j with default properties");
    }

    loadStartupProperties();
    String hostKey = properties.getProperty("host.key");
    if(hostKey == null) {
      InetAddress inetAddr = NetHelper.getFirstNonLoopbackLocalInetAddress();
      if(inetAddr != null)
        hostKey = NetHelper.getMacAddress(inetAddr);
    }
    if(hostKey == null)
      throw new ConfigurationException("Please configure host.key property in cloud-bridge.properites");
    String host = properties.getProperty("host");
    if(host == null)
      host = NetHelper.getHostName();

    if(properties.get("bucket.dns") != null &&
        ((String)properties.get("bucket.dns")).equalsIgnoreCase("true")) {
      useSubDomain = true;
    }

    serviceEndpoint = (String)properties.get("serviceEndpoint");
    masterDomain = new String( "." + serviceEndpoint );

    setupHost(hostKey, host);

    // we will commit and start a new transaction to allow host info be flushed to DB
    PersistContext.flush();

    String localStorageRoot = properties.getProperty("storage.root");
    if (localStorageRoot != null) setupLocalStorage(localStorageRoot);

    multipartDir = properties.getProperty("storage.multipartDir");

    timer.schedule(getHeartbeatTask(), HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL);

    if(logger.isInfoEnabled())
      logger.info("ServiceProvider initialized");
  }

  private void loadStartupProperties() {
    File propertiesFile = ConfigurationHelper.findConfigurationFile("cloud-bridge.properties");
    properties = new Properties();
    if(propertiesFile != null) {
      try {
        properties.load(new FileInputStream(propertiesFile));
      } catch (FileNotFoundException e) {
        logger.warn("Unable to open properties file: " + propertiesFile.getAbsolutePath(), e);
      } catch (IOException e) {
        logger.warn("Unable to read properties file: " + propertiesFile.getAbsolutePath(), e);
      }

      logger.info("Use startup properties file: " + propertiesFile.getAbsolutePath());
    } else {
      if(logger.isInfoEnabled())
        logger.info("Startup properties is not found.");
    }
  }

  private TimerTask getHeartbeatTask() {
    return new TimerTask() {

      @Override
      public void run() {
        try {
          MHostDao mhostDao = new MHostDao();
          mhost.setLastHeartbeatTime(DateHelper.currentGMTTime());
          mhostDao.update(mhost);
          PersistContext.commitTransaction();
        } catch(Throwable e){
          logger.error("Unexpected exception " + e.getMessage(), e);
        } finally {
          PersistContext.closeSession();
        }
      }
    };
  }

  private void setupHost(String hostKey, String host) {
    MHostDao mhostDao = new MHostDao();
    mhost = mhostDao.getByHostKey(hostKey);
    if(mhost == null) {
      mhost = new MHost();
      mhost.setHostKey(hostKey);
      mhost.setHost(host);
      mhost.setLastHeartbeatTime(DateHelper.currentGMTTime());
      mhostDao.save(mhost);
    } else {
      mhost.setHost(host);
      mhostDao.update(mhost);
    }
  }

  private void setupLocalStorage(String storageRoot) {
    SHostDao shostDao = new SHostDao();
    SHost shost = shostDao.getLocalStorageHost(mhost.getId(), storageRoot);
    if(shost == null) {
      shost = new SHost();
      shost.setMhost(mhost);
      mhost.getLocalSHosts().add(shost);
      shost.setHostType(SHost.STORAGE_HOST_TYPE_LOCAL);
      shost.setHost(NetHelper.getHostName());
      shost.setExportRoot(storageRoot);
      PersistContext.getSession().save(shost);
    }
  }

  public void shutdown() {
    timer.cancel();

    if(logger.isInfoEnabled())
      logger.info("ServiceProvider stopped");
  }

  @SuppressWarnings("unchecked")
  private static <T> T getProxy(Class<?> serviceInterface, final T serviceObject) {
    return (T) Proxy.newProxyInstance(serviceObject.getClass().getClassLoader(),
        new Class[] { serviceInterface },
        new InvocationHandler() {
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try {
          result = method.invoke(serviceObject, args);
          PersistContext.commitTransaction();
        } catch (PersistException e) {
        } catch (SessionException e) {
        } catch(Throwable e) {
          // Rethrow the exception to Axis:
            // Check if the exception is an AxisFault or a RuntimeException
            // enveloped AxisFault and if so, pass it on as such. Otherwise
          // log to help debugging and throw as is.
          if (e.getCause() != null && e.getCause() instanceof AxisFault)
            throw e.getCause();
          else if (e.getCause() != null && e.getCause().getCause() != null
              && e.getCause().getCause() instanceof AxisFault)
            throw e.getCause().getCause();
          else {
            logger.warn("Unhandled exception " + e.getMessage(), e);
            throw e;
          }
        } finally {
          PersistContext.closeSession();
        }
        return result;
      }
    });
  }

  @SuppressWarnings("unchecked")
  public <T> T getServiceImpl(Class<?> serviceInterface) {
    return getProxy(serviceInterface, (T)serviceMap.get(serviceInterface));
  }
}
TOP

Related Classes of com.cloud.bridge.service.ServiceProvider

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.