org.jclarion.clarion.swing.gui.NetworkModel Maven / Gradle / Ivy
package org.jclarion.clarion.swing.gui;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import org.jclarion.clarion.Clarion;
import org.jclarion.clarion.ClarionRandomAccessFile;
import org.jclarion.clarion.constants.Icon;
import org.jclarion.clarion.runtime.CConfigImpl;
import org.jclarion.clarion.runtime.CWin;
/**
* Represent a network node
*
* Actual work is deferred to supplied underlying model
*
* @author barney
*
*/
public class NetworkModel extends GUIModel implements Runnable
{
private GUIModel local;
private RemoteNetwork network;
private InputStream in;
private OutputStream out;
private Thread reader;
private TaskProcessor processor;
private String name;
private boolean shutdown=false;
private LinkedList tasks = new LinkedList();
private boolean runShutdownActivities=true;
public static final int VERSION=2;
private class TaskProcessor extends Thread
{
public TaskProcessor(String name)
{
super(name);
}
public void run()
{
processTasks();
}
}
public NetworkModel()
{
}
@SuppressWarnings("unchecked")
public K getWidget(K aWidget)
{
return (K)network.getWidget(aWidget.getID());
}
public NetworkModel(GUIModel local,RemoteNetwork network,InputStream in,OutputStream out)
{
init(local,network,in,out);
}
public void doNotRunShutdownActivities()
{
runShutdownActivities=false;
}
public void init(GUIModel local,RemoteNetwork network,InputStream in,OutputStream out)
{
name = local.getClass().getName();
name=name.substring(name.lastIndexOf('.')+1);
this.local=local;
this.network=network;
this.out=new BufferedOutputStream(out);
this.in=in;
//this.in=new InputStreamCounter(in);
reader=new Thread(this,name+" Reader");
reader.start();
processor = new TaskProcessor(name+" Processor");
processor.start();
try {
out.write(VERSION);
} catch (IOException ex) {
handleException(ex);
}
}
public Thread getReaderThread()
{
return reader;
}
public NetworkModel(RemoteNetwork network,OutputStream out)
{
this.network=network;
this.out=out;
}
@Override
public void send(RemoteWidget w, int command, Object... params)
{
try {
synchronized(out) {
if (shutdown) throw new NetworkError();
network.writeCommand(out,command,false,null,w,params);
}
} catch (IOException e) {
handleException(e);
}
}
@Override
public void send(RemoteWidget w, ResponseRunnable nextTask, int command,Object... params) {
try {
synchronized(out) {
if (shutdown) throw new NetworkError();
network.writeCommand(out,command,true,nextTask,w,params);
}
} catch (IOException e) {
handleException(e);
}
}
@Override
public void send(RemoteSemaphore rs, Object result)
{
try {
synchronized(out) {
if (shutdown) throw new NetworkError();
network.notifySemaphore(out,rs,result);
}
} catch (IOException e) {
handleException(e);
}
}
@Override
public Object sendRecv(RemoteWidget w, int command, Object... params)
{
if (Thread.currentThread()==this.processor) {
throw new IllegalStateException("Network processor wants to block on remote response. This is a deadlock risk!");
}
try {
RemoteResponse rr;
synchronized(out) {
if (shutdown) throw new NetworkError();
rr=network.writeCommand(out,command,true,null,w,params);
}
Object o = rr.waitForResponse();
return o;
} catch (IOException e) {
handleException(e);
return null;
}
}
@Override
public void run() {
//System.out.println("START "+name);
try {
int version = in.read();
if (version==-1) {
shutdown();
return;
}
if (version!=VERSION) {
if (local instanceof LocalClient) {
CWin.message(
Clarion.newString("Incompatible client/server versions. Network GUI cannot run"),
Clarion.newString("Network GUI"),
Icon.HAND
);
}
shutdown();
return;
}
} catch (IOException ex) {
handleException(ex);
}
while ( true ) {
try {
final RemoteCommand c = network.readCommand(in,this,false);
if (c==null) break;
//System.out.println(c);
//in.resetCounter();
synchronized(tasks) {
tasks.add(c);
tasks.notifyAll();
}
} catch (IOException ex) {
handleException(ex);
break;
} catch (Exception e) {
e.printStackTrace();
}
}
shutdown();
}
public void processTasks()
{
main: while(true) {
final RemoteCommand c;
synchronized(tasks) {
while (tasks.isEmpty()) {
if (shutdown) break main;
try {
tasks.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
c=tasks.removeFirst();
}
try {
if (c.command==RemoteNetwork.COMMAND_RESPONSE) {
network.processResponse(c);
continue;
}
if (c.source==null) {
continue;
}
if (c.response!=0) {
//if (c.response>32767) {
// run and async followup.
ResponseRunnable rr=new ResponseRunnable() {
@Override
public void run(Object result) {
try {
synchronized(out) {
if (shutdown) return;
network.writeResponse(out,c,result);
}
} catch (IOException e) {
handleException(e);
}
}
};
local.send(c.source,rr,c.command,c.params);
/*} else {
// want a fast reply
Object o = local.sendRecv(c.source,c.command,c.params);
synchronized(out) {
if (!shutdown) {
network.writeResponse(out,c,o);
}
}
}*/
} else {
local.send(c.source,c.command,c.params);
}
/*} catch (IOException ex) {
ex.printStackTrace();
shutdown();
return;*/
} catch (RuntimeException ex) {
ex.printStackTrace();
}
}
if (!runShutdownActivities) return;
if (GUIModel.getClient() instanceof LocalClient ) {
if (network.testMemoryUsage("local")) {
CWin.message(Clarion.newString("Connection Lost"),
Clarion.newString("Local Connection"),
Icon.CONNECT
);
System.exit(0);
}
}
if (GUIModel.getServer() instanceof LocalServer ) {
CWin.getInstance().shutdown();
}
}
public void shutdown()
{
synchronized(out) {
if (shutdown) return;
shutdown=true;
out.notifyAll();
}
try {
out.close();
} catch (IOException ex) { }
try {
in.close();
} catch (IOException ex) { }
synchronized(tasks) {
tasks.notifyAll();
}
network.shutdown();
}
private void handleException(IOException ex)
{
ex.printStackTrace();
shutdown();
throw new NetworkError(ex);
}
public String toString()
{
return "NetworkModel:"+name;
}
@Override
public ClarionRandomAccessFile getFile(String name) throws FileNotFoundException
{
return new NetworkedFile(name,network.getNextID());
}
@Override
public void dispose(RemoteSemaphore rs) {
network.dispose(rs);
}
@Override
public void dispose(RemoteWidget w) {
network.dispose(w);
}
public boolean testMemoryUsage()
{
return network.testMemoryUsage(this.name);
}
public void cleanup() {
network.cleanup();
}
private Map config=new HashMap();
@Override
public CConfigImpl getConfig(String name) {
if ((GUIModel.getServer() instanceof LocalServer) && !name.equals("db.properties") ) {
synchronized(config) {
RemoteConfig rc = config.get(name);
if (rc==null) {
rc=new RemoteConfig(name);
config.put(name, rc);
}
return rc;
}
}
return super.getConfig(name);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy