1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

feature #198: Base Classes for the OCA API - JAVA Bindings

This commit is contained in:
Carlos Martin and Ruben S. Montero 2010-03-20 00:49:20 +01:00 committed by Ruben S. Montero
parent 61d7079cc2
commit c86f2d0445
6 changed files with 693 additions and 0 deletions

105
src/oca/java/build.sh Executable file
View File

@ -0,0 +1,105 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org) #
# #
# Licensed 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. #
#--------------------------------------------------------------------------- #
#-------------------------------------------------------------------------------
# DIR DEFINITIONS
#-------------------------------------------------------------------------------
DOC_DIR="./doc"
BIN_DIR="./bin"
JAR_DIR="./jar/org.opennebula.client.jar"
LIB_DIR="./lib"
#-------------------------------------------------------------------------------
# COMMAND LINE PARSING
#-------------------------------------------------------------------------------
usage() {
echo
echo "Usage: build.sh [-d ] [-h] [-s]"
echo
echo "-d: build the documentation"
echo "-s: compile the examples"
echo "-h: prints this help"
}
#-------------------------------------------------------------------------------
TEMP_OPT=`getopt -o hsd -n 'build.sh' -- "$@"`
eval set -- "$TEMP_OPT"
DO_DOC="no"
DO_EXA="no"
while true ; do
case "$1" in
-h) usage; exit 0;;
-d) DO_DOC="yes"; shift ;;
-s) DO_EXA="yes"; shift ;;
--) shift ; break ;;
*) usage; exit 1 ;;
esac
done
#-------------------------------------------------------------------------------
# BUILD FUNCTIONS
#-------------------------------------------------------------------------------
do_documentation()
{
echo "Generating javadocs..."
rm -rf $DOC_DIR > /dev/null 2>&1
mkdir -p $DOC_DIR
javadoc -quiet -classpath $LIB_DIR"/*" -d $DOC_DIR \
-sourcepath ./src/ \
-subpackages org.opennebula \
-windowtitle 'OpenNebula Cloud API' \
-doctitle 'OpenNebula Cloud API Specification' \
-header '<b>OpenNebula</b><br><font size="-1">Java API</font>' \
-bottom 'Visit <a
href="http://opennebula.org/">OpenNebula.org</a><br>Copyright 2002-2010 &copy;
OpenNebula Project Leads (OpenNebula.org).'
}
do_jar()
{
rm -rf $BIN_DIR > /dev/null 2>&1
mkdir -p $BIN_DIR
echo "Compiling java files into class files..."
javac -d $BIN_DIR -cp $LIB_DIR"/*" `find src -name *.java`
if [ $? -eq 0 ]; then
echo "Packaging class files in a jar..."
jar cf $JAR_DIR -C $BIN_DIR org
fi
}
do_examples()
{
echo "Compiling OpenNebula Cloud API Examples..."
}
do_jar
if [ "$DO_DOC" = "yes" ] ; then
do_documentation
fi
if [ "$DO_EXA" = "yes" ] ; then
do_examples
fi

Binary file not shown.

View File

