Imported Upstream version 2.6.2

This commit is contained in:
Arnaud Quette 2011-09-29 20:14:46 +02:00
parent a367d9bc54
commit 45043b58d0
246 changed files with 18228 additions and 1415 deletions

View file

@ -0,0 +1,619 @@
/* Client.java
Copyright (C) 2011 Eaton
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.networkupstools.jnut;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
/**
* A jNut client is start point to dialog to UPSD.
* It can connect to an UPSD then retrieve its device list.
* It support authentication by login/password.
* <p>
* You can directly create and connect a client by using the
* Client(String host, int port, String login, String passwd) constructor
* or use a three phase construction:
* <ul>
* <li>empty constructor
* <li>setting host, port, login and password with setters
* <li>call empty connect()
* </ul>
* <p>
* Objects retrieved by Client are attached (directly or indirectly) to it.
* If the connection is closed, attached objects must not be used anymore (GC).
* <p>
* Note: The jNut Client does not support any reconnection nor ping mechanism,
* so the calling application must know the UPSD can timeout the connection.
* <p>
* Note: Retrieved values are not valid along the time, they are valid at the
* precise moment they are retrieved.
*
* @author <a href="mailto:EmilienKia@eaton.com">Emilien Kia</a>
*/
public class Client {
/**
* Host to which connect.
* Network name or IP.
* Default to "127.0.0.1"
*/
private String host = "127.0.0.1";
/**
* IP port.
* Default to 3493
*/
private int port = 3493;
/**
* Login to use to connect to UPSD.
*/
private String login = null;
/**
* Password to use to connect to UPSD.
*/
private String passwd = null;
/**
* Communication socket
*/
private StringLineSocket socket = null;
/**
* Get the host name or address to which client is (or will be) connected.
* @return Host name or address.
*/
public String getHost() {
return host;
}
/**
* Set the host name (or address) to which the client will intend to connect to at next connection.
* @param host New host name or address.
*/
public void setHost(String host) {
this.host = host;
}
/**
* Get the login with which the client is (or will be connected).
* @return The login.
*/
public String getLogin() {
return login;
}
/**
* Set the login with which the client will intend to connect.
* @param login New login.
*/
public void setLogin(String login) {
this.login = login;
}
/**
* Get the password with which the client is (or will be connected).
* @return The password.
*/
public String getPasswd() {
return passwd;
}
/**
* Set the password with which the client will intend to connect.
* @param passwd New password.
*/
public void setPasswd(String passwd) {
this.passwd = passwd;
}
/**
* Get the port to which client is (or will be) connected.
* @return Port number.
*/
public int getPort() {
return port;
}
/**
* Set the port to which client is (or will be) connected.
* @param port Port number.
*/
public void setPort(int port) {
this.port = port;
}
/**
* Default constructor.
*/
public Client()
{
}
/**
* Connection constructor.
* Construct the Client object and intend to connect.
* Throw an exception if cannot connect.
* @param host Host to which connect.
* @param port IP port.
* @param login Login to use to connect to UPSD.
* @param passwd Password to use to connect to UPSD.
*/
public Client(String host, int port, String login, String passwd) throws IOException, UnknownHostException, NutException
{
connect(host, port, login, passwd);
}
/**
* Intent to connect and authenticate to an UPSD with specified parameters.
* Throw an exception if cannot connect.
* @param host Host to which connect.
* @param port IP port.
* @param login Login to use to connect to UPSD.
* @param passwd Password to use to connect to UPSD.
*/
public void connect(String host, int port, String login, String passwd) throws IOException, UnknownHostException, NutException
{
this.host = host;
this.port = port;
this.login = login;
this.passwd = passwd;
connect();
}
/**
* Intent to connect to an UPSD with specified parameters without authentication.
* Throw an exception if cannot connect.
* @param host Host to which connect.
* @param port IP port.
*/
public void connect(String host, int port) throws IOException, UnknownHostException, NutException
{
this.host = host;
this.port = port;
connect();
}
/**
* Connection to UPSD with already specified parameters.
* Throw an exception if cannot connect.
*/
public void connect() throws IOException, UnknownHostException, NutException
{
// Force disconnect if another connection is alive.
if(socket!=null)
disconnect();
socket = new StringLineSocket(host, port);
authenticate();
}
/**
* Intend to authenticate with specified login and password, overriding
* already defined ones.
* @param login
* @param passwd
* @throws IOException
* @throws NutException
*/
public void authenticate(String login, String passwd) throws IOException, NutException
{
this.login = login;
this.passwd = passwd;
authenticate();
}
/**
* Intend to authenticate with alread set login and password.
* @throws IOException
* @throws NutException
*/
public void authenticate() throws IOException, NutException
{
// Send login
if(login!=null && !login.isEmpty())
{
String res = query("USERNAME", login);
if(!res.startsWith("OK"))
{
// Normaly response should be OK or ERR and nothing else.
throw new NutException(NutException.UnknownResponse, "Unknown response in Client.connect (USERNAME) : " + res);
}
}
// Send password
if(passwd!=null && !passwd.isEmpty())
{
String res = query("PASSWORD", passwd);
if(!res.startsWith("OK"))
{
// Normaly response should be OK or ERR and nothing else.
throw new NutException(NutException.UnknownResponse, "Unknown response in Client.connect (PASSWORD) : " + res);
}
}
}
/**
* Test if the client is connected to the UPSD.
* Note: it does not detect if the connection have been closed by server.
* @return True if connected.
*/
public boolean isConnected()
{
return socket!=null && socket.isConnected();
}
/**
* Disconnect.
*/
public void disconnect()
{
if(socket!=null)
{
try
{
if(socket.isConnected())
socket.close();
}
catch(IOException e)
{
e.printStackTrace();
}
socket = null;
}
}
/**
* Log out.
*/
public void logout()
{
if(socket!=null)
{
try
{
if(socket.isConnected())
{
socket.write("LOGOUT");
socket.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
socket = null;
}
}
/**
* Merge an array of stings into on string, with a space ' ' separator.
* @param str First string to merge
* @param strings Additionnal strings to merge
* @param sep Separator.
* @return The merged string, empty if no source string.
*/
static String merge(String str, String[] strings)
{
String res = str;
if(strings!=null)
{
for(int n=0; n<strings.length; n++)
{
res += " " + strings[n];
}
}
return res;
}
/**
* Intend to split a name/value string of the form '<name> "<value>"'.
* @param source String source to split.
* @return String couple with name and value.
*/
static String[] splitNameValueString(String source)
{
int pos = source.indexOf(' ');
if(pos<1)
return null;
String name = source.substring(0, pos);
String value = extractDoublequotedValue(source.substring(pos+1));
if(value==null)
return null;
String[] res = new String[2];
res[0] = name;
res[1] = value;
return res;
}
/**
* Intend to extract a value from its doublequoted and escaped representation.
* @param source Source string to convert.
* @return Extracted value
*/
static String extractDoublequotedValue(String source)
{
// Test doublequote at begin and end of string, then remove them.
if(!(source.startsWith("\"") && source.endsWith("\"")))
return null;
source = source.substring(1, source.length()-1);
// Unescape it.
return unescape(source);
}
/**
* Escape string with backslashes.
* @param str String to escape.
* @return Escaped string.
*/
static String escape(String str)
{
// Replace a backslash by two backslash (regexp)
str = str.replaceAll("\\\\", "\\\\\\\\");
// Replace a doublequote by backslash-doublequote (regexp)
str = str.replaceAll("\"", "\\\\\"");
return str;
}
/**
* Unescape string with backslashes.
* @param str String to unescape.
* @return Unescaped string.
*/
static String unescape(String str)
{
// Replace a backslash-doublequote by doublequote (regexp)
str = str.replaceAll("\\\\\"", "\"");
// Replace two backslash by a backslash (regexp)
str = str.replaceAll("\\\\\\\\", "\\\\");
return str;
}
/**
* Detect an UPSD ERR line.
* If found, parse it, construct and throw an NutException
* @param str Line to analyse.
* @throws NutException
*/
private void detectError(String str) throws NutException
{
if(str.startsWith("ERR "))
{
String[] arr = str.split(" ", 3);
switch(arr.length)
{
case 2:
throw new NutException(arr[1]);
case 3:
throw new NutException(arr[1], arr[2]);
default:
throw new NutException();
}
}
}
/**
* Send a query line then read the response.
* Helper around query(String).
* @param query Query to send.
* @param subquery Sub query to send.
* @return The reply.
* @throws IOException
*/
protected String query(String query, String subquery) throws IOException, NutException
{
return query(query + " " + subquery);
}
/**
* Send a query line then read the response.
* Helper around query(String, String ...).
* @param query Query to send.
* @param subquery Sub query to send.
* @param params Optionnal additionnal parameters.
* @return The reply.
* @throws IOException
*/
protected String query(String query, String subquery, String[] params) throws IOException, NutException
{
return query(query + " " + subquery, params);
}
/**
* Send a query line then read the response.
* @param query Query to send.
* @param params Optionnal additionnal parameters.
* @return The reply.
* @throws IOException
*/
protected String query(String query, String [] params) throws IOException, NutException
{
query = merge(query, params);
return query(query);
}
/**
* Send a query line then read the response.
* @param query Query to send.
* @return The reply.
* @throws IOException
*/
protected String query(String query) throws IOException, NutException
{
if(!isConnected())
return null;
socket.write(query);
String res = socket.read();
detectError(res);
return res;
}
/**
* Send a GET query line then read the reply and validate the response.
* @param subcmd GET subcommand to send.
* @param param Extra parameters
* @return GET result return by UPSD, without the subcommand and param prefix.
* @throws IOException
*/
protected String get(String subcmd, String param) throws IOException, NutException
{
String[] params = {param};
return get(subcmd, params);
}
/**
* Send a GET query line then read the reply and validate the response.
* @param subcmd GET subcommand to send.
* @param params Eventual extra parameters.
* @return GET result return by UPSD, without the subcommand and param prefix.
* @throws IOException
*/
protected String get(String subcmd, String [] params) throws IOException, NutException
{
if(!isConnected())
return null;
subcmd = merge(subcmd, params);
socket.write("GET " + subcmd);
String res = socket.read();
if(res==null)
return null;
detectError(res);
if(res.startsWith(subcmd + " "))
{
return res.substring(subcmd.length()+1);
}
else
{
return null;
}
}
/**
* Send a LIST query line then read replies and validate them.
* @param subcmd LIST subcommand to send.
* @return LIST results return by UPSD, without the subcommand and param prefix.
* @throws IOException
*/
protected String[] list(String subcmd) throws IOException, NutException
{
return list(subcmd, (String[])null);
}
/**
* Send a LIST query line then read replies and validate them.
* @param subcmd LIST subcommand to send.
* @param param Extra parameters.
* @return LIST results return by UPSD, without the subcommand and param prefix.
* @throws IOException
*/
protected String[] list(String subcmd, String param) throws IOException, NutException
{
String[] params = {param};
return list(subcmd, params);
}
/**
* Send a LIST query line then read replies and validate them.
* @param subcmd LIST subcommand to send.
* @param params Eventual extra parameters.
* @return LIST results return by UPSD, without the subcommand and param prefix.
* @throws IOException
*/
protected String[] list(String subcmd, String [] params) throws IOException, NutException
{
if(!isConnected())
return null;
subcmd = merge(subcmd, params);
socket.write("LIST " + subcmd);
String res = socket.read();
if(res==null)
return null;
detectError(res);
if(!res.startsWith("BEGIN LIST " + subcmd))
return null;
ArrayList/*<String>*/ list = new ArrayList/*<String>*/();
int sz = subcmd.length()+1;
while(true)
{
res = socket.read();
detectError(res);
if(!res.startsWith(subcmd + " "))
break;
list.add(res.substring(sz));
}
if(!res.equals("END LIST " + subcmd))
return null;
return (String[])list.toArray(new String[list.size()]);
}
/**
* Returns the list of available devices from the NUT server.
* @return List of devices, empty if nothing,
* null if not connected or failed.
*
*/
public Device[] getDeviceList() throws IOException, NutException
{
String[] res = list("UPS");
if(res==null)
return null;
ArrayList/*<Device>*/ list = new ArrayList/*<Device>*/();
for(int i=0; i<res.length; i++)
{
String[] arr = splitNameValueString(res[i]);
if(arr!=null)
{
list.add(new Device(arr[0], this));
}
}
return (Device[])list.toArray(new Device[list.size()]);
}
/**
* Intend to retrieve a device by its name.
* @param name Name of the device to look at.
* @return Device
* @throws IOException
* @throws NutException
*/
public Device getDevice(String name)throws IOException, NutException
{
// Note: an exception "DRIVER-NOT-CONNECT" should not prevent Device creation.
try{
get("UPSDESC", name);
}catch(NutException ex){
if(!ex.is(NutException.DriverNotConnected)){
throw ex;
}
}
return new Device(name, this);
}
}

View file

@ -0,0 +1,100 @@
/* Command.java
Copyright (C) 2011 Eaton
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.networkupstools.jnut;
import java.io.IOException;
/**
* Class representing a command of a device.
* <p>
* It can be used to retrieve description and execute commands.
* A Command object can be retrieved from Device instance and can not be constructed directly.
*
* @author <a href="mailto:EmilienKia@eaton.com">Emilien Kia</a>
*/
public class Command {
/**
* Device to which command is attached
*/
Device device = null;
/**
* Command name
*/
String name = null;
/**
* Internally create a command.
* @param name Command name.
* @param device Device to which the command is attached.
*/
protected Command(String name, Device device)
{
this.device = device;
this.name = name;
}
/**
* Return the device to which the command can be executed.
* @return Attached device.
*/
public Device getDevice() {
return device;
}
/**
* Return the command name.
* @return Command name.
*/
public String getName() {
return name;
}
/**
* Retrieve the command description from UPSD and store it in cache.
* @return Command description
* @throws IOException
*/
public String getDescription() throws IOException, NutException {
if(device!=null && device.getClient()!=null)
{
String[] params = {device.getName(), name};
String res = device.getClient().get("CMDDESC", params);
return res!=null?Client.extractDoublequotedValue(res):null;
}
return null;
}
/**
* Execute the instant command.
* @throws IOException
*/
public void execute() throws IOException, NutException {
if(device!=null && device.getClient()!=null)
{
String[] params = {device.getName(), name};
String res = device.getClient().query("INSTCMD", params);
if(!res.equals("OK"))
{
// Normaly response should be OK or ERR and nothing else.
throw new NutException(NutException.UnknownResponse, "Unknown response in Command.execute : " + res);
}
}
}
}

View file

@ -0,0 +1,279 @@
/* Device.java
Copyright (C) 2011 Eaton
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.networkupstools.jnut;
import java.io.IOException;
import java.util.ArrayList;
/**
* Class representing a device attached to a Client.
* <p>
* It can retrieve its description, its number of logins, its variable and command lists.
* A Device object can be retrieved from Client instance and can not be constructed directly.
*
* @author <a href="mailto:EmilienKia@eaton.com">Emilien Kia</a>
*/
public class Device {
/**
* Client to which device is attached
*/
Client client = null;
/**
* Device name
*/
String name = null;
/**
* Internally create a device.
* @param name Device name.
* @param client Client to which the device is attached.
*/
protected Device(String name, Client client)
{
this.client = client;
this.name = name;
}
/**
* Return the client to which the device is connected.
* @return Attached client.
*/
public Client getClient() {
return client;
}
/**
* Return the device name.
* @return Device name.
*/
public String getName() {
return name;
}
/**
* Retrieve the device description from UPSD and store it in cache.
* @return Device description
* @throws IOException
*/
public String getDescription() throws IOException, NutException {
if(client!=null)
{
return client.get("UPSDESC", name);
}
return null;
}
/**
* Log in to the ups.
* <p>
* Use this to log the fact that a system is drawing power from this UPS.
* The <i>upsmon</i> master will wait until the count of attached systems reaches
* 1 - itself. This allows the slaves to shut down first.
* <p>
* NOTE: You probably shouldn't send this command unless you are upsmon,
* or a upsmon replacement.
* @throws IOException
* @throws NutException
*/
public void login() throws IOException, NutException {
if(client!=null)
{
String res = client.query("LOGIN", name);
if(!res.startsWith("OK"))
{
// Normaly response should be OK or ERR and nothing else.
throw new NutException(NutException.UnknownResponse, "Unknown response in Device.login : " + res);
}
}
}
/**
* This function doesn't do much by itself. It is used by <i>upsmon</i> to make
* sure that master-level functions like FSD are available if necessary
* @throws IOException
* @throws NutException
*/
public void master() throws IOException, NutException {
if(client!=null)
{
String res = client.query("MASTER", name);
if(!res.startsWith("OK"))
{
// Normaly response should be OK or ERR and nothing else.
throw new NutException(NutException.UnknownResponse, "Unknown response in Device.master : " + res);
}
}
}
/**
* Set the "forced shutdown" flag.
* <p>
* <i>upsmon</i> in master mode is the primary user of this function. It sets this
* "forced shutdown" flag on any UPS when it plans to power it off. This is
* done so that slave systems will know about it and shut down before the
* power disappears.
* <p>
* Setting this flag makes "FSD" appear in a STATUS request for this UPS.
* Finding "FSD" in a status request should be treated just like a "OB LB".
* <p>
* It should be noted that FSD is currently a latch - once set, there is
* no way to clear it short of restarting upsd or dropping then re-adding
* it in the ups.conf. This may cause issues when upsd is running on a
* system that is not shut down due to the UPS event.
* @throws IOException
* @throws NutException
*/
public void setForcedShutdown() throws IOException, NutException {
if(client!=null)
{
String res = client.query("FSD", name);
if(!res.startsWith("OK"))
{
// Normaly response should be OK or ERR and nothing else.
throw new NutException(NutException.UnknownResponse, "Unknown response in Device.setForcedShutdown : " + res);
}
}
}
/**
* Return the number of clients which have done LOGIN for this UPS.
* Force to retrieve it from UPSD and store it in cache.
* @return Number of clients, -1 if error.
* @throws IOException
*/
public int getNumLogin() throws IOException, NutException {
if(client!=null)
{
String res = client.get("NUMLOGINS", name);
return res!=null?Integer.parseInt(res):-1;
}
return -1;
}
/**
* Return the list of device variables from the NUT server.
* @return List of variables, empty if nothing,
* null if not connected or failed.
* @throws IOException
*/
public Variable[] getVariableList() throws IOException, NutException {
if(client==null)
return null;
String[] res = client.list("VAR", name);
if(res==null)
return null;
ArrayList/*<Variable>*/ list = new ArrayList/*<Variable>*/();
for(int i=0; i<res.length; i++)
{
String[] arr = Client.splitNameValueString(res[i]);
if(arr!=null)
{
list.add(new Variable(arr[0], this));
}
}
return (Variable[])list.toArray(new Variable[list.size()]);
}
/**
* Return the list of device RW variables from the NUT server.
* @return List of variables, empty if nothing,
* null if not connected or failed.
* @throws IOException
*/
public Variable[] getRWVariableList() throws IOException, NutException {
if(client==null)
return null;
String[] res = client.list("RW", name);
if(res==null)
return null;
ArrayList/*<Variable>*/ list = new ArrayList/*<Variable>*/();
for(int i=0; i<res.length; i++)
{
String[] arr = Client.splitNameValueString(res[i]);
if(arr!=null)
{
list.add(new Variable(arr[0], this));
}
}
return (Variable[])list.toArray(new Variable[list.size()]);
}
/**
* Return a variable from its name.
* @param name Name of the queried variable.
* @return The corresponding variable object if exists.
* @throws IOException
* @throws NutException
*/
public Variable getVariable(String name) throws IOException, NutException {
if(client==null)
return null;
String[] params = {this.name, name};
client.get("VAR", params);
return new Variable(name, this);
}
/**
* Return the list of device commands from the NUT server.
* @return List of commands, empty if nothing,
* null if not connected or failed.
* @throws IOException
*/
public Command[] getCommandList() throws IOException, NutException {
if(client==null)
return null;
String[] res = client.list("CMD", name);
if(res==null)
return null;
ArrayList/*<Command>*/ list = new ArrayList/*<Command>*/();
for(int i=0; i<res.length; i++)
{
list.add(new Command(res[i], this));
}
return (Command[])list.toArray(new Command[list.size()]);
}
/**
* Return a command from its name.
* @param name Name of the queried command.
* @return The corresponding command object if exists.
* @throws IOException
* @throws NutException
*/
public Command getCommand(String name)throws IOException, NutException {
if(client==null)
return null;
String[] params = {this.name, name};
String res = client.get("CMDDESC", params);
// Note: there is no way to test if the command is really available or not
// because a GET CMDDESC ups badcmdname does not return an error.
return new Command(name, this);
}
}

View file

@ -0,0 +1,107 @@
/* NutException.java
Copyright (C) 2011 Eaton
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.networkupstools.jnut;
/**
* Class representing a NUT exception.
* <p>
* Instance are thrown when an UPSD returns an error with an "ERR" directive.
* Moreover it can ben thrown with some extra errors like:
* <ul>
* <li>UNKNOWN-RESPONSE : The response is not understood
* </ul>
* <p>
* A Nut exception has a (standard java exception message) message which correspond
* to error code returns by UPSD (like 'ACCESS-DENIED', 'UNKNOWN-UPS' ...).
* An extra string embed a more descriptive english message.
*
* @author <a href="mailto:EmilienKia@eaton.com">Emilien Kia</a>
*/
public class NutException extends java.lang.Exception{
public static String UnknownResponse = "UNKNOWN-RESPONSE";
public static String DriverNotConnected = "DRIVER-NOT-CONNECTED";
public String extra = "";
public NutException()
{
}
public NutException(String message)
{
super(message);
}
public NutException(String message, String extra)
{
super(message);
this.extra = extra;
}
public NutException(Throwable cause)
{
super(cause);
}
public NutException(String message, Throwable cause)
{
super(message, cause);
}
public NutException(String message, String extra, Throwable cause)
{
super(message, cause);
this.extra = extra;
}
/**
* Returns the extra message.
* @return Extra message if any.
*/
public String getExtra() {
return extra;
}
/**
* Set the extra message.
* @param extra The new extra message.
*/
public void setExtra(String extra) {
this.extra = extra;
}
/**
* Test is the exception corresponds to the specified name.
* @param name Name to test
* @return True if exception corresponds.
*/
public boolean is(String name) {
return getMessage()!=null&&getMessage().equals(name);
}
/**
* Format an exception message.
* @return Exception message
*/
public String toString() {
return "[" + getClass().getSimpleName() + "]" + getMessage() + " : " + getExtra();
}
}

View file

@ -0,0 +1,137 @@
/* StringLineSocket.java
Copyright (C) 2011 Eaton
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.networkupstools.jnut;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* Class representing a socket, internally used to communicate with UPSD.
* Abstract some stream mechanisms.
*
* @author <a href="mailto:EmilienKia@eaton.com">Emilien Kia</a>
*/
class StringLineSocket {
/**
* Real internal TCP socket.
*/
Socket socket = null;
/**
* Writer to the socket.
*/
private OutputStreamWriter writer = null;
/**
* Reader from the socket.
*/
private BufferedReader reader = null;
/**
* Create a new line socket.
*/
public StringLineSocket(){
}
/**
* Create a new line socket and connect it.
* @param host Host to connect to
* @param port Port to connect to
* @throws UnknownHostException
* @throws IOException
*/
public StringLineSocket(String host, int port) throws UnknownHostException, IOException{
connect(host, port);
}
/**
* Connect a new line socket.
* @param host Host to connect to
* @param port Port to connect to
* @throws UnknownHostException
* @throws IOException
*/
public void connect(String host, int port) throws UnknownHostException, IOException{
socket = new Socket(host, port);
if(socket!=null)
{
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
writer = new OutputStreamWriter(socket.getOutputStream());
}
}
/**
* Close the socket.
*/
public void close() throws IOException{
if(socket!=null){
writer.close();
reader.close();
socket.close();
socket = null;
writer = null;
reader = null;
}
}
/**
* Test if the soecket is connected.
* @return True if connected.
*/
public boolean isConnected() {
return socket!=null && socket.isConnected() && !socket.isClosed();
}
/**
* Write a line follow by a '\n' character.
* @param line
* @throws IOException
*/
public void write(String line) throws IOException
{
if(isConnected())
{
writer.write(line + "\n");
writer.flush();
}
}
/**
* Read a line terminated by a '\n'.
* @return The line without the ending '\n'
* @throws IOException
*/
public String read() throws IOException
{
if(isConnected())
{
String res = reader.readLine();
return res;
}
return "";
}
}

View file

@ -0,0 +1,120 @@
/* Variable.java
Copyright (C) 2011 Eaton
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.networkupstools.jnut;
import java.io.IOException;
/**
* Class representing a variable of a device.
* <p>
* It can be used to get and set its value (if possible).
* A Variable object can be retrieved from Device instance and can not be constructed directly.
*
* @author <a href="mailto:EmilienKia@eaton.com">Emilien Kia</a>
*/
public class Variable {
/**
* Device to which variable is attached
*/
Device device = null;
/**
* Variable name
*/
String name = null;
/**
* Internally create a variable.
* @param name Variable name.
* @param device Device to which the variable is attached.
*/
protected Variable(String name, Device device)
{
this.device = device;
this.name = name;
}
/**
* Return the device to which the variable is related.
* @return Attached device.
*/
public Device getDevice() {
return device;
}
/**
* Return the variable name.
* @return Command name.
*/
public String getName() {
return name;
}
/**
* Retrieve the variable value from UPSD and store it in cache.
* @return Variable value
* @throws IOException
*/
public String getValue() throws IOException, NutException {
if(device!=null && device.getClient()!=null)
{
String[] params = {device.getName(), name};
String res = device.getClient().get("VAR", params);
return res!=null?Client.extractDoublequotedValue(res):null;
}
return null;
}
/**
* Retrieve the variable description from UPSD and store it in cache.
* @return Variable description
* @throws IOException
*/
public String getDescription() throws IOException, NutException {
if(device!=null && device.getClient()!=null)
{
String[] params = {device.getName(), name};
String res = device.getClient().get("DESC", params);
return res!=null?Client.extractDoublequotedValue(res):null;
}
return null;
}
/**
* Set the variable value.
* Note the new value can be applied with a little delay depending of UPSD and connection.
* @param value New value for the variable
* @throws IOException
*/
public void setValue(String value) throws IOException, NutException {
if(device!=null && device.getClient()!=null)
{
String[] params = {"VAR", device.getName(),
name, " \"" + Client.escape(value) + "\""};
String res = device.getClient().query("SET", params);
if(!res.equals("OK"))
{
// Normaly response should be OK or ERR and nothing else.
throw new NutException(NutException.UnknownResponse, "Unknown response in Variable.setValue : " + res);
}
}
}
// TODO Add query for type and enum values
}

View file

@ -0,0 +1,95 @@
package org.networkupstools.jnut;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class ClientTest extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public ClientTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( ClientTest.class );
}
/**
* Escape function test.
*/
public void testEscape()
{
assertEquals("Empty string", "", Client.escape(""));
assertEquals("Simple string", "hello", Client.escape("hello"));
assertEquals("Internal doublequote", "he\\\"llo", Client.escape("he\"llo"));
assertEquals("Internal backslash", "he\\\\llo", Client.escape("he\\llo"));
assertEquals("Internal backslash and doublequote", "he\\\\\\\"llo", Client.escape("he\\\"llo"));
assertEquals("Initial and final doublequote", "\\\"hello\\\"", Client.escape("\"hello\""));
}
/**
* Unescape function test.
*/
public void testUnescape()
{
assertEquals("Empty string", "", Client.unescape(""));
assertEquals("Simple string", "hello", Client.unescape("hello"));
assertEquals("Internal doublequote", "he\"llo", Client.unescape("he\\\"llo"));
assertEquals("Internal backslash", "he\\llo", Client.unescape("he\\\\llo"));
assertEquals("Internal backslash and doublequote", "he\\\"llo", Client.unescape("he\\\\\\\"llo"));
assertEquals("Initial and final doublequote", "\"hello\"", Client.unescape("\\\"hello\\\""));
}
/**
* extractDoublequotedValue function test.
*/
public void testExtractDoublequotedValue()
{
assertNull("Empty string", Client.extractDoublequotedValue(""));
assertNull("Non doublequoted string", Client.extractDoublequotedValue("hello"));
assertNull("No begining doublequote", Client.extractDoublequotedValue("hello\""));
assertNull("No ending doublequote", Client.extractDoublequotedValue("\"hello"));
assertEquals("Simple string", "hello", Client.extractDoublequotedValue("\"hello\""));
assertEquals("String with doublequote", "he\"llo", Client.extractDoublequotedValue("\"he\\\"llo\""));
assertEquals("String with backslash", "he\\llo", Client.extractDoublequotedValue("\"he\\\\llo\""));
assertEquals("String with backslash and doublequote", "he\\\"llo", Client.extractDoublequotedValue("\"he\\\\\\\"llo\""));
}
/**
* splitNameValueString function test.
*/
public void testSplitNameValueString()
{
String[] res;
assertNull("Empty string", Client.splitNameValueString(""));
assertNull("One word string", Client.splitNameValueString("name"));
assertNull("Non doublequoted string", Client.extractDoublequotedValue("name value"));
assertNull("No begining doublequote", Client.extractDoublequotedValue("name value\""));
assertNull("No ending doublequote", Client.extractDoublequotedValue("name \"value"));
res = Client.splitNameValueString("name \"value\"");
assertEquals("Simple name/value (name)", "name", res[0]);
assertEquals("Simple name/value (value)", "value", res[1]);
res = Client.splitNameValueString("name \"complex value\"");
assertEquals("Simple name / complex value (name)", "name", res[0]);
assertEquals("Simple name / complex value (value)", "complex value", res[1]);
res = Client.splitNameValueString("name \"complex\\\\value\"");
assertEquals("Simple name / backslash value (name)", "name", res[0]);
assertEquals("Simple name / backslash value (value)", "complex\\value", res[1]);
res = Client.splitNameValueString("name \"complex\\\"value\"");
assertEquals("Simple name / doublequote value (name)", "name", res[0]);
assertEquals("Simple name / doublequote value (value)", "complex\"value", res[1]);
}
}