KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > proactive > examples > c3d > C3DDispatcher


1 /*
2 * ################################################################
3 *
4 * ProActive: The Java(TM) library for Parallel, Distributed,
5 * Concurrent computing with Security and Mobility
6 *
7 * Copyright (C) 1997-2002 INRIA/University of Nice-Sophia Antipolis
8 * Contact: proactive-support@inria.fr
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
25 * Initial developer(s): The ProActive Team
26 * http://www.inria.fr/oasis/ProActive/contacts.html
27 * Contributor(s):
28 *
29 * ################################################################
30 */

31 package org.objectweb.proactive.examples.c3d;
32
33 import java.awt.Button JavaDoc;
34 import java.awt.Color JavaDoc;
35 import java.awt.Font JavaDoc;
36 import java.awt.Frame JavaDoc;
37 import java.awt.Graphics JavaDoc;
38 import java.awt.GridBagConstraints JavaDoc;
39 import java.awt.GridBagLayout JavaDoc;
40 import java.awt.Insets JavaDoc;
41 import java.awt.Label JavaDoc;
42 import java.awt.List JavaDoc;
43 import java.awt.Menu JavaDoc;
44 import java.awt.MenuBar JavaDoc;
45 import java.awt.MenuItem JavaDoc;
46 import java.awt.Panel JavaDoc;
47 import java.awt.TextArea JavaDoc;
48 import java.awt.event.ActionEvent JavaDoc;
49 import java.awt.event.ActionListener JavaDoc;
50 import java.awt.event.WindowAdapter JavaDoc;
51 import java.awt.event.WindowEvent JavaDoc;
52 import java.io.FileWriter JavaDoc;
53 import java.io.IOException JavaDoc;
54 import java.io.RandomAccessFile JavaDoc;
55 import java.net.InetAddress JavaDoc;
56 import java.net.UnknownHostException JavaDoc;
57 import java.util.Date JavaDoc;
58 import java.util.Enumeration JavaDoc;
59 import java.util.Hashtable JavaDoc;
60 import java.util.Stack JavaDoc;
61
62 import org.apache.log4j.Logger;
63 import org.objectweb.proactive.ProActive;
64 import org.objectweb.proactive.core.body.request.Request;
65 import org.objectweb.proactive.core.config.ProActiveConfiguration;
66 import org.objectweb.proactive.core.descriptor.data.ProActiveDescriptor;
67 import org.objectweb.proactive.core.descriptor.data.VirtualNode;
68 import org.objectweb.proactive.core.node.Node;
69 import org.objectweb.proactive.core.node.NodeException;
70 import org.objectweb.proactive.examples.c3d.geom.Vec;
71 import org.objectweb.proactive.examples.c3d.prim.Primitive;
72 import org.objectweb.proactive.examples.c3d.prim.Sphere;
73
74 /**
75  * This class decouples the set of user frames from the set of rendering
76  */

