001/* 002 * $Id: DistributedList.java 5789 2018-01-04 21:38:39Z kredel $ 003 */ 004 005package edu.jas.util; 006 007import java.io.IOException; 008import java.util.Iterator; 009//import java.util.Collection; 010import java.util.List; 011import java.util.ArrayList; 012import java.util.SortedMap; 013import java.util.TreeMap; 014 015import org.apache.log4j.Logger; 016 017//import edu.unima.ky.parallel.ChannelFactory; 018//import edu.unima.ky.parallel.SocketChannel; 019 020 021/** 022 * Distributed version of a List. 023 * Implemented with a SortedMap / TreeMap to keep the sequence order of elements. 024 * @author Heinz Kredel 025 */ 026 027public class DistributedList /* implements List not jet */ { 028 029 private static final Logger logger = Logger.getLogger(DistributedList.class); 030 031 032 protected final SortedMap<Counter,Object> theList; 033 034 protected final ChannelFactory cf; 035 036 protected SocketChannel channel = null; 037 038 protected Listener listener = null; 039 040 041 /** 042 * Constructor for DistributedList. 043 * @param host name or IP of server host. 044 */ 045 public DistributedList(String host) { 046 this(host,DistributedListServer.DEFAULT_PORT); 047 } 048 049 050 /** 051 * Constructor for DistributedList. 052 * @param host name or IP of server host. 053 * @param port of server. 054 */ 055 public DistributedList(String host,int port) { 056 this(new ChannelFactory(port+1),host,port); 057 } 058 059 060 /** 061 * Constructor for DistributedList. 062 * @param cf ChannelFactory to use. 063 * @param host name or IP of server host. 064 * @param port of server. 065 */ 066 public DistributedList(ChannelFactory cf,String host,int port) { 067 this.cf = cf; 068 cf.init(); 069 try { 070 channel = cf.getChannel(host,port); 071 } catch (IOException e) { 072 e.printStackTrace(); 073 } 074 logger.debug("dl channel = " + channel); 075 theList = new TreeMap<Counter,Object>(); 076 } 077 078 079 /** 080 * Constructor for DistributedList. 081 * @param sc SocketChannel to use. 082 */ 083 public DistributedList(SocketChannel sc) { 084 cf = null; 085 channel = sc; 086 theList = new TreeMap<Counter,Object>(); 087 } 088 089 090 /** 091 * List thread initialization and start. 092 */ 093 public void init() { 094 listener = new Listener(channel,theList); 095 listener.start(); 096 } 097 098 099 /** 100 * Terminate the list thread. 101 */ 102 public void terminate() { 103 if ( cf != null ) { 104 cf.terminate(); 105 //logger.warn("terminating " + cf); 106 } 107 if ( channel != null ) { 108 channel.close(); 109 } 110 //theList.clear(); 111 if ( listener == null ) { 112 return; 113 } 114 logger.debug("terminate " + listener); 115 listener.setDone(); 116 try { 117 while ( listener.isAlive() ) { 118 listener.interrupt(); 119 listener.join(100); 120 } 121 } catch (InterruptedException u) { 122 Thread.currentThread().interrupt(); 123 } 124 listener = null; 125 } 126 127 128 /** 129 * Get the internal list, convert from Collection. 130 */ 131 public List<Object> getList() { 132 return new ArrayList<Object>( theList.values() ); 133 } 134 135 136 /** 137 * Size of the (local) list. 138 */ 139 public int size() { 140 return theList.size(); 141 } 142 143 144 /** 145 * Add object to the list and distribute to other lists. 146 * Blocks until the object is send and received from the server 147 * (actually it blocks until some object is received). 148 * @param o 149 */ 150 public synchronized void add(Object o) { 151 int sz1 = theList.size() + 1; 152 try { 153 channel.send(o); 154 //System.out.println("send: "+o+" @ "+listener); 155 } catch (IOException e) { 156 e.printStackTrace(); 157 } 158 try { 159 while ( theList.size() < sz1 ) { 160 this.wait(100); 161 } 162 } catch (InterruptedException e) { 163 Thread.currentThread().interrupt(); 164 e.printStackTrace(); 165 } 166 } 167 168 169 /** 170 * Clear the List. 171 * caveat: must be called on all clients. 172 */ 173 public synchronized void clear() { 174 theList.clear(); 175 } 176 177 178 /** 179 * Is the List empty? 180 */ 181 public boolean isEmpty() { 182 return theList.isEmpty(); 183 } 184 185 186 /** 187 * List iterator. 188 */ 189 public Iterator iterator() { 190 return theList.values().iterator(); 191 } 192 193} 194 195 196/** 197 * Thread to comunicate with the list server. 198 */ 199 200class Listener extends Thread { 201 202 private SocketChannel channel; 203 204 private SortedMap<Counter,Object> theList; 205 206 private volatile boolean goon; 207 208 209 Listener(SocketChannel s, SortedMap<Counter,Object> list) { 210 channel = s; 211 theList = list; 212 } 213 214 215 void setDone() { 216 goon = false; 217 } 218 219 220 @Override 221 public void run() { 222 Counter n; 223 Object o; 224 goon = true; 225 while (goon) { 226 n = null; 227 o = null; 228 try { 229 n = (Counter) channel.receive(); 230 if ( this.isInterrupted() ) { 231 goon = false; 232 } else { 233 o = channel.receive(); 234 //System.out.println("receive("+n+","+o+" @ "+Thread.currentThread()); 235 if ( this.isInterrupted() ) { 236 goon = false; 237 } 238 theList.put(n,o); 239 } 240 } catch (IOException e) { 241 goon = false; 242 } catch (ClassNotFoundException e) { 243 e.printStackTrace(); 244 goon = false; 245 } 246 } 247 } 248 249}