@ -0,0 +1,227 @@
/*******************************************************************************
* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org)
*
* Licensed 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 org.opennebula.client;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
/**
* This class represents the connection with the core and handles the
* xml-rpc calls.
*
*/
public class Client {
//--------------------------------------------------------------------------
// PUBLIC INTERFACE
//--------------------------------------------------------------------------
/**
* Creates a new xml-rpc client with default options:
* the auth. file will be assumed to be at $ONE_AUTH, and
* the endpoint will be set to $ONE_XMLRPC.
* <br/>
* It is the equivalent of Client(null, null).
*
* @throws Exception if one authorization file cannot be located.
*/
public Client() throws Exception
{
setOneAuth(null);
setOneEndPoint(null);
}
/**
* Creates a new xml-rpc client with specified options.
*
* @param secret A string containing the ONE user:password tuple.
* Can be null
* @param endpoint Where the rpc server is listening, must be something
* like "http://localhost:2633/RPC2". Can be null
* @throws Exception if the authorization options are invalid
*/
public Client(String secret, String endpoint) throws Exception
{
setOneAuth(secret);
setOneEndPoint(endpoint);
}
/**
* Performs an XML-RPC call.
*
* @param action ONE action
* @param args ONE arguments
* @return The server's xml-rpc response encapsulated
*/
public OneResponse call(String action, Object...args)
{
boolean success = false;
String msg = null;
try
{
Object[] params = new Object[args.length + 1];
params[0] = oneAuth;
for(int i=0; i<args.length; i++)
params[i+1] = args[i];
Object[] result = (Object[]) client.execute("one."+action, params);
success = (Boolean) result[0];
// In some cases, the xml-rpc response only has a boolean
// OUT parameter
if(result.length > 1)
{
try
{
msg = (String) result[1];
}
catch (ClassCastException e)
{
// The result may be an Integer
msg = ((Integer) result[1]).toString();
}
}
}
catch (XmlRpcException e)
{
msg = e.getMessage();
}
return new OneResponse(success, msg);
}
//--------------------------------------------------------------------------
// PRIVATE ATTRIBUTES AND METHODS
//--------------------------------------------------------------------------
private String oneAuth;
private String oneEndPoint;
private XmlRpcClient client;
private void setOneAuth(String secret) throws Exception
{
String oneSecret = secret;
try
{
if(oneSecret == null)
{
String oneAuthEnv = System.getenv("ONE_AUTH");
File authFile;
if ( oneAuthEnv != null && oneAuthEnv.length() != 0)
{
authFile = new File(oneAuthEnv);
}
else
{
authFile = new File(System.getenv("HOME")+"/.one/one_auth");
}
oneSecret =
(new BufferedReader(new FileReader(authFile))).readLine();
}
String[] token = oneSecret.split(":");
if(token.length != 2 )
{
throw new Exception("Wrong format for authorization string: "
+ oneSecret);
}
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(token[1].getBytes());
String hash = "";
for(byte aux : digest)
{
int b = aux & 0xff;
if (Integer.toHexString(b).length() == 1)
{
hash += "0";
}
hash += Integer.toHexString(b);
}
oneAuth = token[0] + ":" + hash;
}
catch (FileNotFoundException e)
{
throw new Exception("ONE_AUTH file not present");
}
catch (NoSuchAlgorithmException e)
{
throw new Exception("Error initializing MessageDigest with SHA-1");
}
}
private void setOneEndPoint(String endpoint) throws Exception
{
oneEndPoint = "http://localhost:2633/RPC2";
if(endpoint != null)
{
oneEndPoint = endpoint;
}
else
{
String oneXmlRpcEnv = System.getenv("ONE_XMLRPC");
if ( oneXmlRpcEnv != null && oneXmlRpcEnv.length() != 0 )
{
oneEndPoint = oneXmlRpcEnv;
}
}
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
try
{
config.setServerURL(new URL(oneEndPoint));
}
catch (MalformedURLException e)
{
throw new Exception("The URL "+oneEndPoint+" is malformed.");
}
client = new XmlRpcClient();
client.setConfig(config);
}
}

View File

@ -0,0 +1,80 @@
/*******************************************************************************
* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org)
*
* Licensed 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 org.opennebula.client;
/**
* This class encapsulates OpenNebula's XML-RPC responses. Each response
* carries a boolean indicating if it is an error. It can also contain a
* success message, or an error message.
*/
public class OneResponse {
/**
* Creates a new response.
*
* @param success Indicates if the call was successful, and if
* the message is an error or an information string.
* @param message String containing the response message, or
* the error message.
*/
public OneResponse(boolean success, String message)
{
this.success = success;
this.msg = message;
}
/**
* Returns true if the call resulted in error.
*
* @return True if the call resulted in error.
*/
public boolean isError()
{
return !success;
}
/**
* Returns a string containing the error message, or null
* if the response isn't an error.
*
* @return A string containing the error message, or null
* if the response isn't an error.
*/
public String getErrorMessage()
{
return success ? null : msg;
}
/**
* Returns a string containing the response information, or
* null if the response was an error. Note that the success
* message could be also null.
*
* @return A string containing the response information, or
* null if the response was an error. Note that the success
* message could be also null.
*/
public String getMessage()
{
return success ? msg : null;
}
// ------------------------------------------------------------------------
// PRIVATE ATTRIBUTES
// ------------------------------------------------------------------------
private boolean success;
private String msg;
}

View File

