/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.cimadapter.connections.cim;
// Java security imports
import javax.cim.CIMObjectPath;
import javax.security.auth.Subject;
import javax.wbem.WBEMException;
import javax.wbem.client.PasswordCredential;
import javax.wbem.client.UserPrincipal;
import javax.wbem.client.WBEMClient;
import javax.wbem.client.WBEMClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.cimadapter.connections.ConnectionManager;
import com.emc.storageos.cimadapter.processors.CimIndicationProcessor;
import com.emc.storageos.cimadapter.processors.DefaultCimIndicationProcessor;
/**
* Represents a CIM connection to a CIM provider.
*/
public class CimConnection {
// The host to which the connection is made.
protected String _host = CimConstants.DFLT_CIM_CONNECTION_HOST;
// The host port to which the connection is made.
protected int _port = 0;
// The name of the user for which the connection is to be made.
protected String _user = "";
// The password for the user.
protected String _pass_word = "";
// The interop namespace for the CIMOM.
protected String _interopNS = "";
// The implementation namespace for the connection.
protected String _implNS = "";
// Indicates whether to use http or https as the connection protocol.
private boolean _useSSL = false;
// A unique name given to the connection. The connection name helps the
// listener identify the connection which generated the indication.
protected String _connectionName;
// A reference to the CIM client.
private WBEMClient _cimClient;
// A reference to the CIM subscription manager used to manage the
// subscriptions for this connection.
private CimSubscriptionManager _subscriptionManager;
// A reference to the CIM listener that listens for indications generated as
// a result of this connection.
private CimListener _listener;
// A reference to the indication filter map.
private CimFilterMap _filterMap;
// A reference to the default indication processor for the connection.
// Indication consumers can be configured to use the default processor, a
// custom processor, or no processor at all.
protected CimIndicationProcessor _dfltIndicationProcessor = null;
// A reference to a logger.
protected static final Logger s_logger = LoggerFactory.getLogger(CimConnection.class);
/**
* Constructs a CIM connection.
*
* @param connectionInfo The bean containing the connection information.
* @param listener The CIM indication listener for this connection.
* @param filterMap The indication filters to be subscribed for this
* connection.
*/
public CimConnection(CimConnectionInfo connectionInfo,
CimListener listener, CimFilterMap filterMap) throws Exception {
_host = connectionInfo.getConnectionParameter(CimConstants.CIM_HOST);
_port = Integer.parseInt(connectionInfo.getConnectionParameter(CimConstants.CIM_PORT));
_user = connectionInfo.getConnectionParameter(CimConstants.CIM_USER);
_pass_word = connectionInfo.getConnectionParameter(CimConstants.CIM_PW);
_interopNS = connectionInfo.getConnectionParameter(CimConstants.CIM_INTEROP_NS);
_implNS = connectionInfo.getConnectionParameter(CimConstants.CIM_IMPL_NS);
_useSSL = Boolean.parseBoolean(connectionInfo.getConnectionParameter(CimConstants.CIM_USE_SSL));
// Create a unique name for the connection. The name is used by the
// listener to associate an indication that it receives to the
// connection the generated the indication. Be sure to create
// the name after the connection info has been extracted.
_connectionName = createConnectionName();
// Keep a reference to the listener for when indications are enabled.
_listener = listener;
if (_listener == null) {
throw new Exception("No indication listener");
}
// Keep a reference to the subscription filter map for when indications
// are enabled for the connection.
_filterMap = filterMap;
if (_filterMap == null) {
throw new Exception("No indication filter map");
}
s_logger.info("Created new CIM connection {}", _connectionName);
}
/**
* Constructs a name for the connection using the connection type, host, and
* port.
*
* @return The name created for the connection.
*/
private String createConnectionName() {
StringBuilder nameBuffer = new StringBuilder();
nameBuffer.append(getConnectionType());
nameBuffer.append("-");
nameBuffer.append(_host);
nameBuffer.append("-");
nameBuffer.append(_port);
return nameBuffer.toString();
}
/**
* Getter for the connection host.
*
* @return The connection host
*/
public String getHost() {
return _host;
}
/**
* Getter for the connection port.
*
* @return The connection port
*/
public int getPort() {
return _port;
}
/**
* Getter for the interop namespace for the CIMOM.
*
* @return The interop namespace for the CIMOM.
*/
public String getInteropNamespace() {
return _interopNS;
}
/**
* Getter for the implementation namespace for this CIMOM connection.
*
* @return The implementation namespace for this CIMOM connection.
*/
public String getImplNamespace() {
return _implNS;
}
/**
* Getter for the connection name.
*
* @return The connection name
*/
public String getConnectionName() {
return _connectionName;
}
/**
* Getter for the underlying CIM client.
*
* @return The underlying CIM client.
*/
public WBEMClient getCimClient() {
return _cimClient;
}
/**
* Getter for the indication filter map.
*
* @return The indication filter map.
*/
public CimFilterMap getIndicationFilterMap() {
return _filterMap;
}
/**
* Getter for the indication listener.
*
* @return The indication listener.
*/
public CimListener getIndicationListener() {
return _listener;
}
/**
* Opens the connection and sets up indication subscriptions on the CIMOM.
* Call is synchronized by the caller {@link ConnectionManager}. If the
* passed flag indicates, prior to setting up the indication subscriptions
* for the connection, the subscription manager should attempt to delete any
* old/stale subscriptions that exist on the provider to which the
* connection is being made. The passed identifier is used by the
* subscription manager to identify the stale subscriptions to be deleted.
*
* Also registers this connection with the indication listener.
*
* @param subscriptionsIdentifier The identifier to be used to identify
* subscriptions on the provider.
* @param deleteStaleSubscriptions true to delete stale subscriptions on the
* provider to which the connection is being made.
*
* @throws Exception if the connection cannot be established or if there is
* a problem setting up subscriptions.
*/
public void connect(String subscriptionsIdentifier, boolean deleteStaleSubscriptions) throws Exception {
s_logger.info("Establising connection for {}", _connectionName);
String protocol = _useSSL ? CimConstants.SECURE_PROTOCOL : CimConstants.DEFAULT_PROTOCOL;
CIMObjectPath path = CimObjectPathCreator.createInstance(protocol, _host, Integer.toString(_port), _interopNS, null, null);
try {
Subject subject = new Subject();
subject.getPrincipals().add(new UserPrincipal(_user));
subject.getPrivateCredentials().add(new PasswordCredential(_pass_word));
_cimClient = WBEMClientFactory.getClient(CimConstants.CIM_CLIENT_PROTOCOL);
// Operations block by default, so a timeout must be set in case the
// CIM server becomes unreachable.
// Commenting out, as timeout had been moved to cimom.properties file
// _cimClient.setProperty(WBEMClientConstants.PROP_TIMEOUT, CimConstants.CIM_CLIENT_TIMEOUT);
_cimClient.initialize(path, subject, null);
} catch (Exception e) {
s_logger.error("Could not establish connection for {}", _host, e);
_cimClient.close();
throw e;
}
}
/**
* Make new subscription to active SMIS provider to get indications for monitoring
*
* @param subscriptionsIdentifier {@link String} subscriptionIdentifer to make subscription
* @throws Exception
*/
public void subscribeForIndications(String subscriptionsIdentifier) throws Exception {
s_logger.debug("Entering {}", Thread.currentThread().getStackTrace()[1].getMethodName());
s_logger.info("Initiating subscrption for monitoring use cases");
try {
// Register the connection with the listener if indications are enabled
// for the connection.
if ((_listener != null)) {
_listener.register(this);
}
_subscriptionManager = new CimSubscriptionManager(this, subscriptionsIdentifier);
_subscriptionManager.subscribe();
} catch (Exception e) {
s_logger.error("Error occurred while making subscription", e);
_subscriptionManager.unsubscribe();
throw e;
}
s_logger.info("Subscription for the {} is completed", subscriptionsIdentifier);
s_logger.debug("Exiting {}", Thread.currentThread().getStackTrace()[1].getMethodName());
}
/**
* Un-subscribe monitoring connection with passive SMIS provider
*
* @param subscriptionsIdentifier {@link String} subscriptionIdentifer to make Un-Subscription
*/
public void unsubscribeForIndications(String subscriptionsIdentifier) {
s_logger.debug("Entering {}", Thread.currentThread().getStackTrace()[1].getMethodName());
s_logger.info("Initiating unsubscription of passive provider {}", subscriptionsIdentifier);
_subscriptionManager = new CimSubscriptionManager(this, subscriptionsIdentifier);
_listener.unregister(this);
_subscriptionManager.unsubscribe();
s_logger.info("unsubscription of passive provider {} completed", subscriptionsIdentifier);
s_logger.debug("Exiting {}", Thread.currentThread().getStackTrace()[1].getMethodName());
}
/**
* Deletes Stale subscriptions
*
* @param subscriptionsIdentifier {@link String} subscriptionIdentifer to delete stale subscriptions
*/
public void deleteStaleSubscriptions(String subscriptionsIdentifier) {
s_logger.debug("Entering {}", Thread.currentThread().getStackTrace()[1].getMethodName());
_subscriptionManager = new CimSubscriptionManager(this, subscriptionsIdentifier);
try {
_subscriptionManager.deleteStaleSubscriptions();
} catch (WBEMException e) {
s_logger.error("Unable to delete Stale Subscriptions", e);
// throw e;
}
s_logger.debug("Exiting {}", Thread.currentThread().getStackTrace()[1].getMethodName());
}
/**
* Checks the connection.
*
* Call is synchronized by the caller {@link ConnectionManager}
*
* @return true if the connection is ok, otherwise false.
*/
public boolean isConnected() {
boolean connected = false;
try {
// Simple operation that should always succeed if the
// connection is up.
_cimClient.getClass(CimObjectPathCreator.createInstance(CimConstants.CIM_INDICATION_OBJ_PATH, getInteropNamespace()), true,
true, false, null);
connected = true;
} catch (Exception e) {
s_logger.error("Failed checking the CIM client connection", e);
}
return connected;
}
/**
* Closes the connection.
*/
public void close() {
try {
if (_cimClient != null) {
_cimClient.close();
}
} catch (Exception e) {
s_logger.error(e.getMessage(), e);
}
}
/**
* Returns the connection type.
*
* @return The connection type
*/
public String getConnectionType() {
return CimConstants.CIM_CONNECTION_TYPE;
}
/**
* Returns an instance of the default indication processor for CIM
* connections. Overridden by derived connection classes to return an
* instance of the default processor for those connection types.
*
* @return An instance of the default indication processor for CIM
* connections.
*/
protected CimIndicationProcessor getDefaultIndicationProcessor() {
if (_dfltIndicationProcessor == null) {
_dfltIndicationProcessor = new DefaultCimIndicationProcessor(this);
}
return _dfltIndicationProcessor;
}
}