package mj.ocraptor.rmi_client;
import static mj.ocraptor.database.dao.ResultError.NOT_SUPPORTED;
import static mj.ocraptor.database.dao.ResultError.PARSING;
import static mj.ocraptor.database.dao.ResultError.TIMEOUT;
import java.io.File;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import mj.ocraptor.configuration.Config;
import mj.ocraptor.database.dao.FileEntry;
import mj.ocraptor.file_handler.TextExtractorSub;
import mj.ocraptor.rmi_server.RMIServer;
import mj.ocraptor.tools.SystemTools;
public class RMIClientImpl implements RMIClient {
// ------------------------------------------------ //
/**
* Let's test some shit!
*
* @throws RemoteException
*/
public static void main(String[] args) {
if (args == null || args.length < 2) {
throw new NullPointerException("Two arguments expected [0]=clientId, [1]=port");
}
try {
final String clientID = args[0];
final Integer port = Integer.valueOf(args[1]);
RMIClientImpl client = RMIClientImpl.init(clientID, port);
client.connect();
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
// ------------------------------------------------ //
// *INDENT-OFF*
private String id;
private RMIServer server = null;
private boolean busy;
private Integer port;
private File currentFile;
final Long clientXmx;
// *INDENT-ON*
private static RMIClientImpl rmiClient;
// *INDENT-OFF*
private int
countConnectionErrors = 0,
amountOfExtractionsBeforeRestart = 1,
extractionsCounter = 0;
// *INDENT-ON*
// ------------------------------------------------ //
/**
*
*
* @return
*/
public static RMIClientImpl instance() {
if (rmiClient == null) {
throw new NullPointerException("RMI Client instance is null");
}
return rmiClient;
}
/**
*
*
* @param id
* @param port
* @return
*
* @throws RemoteException
*/
public static RMIClientImpl init(final String id, final Integer port) throws RemoteException {
rmiClient = new RMIClientImpl(id, port);
return rmiClient;
}
/**
* @param id
* @param port
* @throws RemoteException
*
*/
private RMIClientImpl(final String id, final Integer port) throws RemoteException {
this.id = id;
this.port = port;
UnicastRemoteObject.exportObject(this, 0);
clientXmx = SystemTools.getXmxParameterInMB();
if (clientXmx != null && clientXmx < 512) {
amountOfExtractionsBeforeRestart = 1;
} else {
amountOfExtractionsBeforeRestart = 10;
}
}
/**
*
*
* @return
* @throws RemoteException
*/
public void connect() throws RemoteException {
// ------------------------------------------------ //
try {
Thread.currentThread().setName(Config.APP_NAME + "RMIClient start thread");
Registry reg = LocateRegistry.getRegistry(Config.SERVER_HOST, port);
this.server = (RMIServer) reg.lookup(Config.SERVER_NAME);
this.server.addClient(this);
this.monitor();
// throw new RemoteException();
} catch (Exception e) {
e.printStackTrace();
this.shutdown();
}
// ------------------------------------------------ //
}
/**
*
*
*/
@Override
public void shutdown() throws RemoteException {
try {
if (this.server != null)
if (Config.inst().isClientDelayedShutdown()) {
final FileEntry timeoutResult = new FileEntry(currentFile);
timeoutResult.setError(TIMEOUT);
this.server.transmitResult(this, timeoutResult);
}
this.server.removeClient(this);
} catch (Exception e) {
} finally {
System.exit(0);
}
}
@Override
public String getID() throws RemoteException {
return this.id;
}
@Override
public void handleFile(final File file) throws RemoteException {
if (file != null) {
this.currentFile = file;
new Thread(new FileProcessor(this, file)).start();
} else {
this.server.sendDebugError(this, "Given filepath is null!", null, false);
}
}
@Override
public void init(Config config) throws RemoteException {
if (config != null) {
try {
Config.init(config);
} catch (Exception e) {
this.server.sendDebugError(this, "Config init error", e, false);
e.printStackTrace();
}
}
}
/**
*
*/
private class FileProcessor implements Runnable {
private File file;
private RMIClient client;
/**
*
*/
public FileProcessor(RMIClient client, File file) {
this.file = file;
this.client = client;
}
@Override
public void run() {
Thread.currentThread().setName(Config.APP_NAME + "RMIClientImpl: Textextraction");
try {
busy = true;
FileEntry result = null;
// ------------------------------------------------ //
if (file.exists() && file.canRead() && file.isFile()) {
try {
final TextExtractorSub extractor = new TextExtractorSub();
result = extractor.extractTextTika(file);
// if the filetype was not supported,
// do not count it as a text extraction
if (result != null && !result.getFullTextString().equals(NOT_SUPPORTED.getErrorCode())) {
extractionsCounter++;
}
} catch (Exception e) {
result = new FileEntry(file);
result.setError(PARSING);
server.sendDebugError(client, "Textextraction failed: " + file, e, false);
e.printStackTrace();
}
} else {
server.sendDebugError(client, "Given file is not valid: " + file, null, false);
}
// ------------------------------------------------ //
server.transmitResult(this.client, result);
} catch (RemoteException e) {
e.printStackTrace();
try {
shutdown();
} catch (RemoteException e1) {
}
} finally {
boolean memoryRunsOut = false;
// TODO: more testing
if (clientXmx != null && clientXmx > 0) {
final long freeMemory = SystemTools.getRuntimeFreeMemoryInMB();
final double totalMemory = (double) SystemTools.getRuntimeTotalMemoryInMB();
memoryRunsOut = freeMemory < 100 && ((totalMemory / (double) clientXmx) > 0.6);
// try {
// server.sendDebugError(client, "Memory footprint: " + freeMemory +
// "mb, " + totalMemory
// + "mb, " + memoryRunsOut, null);
// } catch (RemoteException e) {
// }
}
if (extractionsCounter >= amountOfExtractionsBeforeRestart || memoryRunsOut) {
try {
shutdown();
} catch (RemoteException e1) {
}
} else {
busy = false;
}
}
}
}
/**
* @throws RemoteException
*
*
*/
private void monitor() throws RemoteException {
while (countConnectionErrors < 4) {
try {
if (this.server == null) {
System.exit(0);
}
Thread.sleep(500);
if (this.server != null) {
this.server.ping(this);
}
} catch (RemoteException e) {
this.countConnectionErrors++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
shutdown();
}
@Override
public void ping() throws RemoteException {
}
/**
* @return the server
*/
public RMIServer getServer() {
return server;
}
@Override
public boolean isBusy() throws RemoteException {
return this.busy;
}
/**
* @param delay
*
* @throws RemoteException
*/
@Override
public void shutdownDelayed(final int delay) throws RemoteException {
Config.inst().setClientDelayedShutdown(true);
new Thread(new ShutdownWorker(delay)).start();
}
/**
*
*/
private class ShutdownWorker implements Runnable {
public ShutdownWorker(final int delay) {
Thread.currentThread().setName(Config.APP_NAME + "ShutdownWorker-Thread");
try {
Thread.sleep(delay);
shutdown();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
}
}
/**
*
*
* @param msg
* @param e
* @param consoleOnly
*/
public void sendDebugInfoToServer(final String msg, final Throwable e, final boolean consoleOnly) {
try {
this.server.sendDebugInfo(this, msg, e, true);
} catch (RemoteException e1) {
}
}
/**
*
*
* @param msg
* @param e
* @param consoleOnly
*/
public void sendDebugErrorToServer(final String msg, final Throwable e, final boolean consoleOnly) {
try {
this.server.sendDebugError(this, msg, e, true);
} catch (RemoteException e1) {
}
}
}