Skip to content

Instantly share code, notes, and snippets.

@gjb2048
Last active August 29, 2015 14:16
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/63a5c0f0e2cfd7043774 to your computer and use it in GitHub Desktop.
Save gjb2048/63a5c0f0e2cfd7043774 to your computer and use it in GitHub Desktop.
PiRMI Version two.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project default="create_run_jar" name="Create Runnable Jar for PiRMI" basedir=".">
<tstamp>
<format property="TODAY" pattern="yyyy-MM-dd HH:mm:ss" />
</tstamp>
<property name="version.num" value="1" />
<buildnumber file="build.num" />
<!-- No RMIC: http://docs.oracle.com/javase/8/docs/api/java/rmi/server/UnicastRemoteObject.html -->
<!-- Standard Directory Identifiers-->
<property name="java.src.dir" value="${basedir}/src/pirmi/" />
<property name="java.dest.dir" value="${basedir}/build/" />
<property name="java.dist.dir" value="${basedir}/dist/" />
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${java.dest.dir}"/>
</target>
<!-- Compile -->
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${java.src.dir} into ${java.dest.dir} -->
<javac srcdir="${java.src.dir}" destdir="${java.dest.dir}" includeantruntime="false"/>
</target>
<target name="PiInfoClient" depends="compile">
<jar destfile="${java.dist.dir}Client.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class" value="pirmi.client.PiInfoClient" />
<attribute name="Class-Path" value="." />
<attribute name="Built-Date" value="${TODAY}" />
<attribute name="Implementation-Title" value="Pi Info Client" />
<attribute name="Implementation-Version" value="${version.num}-b${build.number}" />
<attribute name="Built-By" value="G J Barnard" />
</manifest>
<fileset dir="${java.dest.dir}" excludes="**/info/*, **/pirmi/server/*" />
</jar>
</target>
<target name="PiInfoServer" depends="compile">
<jar destfile="${java.dist.dir}Server.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class" value="pirmi.server.PiInfoServer" />
<attribute name="Class-Path" value="." />
<attribute name="Built-Date" value="${TODAY}" />
<attribute name="Implementation-Title" value="Pi Info Server" />
<attribute name="Implementation-Version" value="${version.num}-b${build.number}" />
<attribute name="Built-By" value="G J Barnard" />
</manifest>
<fileset dir="${java.dest.dir}" excludes="**/info/*, **/pirmi/client/*" />
</jar>
</target>
<target name="create_run_jar" depends="PiInfoClient, PiInfoServer">
</target>
<target name="clean"
description="clean up" >
<delete dir="${java.dest.dir}"/>
<delete dir="${java.dist.dir}"/>
</target>
</project>
build.number=1
/*
* PiRMI.
* Copyright (C) 2015 Gareth J Barnard
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* Also see: http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
package pirmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.LinkedList;
/**
* 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 LinkedList<PiPairInfo> getOSDetails(String client) throws RemoteException;
public String getDataModel(String client) throws RemoteException;
public String getEndian(String client) throws RemoteException;
public LinkedList<PiPairInfo> getUserDetails(String client) throws RemoteException;
}
/*
* PiRMI.
* Copyright (C) 2015 Gareth J Barnard
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* Also see: http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
package pirmi.client;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.UnmarshalException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.security.AccessControlException;
import java.util.Iterator;
import java.util.LinkedList;
import pirmi.PiInfo;
import pirmi.PiPairInfo;
/**
* 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=\"./Policy\" -jar Client..jar 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));
LinkedList<PiPairInfo> osInfo = connection.getOSDetails(client);
System.out.println(serverName + "'s OS details are:");
displayPiPairInfoList(osInfo);
System.out.println(serverName + "'s data model is: " + connection.getDataModel(client));
System.out.println(serverName + "'s endian is: " + connection.getEndian(client));
LinkedList<PiPairInfo> userInfo = connection.getUserDetails(client);
System.out.println(serverName + "'s User details are:");
displayPiPairInfoList(userInfo);
}
catch (UnknownHostException | NotBoundException | MalformedURLException | RemoteException | ClassNotFoundException | AccessControlException ex)
{
ex.printStackTrace(System.err);
}
}
private void displayPiPairInfoList(LinkedList<PiPairInfo> info)
{
Iterator<PiPairInfo> it = info.iterator();
PiPairInfo current;
while (it.hasNext())
{
current = it.next();
System.out.println(" " + current.getKey() + " is: " + current.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"));
Registry registry = LocateRegistry.getRegistry(connectionHost, PiInfo.RMIRegistryPort);
/*
* This does the actual connection returning a reference to the
* server service if it suceeds.
*/
connection = (PiInfo) registry.lookup(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;
}
}
/*
* PiRMI.
* Copyright (C) 2015 Gareth J Barnard
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* Also see: http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
package pirmi.server;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import pirmi.PiInfo;
/**
* 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
{
// Create the service with the specified port.
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;
}
}
/*
* PiRMI.
* Copyright (C) 2015 Gareth J Barnard
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* Also see: http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
package pirmi.server;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;
import pirmi.PiInfo;
import pirmi.PiPairInfo;
/**
* This is the class that implements the service served by the server for the
* client. It extends UnicastRemoteObject -
* http://docs.oracle.com/javase/8/docs/api/java/rmi/server/UnicastRemoteObject.html
* - so that will serve RMI requests and thus the 'rmic' tool is not required.
*/
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 LinkedList<PiPairInfo> getOSDetails(String client) throws RemoteException
{
System.out.println("PiInfoService:getOSDetails("+ client +") called.");
LinkedList<PiPairInfo> info = new LinkedList<>();
info.add(new PiPairInfo("os.name", System.getProperty("os.name")));
info.add(new PiPairInfo("os.arch", System.getProperty("os.arch")));
info.add(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 LinkedList<PiPairInfo> getUserDetails(String client) throws RemoteException
{
System.out.println("PiInfoService:getUserDetails("+ client +") called.");
LinkedList<PiPairInfo> info = new LinkedList<>();
info.add(new PiPairInfo("user.name", System.getProperty("user.name")));
info.add(new PiPairInfo("user.home", System.getProperty("user.home")));
info.add(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";
}
}
}
/*
* PiRMI.
* Copyright (C) 2015 Gareth J Barnard
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* Also see: http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
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.
*
* I could have used the 'java.util.Properties' class instead to contain many
* properties but this class illustrates how you can create your own classes
* for use with RMI.
*
* @author G J Barnard
*/
public class PiPairInfo implements Serializable
{
private final 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;
}
}
/*
* PiRMI.
* Copyright (C) 2015 Gareth J Barnard
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* Also see: http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
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="./Policy" -jar ./dist/Client.jar %1
java -Djava.security.policy="./Policy" -jar ./dist/Client.jar $1
java -Djava.rmi.server.hostname="Enter IP / hostname here" -Djava.security.policy="./Policy" -jar ./dist/Server.jar
java -Djava.rmi.server.hostname="Enter IP / hostname here" -Djava.security.policy="./Policy" -jar ./dist/Server.jar
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment