001    
002    package gui;
003    
004    import java.util.Random;
005    import java.io.IOException;
006    import java.io.Serializable;
007    
008    import java.awt.event.ActionListener;
009    import java.awt.event.ActionEvent;
010    
011    import javax.swing.Timer;
012    //import javax.swing.SwingUtilities;
013    
014    import comm.ExecutableServer;
015    import thread.ThreadPool;
016    import comm.ChannelFactory;
017    import comm.SocketChannel;
018    import comm.RemoteExecutable;
019    import algo.Point;
020    import algo.Graph;
021    import algo.Path;
022    import algo.PathByteArray;
023    import algo.PlaneGraph;
024    import algo.TSPInf;
025    import algo.DistTSP;
026    import algo.ParByteLocalTSP;
027    import algo.SeqByteTSP;
028    
029    /**
030     * Model class to be viewed and controled by the GUI.
031     * @author Heinz Kredel.
032     */
033    public class TSPguiModel  {
034    
035        protected String algorithm = "sequential";
036        protected int algo = 0;
037        protected String server = "localhost";
038        protected int port = 9000;
039        protected boolean standAlone = false;
040        protected ExecutableServer es = null;
041    
042    
043        protected int probSize;
044        protected Point[] points = null;
045        protected Graph graph = null;
046        protected Point[] scaledPoints = null;
047        protected boolean isBestPath = false;
048        protected Path bestPath = null;
049        protected Path actualBestPath = null;
050        protected long iter;
051        protected long maxIter;
052        protected int numThread;
053        protected double iterPercent;
054    
055        protected boolean done;
056        private TSPModelConnectThread thread = null;
057        private Timer wecker = null;
058        private TSPguiUpdate updater = null;
059        
060        public TSPguiModel() {
061            probSize = 12;
062            done = false;
063            iter = 0l;
064            maxIter = Long.MAX_VALUE;
065            numThread = 1;
066            iterPercent = 0.0;
067        }
068    
069        public void generateProblem() {
070            assureStopped();
071            points = new Point[probSize];
072            double m = 100;
073            Random r = new Random();
074            double mx = 0.0;
075            for ( int i = 0; i < probSize; i++ ) {
076                Point p = Point.random(i,r,m);
077                points[i] = p;
078                if ( p.x > mx ) {
079                       mx = p.x;
080                }
081                if ( p.y > mx ) {
082                       mx = p.y;
083                 }
084             }
085            graph = new PlaneGraph(points);
086            scaledPoints = new Point[probSize];
087            double scale = 1.0 / mx;
088            for ( int i = 0; i < probSize; i++ ) {
089                scaledPoints[i] = Point.scaleTo(points[i],scale);
090            }
091            iter = 0l;
092            bestPath = PathByteArray.standardPath(graph);
093            actualBestPath = bestPath;
094            isBestPath = false;
095            doStatus();
096        }
097    
098        public void solveProblem() {
099            if ( points == null ) {
100                return;
101            }
102            assureStopped();
103            if ( standAlone && "localhost".equals(server) ) {
104                if ( es == null ) {
105                    es = new ExecutableServer(port);
106                    System.out.println("es = "+es);
107                    es.start();
108                }
109            }
110            thread = new TSPModelConnectThread(points,
111                                               algo,
112                                               numThread,
113                                               maxIter,
114                                               server,
115                                               port,
116                                               this);
117            thread.start();
118        } 
119     
120    /**
121     * @return true if thread is running, else false.
122     */
123        public boolean isRunning() {
124            if ( thread == null ) {
125                return false;
126            }
127            return thread.isRunning();
128        }
129    
130        // todo: collect history
131        public void waitProblem() {
132            if ( thread == null ) {
133                    return;
134            }
135            try {
136                thread.join();
137                thread = null;
138            } catch (InterruptedException ignored) {
139            }
140            // doStatus();
141        } 
142    
143        public void assureStopped() {
144            if ( thread != null ) {
145                if ( thread.isRunning() ) {
146                   long curi = thread.getIterations() / numThread;
147                   thread.setMaxIterations(curi);
148                   //waitProblem();
149                   thread = null;
150                }
151            }
152        } 
153    
154        public void stopProblem() {
155            if ( thread == null ) {
156                    return;
157            }
158            ActionListener joiner = new ActionListener() {
159               public void actionPerformed(ActionEvent evt) {
160                   if ( wecker != null ) {
161                      wecker.stop();
162                   }
163                   assureStopped();
164               }
165            };
166            if ( wecker != null ) {
167                wecker.stop();
168            }
169            wecker = new Timer(100, joiner);
170            //wecker.setLogTimers(true);
171            wecker.setRepeats(false);
172            wecker.start();
173        } 
174    
175        
176    /**
177     * @return points of the cities.
178     */
179        public Point[] getPoints() {
180            return points;
181        }
182    
183    /**
184     * @return scaled points of the cities, i.e. all coordiates lie within 0.0 and 1.0.
185     */
186        public Point[] getScaledPoints() {
187           return scaledPoints;
188        }
189    
190    /**
191     * @return the graph.
192     */
193        public Graph getGraph() {
194            return graph;
195        }
196        
197    /** 
198     * @return true if the actual path is the best path, else false.
199     */
200        public boolean isBestPath() {
201            return isBestPath;
202        }
203    
204    /**
205     * @return return best path if known.
206     */
207        public Path getBestPath() {
208            if ( thread != null ) {
209               bestPath = thread.getBestPath();
210               isBestPath = thread.isBestPath();
211            }
212            return bestPath;
213        }
214    
215    /**
216     * @return return actual best path
217     */
218        public Path getActualBestPath() {
219            if ( thread != null ) {
220               actualBestPath = thread.getActualBestPath();
221               isBestPath = thread.isBestPath();
222            }
223            return actualBestPath;
224        }
225    
226    /**
227     * @return number of threads used.
228     */
229        public int getThreads() {
230            return numThread;
231        }
232    
233    /**
234     * @param n number of threads to be used.
235     */
236        public void setThreads(int n) {
237            numThread = n;
238        }
239    
240    /**
241     * @return iteration count.
242     */
243        public long getIterations() {
244            if ( thread != null ) {
245               iter = thread.getIterations();
246            }
247            return iter;
248        }
249    
250    /**
251     * @return maximal iteration count.
252     */
253        public long getMaxIterations() {
254            if ( thread != null ) {
255               maxIter = thread.getMaxIterations();
256            }
257            return maxIter;
258        }
259    
260    /**
261     * @return per centage of used iterations of total number of possible paths.
262     */
263        public double getIterPercent() {
264            iter = getIterations();
265            double ip = 100.0*((double)iter)/((double)facul(points.length-1));
266            iterPercent = ((int)(ip*100.0))/100.0;
267            return iterPercent;
268        }
269    
270    /**
271     * @param n input.
272     * @return n * facul( n-1 ).
273     */
274        protected long facul(long n) {
275            if ( n <= 1l ) {
276                return 1l;
277            }
278            return n * facul( n-1 );
279        }
280    
281    /**
282     * Set maximal iteration count.
283     * @param m new maximal iteration count.
284     * @return old maximal iteration count.
285     */
286        public long setMaxIterations(long m){
287            maxIter = m;
288            if ( thread == null ) {
289                   return 0l;
290            }
291            return thread.setMaxIterations(m);
292        }
293        
294    /**
295     * @return true if user requests exit.
296     */
297        public boolean isDone() {
298            return done;
299        }
300    
301        public synchronized void setDone() {
302            // do cleanup
303            assureStopped();
304            if ( es != null ) {
305                es.terminate();
306                try {
307                    es.join();
308                } catch (InterruptedException ignored) {
309                }
310            }
311            done = true;
312            notify();
313        }
314    
315        public synchronized void waitDone() {
316            if ( done ) {
317                   return;
318            }
319            try {
320                  wait(); 
321            } catch(InterruptedException ignored) {
322            }
323        }
324    
325    /**
326     * @return problem size, i.e. number of points / nodes / cities.
327     */
328        public int getProbSize() {
329            return probSize;
330        }
331    
332    /**
333     * @param s new problem size.
334     */
335        public void setProbSize(int s) {
336            probSize = s;
337        }
338    
339    /**
340     * @return the algorithm to be used.
341     */
342        public String getAlgorithm() {
343            return algorithm;
344        }
345    
346    /**
347     * @param alg the new algorithm to be used.
348     */
349        public void setAlgorithm(String alg) {
350            int a = -1;
351            if ( alg == null ) {
352                return;
353            }
354            if ( alg.compareToIgnoreCase("sequential") == 0 ) {
355                // setThreads(1); doUpdate();
356                a = 0;
357            }
358            if ( alg.compareToIgnoreCase("parallel") == 0 ) {
359                //if ( getThreads() <= 1 ) {
360                //   setThreads(4); doUpdate();
361                //}
362                a = 1;
363            }
364            if ( alg.compareToIgnoreCase("distributed") == 0 ) {
365                //if ( getThreads() <= 1 ) {
366                //   setThreads(2); doUpdate();
367                //}
368                a = 2;
369            }
370            if ( a >= 0 ) {
371                algo = a;
372                algorithm = alg;
373            }
374        }
375    
376    /**
377     * @return name of compute server.
378     */
379        public String getServer() {
380            return server;
381        }
382    
383    /**
384     * @param s name of compute server.
385     */
386        public void setServer(String s) {
387            server = s;
388        }
389    
390    /**
391     * @return port of compute server.
392     */
393        public int getPort() {
394            return port;
395        }
396    
397    /**
398     * @param p port of compute server.
399     */
400        public void setPort(int p) {
401            port = p;
402        }
403    
404    /**
405     * @return true if no remote compute server should be used.
406     */
407        public boolean getStandAlone() {
408            return standAlone;
409        }
410    
411    /**
412     * @param a true if no remote compute server should be used.
413     */
414        public void setStandAlone(boolean a) {
415            standAlone = a;
416        }
417    
418    /**
419     * @param u the TSPguiUpdate.
420     */
421        public void setUpdater(TSPguiUpdate u) {
422            updater = u;
423        }
424    
425        public void doUpdate() {
426            if ( updater != null ) {
427               updater.modelUpdated();
428            }
429        }
430    
431        public void doStatus() {
432            if ( updater != null ) {
433               updater.modelStatus();
434            }
435        }
436    
437    }
438    
439    /**
440     * Class to communicate with the thread on the compute server.
441     */
442    class TSPModelConnectThread extends Thread {
443    
444        private Point[] points;
445        private Path path;
446        private int numThread;
447        private int algo;
448        private long iter;
449        private long maxIter;
450        private long maxIterTemp;
451        private boolean isBestPath;
452        private String server = "localhost";
453        private int port = 9000;
454        private String guiHost = "localhost";
455        private int guiPort = 9009;
456        private int guiClientPort = port + 100;
457        private TSPguiModel model;
458        private ChannelFactory cf;
459        private SocketChannel comm = null;
460        private ThreadPool pool = null;
461        
462    
463    /**
464     * @param points array city coordinates.
465     * @param algo algorithm to use.
466     * @param threads number of thread to use.
467     * @param mit maximal iteration count.
468     * @param server host name of compute server.
469     * @param port of compute server.
470     * @param model the TSPguiModel.
471     */
472        public TSPModelConnectThread(Point[] points, 
473                                     int algo, 
474                                     int threads, 
475                                     long mit, 
476                                     String server,
477                                     int port,
478                                     TSPguiModel model) {
479            this.points = points;   
480            this.algo = algo;
481            this.numThread = threads;
482            this.model = model;
483            this.server = server;
484            this.port = port;
485            guiClientPort = port + 100;
486            path = null;
487            iter = 0l;
488            maxIter = mit;
489            isBestPath = false;
490            cf = new ChannelFactory(guiPort);
491            pool = new ThreadPool(3);
492        }
493    
494        /* (non-Javadoc)
495         * @see java.lang.Runnable#run()
496         */
497        public void run() {
498            SocketChannel sc = null;
499            try {
500                sc = cf.getChannel(server,port);
501            } catch (IOException e) {
502                e.printStackTrace();
503                cf.terminate();
504                return;
505            }
506            guiHost = sc.getSocket().getLocalAddress().getHostAddress();
507            // guiPort = sc.getSocket().getLocalPort();
508            //System.out.println("sc.getSocket() = " + sc.getSocket()
509            //                   + " guiHost = " + guiHost);
510    
511            TSPModelRemote thread = new TSPModelRemote(points,
512                                                       algo,
513                                                       numThread,
514                                                       maxIter,
515                                                       guiHost,
516                                                       guiPort,
517                                                       guiClientPort);
518            try {
519                sc.send( thread );
520            } catch (IOException e) {
521                e.printStackTrace();
522                sc.close();
523                cf.terminate();
524                return;
525            }
526            try {
527                  comm = cf.getChannel(server,guiClientPort); // wg firewall
528               // comm = cf.getChannel(); // @ guiPort
529            } catch (IOException e) {
530                e.printStackTrace();
531                sc.close();
532                cf.terminate();
533                return;
534            }
535            Object o = null;
536            try {
537                o = sc.receive();
538            } catch (IOException e) {
539                e.printStackTrace();
540            } catch (ClassNotFoundException e) {
541                e.printStackTrace();
542            }
543            if ( o != null ) {
544               if ( o instanceof String ) {
545                  String s = (String)o;
546                  if ( s.equals(ExecutableServer.DONE) ) {
547                     System.out.println("normal end");
548                  }
549               }
550            }
551            sc.close();
552            cf.terminate();
553            model.doStatus();
554        }
555    
556    /**
557     * @return true if thread is runnning.
558     */
559        public boolean isRunning() {
560            return (comm != null);
561        }
562    
563    /**
564     * @return true if path is best path, else false.
565     */
566        public boolean isBestPath() {
567            // communication done by getActualBestPath
568            return isBestPath; 
569        }
570    
571    /**
572     * @return iteration count.
573     */
574        public long getIterations() {
575            // communication done by getActualBestPath
576            return iter; 
577        }
578    
579    /**
580     * @return actual best path.
581     */
582        public Path getActualBestPath() {
583            if ( comm == null ) {
584                   return path;
585            }
586            Runnable getter = new Runnable() {
587                  public void run() {
588                      Object o = sendReceive( new TransportContainer() );
589                      if ( o != null ) {
590                         if ( o instanceof TransportContainerGet ) {
591                            TransportContainerGet t = (TransportContainerGet)o;
592                            path       = t.path;
593                            iter       = t.iter;
594                            isBestPath = t.best;
595                         }
596                      }
597                  }
598                };
599            pool.addJob( getter );
600            return path; // tsp.actualBest();
601        }
602    
603    /**
604     * @return best known path.
605     */
606        public Path getBestPath() {
607            if ( comm == null ) {
608                   return path;
609            }
610            Runnable getter = new Runnable() {
611                  public void run() {
612                      Object o = sendReceive( new TransportContainer() );
613                      if ( o != null ) {
614                         if ( o instanceof TransportContainerGet ) {
615                            TransportContainerGet t = (TransportContainerGet)o;
616                            path       = t.path;
617                            iter       = t.iter;
618                            isBestPath = t.best;
619                         }
620                      }
621                  }
622                };
623            pool.addJob( getter );
624            return path; // tsp.getBest();
625        }
626    
627    /**
628     * @return maximal iteration count.
629     */
630        public long getMaxIterations() {
631            if ( comm == null ) {
632                   return maxIter;
633            }
634            Runnable getter = new Runnable() {
635                  public void run() {
636                      Object o = sendReceive( new TransportContainerMax(maxIter) );
637                      if ( o != null ) {
638                         if ( o instanceof TransportContainerMax ) {
639                            TransportContainerMax t = (TransportContainerMax)o;
640                            maxIter = t.maxIter;
641                         }
642                      }
643                  }
644                };
645            pool.addJob( getter );
646            return maxIter; // tsp.getmaxIterations();
647        }
648    
649    /**
650     * @param m new maximal iteration count.
651     * @return old maximal iteration count.
652     */
653        public long setMaxIterations(final long m){
654            maxIterTemp = maxIter;
655            maxIter = m;
656            if ( comm == null ) {
657                   return maxIterTemp;
658            }
659            Runnable getter = new Runnable() {
660                  public void run() {
661                      Object o = sendReceive( new TransportContainerMax(maxIter) );
662                      if ( o != null ) {
663                         if ( o instanceof TransportContainerMax ) {
664                            TransportContainerMax t = (TransportContainerMax)o;
665                            maxIterTemp = t.maxIter;
666                         }
667                      }
668                  }
669                };
670            pool.addJob( getter );
671            return maxIterTemp; // tsp.setMaxIterations(m);
672        }
673    
674    /**
675     * RPC style communication.
676     * @param m a TransportContainer.
677     * @return received Object.
678     */
679        protected Object sendReceive(TransportContainer m) {
680            Object r = null;
681            try {
682                //synchronized( comm ) {
683                comm.send( m );
684                //}
685                r = comm.receive();
686            } catch (IOException e) {
687                //e.printStackTrace();
688            } catch (ClassNotFoundException e) {
689                //e.printStackTrace();
690            }
691            return r;
692        }
693    
694    }
695    
696    
697    /**
698     * Objects send to the compute server to execute TSP algorithm.
699     */
700    class TSPModelRemote implements RemoteExecutable {
701    
702        private Point[] points;
703        private Path path;
704        private int threads;
705        private int algo;
706        private TSPInf tsp = null;
707        private long iter;
708        private long maxIter;
709        private boolean isBestPath;
710        private String guiHost = "localhost";
711        private int guiPort = 9009;
712        private int guiClientPort = 9100;
713        
714    /**
715     * @param points array of cities.
716     * @param algo algorithm.
717     * @param threads number of threads.
718     * @param mit maximal iterations.
719     * @param guiHost host name of gui server. Unused because of firewalls.
720     * @param guiPort port of gui server. Unused because of firewalls.
721     * @param guiClientPort port at compute server.
722     */
723        public TSPModelRemote(Point[] points, 
724                              int algo, 
725                              int threads, 
726                              long mit, 
727                              String guiHost,
728                              int guiPort,
729                              int guiClientPort) {
730            this.points = points;   
731            this.algo = algo;
732            this.threads = threads;
733            this.guiHost = guiHost;
734            this.guiPort = guiPort;
735            this.guiClientPort = guiClientPort;
736            path = null;
737            iter = 0l;
738            maxIter = mit;
739            isBestPath = false;
740        }
741    
742        public void run() {
743            TSPModelCommRemote communi = new TSPModelCommRemote(this,
744                                                                guiHost,
745                                                                guiPort,
746                                                                guiClientPort);
747            communi.start();
748            switch ( algo ) {
749             case 0: tsp = new SeqByteTSP(points);
750                     break;
751             case 1: tsp = new ParByteLocalTSP(points,threads);
752                     break;
753             case 2: tsp = new DistTSP(points,threads);
754                     break;
755            default: tsp = new SeqByteTSP(points);
756            }
757            long mi = maxIter;
758            path = tsp.getBest(maxIter); // blocks
759            if ( mi <= maxIter ) {
760               isBestPath = true;
761               //System.out.println("isBestPath = " + isBestPath );
762            } 
763            // model.doStatus();
764            tsp = null;
765            communi.terminate();
766        }
767            
768    /**
769     * @return true if tsp is executing.
770     */
771        public boolean isRunning() {
772            return (tsp != null);
773        }
774    
775    /**
776     * @return best known path.
777     */
778        public Path getBestPath() {
779            return path;
780        }
781    
782    /**
783     * @return true if path is best path.
784     */
785        public boolean isBestPath() {
786            return isBestPath;
787        }
788    
789    /**
790     * @return actual best path.
791     */
792        public Path getActualBestPath() {
793            if ( tsp == null ) {
794                   return path;
795            }
796            return tsp.actualBest();
797        }
798    
799    /**
800     * @return iteration count.
801     */
802        public long getIterations() {
803            if ( tsp != null ) {
804               iter = tsp.getIterations();
805            }
806            return iter;
807        }
808    
809    /**
810     * @return maximal iteration count.
811     */
812        public long getMaxIterations() {
813            if ( tsp != null ) {
814               return tsp.getMaxIterations();
815            }
816            return maxIter;
817        }
818    
819    /**
820     * @param m new maximal iteration count.
821     * @return old maximal iteration count.
822     */
823        public long setMaxIterations(long m){
824            long x = maxIter;
825            maxIter = m;
826            if ( tsp != null ) {
827               x = tsp.setMaxIterations(m);
828            }
829            return x;
830        }
831    
832    }
833    
834    
835    /**
836     * Container for transport of path, iterations, etc.
837     */
838    class TransportContainer implements Serializable {
839        public TransportContainer() {
840        }
841    }
842    
843    /**
844     * Get message.
845     */
846    class TransportContainerGet extends TransportContainer {
847        final Path path;
848        final long iter;
849        final boolean best;
850    
851        /**
852         * @param p a path.
853         * @param i iteration count.
854         * @param b true if p is best path.
855         */
856        public TransportContainerGet(Path p, long i, boolean b) {
857            super();
858            path = p;
859            iter = i;
860            best = b;
861        }
862    }
863    
864    /**
865     * Set maximal iteration count message.
866     */
867    class TransportContainerMax extends TransportContainer {
868        final long maxIter;
869    
870        /**
871         * @param m maximal iteration count.
872         */
873        public TransportContainerMax(long m) {
874            super();
875            maxIter = m;
876        }
877    }
878    
879    
880    /**
881     * Class to communicate with the gui server.
882     */
883    class TSPModelCommRemote extends Thread {
884        /*
885        public static final String COMM_getActualBestPath = "getActualBestPath";
886        public static final String COMM_getBestPath       = "getBestPath";
887        public static final String COMM_getMaxIterations  = "getMaxIterations";
888        public static final String COMM_setMaxIterations  = "setMaxIterations";
889        */
890        private TSPModelRemote rem;
891        private SocketChannel comm;
892        private String guiHost = "localhost";
893        private int guiPort = 9009;
894        private int guiClientPort = 9100;
895    
896    /**
897     * @param rem master process for call back.
898     * @param guiHost host name of gui server. Unused because of firewalls.
899     * @param guiPort port of gui server. Unused because of firewalls.
900     * @param guiClientPort my local port for communication with gui.
901     */
902        public TSPModelCommRemote(TSPModelRemote rem,
903                                  String guiHost,
904                                  int guiPort,
905                                  int guiClientPort) {
906            this.rem = rem;
907            this.guiHost = guiHost;
908            this.guiPort = guiPort;
909            this.guiClientPort = guiClientPort;
910            ChannelFactory cf = new ChannelFactory(guiClientPort);
911            try {
912                //comm = cf.getChannel(guiHost,guiPort);
913                comm = cf.getChannel(); // wg. firewall
914            } catch (InterruptedException e) {
915                e.printStackTrace();
916                return;
917            }
918            cf.terminate();
919        }
920    
921        public void terminate() {
922            try { // wg isBestPath before comm.close()
923                Thread.sleep(200); 
924            } catch (InterruptedException e) { 
925            }
926            if ( comm != null ) {
927               comm.close();
928            }
929            try { 
930                while ( this.isAlive() ) {
931                      //System.out.print(".");
932                      this.interrupt(); 
933                      this.join(100);
934                }
935                //System.out.println("TSPModelCommRemote terminated");
936            } catch (InterruptedException e) { 
937            }
938        }
939    
940        public void run() {
941            if ( comm == null ) {
942                return;
943            }
944            while ( true ) { // protocoll: receive send
945                  Object m = null;
946                  try {
947                      m = comm.receive();
948                  } catch (IOException e) {
949                      //e.printStackTrace();
950                  } catch (ClassNotFoundException e) {
951                      e.printStackTrace();
952                  }
953                  //System.out.println("TSPModelCommRemote, receive = " + o);
954                  if ( m == null ) {
955                      break;
956                  }
957                  if ( ! (m instanceof TransportContainer) ) {
958                      break;
959                  }
960                  TransportContainer t = (TransportContainer)m;
961                  Object response = null;
962                  if ( t instanceof TransportContainerMax ) {
963                     TransportContainerMax x = (TransportContainerMax)t;
964                     long ml = x.maxIter;
965                     response = new TransportContainerMax(
966                                                      rem.setMaxIterations(ml)
967                                                         );
968                  } else {
969                     // TransportContainerGet g = (TransportContainerGet)t;
970                     response = new TransportContainerGet(
971                                                      rem.getActualBestPath(),
972                                                      rem.getIterations(),
973                                                      rem.isBestPath()
974                                                         );
975                     //} else if ( t instanceof TransportContainerGet ) {
976                  }
977                  try {
978                      comm.send( response );
979                  } catch (IOException e) {
980                      //e.printStackTrace();
981                      break;
982                  }
983            }
984            System.out.println("TSPModelCommRemote done");
985            comm.close();
986        }
987    
988    }