@ -0,0 +1,125 @@
/*******************************************************************************
* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org)
*
* Licensed 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 org.opennebula.client;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
/**
* Represents a generic OpenNebula Pool in XML format
* and provides the basic functionality to handle the Pool elements.
*/
public abstract class Pool{
protected Client client;
protected String elementName;
protected NodeList poolElements;
/**
* Sets the Pool attributes.
* @param elementName Name of the PoolElement's xml element
* @param client XML-RPC client which will handle calls
*/
protected Pool(String elementName, Client client)
{
this.elementName = elementName;
this.client = client;
}
/**
* The factory method returns a suitable PoolElement object from
* an XML node. Each Pool must implement the corresponding factory method.
*
* @param node XML Dom node to build the PoolElement from
* @return The corresponding PoolElement
*/
public abstract PoolElement factory(Node node);
/**
* After a *pool.info call, this method builds the internal xml
* representation of the pool.
* @param info The XML-RPC *pool.info response
*/
public void processInfo(OneResponse info)
{
if (info.isError())
{
return;
}
try
{
DocumentBuilder builder;
Document doc;
Element xml;
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
doc = builder.parse(
new ByteArrayInputStream(info.getMessage().getBytes()));
xml = doc.getDocumentElement();
poolElements = xml.getElementsByTagName(elementName);
}
catch (ParserConfigurationException e) {}
catch (SAXException e) {}
catch (IOException e) {}
}
/**
* Returns the indexth element in the pool. If index is greater than or
* equal to the number of elements in the pool, this returns null.
*
* @param index Index of the element.
* @return The element at the indexth position in the pool, or
* null if that is not a valid index.
*/
public PoolElement item(int index)
{
PoolElement the_element = null;
if (poolElements != null)
{
Node node =poolElements.item(index);
if (node != null)
{
the_element = factory(node);
}
}
return the_element;
}
/**
* The number of elements in the pool.
* @return The number of elements in the pool.
*/
public int getLength()
{
return poolElements == null ? 0 : poolElements.getLength();
}
}

View File

@ -0,0 +1,156 @@
/*******************************************************************************
* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org)
*
* Licensed 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 org.opennebula.client;
import java.io.ByteArrayInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
/**
* Represents a generic element of a Pool in
* XML format.
*
*/
public abstract class PoolElement {
protected static XPath xpath;
protected int id;
protected Node xml;
protected Client client;
/**
* Creates a new PoolElement with the specified attributes.
* @param id Id of the element.
* @param client XML-RPC Client.
* @param root Name of the xml's root element.
*/
protected PoolElement(int id, Client client)
{
if(xpath == null)
{
XPathFactory factory = XPathFactory.newInstance();
xpath = factory.newXPath();
}
this.id = id;
this.client = client;
}
/**
* Creates a new PoolElement from the xml provided.
*
* @param client XML-RPC Client.
* @param xmlElement XML representation of the element.
* @param root Name of the xml's root element.
*/
protected PoolElement(Node xmlElement, Client client)
{
if(xpath == null)
{
XPathFactory factory = XPathFactory.newInstance();
xpath = factory.newXPath();
}
this.xml = xmlElement;
this.client = client;
this.id = Integer.parseInt(xpath("id"));
}
/**
* After a *.info call, this method builds the internal xml
* representation of the pool.
* @param info The XML-RPC *.info response
*/
protected void processInfo(OneResponse info)
{
if (info.isError())
{
return;
}
try
{
DocumentBuilder builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(
new ByteArrayInputStream(info.getMessage().getBytes()));
xml = doc.getDocumentElement();
}
catch (Exception e) {}
}
/**
* Returns the element's ID.
* @return the element's ID.
*/
public String getId()
{
return Integer.toString(id);
}
/**
* Returns the element's name.
* @return the element's name.
*/
public String getName()
{
return xpath("name");
}
/**
* Performs an xpath evaluation for the "state" expression.
* @return The value of the STATE element.
*/
public int state()
{
String state = xpath("state");
return state != null ? Integer.parseInt( state ) : -1;
}
/**
* Evaluates an XPath expression and returns the result as a String.
* If the internal xml representation is not built, returns null. The
* subclass method info() must be called before.
*
* @param expression The XPath expression.
* @return The String that is the result of evaluating the
* expression and converting the result to a String. Null if
* the internal xml representation is not built.
*/
public String xpath(String expression)
{
String result = null;
try
{
result = xpath.evaluate(expression.toUpperCase(), xml);
}
catch (XPathExpressionException e) {}
return result;
}
}