com.xensource.xenapi.Connection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xen-api Show documentation
Show all versions of xen-api Show documentation
Mavenized build of the XenServer SDK for Java.
/*
* Copyright (c) 2007-2009 Citrix Systems, Inc.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as published
* by the Free Software Foundation, with the additional linking exception as
* follows:
*
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole combination.
*
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent modules,
* and to copy and distribute the resulting executable under terms of your
* choice, provided that you also meet, for each linked independent module,
* the terms and conditions of the license of that module. An independent
* module is a module which is not derived from or based on this library. If
* you modify this library, you may extend this exception to your version of
* the library, but you are not obligated to do so. If you do not wish to do
* so, delete this exception statement from your 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, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package com.xensource.xenapi;
import java.net.URL;
import java.util.Map;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfig;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.client.XmlRpcHttpClientConfig;
import com.xensource.xenapi.Types.BadServerResponse;
import com.xensource.xenapi.Types.SessionAuthenticationFailed;
import com.xensource.xenapi.Types.XenAPIException;
/**
* Represents a connection to a XenServer. Creating a new instance of this class initialises a new XmlRpcClient that is
* then used by all method calls: each method call in xenapi takes a Connection as a parameter, composes an XMLRPC
* method call, and dispatches it on the Connection's client via the dispatch method.
*/
public class Connection
{
/**
* The version of the bindings that this class belongs to.
*/
public static final String BINDINGS_VERSION = "5.0.0-3";
/**
* true if the connection is to the Rio edition of XenServer. Certain function calls are not allowed.
*
* @deprecated Use getAPIVersion() instead.
*/
@Deprecated
public Boolean rioConnection = false;
private APIVersion apiVersion;
/**
* Updated when Session.login_with_password() is called.
*/
public APIVersion getAPIVersion()
{
return apiVersion;
}
/**
* The opaque reference to the session used by this connection
*/
private String sessionReference;
/**
* As seen by the xmlrpc library. From our point of view it's a server.
*/
private final XmlRpcClient client;
private final boolean deprecatedConstructorUsed;
/**
* Creates a connection to a particular server using a given username and password. This object can then be passed
* in to any other API calls.
*
* This constructor calls Session.loginWithPassword, passing itself as the first parameter.
*
* When this constructor is used, a call to dispose() (also called in the Connection's finalizer) will attempt a
* Session.logout on this connection.
*
* @deprecated Use a constructor that takes a URL as the first parameter instead.
*/
@Deprecated
public Connection(String client, String username, String password) throws java.net.MalformedURLException,
XmlRpcException, BadServerResponse, SessionAuthenticationFailed, XenAPIException
{
deprecatedConstructorUsed = true;
// To login normally we call login_with_password(username, password, "1.X"). On rio this call fails and we
// should use login_with_password(username,password) instead, and note that we are talking to a rio host so that we
// can refuse to make certain miami-specific calls
final String ApiVersion = APIVersion.latest().toString();
this.client = getClientFromURL(new URL(client));
try
{
//first try to login the modern way
this.sessionReference = loginWithPassword(this.client, username, password, ApiVersion);
} catch (BadServerResponse e)
{
//oops, something went wrong
String[] errDesc = e.errorDescription;
//was the problem that the host was running rio? If so it will have complained that it got three parameters
//instead of two. Let us carefully verify the details of this complaint
if (0 == errDesc[0].compareTo("MESSAGE_PARAMETER_COUNT_MISMATCH")
&& 0 == errDesc[1].compareTo("session.login_with_password")
&& 0 == errDesc[2].compareTo("2")
&& 0 == errDesc[3].compareTo("3"))
{
//and if so, we can have another go, using the older login method, and see how that goes.
this.sessionReference = loginWithPassword(this.client, username, password);
//success!. Note that we are talking to an old host on this connection
this.rioConnection = true;
} else
{
//Hmm... Can't solve this here. Let upstairs know about the problem.
throw e;
}
}
try
{
setAPIVersion(new Session(sessionReference));
}
catch (XenAPIException exn)
{
dispose();
throw exn;
}
catch (XmlRpcException exn)
{
dispose();
throw exn;
}
}
/**
* Creates a connection to a particular server using a given username and password. This object can then be passed
* in to any other API calls.
*
* Note this constructor does NOT call Session.loginWithPassword; the programmer is responsible for calling it,
* passing the Connection as a parameter. No attempt to connect to the server is made until login is called.
*
* When this constructor is used, a call to dispose() will do nothing. The programmer is responsible for manually
* logging out the Session.
*/
public Connection(URL url)
{
deprecatedConstructorUsed = false;
this.client = getClientFromURL(url);
}
/**
* Creates a connection to a particular server using a given username and password. This object can then be passed
* in to any other API calls.
*
* The additional sessionReference parameter must be a reference to a logged-in Session. Any method calls on this
* Connection will use it. This constructor does not call Session.loginWithPassword, and dispose() on the resulting
* Connection object does not call Session.logout. The programmer is responsible for ensuring the Session is logged
* in and out correctly.
*/
public Connection(URL url, String sessionReference)
{
deprecatedConstructorUsed = false;
this.client = getClientFromURL(url);
this.sessionReference = sessionReference;
}
protected void finalize() throws Throwable
{
dispose();
super.finalize();
}
/**
* Nothrow guarantee.
*/
public void dispose()
{
if (!deprecatedConstructorUsed)
{
// We only need to do the Session.logout if they used the old deprecated constructor.
return;
}
try
{
if (sessionReference != null)
{
String method_call = "session.logout";
Object[] method_params = { Marshalling.toXMLRPC(this.sessionReference) };
client.execute(method_call, method_params);
sessionReference = null;
}
}
catch (XmlRpcException exn)
{
}
}
/**
* @deprecated The programmer is now responsible for calling login/logout themselves.
*/
@Deprecated
private static String loginWithPassword(XmlRpcClient client, String username, String password)
throws BadServerResponse, XmlRpcException, SessionAuthenticationFailed
{
String method_call = "session.login_with_password";
Object[] method_params = { Marshalling.toXMLRPC(username), Marshalling.toXMLRPC(password) };
Map response = (Map) client.execute(method_call, method_params);
if (response.get("Status").equals("Success"))
{
return (String) response.get("Value");
} else if (response.get("Status").equals("Failure"))
{
Object[] error = (Object[]) response.get("ErrorDescription");
if (error[0].equals("SESSION_AUTHENTICATION_FAILED"))
{
throw new SessionAuthenticationFailed();
}
}
throw new BadServerResponse(response);
}
/**
* @deprecated The programmer is now responsible for calling login/logout themselves.
*/
@Deprecated
private static String loginWithPassword(XmlRpcClient client, String username, String password, String ApiVersion)
throws BadServerResponse, XmlRpcException, SessionAuthenticationFailed
{
String method_call = "session.login_with_password";
Object[] method_params = { Marshalling.toXMLRPC(username), Marshalling.toXMLRPC(password),
Marshalling.toXMLRPC(ApiVersion) };
Map response = (Map) client.execute(method_call, method_params);
if (response.get("Status").equals("Success"))
{
return (String) response.get("Value");
} else if (response.get("Status").equals("Failure"))
{
Object[] error = (Object[]) response.get("ErrorDescription");
if (error[0].equals("SESSION_AUTHENTICATION_FAILED"))
{
throw new SessionAuthenticationFailed();
}
}
throw new BadServerResponse(response);
}
private static XmlRpcClient getClientFromURL(URL url)
{
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(url);
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
return client;
}
/*
* Because the binding calls are constructing their own parameter lists, they need to be able to get to
* the session reference directly. This is all rather ugly and needs redone
* Changed to public to allow easier integration with HTTP-level streaming interface,
* see CA-15447
*/
public String getSessionReference()
{
return this.sessionReference;
}
/**
* The (auto-generated parts of) the bindings dispatch XMLRPC calls on this Connection's client through this method.
*/
Map dispatch(String method_call, Object[] method_params) throws XmlRpcException, XenAPIException
{
Map response = (Map) client.execute(method_call, method_params);
if (!deprecatedConstructorUsed)
{
// We are using the new-style constructor which doesn't perform login.
// Set this Connection's Session reference from the value returned on the wire.
if (method_call.equals("session.login_with_password") &&
response.get("Status").equals("Success"))
{
// Store the Session reference and ask the server what the
// API version it's using is.
Session session = Types.toSession(response.get("Value"));
sessionReference = session.ref;
setAPIVersion(session);
}
else if (method_call.equals("session.slave_local_login_with_password") &&
response.get("Status").equals("Success"))
{
// Store the Session reference and assume API version 1.2.
sessionReference = Types.toSession(response.get("Value")).ref;
apiVersion = APIVersion.API_1_2;
}
else if (method_call.equals("session.logout"))
{
// Work around a bug in XenServer 5.0 and below.
// session.login_with_password should have rejected us with
// HOST_IS_SLAVE, but instead we don't find out until later.
// We don't want to leak the session, so we need to log out
// this session from the master instead.
if (response.get("Status").equals("Failure"))
{
Object[] error = (Object[]) response.get("ErrorDescription");
if (error.length == 2 && error[0].equals("HOST_IS_SLAVE"))
{
try
{
URL client_url =
((XmlRpcHttpClientConfig)client.getClientConfig()).getServerURL();
Connection tmp_conn =
new Connection(new URL(client_url.getProtocol(),
(String)error[1],
client_url.getPort(),
client_url.getFile()));
tmp_conn.sessionReference = sessionReference;
try
{
Session.logout(tmp_conn);
}
finally
{
tmp_conn.dispose();
}
}
catch (Exception exn2)
{
// Ignore -- we're going to throw HostIsSlave anyway.
}
}
}
// Clear the stored Session reference.
this.sessionReference = null;
}
}
return Types.checkResponse(response);
}
private void setAPIVersion(Session session) throws XenAPIException, XmlRpcException
{
try
{
long major = session.getThisHost(this).getAPIVersionMajor(this);
long minor = session.getThisHost(this).getAPIVersionMinor(this);
apiVersion = APIVersion.fromMajorMinor(major, minor);
}
catch (BadServerResponse exn)
{
apiVersion = APIVersion.API_1_1;
}
}
}