Package com.cloud.bridge.service.controller.s3

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

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.
package com.cloud.bridge.service.controller.s3;


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 com.amazon.s3.AmazonS3SkeletonInterface;
import com.amazon.ec2.AmazonEC2SkeletonInterface;
import com.cloud.bridge.model.MHostVO;
import com.cloud.bridge.model.SHost;
import com.cloud.bridge.model.SHostVO;
import com.cloud.bridge.model.UserCredentialsVO;
import com.cloud.bridge.persist.dao.MHostDao;
import com.cloud.bridge.persist.dao.MHostDaoImpl;
import com.cloud.bridge.persist.dao.SHostDao;
import com.cloud.bridge.persist.dao.SHostDaoImpl;
import com.cloud.bridge.persist.dao.UserCredentialsDao;
import com.cloud.bridge.persist.dao.UserCredentialsDaoImpl;
import com.cloud.bridge.service.EC2SoapServiceImpl;
import com.cloud.bridge.service.UserInfo;
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.OrderedPair;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Transaction;

public class ServiceProvider {
  protected final static Logger logger = Logger.getLogger(ServiceProvider.class);
  protected final MHostDao mhostDao = ComponentLocator.inject(MHostDaoImpl.class);
  protected final SHostDao shostDao = ComponentLocator.inject(SHostDaoImpl.class);
  protected final UserCredentialsDao ucDao = ComponentLocator.inject(UserCredentialsDaoImpl.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 MHostVO 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
      Transaction txn = Transaction.open(Transaction.AWSAPI_DB);
      txn.close();
    engine = new S3Engine();
    EC2_engine = new EC2Engine();
    serviceMap.put(AmazonS3SkeletonInterface.class, new S3SerializableServiceImplementation(engine));
    serviceMap.put(AmazonEC2SkeletonInterface.class, new EC2SoapServiceImpl(EC2_engine));
  }

  public synchronized static ServiceProvider getInstance() {
    if(instance == null)
    {
      try {
        instance = new ServiceProvider();
        instance.initialize();
      } catch(Throwable e) {
        logger.error("Unexpected exception " + e.getMessage(), e);
      } finally {
      }
    }
    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 2-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 cache 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 it is set at null.
   */
  public OrderedPair<S3BucketPolicy,Integer> getBucketPolicy(String bucketName) {

    if (policyMap.containsKey( bucketName )) {
      S3BucketPolicy policy = policyMap.get( bucketName );
      return new OrderedPair<S3BucketPolicy,Integer>( policy, 0 );
    }
    else return new OrderedPair<S3BucketPolicy,Integer>( null, -1 );           // For case (1) where the map has no entry for bucketName
  }

  /**
   * 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) {
    UserInfo info = new UserInfo();
    Transaction txn = Transaction.open(Transaction.AWSAPI_DB);
    try {
        txn.start();
        UserCredentialsVO cloudKeys = ucDao.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;
        }
    }finally {
        txn.commit();
    }
  }
 
  @DB
  protected void initialize() {
    if(logger.isInfoEnabled())
      logger.info("Initializing ServiceProvider...");
   
    Transaction txn = Transaction.open(Transaction.AWSAPI_DB);
    //txn.close();

    File file = ConfigurationHelper.findConfigurationFile("log4j-cloud.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) {
            if (localStorageRoot.toLowerCase().startsWith("castor")) {
                setupCAStorStorage(localStorageRoot);
            } else {
                setupLocalStorage(localStorageRoot);
            }
        }

    multipartDir = properties.getProperty("storage.multipartDir");
   
    Transaction txn1 = Transaction.open(Transaction.AWSAPI_DB);
    timer.schedule(getHeartbeatTask(), HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL);
    txn1.close();

    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 {
          mhost.setLastHeartbeatTime(DateHelper.currentGMTTime());
          mhostDao.updateHeartBeat(mhost);
        } catch(Throwable e){
          logger.error("Unexpected exception " + e.getMessage(), e);
        } finally {
        }
      }
    };
  }

  private void setupHost(String hostKey, String host) {

      mhost = mhostDao.getByHostKey(hostKey);
    if(mhost == null) {
      mhost = new MHostVO();
      mhost.setHostKey(hostKey);
      mhost.setHost(host);
      mhost.setLastHeartbeatTime(DateHelper.currentGMTTime());
      mhost = mhostDao.persist(mhost);
    } else {
      mhost.setHost(host);
      mhostDao.update(mhost.getId(), mhost);
    }
  }

  private void setupLocalStorage(String storageRoot) {
    SHostVO shost = shostDao.getLocalStorageHost(mhost.getId(), storageRoot);
    if(shost == null) {
      shost = new SHostVO();
      shost.setMhost(mhost);
      shost.setMhostid(mhost.getId());
      shost.setHostType(SHost.STORAGE_HOST_TYPE_LOCAL);
      shost.setHost(NetHelper.getHostName());
      shost.setExportRoot(storageRoot);
      shostDao.persist(shost);
    }
  }

    private void setupCAStorStorage(String storageRoot) {
    SHostVO shost = shostDao.getLocalStorageHost(mhost.getId(), storageRoot);
    if(shost == null) {
      shost = new SHostVO();
      shost.setMhost(mhost);
      shost.setMhostid(mhost.getId());
      shost.setHostType(SHost.STORAGE_HOST_TYPE_CASTOR);
      shost.setHost(NetHelper.getHostName());
      shost.setExportRoot(storageRoot);
      shostDao.persist(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);
                        } 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 {
                        }
                        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.controller.s3.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.