/* ****************************************************************************
 * Copyright 2013-2014 VMware, Inc.  All rights reserved.
 * ***************************************************************************/

package com.vmware.samples.srm;

import java.net.URL;
import java.rmi.RemoteException;

import javax.xml.rpc.ServiceException;

import com.vmware.srm.ManagedObjectReference;
import com.vmware.srm.SrmFaultAlreadyLoggedInFault;
import com.vmware.srm.SrmPortType;
import com.vmware.srm.SrmServiceInstanceContent;
import com.vmware.srm.SrmServiceLocator;


/**
 * This is a simple interface for connecting to SRM's API.  It is not specific
 * to any particular sample application.
 */
public final class SrmConnectionUtil {
   /**
    * The reference to the managed object that contains SRM's service
    * information.  This object is a singleton on the SRM server, and its
    * reference information never changes.  Thus, it is safe to use this
    * reference statically, and without locking.
    */
   public static final ManagedObjectReference _serviceInstanceRef =
      SrmConnectionUtil.createServiceInstanceRef();

   /**
    * Retrieve the SRM service instance content.  With this content, you can
    * access the more specific sub-components of the SRM API (e.g., the recovery
    * API).
    *
    * @param srmPort The open connection to the SRM API.
    * @return SRM's service-instance content object.
    * @throws ApplicationException If the content could not be retrieved.
    */
   public static SrmServiceInstanceContent findSrmServiceInstanceContent(
      final SrmPortType srmPort)
      throws ApplicationException {

      try {
         return srmPort.retrieveContent(SrmConnectionUtil._serviceInstanceRef);
      } catch (final RemoteException e) {
         throw new ApplicationException(
            "Cannot retrieve SRM service content", e);
      }
   }

   /**
    * (Application global) disabling of the SSL certificate verification.
    */
   public static void ignoreSslCert() {
      System.setProperty(
         "org.apache.axis.components.net.SecureSocketFactory",
         "org.apache.axis.components.net.SunFakeTrustSocketFactory");
   }

   /**
    * Open a connection to the SRM API and log in with the provided credentials.
    *
    * @param url      The URL to the SRM API's end-point.
    * @param userName An SRM user with sufficient privileges to execute the API.
    * @param password The password for the provided user.
    *
    * @return A connected port to SRM through which the API can be used.
    * @throws ApplicationException If there was an error logging in or using the
    *    SRM API port in general.
    */
   public static SrmPortType openSrmPort(
      final URL url, final String userName, final String password)
      throws ApplicationException {

      // First, find and open the port.

      final SrmServiceLocator locator = new SrmServiceLocator();
      locator.setMaintainSession(true);

      final SrmPortType srmPort;
      try {
         srmPort = locator.getSrmPort(url);
      } catch (final ServiceException e) {
         throw new ApplicationException("Cannot locate SRM port", e);
      }

      // Now that we've opened a port, log in.

      try {
         srmPort.srmLoginLocale(
            SrmConnectionUtil._serviceInstanceRef, userName, password, null);
      } catch (final SrmFaultAlreadyLoggedInFault ali) {
         // If we're already logged in, that is OK.  Continue on.
      } catch (final RemoteException e) {
         throw new ApplicationException("Cannot log into SRM", e);
      }

      return srmPort;
   }

   /**
    * This class defines a library of functions.  So far there is no need for an
    * instance, so we will hide the CTOR.
    */
   private SrmConnectionUtil() {
      // Does nothing.
   }

   /**
    * Create a managed-object reference referring to the ServiceInstanceContent
    * (singleton) for SRM.
    *
    * @return A newly allocated reference.  This will not return {@code null}.
    */
   private static ManagedObjectReference createServiceInstanceRef() {

      final ManagedObjectReference svcRef = new ManagedObjectReference();
      svcRef.setType("SrmServiceInstance");
      svcRef.set_value("SrmServiceInstance");

      return svcRef;
   }
}