77 public class C3DDispatcher implements org.objectweb.proactive.RunActive
78 {
79     static Logger logger = Logger.getLogger(C3DDispatcher.class.getName());
80
81     protected VirtualNode vn;
82     /**
83      * Uses active objects if set to true
84      */

85     private static final boolean ACTIVE = true;
86     /*
87      * Stores the users in a hash table
88      */

89     private Hashtable JavaDoc h_users = new Hashtable JavaDoc();
90
91     /*
92      * Timestamp used to estimate rendering time
93      */

94     private long startTime;
95     /**
96      * Avg time for a rendering
97      */

98     private long avgRender = 0;
99     /**
100      * Number of renderings
101      */

102     private long totalRender = 0;
103     /**
104      * Interval stack; each interval holds information regarding its
105      * height, width and relative position within the whole image
106      */

107     private Stack JavaDoc int_stack = new Stack JavaDoc();
108     /**
109      * Array of rendering engines; each C3DRenderingEngine is a possibly remote,
110      * active object
111      */

112     private C3DRenderingEngine engine[];
113     /**
114      * Hashtable of the rendering engines
115      */

116     private Hashtable JavaDoc h_engines = new Hashtable JavaDoc();
117     /**
118      * Scene to be rendered; set by the first user frame to register;
119      * contains lights, spheres and one view
120      */

121     private Scene scene;
122     /**
123      * Number of rendering engines
124      */

125     private int engines;
126
127     /**
128      * Number of intervals, the whole picture should be divided into; this
129      * value has got an impact on the performance; it should be in
130      * the size of 'three times the number of rendering engines'
131      */

132     private int intervals;
133     /**
134      * Width of the rendering image
135      */

136     private int width;
137     /**
138      * Height of the rendering image
139      */

140     private int height;
141     /**
142      * Height of one rendering interval; provided for convenience only;
143      * carries the value of height / intervals
144      */

145     private int intheight;
146     /**
147      * Pixel array to store the rendered pixels; used to initialize the
148      * image on new-coming user frames, actualized in setPixels
149      */

150     private int[] pixels;
151     /**
152      * Number of intervals not yet rendered; used to determine the progress
153      * of the asynchronous rendering process; may or may not stay in
154      * future versions of live()
155      */

156     private int i_left = 0;
157     private int i_lastuser = 0;
158     private TextArea JavaDoc ta_log;
159     private List JavaDoc li_users;
160     private List JavaDoc li_enginesUsed;
161     private List JavaDoc li_enginesAvailable;
162     private String JavaDoc s_access_url;
163     private String JavaDoc s_hosts;
164     private Button JavaDoc b_addEng = new Button JavaDoc("Add engine");
165     private Button JavaDoc b_rmEng = new Button JavaDoc("Remove engine");
166     private Election election = null;
167     /**
168      * The average pining time for users
169      */

170     private long userPing = 0;
171     /**
172      * The number of User connected from the beginning
173      */

174     private long userTotal = 0;
175     /**
176      * The average pining time for rendering engines
177      */

178     private long enginePing = 0;
179     /**
180      * True if a rendering is going on [init = true because when 1st
181      * user registers, render starts]
182      */

183     private boolean b_render = false;
184     /**
185      * ProactiveDescriptor object for the dispatcher
186      */

187     private ProActiveDescriptor proActiveDescriptor;
188     private String JavaDoc[] rendererNodes;
189
190     /**
191      * The no-argument Constructor as commanded by Java//; otherwise unused
192      */

193     public C3DDispatcher()
194     {
195     }
196
197     /**
198      * Real Constructor
199      */

200     //public C3DDispatcher(String s_hosts)
201
//{
202
//new C3DDispatcherFrame();
203
//this.s_hosts = s_hosts;
204
//}
205

206     /**
207      * Constructor to call when using XML Descriptor
208      */

209     public C3DDispatcher(String JavaDoc [] rendererNodes,VirtualNode vn, ProActiveDescriptor pad)
210     {
211         new C3DDispatcherFrame();
212         this.rendererNodes=rendererNodes;
213         this.vn = vn;
214         this.proActiveDescriptor = pad;
215     }
216     /**
217      * Continues the initialization; called when the first user registers.
218      * It creates a set of rendering engines (one on each machine given by
219      * the Mapping in Utils) and passes a reference to its own stub to
220      * every engine.
221      */

222     public void init()
223     {
224         try
225         {
226             C3DDispatcher d =
227                 (C3DDispatcher) org
228                     .objectweb
229                     .proactive
230                     .ProActive
231                     .getStubOnThis();
232             /* Initializes the pixel array holding the whole image */
233             //Hosts hosts = new Hosts(s_hosts);
234
//engines = hosts.getMachines();
235
//engines = proActiveDescriptor.getVirtualNodeMappingSize()-1;
236
//System.out.println("taille du tableau d'engines "+engines);
237
/* Initializes the array to hold the rendering engines */
238             //engine = new C3DRenderingEngine[engines];
239
Object JavaDoc[] param = { d };
240             /* Creates rendering engines */
241             //for (int n = 1; n <= engines; n++)
242
//{
243
//String node = hosts.getNextNode();
244
//VirtualNode renderer = proActiveDescriptor.getVirtualNode("Renderer");
245
//System.out.println(renderer.getName());
246
//JVMNodeProcess jvmNodeProcess = (JVMNodeProcess)renderer.getVirtualMachine().getProcess();
247
//System.out.println(jvmNodeProcess.getClassname());
248
//renderer.activate();
249
//we have to wait for the creation of the nodes
250

251         //Node[] nodeTab = renderer.getNodes();
252
engines = rendererNodes.length;
253         engine = new C3DRenderingEngine[engines];
254         for (int i = 0; i < rendererNodes.length; i++)
255         {
256             C3DRenderingEngine tmp =
257                     (
258                         C3DRenderingEngine)ProActive
259                             .newActive(
260                         "org.objectweb.proactive.examples.c3d.C3DRenderingEngine",
261                         param,
262                         rendererNodes[i]);
263                 //String nodeURL = nodeTab[i].getNodeInformation().getURL();
264
log("New rendering engine " + i + " created at " + rendererNodes[i]);
265                 
266                 // always have a renderer used when launching the program
267
if (i == 1)
268                     li_enginesUsed.add(rendererNodes[i].toString());
269                 else
270                     li_enginesAvailable.add(rendererNodes[i].toString());
271
272                 // adds the engine in the hashtable
273
h_engines.put(rendererNodes[i], tmp);
274         }
275                 //String nodeURL = node.getNodeInformation().getURL();
276
// C3DRenderingEngine tmp =
277
// (
278
// C3DRenderingEngine)ProActive
279
// .newActive(
280
// "org.objectweb.proactive.examples.c3d.C3DRenderingEngine",
281
// param,
282
// node);
283
// log("New rendering engine " + n + " created at " + nodeURL);
284
//
285
// // always have a renderer used when launching the program
286
// if (n == 1)
287
// li_enginesUsed.add(nodeURL.toString());
288
// else
289
// li_enginesAvailable.add(nodeURL.toString());
290
//
291
// // adds the engine in the hashtable
292
// h_engines.put(nodeURL, tmp);
293
//}
294
}
295         catch (Exception JavaDoc e)
296         {
297             e.printStackTrace();
298             throw new RuntimeException JavaDoc(e.toString());
299         }
300     }
301
302     /**
303      * Appends message to the end of the list
304      */

305     public void log(String JavaDoc s_message)
306     {
307         ta_log.append(s_message + "\n");
308     }
309
310     /**
311      * Does the rendering; creates the interval stack, registers the current
312      * scene with the engines, assigns one initial interval to each engine
313      * and triggers the calculation
314      */

315     private void render()
316     {
317
318         // Checks there are some engines usde
319
if (li_enginesUsed.getItems().length == 0)
320         {
321             showMessageAll("No engines ... contact the dispatcher");
322             return;
323         }
324
325         // Toggles the rendering flag..
326
b_render = true;
327
328         // Benchmarking stuff...
329
startTime = System.currentTimeMillis();
330
331         Interval interval;
332         String JavaDoc keys[] = li_enginesUsed.getItems();
333         engines = keys.length;
334
335         log("Creating " + intervals + " intervals");
336         intervals = 3 * keys.length;
337         intheight = height / intervals;
338
339         /* Sets the number of intervals not yet calculated to 'all' */
340         i_left = intervals;
341
342         /* Creates the interval stack */
343         int_stack = new Stack JavaDoc();
344         for (int i = 0; i < intervals; i++)
345         {
346             // log("Creating inter : "+i);
347
Interval newint =
348                 new Interval(
349                     i,
350                     width,
351                     height,
352                     i * intheight,
353                     (i + 1) * intheight,
354                     intervals);
355             int_stack.push(newint);
356         }
357
358         engine = null;
359         engine = new C3DRenderingEngine[keys.length];
360
361         C3DRenderingEngine tmp;
362         if (keys != null)
363         {
364             for (int e = 0; e < keys.length; e++)
365             {
366
367                 /* Assigns one initial interval to each engine */
368                 if (!int_stack.empty())
369                 {
370                     interval = (Interval) int_stack.pop();
371
372                     tmp = (C3DRenderingEngine) h_engines.get(keys[e]);
373
374                     if (tmp != null)
375                     {
376
377                         tmp.setScene(scene);
378
379                         engine[e] = tmp;
380
381                         /* Triggers the calculation of this interval on engine e */
382                         tmp.render(e, interval);
383
384                         log(
385                             "Interval "
386                                 + interval.number
387                                 + " assigned to engine "
388                                 + keys[e]
389                                 + "["
390                                 + e
391                                 + "]");
392                     }
393                     else
394                     {
395                         log(
396                             "Failed to assign an interval to engine "
397                                 + keys[e]);
398                         h_engines.get(keys[e]);
399                     }
400                 }
401             }
402         }
403         else
404             b_render = false;
405     }
406
407     long previousTime = -1;
408
409     /**
410      * Forwards the newly calculated pixels from the rendering engine to the
411      * redirectors (i.e. the consumers). This method is called directly by
412      * the rendering engines via their reference to this C3DDispatcher.
413      *
414      * @param newpix the newly calculated pixels as int[]
415      * @param interval the interval, the pixels belong to (width, height ...)
416      * @param engine_number number of the engine, that has calculated this
417      * interval; this value is used to assign the next interval to
418      * this same engine
419      */

420     public void setPixels(int[] newpix, Interval interval, int engine_number)
421     {
422         // public void setPixels(int[] newpix, Interval interval, C3DRenderingEngine currentEngine) {
423

424         long elapsed;
425         
426         /* Delivers the new pixels to all user frames */
427         for (Enumeration JavaDoc e = h_users.elements(); e.hasMoreElements();)
428         {
429             User user = (User) e.nextElement();
430             
431             user.getObject().setPixels(newpix, interval);
432         }
433
434         /* Stores the newly rendered interval in <code>pixels</code>; this
435          * is later used to initialize the images of newcoming consumers */

436         System.arraycopy(
437             newpix,
438             0,
439             pixels,
440             interval.width * interval.yfrom,
441             newpix.length);
442         /* Decreases the counter of not yet rendered intervals */
443         i_left--;
444
445         /* Has the next interval rendered by the same engine */
446         Interval nextinterval;
447         if (!int_stack.empty())
448         {
449             nextinterval = (Interval) int_stack.pop();
450             log(
451                 "Next interval ["
452                     + nextinterval.number
453                     + "] assigned to engine "
454                     + engine_number);
455             // new NextInterval(engine_number, engine[engine_number], nextinterval);
456
engine[engine_number].render(engine_number, nextinterval);
457             // currentEngine.render(0, nextinterval);
458

459         }
460         else if (i_left == 0)
461         {
462             // Debugging: estimates the number of milliseconds elapsed
463
elapsed = System.currentTimeMillis() - startTime;
464
465             totalRender++;
466             avgRender += ((elapsed - avgRender) / totalRender);
467
468             showMessageAll("All intervals rendered in " + elapsed + " ms");
469             if (previousTime != -1)
470                 showMessageAll(
471                     "Speed Up : "
472                         + java.lang.Math.rint(
473                             ((double) previousTime / elapsed) * 1000)
474                             / 1000
475                         + "\n");
476             else
477                 showMessageAll("");
478             previousTime = elapsed;
479
480             b_render = false;
481         }
482     }
483
484     /**
485      * Rotates all the objects (spheres, for the moment) by <code>angle</code>
486      * around their y axis; re-renders the image afterwards
487      *
488      * @param angle the angle to rotate the objects in radians, a positive
489      * value means a rotation to the 'right'
490      */

491     private void rotateSceneY(double angle)
492     {
493         int objects = scene.getObjects();
494         Sphere o;
495         /* on every object ... */
496         for (int i = 0; i < objects; i++)
497         {
498             o = (Sphere) scene.getObject(i);
499             Vec c = o.getCenter();
500             double phi = Math.atan2(c.z, c.x);
501             double l = Math.sqrt(c.x * c.x + c.z * c.z);
502             /* ... perform the standard rotation math */
503             c.x = l * Math.cos(phi + angle);
504             c.z = l * Math.sin(phi + angle);
505             o.setCenter(c);
506             scene.setObject(o, i);
507         }
508         /* re-renders the image to reflect the rotation */
509         render();
510     }
511
512     /**
513      * Rotates all the objects (spheres, for the moment) by <code>angle</code>
514      * around their x axis; re-renders the image afterwards
515      *
516      * @param angle the angle to rotate the objects in radians, a positive
517      * value means a rotation to the 'right'
518      */

519     private void rotateSceneX(double angle)
520     {
521         int objects = scene.getObjects();
522         Sphere o;
523         /* on every object ... */
524         for (int i = 0; i < objects; i++)
525         {
526             o = (Sphere) scene.getObject(i);
527             Vec c = o.getCenter();
528             double phi = Math.atan2(c.z, c.y);
529             double l = Math.sqrt(c.y * c.y + c.z * c.z);
530             /* ... perform the standard rotation math */
531             c.y = l * Math.cos(phi + angle);
532             c.z = l * Math.sin(phi + angle);
533             o.setCenter(c);
534             scene.setObject(o, i);
535         }
536         /* re-renders the image to reflect the rotation */
537         render();
538     }
539
540     /**
541      * Rotates all the objects (spheres, for the moment) by <code>angle</code>
542      * around their x axis; re-renders the image afterwards
543      *
544      * @param angle the angle to rotate the objects in radians, a positive
545      * value means a rotation to the 'right'
546      */

547     private void rotateSceneZ(double angle)
548     {
549         int objects = scene.getObjects();
550         Sphere o;
551         /* on every object ... */
552         for (int i = 0; i < objects; i++)
553         {
554             o = (Sphere) scene.getObject(i);
555             Vec c = o.getCenter();
556             double phi = Math.atan2(c.x, c.y);
557             double l = Math.sqrt(c.y * c.y + c.x * c.x);
558             /* ... perform the standard rotation math */
559             c.y = l * Math.cos(phi + angle);
560             c.x = l * Math.sin(phi + angle);
561             o.setCenter(c);
562             scene.setObject(o, i);
563         }
564         /* re-renders the image to reflect the rotation */
565         render();
566     }
567
568     /**
569      * Rotates the objects in the rendering scene by pi/4 to the left
570      *
571      * @param i_user number of the user requesting this rotation; this
572      * value used for the synchronization and notification of several
573      * users
574      */

575     public void rotateLeft(int i_user)
576     {
577         rotateSceneY(-Math.PI / 4);
578     }
579
580     /**
581      * Rotates the objects in the rendering scene by pi/4 to the right
582      *
583      * @param i_user number of the user requesting this rotation; this
584      * value used for the synchronization and notification of several
585      * users
586      */

587     public void rotateRight(int i_user)
588     {
589         rotateSceneY(Math.PI / 4);
590     }
591
592     /**
593      * Rotates the objects in the rendering scene by pi/4 to the left
594      *
595      * @param i_user number of the user requesting this rotation; this
596      * value used for the synchronization and notification of several
597      * users
598      */

599     public void rotateUp(int i_user)
600     {
601         rotateSceneX(Math.PI / 4);
602     }
603
604     /**
605      * Rotates the objects in the rendering scene by pi/4 down
606      *
607      * @param i_user number of the user requesting this rotation; this
608      * value used for the synchronization and notification of several
609      * users
610      */

611     public void rotateDown(int i_user)
612     {
613         rotateSceneX(-Math.PI / 4);
614     }
615
616     /**
617      * Spins clockwise
618      *
619      * @param i_user number of the user requesting this rotation; this
620      * value used for the synchronization and notification of several
621      * users
622      */

623     public void spinClock(int i_user)
624     {
625         rotateSceneZ(Math.PI / 4);
626     }
627
628     /**
629      * Spins the scene un-clockwise
630      *
631      * @param i_user number of the user requesting this rotation; this
632      * value used for the synchronization and notification of several
633      * users
634      */

635     public void spinUnclock(int i_user)
636     {
637         rotateSceneZ(-Math.PI / 4);
638     }
639
640     public void changeColorAll()
641     {
642         logger.info("changeColorAll()");
643         for (Enumeration JavaDoc e = h_users.elements(); e.hasMoreElements();)
644             ((User) e.nextElement())
645                 .getObject()
646                 .getUserFrame()
647                 .getB_left()
648                 .setBackground(
649                 Color.yellow);
650     }
651
652     /**
653      * Java// object life routine
654      * To be remdelled..
655      */

656     public void runActivity(org.objectweb.proactive.Body body)
657     {
658         //registerDispatcher(body.getNodeURL());
659
/* Creates the rendering engines */
660         init();
661         org
662
            .objectweb
663             .proactive
664             .core
665             .body
666             .request
667             .BlockingRequestQueue requestQueue =
668             body.getRequestQueue();
669         /* Loops over lifetime */
670         while (body.isActive())
671         {
672
673                 /* Waits on any method call */
674                 Request r = requestQueue.blockingRemoveOldest();
675                 String JavaDoc methodName = r.getMethodName();
676                 if (methodName.startsWith("rotate")|| methodName.startsWith("spin")){
677                     processRotate(body, methodName, r);
678                 }
679                 else{
680                     if (!Election.isRunning())
681                     {
682                         // No election and the method != up,down,left,right
683
body.serve(r);
684                     }
685                     else if (methodName.equals("addSphere"))
686                     {
687                     // There is an election and addsphere comes..
688
// nothing happens...
689
showMessageAll("Cannot add spheres while an election is running");
690                     }
691                     else
692                     {
693                     // THERE IS a running election and the method name is not left or right..
694

695                     body.serve(r);
696                     }
697                 }
698
699             }
700         //}
701
}
702
703 // private void registerDispatcher(String nodeURL)
704
// {
705
// /* Register this C3DDispatcher, this will serve as entry point to the
706
// * raytracing system for the user frames */
707
//
708
// try
709
// {
710
// org.objectweb.proactive.core.node.Node node =
711
// org.objectweb.proactive.core.node.NodeFactory.getNode(nodeURL);
712
// s_access_url =
713
// "//"
714
// + node.getNodeInformation().getInetAddress().getHostName()
715
// + "/"
716
// + C3D_DISPATCHER_BIND_NAME;
717
// org.objectweb.proactive.ProActive.register(
718
// org.objectweb.proactive.ProActive.getStubOnThis(),
719
// s_access_url);
720
// log("Successfully registered at " + s_access_url + " and ready.");
721
//
722
// }
723
// catch (org.objectweb.proactive.core.node.NodeException e)
724
// {
725
// log("Error: The node of the body cannot be found!");
726
// e.printStackTrace();
727
// }
728
// catch (UnknownHostException e)
729
// {
730
// log("Error: Name of the local host could not be determined!");
731
// e.printStackTrace();
732
// }
733
// catch (java.io.IOException e)
734
// {
735
// log("Error: could not register, RMI registry not found!");
736
// e.printStackTrace();
737
// }
738
// }
739

740     /**
741      * Processes the requests which are relative to rotations
742      * @param body The body of the active object
743      * @param methodName The methodname <font size="-1">Not reconputed in order to gain time</font>
744      * @param r The request object
745      */

746     public void processRotate(
747         org.objectweb.proactive.Body body,
748         String JavaDoc methodName,
749         Request r)
750     {
751         int i_user = 0;
752         try
753         {
754             i_user = ((Integer JavaDoc) r.getParameter(0)).intValue();
755         }
756         catch (Exception JavaDoc e)
757         {
758             e.printStackTrace();
759         }
760         if (methodName.equals("rotateLeft"))
761         {
762             // A user wants to rotate left
763
if (Election.isRunning())
764             {
765                 // There is an election
766
int i_votes = Election.vote(i_user, new Integer JavaDoc(Election.LEFT));
767                 if (i_votes == h_users.size())
768                 {
769                     election.finish();
770                 }
771             }
772             else
773             {
774                 // There is no election
775
if (i_left > 0)
776                 {
777                     showMessage(
778                         i_user,
779                         "Rendering in progress, request invalid");
780                 }
781                 else if (h_users.size() == 1)
782                 {
783                     showMessage(i_user, "Scene is being rotated left");
784                     body.serve(r);
785                 }
786                 else
787                 {
788                     election =
789                         new Election(i_user, new Integer JavaDoc(Election.LEFT), this);
790                 }
791             }
792         }
793         else if (methodName.equals("rotateRight"))
794         {
795             // A user wants to go right
796
if (Election.isRunning())
797             {
798                 // there is an election
799
int i_votes =
800                     Election.vote(i_user, new Integer JavaDoc(Election.RIGHT));
801                 if (i_votes == h_users.size())
802                 {
803                     election.finish();
804                 }
805             }
806             else
807             {
808                 // there is no election
809
if (i_left > 0)
810                 {
811                     showMessage(
812                         i_user,
813                         "Rendering in progress, request invalid");
814                 }
815                 else if (h_users.size() == 1)
816                 {
817                     showMessage(i_user, "Scene is being rotated right");
818                     body.serve(r);
819                 }
820                 else
821                 {
822                     election =
823                         new Election(i_user, new Integer JavaDoc(Election.RIGHT), this);
824                 }
825             }
826         }
827         else if (methodName.equals("rotateUp"))
828         {
829             // A user wants to go up
830
if (Election.isRunning())
831             {
832                 // There is an election
833
int i_votes = Election.vote(i_user, new Integer JavaDoc(Election.UP));
834                 if (i_votes == h_users.size())
835                 {
836                     election.finish();
837                 }
838             }
839             else
840             {
841                 // There is no election
842
if (i_left > 0)
843                 {
844                     showMessage(
845                         i_user,
846                         "Rendering in progress, request invalid");
847                 }
848                 else if (h_users.size() == 1)
849                 {
850                     showMessage(i_user, "Scene is being rotated up");
851                     body.serve(r);
852             &nb