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}