Skip to content

Instantly share code, notes, and snippets.

@gjb2048
Created August 20, 2013 17:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gjb2048/6284708 to your computer and use it in GitHub Desktop.
Save gjb2048/6284708 to your computer and use it in GitHub Desktop.
RMI on the Raspberry Pi
/*
* Pi RMI.
* © G J Barnard 2013 - Attribution-NonCommercial-ShareAlike 3.0 Unported - http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB.
*/
package pirmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* This interface defines the methods you want your server to provide as a
* service to the client.
*
* The client will use it as it's RMI connection 'class' and the server
* will implement it.
*
* @author G J Barnard
*/
public interface PiInfo extends Remote
{
public static final String PIINFO_SERVICE = "PiInfoServer";
public static final int RMIRegistryPort = 2024;
public static final int ServicePort = 2025;
public String getHostName(String client) throws RemoteException;
public String getJavaVersion(String client) throws RemoteException;
public PiTriInfo getOSDetails(String client) throws RemoteException;
public String getDataModel(String client) throws RemoteException;
public String getEndian(String client) throws RemoteException;
public PiTriInfo getUserDetails(String client) throws RemoteException;
}
/*
* Pi RMI.
* © G J Barnard 2013 - Attribution-NonCommercial-ShareAlike 3.0 Unported - http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB.
*/
package pirmi;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.UnmarshalException;
/**
* This is the client that connects to the server and service within using the
* details supplied.
*
* It does this by contacting the RMI Registry on the port it is running on
* with the name of the service it wishes to use. Therefore three items are
* required to be known beforehand: server name addressable name / IP address,
* RMI Registry port on the server and the name of the service.
*
* @author G J Barnard
*/
public class PiInfoClient
{
private PiInfo connection = null;
private static PiInfoClient instance = null;
private String client;
public static void main(String[] args)
{
if (args.length == 1)
{
PiInfoClient us = PiInfoClient.getInstance();
us.reportPiInfo(args[0]);
}
else
{
System.err.println("Usage: java -Djava.security.policy=\"./pirmi/Policy\" pirmi.PiInfoClient server name (or server IP)");
}
}
private PiInfoClient()
{
}
/**
*
*/
private void reportPiInfo(String host)
{
try
{
connection = connectToServer(host);
String serverName = connection.getHostName(client);
System.out.println(serverName + "'s Java version is: " + connection.getJavaVersion(client));
PiTriInfo osInfo = connection.getOSDetails(client);
System.out.println(serverName + "'s OS details are:");
displayPiTriInfo(osInfo);
System.out.println(serverName + "'s data model is: " + connection.getDataModel(client));
System.out.println(serverName + "'s endian is: " + connection.getEndian(client));
PiTriInfo userInfo = connection.getUserDetails(client);
System.out.println(serverName + "'s User details are:");
displayPiTriInfo(userInfo);
}
catch (Exception ex)
{
ex.printStackTrace(System.err);
}
}
private void displayPiTriInfo(PiTriInfo info)
{
PiPairInfo[] pair = new PiPairInfo[3];
pair[0] = info.getOne();
pair[1] = info.getTwo();
pair[2] = info.getThree();
for (byte i = 0; i <= 2; i++)
{
System.out.println(" " + pair[i].getKey() + " is: " + pair[i].getValue());
}
}
/**
* Gets us in the singleton pattern.
*
* @return Us
*/
public static PiInfoClient getInstance()
{
if (instance == null)
{
instance = new PiInfoClient();
}
return instance;
}
/**
* Attempt a connection to the server.
*
* @param connectionHost server addressable name or IP address.
* @return The connection.
* @throws UnknownHostException
* @throws NotBoundException
* @throws MalformedURLException
* @throws RemoteException
* @throws UnmarshalException
* @throws ClassNotFoundException
* @throws java.rmi.ConnectException
* @throws java.security.AccessControlException
*/
private PiInfo connectToServer(String connectionHost) throws UnknownHostException, NotBoundException, MalformedURLException, RemoteException, UnmarshalException, ClassNotFoundException, java.rmi.ConnectException, java.security.AccessControlException
{
try
{
// Create and install a security manager.
if (System.getSecurityManager() == null)
{
System.out.println("Creating new security manager");
System.setSecurityManager(new SecurityManager());
}
// Info.
client = InetAddress.getLocalHost().getHostName();
System.out.println("Client is on " + client + " with Java version " + System.getProperty("java.version"));
/*
* This does the actual connection returning a reference to the
* server service if it suceeds.
*/
connection = (PiInfo) Naming.lookup("rmi://"
+ connectionHost
+ ":" + PiInfo.RMIRegistryPort + "/" + PiInfo.PIINFO_SERVICE);
System.out.println("PiInfoClient:connectToServer - Connected to " + connectionHost + ":" + PiInfo.RMIRegistryPort + "/" + PiInfo.PIINFO_SERVICE);
}
catch (UnmarshalException ue)
{
System.err.println("PiInfoClient:connectToServer() - UnmarshalException - Check that the server can access it's configuration / policy files");
ue.printStackTrace(System.err);
throw ue;
}
return connection;
}
}
/*
* Pi RMI.
* © G J Barnard 2013 - Attribution-NonCommercial-ShareAlike 3.0 Unported - http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB.
*/
package pirmi;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* This is the server that creates / gets a registry for the client to ask
* where the service we will serve is. Some other examples have you running
* the registry on the command line, but this demonstrates a way of doing so
* within code, saving time.
*
* The registry needs to operate on one port and the service another. This is
* so that one registry can inform clients of lots of services running on their
* own ports. I have chosen to specify the port of the service, but you could
* let the virtual machine to do so. This is helpful if you are using a
* network packet sniffer like WireShark as you can then filter the capture by
* port.
*
* You could have the server implement the service too, but I have decided to
* separate it out for clarity.
*
* @author G J Barnard
*/
public class PiInfoServer extends Thread
{
private static PiInfoServer instance = null;
private PiInfoService piInfoServer = null;
/**
* Constructor.
*
* @throws RemoteException
*/
private PiInfoServer() throws RemoteException
{
super();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
PiInfoServer us = PiInfoServer.getInstance();
us.createServer();
}
/**
* Create the server.
*/
public void createServer()
{
// Create and install a security manager
if (System.getSecurityManager() == null)
{
System.out.println("Creating new security manager");
// http://download.oracle.com/javase/6/docs/api/java/rmi/RMISecurityManager.html
// states to use SecurityManager instead of RMISecurityManager.
System.setSecurityManager(new SecurityManager());
}
try
{
// Now we have the configuration loaded we can create the managers and use them.
piInfoServer = new PiInfoService(PiInfo.ServicePort);
// http://stackoverflow.com/questions/2142668/java-rmi-automating-in-an-ide
Registry r;
try
{
r = LocateRegistry.createRegistry(PiInfo.RMIRegistryPort);
}
catch (java.rmi.server.ExportException ex)
{
r = LocateRegistry.getRegistry(PiInfo.RMIRegistryPort);
}
System.out.println("Service attempts rebind of registry");
r.rebind(PiInfo.PIINFO_SERVICE, piInfoServer);
System.out.println("Server bound in registry");
System.out.println("Press Ctrl-C to exit.");
}
catch (java.rmi.server.ExportException ee)
{
// Cannot get RMI port.
System.err.println("Server cannot use RMI port " + PiInfo.RMIRegistryPort + " as it is already in use, check that you are not running another instance of the server.");
ee.printStackTrace(System.err);
System.exit(-1);
}
catch (Exception e)
{
System.err.println("Server err: " + e.getMessage());
System.exit(-1);
}
}
/**
* Executed at shutdown in response to a Ctrl-C etc.
*/
@Override
public void run()
{
// Perform shutdown methods.
System.out.println("Server Shutting Down.");
}
/**
* Gets us in the singleton pattern.
*
* @return Us
*/
public static PiInfoServer getInstance()
{
if (instance == null)
{
try
{
instance = new PiInfoServer();
// Prepare for shutdown...
Runtime.getRuntime().addShutdownHook(instance);
}
catch (RemoteException ex)
{
System.err.println("PiInfoServer:getInstance() - " + ex.getMessage());
}
}
return instance;
}
}
/*
* Pi RMI.
* © G J Barnard 2013 - Attribution-NonCommercial-ShareAlike 3.0 Unported - http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB.
*/
package pirmi;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* This is the class that implements the service served by the server for the
* client. It extends UnicastRemoteObject -
* http://docs.oracle.com/javase/7/docs/api/java/rmi/server/UnicastRemoteObject.html
* - so that will serve RMI requests and therefore requires to be processed by
* the 'rmic' tool to create the 'stub'used by the client as the reference to
* the server - see:
* http://docs.oracle.com/javase/7/docs/technotes/tools/windows/rmic.html.
*
* @author G J Barnard
*/
public class PiInfoService extends UnicastRemoteObject implements PiInfo
{
public PiInfoService(int port) throws RemoteException
{
super(port);
}
/*
* Methods to get the following:
* java.version
* os.arch
* os.name
* os.version
* sun.arch.data.model
* sun.cpu.endian
* user.name
* user.home
* user.dir
*/
@Override
public PiTriInfo getOSDetails(String client) throws RemoteException
{
System.out.println("PiInfoService:getOSDetails("+ client +") called.");
PiTriInfo info = new PiTriInfo(
new PiPairInfo("os.name", System.getProperty("os.name")),
new PiPairInfo("os.arch", System.getProperty("os.arch")),
new PiPairInfo("os.version", System.getProperty("os.version")));
return info;
}
@Override
public String getDataModel(String client) throws RemoteException
{
System.out.println("PiInfoService:getDataModel("+ client +") called.");
return System.getProperty("sun.arch.data.model");
}
@Override
public String getJavaVersion(String client) throws RemoteException
{
System.out.println("PiInfoService:getJavaVersion("+ client +") called.");
return System.getProperty("java.version");
}
@Override
public String getEndian(String client) throws RemoteException
{
return System.getProperty("sun.cpu.endian");
}
@Override
public PiTriInfo getUserDetails(String client) throws RemoteException
{
System.out.println("PiInfoService:getUserDetails("+ client +") called.");
PiTriInfo info = new PiTriInfo(
new PiPairInfo("user.name", System.getProperty("user.name")),
new PiPairInfo("user.home", System.getProperty("user.home")),
new PiPairInfo("user.dir", System.getProperty("user.dir")));
return info;
}
@Override
public String getHostName(String client) throws RemoteException
{
System.out.println("PiInfoService:getHostName("+ client +") called.");
try
{
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException ex)
{
return "Unknown";
}
}
}
/*
* Pi RMI.
* © G J Barnard 2013 - Attribution-NonCommercial-ShareAlike 3.0 Unported - http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB.
*/
package pirmi;
import java.io.Serializable;
/**
* Wrapper class the key-value pairs found in system properties. Must be
* 'Serializable' so that it can be sent over a stream - i.e. RMI call.
*
* @author G J Barnard
*/
public class PiPairInfo implements Serializable
{
private String key, value;
public PiPairInfo(String key, String value)
{
this.key = key;
this.value = value;
}
public String getKey()
{
return key;
}
public String getValue()
{
return value;
}
}
/*
* Pi RMI.
* © G J Barnard 2013 - Attribution-NonCommercial-ShareAlike 3.0 Unported - http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB.
*/
package pirmi;
import java.io.Serializable;
/**
* Wrapper class for three PiPairInfo's. Must be 'Serializable' so that it can
* be sent over a stream - i.e. RMI call.
*
* @author G J Barnard
*/
public class PiTriInfo implements Serializable
{
private PiPairInfo one, two, three;
public PiTriInfo(PiPairInfo one, PiPairInfo two, PiPairInfo three)
{
this.one = one;
this.two = two;
this.three = three;
}
public PiPairInfo getOne()
{
return one;
}
public PiPairInfo getTwo()
{
return two;
}
public PiPairInfo getThree()
{
return three;
}
}
/*
* Pi RMI.
* © G J Barnard 2013 - Attribution-NonCommercial-ShareAlike 3.0 Unported - http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB.
*/
grant
{
permission java.security.AllPermission; // AllPermission for simplicity here - see http://docs.oracle.com/javase/7/docs/technotes/guides/security/permissions.html.
};
java -Djava.security.policy="./pirmi/Policy" pirmi.PiInfoClient %1
java -Djava.security.policy="./pirmi/Policy" pirmi.PiInfoClient $1
java -Djava.rmi.server.hostname="Enter IP here" -Djava.security.policy="./pirmi/Policy" pirmi.PiInfoServer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment