View Javadoc

1   /*
2      Copyright 2009 Ramon Servadei
3   
4      Licensed under the Apache License, Version 2.0 (the "License");
5      you may not use this file except in compliance with the License.
6      You may obtain a copy of the License at
7   
8          http://www.apache.org/licenses/LICENSE-2.0
9   
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15   */
16  package fulmine.demo;
17  
18  import java.awt.BorderLayout;
19  import java.awt.GridLayout;
20  import java.awt.event.ActionEvent;
21  import java.awt.event.ActionListener;
22  import java.awt.event.KeyEvent;
23  
24  import javax.swing.BorderFactory;
25  import javax.swing.JButton;
26  import javax.swing.JComboBox;
27  import javax.swing.JFrame;
28  import javax.swing.JLabel;
29  import javax.swing.JMenu;
30  import javax.swing.JMenuBar;
31  import javax.swing.JMenuItem;
32  import javax.swing.JOptionPane;
33  import javax.swing.JPanel;
34  import javax.swing.JScrollPane;
35  import javax.swing.JTable;
36  import javax.swing.JTextField;
37  import javax.swing.WindowConstants;
38  
39  import fulmine.Domain;
40  import fulmine.Type;
41  import fulmine.context.FulmineContext;
42  import fulmine.context.IFulmineContext;
43  import fulmine.context.IPermissionProfile;
44  import fulmine.context.RemoteUpdateHandler;
45  import fulmine.distribution.connection.tcp.TcpNetwork;
46  import fulmine.model.container.IContainer;
47  import fulmine.model.container.impl.Record;
48  import fulmine.model.field.FieldUtils;
49  import fulmine.ui.RecordTable;
50  import fulmine.ui.SwingWorker;
51  
52  /**
53   * A GUI application for demonstrating the abilities of the system.
54   * 
55   * @author Ramon Servadei
56   */
57  public final class DemoApp
58  {
59  
60      public DemoApp()
61      {
62          super();
63      }
64  
65      /**
66       * Creates all necessary GUI components. It is rather monolithic but this is
67       * purely a demo app (so does that mean good design principles should be
68       * abandoned!? No, but its hard to get good component based designs when
69       * constructing GUI components...not an excuse, just a statement of fact and
70       * being an advocate of the 80/20 rule its better not to over engineer
71       * this).
72       * 
73       * @throws Exception
74       */
75      public void start() throws Exception
76      {
77          // gather parameters
78          SwingWorker<ContextParameters> worker =
79              new SwingWorker<ContextParameters>()
80              {
81                  @Override
82                  public ContextParameters doWork() throws Exception
83                  {
84                      return new ContextParameters("DemoApp:parameters");
85                  }
86              };
87          final ContextParameters params = worker.invokeAndWait().getResult();
88          synchronized (params)
89          {
90              try
91              {
92                  params.wait();
93              }
94              catch (InterruptedException e)
95              {
96                  e.printStackTrace();
97              }
98          }
99          // now create the context
100         final IFulmineContext context =
101             new FulmineContext(params.getContextName());
102         context.setNetwork(new TcpNetwork((String) null,
103             Integer.parseInt(params.getTcpPort())));
104         // create a permission profile based on the params - this does an exact
105         // match for the application and permission codes
106         context.setPermissionProfile(new IPermissionProfile()
107         {
108 
109             public boolean contains(byte application, short permission)
110             {
111                 return application == getApplicationCode()
112                     && permission == getPermissionCode();
113             }
114 
115             public byte getApplicationCode()
116             {
117                 return Byte.parseByte(params.getApplicationCode());
118             }
119 
120             public short getPermissionCode()
121             {
122                 return Short.parseShort(params.getPermissionCode());
123             }
124 
125             public boolean matches(byte receivedApplication,
126                 short receivedPermission, byte matchWithApplication,
127                 short matchWithPermission)
128             {
129                 return receivedApplication == matchWithApplication
130                     && receivedPermission == matchWithPermission;
131             }
132         });
133         context.setRemoteUpdateHandler(new RemoteUpdateHandler());
134         context.start();
135         System.out.println("Application ready");
136         System.out.println(params);
137 
138         // now create a JFrame for the table listener
139         SwingWorker<RecordTable> recordTableCreator =
140             new SwingWorker<RecordTable>()
141             {
142                 @Override
143                 public RecordTable doWork() throws Exception
144                 {
145                     final RecordTable recordTable = new RecordTable();
146                     recordTable.setRowSelectionAllowed(true);
147                     return recordTable;
148                 }
149             };
150 
151         final RecordTable recordTable =
152             recordTableCreator.invokeAndWait().getResult();
153 
154         SwingWorker<JFrame> mainFrameCreator = new SwingWorker<JFrame>()
155         {
156             @Override
157             public JFrame doWork() throws Exception
158             {
159                 JFrame mainFrame = new JFrame("DemoApp:" + params);
160                 final JMenuBar menuBar = new JMenuBar();
161                 mainFrame.setJMenuBar(menuBar);
162                 final JMenu recordMenu = new JMenu("Actions");
163                 menuBar.add(recordMenu);
164                 JScrollPane scrollPane = new JScrollPane(recordTable);
165                 recordTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
166                 mainFrame.getContentPane().add(scrollPane);
167                 final JMenuItem menuItemAdd =
168                     new JMenuItem("Add Record", KeyEvent.VK_A);
169                 menuItemAdd.addActionListener(new ActionListener()
170                 {
171                     public void actionPerformed(ActionEvent e)
172                     {
173                         final GetRecordParameters window =
174                             new GetRecordParameters("Add record parameters");
175                         window.addActionListener(new ActionListener()
176                         {
177                             public void actionPerformed(ActionEvent e)
178                             {
179                                 context.getLocalContainer(
180                                     window.getIdentity(),
181                                     Type.get(Integer.parseInt(window.getType())),
182                                     Domain.get(Integer.parseInt(window.getDomain())));
183                                 context.subscribe(
184                                     context.getIdentity(),
185                                     window.getIdentity(),
186                                     Type.get(Integer.parseInt(window.getType())),
187                                     Domain.get(Integer.parseInt(window.getDomain())),
188                                     recordTable);
189                             }
190                         });
191                     }
192                 });
193                 final JMenuItem menuItemRemove =
194                     new JMenuItem("Remove Record", KeyEvent.VK_R);
195                 menuItemRemove.addActionListener(new ActionListener()
196                 {
197                     public void actionPerformed(ActionEvent e)
198                     {
199                         final Record selectedRecord =
200                             recordTable.getSelectedRecord();
201                         if (selectedRecord != null && selectedRecord.isLocal())
202                         {
203                             context.getLocalContainer(
204                                 selectedRecord.getIdentity(),
205                                 selectedRecord.getType(),
206                                 selectedRecord.getDomain()).destroy();
207                         }
208                     }
209                 });
210                 final JMenuItem menuItemAddField =
211                     new JMenuItem("Add Field", KeyEvent.VK_F);
212                 menuItemAddField.addActionListener(new ActionListener()
213                 {
214                     public void actionPerformed(ActionEvent e)
215                     {
216                         final AddFieldParameters window =
217                             new AddFieldParameters("Add field");
218                         window.addActionListener(new ActionListener()
219                         {
220                             public void actionPerformed(ActionEvent e)
221                             {
222                                 // get the selected record, construct the field
223                                 // and add the field
224                                 try
225                                 {
226                                     final Record selectedRecord =
227                                         recordTable.getSelectedRecord();
228                                     if (selectedRecord.isLocal())
229                                     {
230                                         final IContainer localContainer =
231                                             context.getLocalContainer(
232                                                 selectedRecord.getIdentity(),
233                                                 selectedRecord.getType(),
234                                                 selectedRecord.getDomain());
235                                         localContainer.add(FieldUtils.createFromString(
236                                             window.getType(),
237                                             window.getIdentity(),
238                                             Byte.parseByte(window.getApplicationCode()),
239                                             Short.parseShort(window.getPermissionCode())));
240                                         localContainer.flushFrame();
241                                     }
242                                 }
243                                 catch (RuntimeException ex)
244                                 {
245                                     JOptionPane.showMessageDialog(null,
246                                         "Select a record and try again");
247                                     throw ex;
248                                 }
249                             }
250                         });
251                     }
252                 });
253                 final JMenuItem menuItemRemoveField =
254                     new JMenuItem("Remove Field", KeyEvent.VK_E);
255                 menuItemRemoveField.addActionListener(new ActionListener()
256                 {
257                     public void actionPerformed(ActionEvent e)
258                     {
259                         // get the selected record, construct the field
260                         // and add the field
261                         try
262                         {
263                             final Record selectedRecord =
264                                 recordTable.getSelectedRecord();
265                             if (selectedRecord.isLocal())
266                             {
267                                 final IContainer localContainer =
268                                     context.getLocalContainer(
269                                         selectedRecord.getIdentity(),
270                                         selectedRecord.getType(),
271                                         selectedRecord.getDomain());
272                                 localContainer.remove(recordTable.getSelectedField());
273                                 localContainer.flushFrame();
274                             }
275                         }
276                         catch (RuntimeException ex)
277                         {
278                             JOptionPane.showMessageDialog(null,
279                                 "Select a record and try again");
280                             throw ex;
281                         }
282                     }
283                 });
284                 final JMenuItem menuItemSubscribe =
285                     new JMenuItem("Subscribe Record", KeyEvent.VK_S);
286                 menuItemSubscribe.addActionListener(new ActionListener()
287                 {
288                     public void actionPerformed(ActionEvent e)
289                     {
290                         final SubscribeRecordParameters window =
291                             new SubscribeRecordParameters(
292                                 "Subscribe parameters");
293                         window.addActionListener(new ActionListener()
294                         {
295                             public void actionPerformed(ActionEvent e)
296                             {
297                                 context.subscribe(
298                                     window.getContextIdentity(),
299                                     window.getIdentity(),
300                                     Type.get(Integer.parseInt(window.getType())),
301                                     Domain.get(Integer.parseInt(window.getDomain())),
302                                     recordTable);
303                             }
304                         });
305                     }
306                 });
307                 final JMenuItem menuItemUnsubscribe =
308                     new JMenuItem("Unsubscribe Record", KeyEvent.VK_U);
309                 menuItemUnsubscribe.addActionListener(new ActionListener()
310                 {
311                     public void actionPerformed(ActionEvent e)
312                     {
313                         final SubscribeRecordParameters window =
314                             new SubscribeRecordParameters(
315                                 "Unsubscribe parameters");
316                         window.addActionListener(new ActionListener()
317                         {
318                             public void actionPerformed(ActionEvent e)
319                             {
320                                 context.unsubscribe(
321                                     window.getContextIdentity(),
322                                     window.getIdentity(),
323                                     Type.get(Integer.parseInt(window.getType())),
324                                     Domain.get(Integer.parseInt(window.getDomain())),
325                                     recordTable);
326                             }
327                         });
328                     }
329                 });
330                 recordMenu.add(menuItemAdd);
331                 recordMenu.add(menuItemRemove);
332                 recordMenu.add(menuItemAddField);
333                 recordMenu.add(menuItemRemoveField);
334                 recordMenu.add(menuItemSubscribe);
335                 recordMenu.add(menuItemUnsubscribe);
336                 mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
337                 mainFrame.pack();
338                 mainFrame.setVisible(true);
339                 return mainFrame;
340             }
341         };
342         mainFrameCreator.invokeAndWait();
343     }
344 
345     public static void main(String[] args) throws Exception
346     {
347         new DemoApp().start();
348     }
349 }
350 
351 /**
352  * Base class for a GUI that gathers parameters
353  * 
354  * @author Ramon Servadei
355  */
356 abstract class ParameterGatherer extends JFrame
357 {
358     private static final long serialVersionUID = 1L;
359 
360     final JButton ok = new JButton("OK");
361 
362     ParameterGatherer(String title)
363     {
364         super(title);
365         getContentPane().setLayout(new BorderLayout());
366         ok.addActionListener(new ActionListener()
367         {
368             public void actionPerformed(ActionEvent e)
369             {
370                 synchronized (ParameterGatherer.this)
371                 {
372                     ParameterGatherer.this.notify();
373                 }
374                 ParameterGatherer.this.dispose();
375             }
376         });
377         getContentPane().add(ok, BorderLayout.SOUTH);
378     }
379 
380     /**
381      * Add the {@link ActionListener} to the actions performed when the "OK"
382      * button is pressed
383      * 
384      * @param listener
385      *            the listener to add
386      */
387     void addActionListener(ActionListener listener)
388     {
389         this.ok.addActionListener(listener);
390     }
391 
392     /**
393      * Call to pack and set visible
394      */
395     void postInit()
396     {
397         pack();
398         setVisible(true);
399     }
400 }
401 
402 /**
403  * A simple UI for gathering parameters about creating a context.
404  * 
405  * @author Ramon Servadei
406  */
407 final class ContextParameters extends ParameterGatherer
408 {
409     private static final long serialVersionUID = 1L;
410 
411     final Parameter contextName, tcpPort, applicationCode, permissionCode;
412 
413     ContextParameters(String title)
414     {
415         super(title);
416         JPanel params = new JPanel();
417         params.setLayout(new GridLayout(4, 2));
418         this.contextName =
419             new Parameter(params, "Context name", "choose a unique name");
420         this.tcpPort =
421             new Parameter(params, "TCP port", "choose an unused TCP port");
422         this.applicationCode =
423             new Parameter(params, "Application code (byte)", "0");
424         this.permissionCode =
425             new Parameter(params, "Permission code (short)", "0");
426         getContentPane().add(params);
427         postInit();
428     }
429 
430     /**
431      * @return the value of the context name field
432      */
433     String getContextName()
434     {
435         return this.contextName.getValue();
436     }
437 
438     /**
439      * @return the value of the tcp port field
440      */
441     String getTcpPort()
442     {
443         return this.tcpPort.getValue();
444     }
445 
446     /**
447      * @return the value of the application code field
448      */
449     String getApplicationCode()
450     {
451         return this.applicationCode.getValue();
452     }
453 
454     /**
455      * @return the value of the permission code field
456      */
457     String getPermissionCode()
458     {
459         return this.permissionCode.getValue();
460     }
461 
462     @Override
463     public String toString()
464     {
465         return "Context name=" + getContextName() + ", TCP port="
466             + getTcpPort() + ", application code=" + getApplicationCode()
467             + ", permission code=" + getPermissionCode();
468     }
469 }
470 
471 /**
472  * Encapsulates a {@link JLabel} and {@link JTextField} for a single parameter
473  * 
474  * @author Ramon Servadei
475  */
476 final class Parameter
477 {
478     private static final long serialVersionUID = 1L;
479 
480     final JLabel name;
481 
482     final JTextField value;
483 
484     Parameter(JPanel parent, String name, String value)
485     {
486         super();
487         this.name = new JLabel(name);
488         this.name.setBorder(BorderFactory.createEtchedBorder());
489         this.value = new JTextField(value);
490         parent.add(this.name);
491         parent.add(this.value);
492     }
493 
494     String getValue()
495     {
496         return value.getText();
497     }
498 }
499 
500 /**
501  * Encapsulates a {@link JLabel} and {@link JComboBox} for a field type
502  * parameter
503  * 
504  * @author Ramon Servadei
505  */
506 final class FieldTypeParameter
507 {
508     private static final long serialVersionUID = 1L;
509 
510     final JLabel name;
511 
512     final JComboBox value;
513 
514     FieldTypeParameter(JPanel parent, String name)
515     {
516         super();
517         this.name = new JLabel(name);
518         this.name.setBorder(BorderFactory.createEtchedBorder());
519         this.value =
520             new JComboBox(new String[] { "StringField", "BooleanField",
521                 "IntegerField", "LongField", "FloatField", "DoubleField" });
522         parent.add(this.name);
523         parent.add(this.value);
524     }
525 
526     String getValue()
527     {
528         return (String) value.getSelectedItem();
529     }
530 }
531 
532 /**
533  * Encapsulates parameters required to add a record
534  * 
535  * @author Ramon Servadei
536  */
537 class AddFieldParameters extends ParameterGatherer
538 {
539     private static final long serialVersionUID = 1L;
540 
541     final Parameter identity, applicationCode, permissionCode;
542 
543     final FieldTypeParameter type;
544 
545     final JPanel params;
546 
547     public AddFieldParameters(String title)
548     {
549         super(title);
550         this.params = new JPanel();
551         this.params.setLayout(new GridLayout(4, 2));
552         this.identity = new Parameter(params, "Identity", "<identity>");
553         this.type = new FieldTypeParameter(params, "Type");
554         this.applicationCode =
555             new Parameter(params, "Application code (byte)", "0");
556         this.permissionCode =
557             new Parameter(params, "Permission code (short)", "0");
558         getContentPane().add(params);
559         postInit();
560     }
561 
562     /**
563      * @return the value of the identity field
564      */
565     String getIdentity()
566     {
567         return this.identity.getValue();
568     }
569 
570     /**
571      * @return the value of the type field
572      */
573     String getType()
574     {
575         return this.type.getValue();
576     }
577 
578     /**
579      * @return the value of the application code field
580      */
581     String getApplicationCode()
582     {
583         return this.applicationCode.getValue();
584     }
585 
586     /**
587      * @return the value of the permission code field
588      */
589     String getPermissionCode()
590     {
591         return this.permissionCode.getValue();
592     }
593 }
594 
595 /**
596  * Encapsulates parameters required to add a record
597  * 
598  * @author Ramon Servadei
599  */
600 class GetRecordParameters extends ParameterGatherer
601 {
602     private static final long serialVersionUID = 1L;
603 
604     final Parameter identity, type, domain;
605 
606     final JPanel params;
607 
608     public GetRecordParameters(String title)
609     {
610         super(title);
611         this.params = new JPanel();
612         this.params.setLayout(new GridLayout(3, 2));
613         this.identity =
614             new Parameter(params, "Identity", "<identity (or regex)>");
615         this.type = new Parameter(params, "Type", "" + Type.RECORD.value());
616         this.domain =
617             new Parameter(params, "Domain", "" + Domain.FRAMEWORK.value());
618         getContentPane().add(params);
619         postInit();
620     }
621 
622     /**
623      * @return the value of the identity field
624      */
625     String getIdentity()
626     {
627         return this.identity.getValue();
628     }
629 
630     /**
631      * @return the value of the type field
632      */
633     String getType()
634     {
635         return this.type.getValue();
636     }
637 
638     /**
639      * @return the value of the domain field
640      */
641     String getDomain()
642     {
643         return this.domain.getValue();
644     }
645 }
646 
647 /**
648  * Encapsulates getting parameters for subscribe/unsubscribe operations
649  * 
650  * @author Ramon Servadei
651  */
652 final class SubscribeRecordParameters extends GetRecordParameters
653 {
654     private static final long serialVersionUID = 1L;
655 
656     final Parameter contextIdentity;
657 
658     public SubscribeRecordParameters(String title)
659     {
660         super(title);
661         super.params.setLayout(new GridLayout(4, 2));
662         this.contextIdentity =
663             new Parameter(params, "Context identity",
664                 "<context name to subscribe from>");
665         postInit();
666     }
667 
668     String getContextIdentity()
669     {
670         return this.contextIdentity.getValue();
671     }
672 
673     public static void main(String[] args)
674     {
675         final SubscribeRecordParameters subscribeRecordParameters =
676             new SubscribeRecordParameters("test");
677         subscribeRecordParameters.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
678     }
679 }