IM269 Coursework 3: HitServer.java
// IM269 - Coursework 3: RMI Client/Server
// Semester A, 7th December 1998
// Eamonn Martin (BSc Computing)
// Student ID: 96/D59682
// efm001@unl.ac.uk
// RMI Hit Counter Server
package hitter;
import java.io.*;
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.UnicastRemoteObject;
import java.text.*;
import java.util.*;
import hitter.HitCounter.Info;
// Static methods for reading and updating a hit-count properties file
class HitsLog {
private static final String
title = "# HitCounter Log File", // Log title
p_created = "created", // Creation date property
p_set = "", // Set-ID property
hitset = "Hit", // Hit-count set-ID
p_url = "url", // File URL property
p_hits = "hits"; // Hit-count property
// Return a DateFormat object to use for date conversions
private static DateFormat getDateFormat() {
return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
}
// Open and return an output stream for a new log-file
private static OutputStream logCreate(File log) throws IOException {
OutputStream o = new FileOutputStream(log); // Create new log
Lib.writeLine(title, o); // Write log title
return o;
}
// Create and initialize a new log file (if none already exists)
private static boolean logInit(String logfile) {
File f = new File(logfile);
OutputStream o = null;
boolean ok = true;
if (!f.exists()) try { // No log exists?
o = logCreate(f); // Create a log-file
PropertySet p = new PropertySet(); // Create log properties
String s = getDateFormat().format(new Date());
p.put(p_created, s); // Set creation date
p.save(o); // Save log properties
} catch (IOException e) {
ok = false;
} finally {
try { if (o!=null) o.close(); } catch (IOException e) {}
}
return ok;
}
// Return true if a property set represents the hit-counter for a URL
private static boolean isFileEntry(PropertySet p, String url) {
return !p.hasProperty(p_set, hitset) ? false :
!p.hasProperty(p_url, url) ? false : true;
}
// Update logfile by updating or appending an entry for file
public static int newHit(String url, String logfile) {
String tmpfile = logfile + ".tmp";
File f = new File(logfile), t = new File(tmpfile);
InputStream i = null;
OutputStream o = null;
int c = -1;
if (logInit(logfile)) try { // Log file exists?
i = new FileInputStream(f); // Existing log file
o = logCreate(t); // Updated log file
String s;
PropertySet p = new PropertySet(); // Entry properties
while (p.loadSet(i)) { // Get next set
if (isFileEntry(p, url)) { // Found url entry?
s = p.getProperty(p_hits);
c = Lib.intValue(s)+1; // Get new count
p.put(p_hits, "" + c); // Update property
}
p.save(o); // Write property set
}
if (c==-1) { // No entry for file?
p.put(p_set, hitset); // Property-set ID
p.put(p_url, url); // Set the URL
p.put(p_hits, "" + (c = 1)); // Initialize count
p.save(o); // Write property set
}
} catch (IOException e) {
c = -1;
} finally {
try { if (o!=null) o.close(); } catch (IOException e) {}
try { if (i!=null) i.close(); } catch (IOException e) {}
}
if (c!=-1) { // Delete logfile, rename tmpfile
if (f.exists()) if (!f.delete()) c = -1;
if (c!=-1) if (!t.renameTo(f)) c = -1;
}
return c;
}
// Return log info (all properties not within a named set) from logfile
private static Properties logInfo(String logfile) {
PropertySet globals = new PropertySet(); // Global properties
InputStream i = null;
try {
i = new FileInputStream(logfile); // Open log-file
PropertySet p = new PropertySet();
while (p.loadSet(i)) // Load next set
if (p.getProperty("")==null) // Untitled set?
globals.addProperties(p);
} catch (IOException e) {}
finally {
try { if (i!=null) i.close(); } catch (IOException e) {}
}
return globals;
}
// Update the hit-count for url (if !null) and return info from the log-file
public static Info getInfo(String url, String logfile) {
if (!logInit(logfile)) return null; // Check/create log
Info i = new Info(); // Create Info object
i.logfile = logfile; // Set log-file name
Properties p = logInfo(logfile); // Get global log info
String s = p.getProperty(p_created); // Get creation date
if (s==null) return null; // No date = not a log
try { i.created = getDateFormat().parse(s); } // Parse date string
catch (ParseException e) {}
if (url!=null) { // URL specified?
i.url = url; // Set target URL
i.hits = newHit(url, logfile); // Get URL hit-count
}
return i;
}
// Display the results of a local test (update local log - no RMI)
public static void test(String url, String log) {
Info i = getInfo(url, log);
if (i==null) return;
System.out.println("Log File.: " + i.logfile);
System.out.println("Created..: " + getDateFormat().format(i.created));
System.out.println("URL......: " + i.url);
System.out.println("Hits.....: " + i.hits);
}
}
// HitCounter RMI Server Implementation
public class HitServer extends UnicastRemoteObject implements HitCounter {
private static final String name = "HitCounter"; // RMI registry name
private static String log = "hits.log"; // Default log-file
// Remote constructor
public HitServer() throws RemoteException { super(); }
// Update and return the hit-count for a URL (no log-info)
public int getHits(String url, String log) throws RemoteException {
return HitsLog.newHit(url, (log!=null) ? log : this.log);
}
// Update the hit-count for a URL and return info from the log-file
public Info getInfo(String url, String log) throws RemoteException {
return HitsLog.getInfo(url, (log!=null) ? log : this.log);
}
// Create and register a HitServer object with the local RMI registry
public static void main(String args[]) {
System.setSecurityManager(new RMISecurityManager());
if (args.length > 0) log = args[0]; // Change default log?
if (args.length > 1) HitsLog.test(args[1], log);// Local test?
else try { // Start server
Registry r = LocateRegistry.getRegistry();
HitServer obj = new HitServer(); // Create a HitServer
r.rebind(name, obj); // Bind in registry
System.out.println(name + " bound in registry");
} catch (Exception e) {
System.out.println(name + " error: " + e.getMessage());
e.printStackTrace();
}
}
}
Go To: IM269: Programming The Internet