Projet

Général

Profil

SpeADL Dynamic Tutorial » Historique » Version 16

Anonyme, 15/10/2014 10:37

1 3 Anonyme
h1. SpeADL for Dynamic Architectures Tutorial
2 2 Anonyme
3 7 Anonyme
{{>toc}}
4
5 1 Anonyme
This is a tutorial for SpeADL: understanding ecosystems and species, defining a simple ecosystem, composing species together with uses.
6 3 Anonyme
7
h2. Objectives
8
9
The objective of this tutorial to understand the abstractions of species and uses.
10
11
We will create a Logging ecosystem that contains Logger species.
12
Then we will create a Banking ecosystem that contains Account species that need to log what happens.
13 16 Anonyme
After, we will create a Bank ecosystem that compose Account species with Logger species thanks to the use abstraction.
14
And finally we will add a GUI that will instantiate species and visualise them.
15 3 Anonyme
16
h2. Prerequisites
17
18
It is needed to understand the content of the [[SpeADL Minus Tutorial|SpeADL⁻ tutorial]] before doing this one.
19
20
h2. Creating a New Project and Organisation
21
22
Create a Java project.
23
We will use again an organisation of the package and namespaces as explained in [[MAY Best Practices#Project Organisation|this best practice]].
24
25
h2. The Logging Ecosystem
26
27
Logging will be an ecosystem, and its particularity is that it will be able to create Loggers: while logging is the subsystem responsible of all logging, each logger will be responsible of logging one particular aspect of the system identified by a _name_.
28
We will have multiple implementation for the Logging ecosystem:
29
* One with only one file where to log with each line prepended with the name.
30
* One with one file per Logger all in the same directory.
31
32 9 Anonyme
In any case, a port will be provided by Logging to create standalone instances of Logger.
33
34 3 Anonyme
h3. Defining the Ecosystem and the Species
35 1 Anonyme
36 8 Anonyme
Create a SpeADL file named _logging.speadl_ in the package _tutorial2.logging_.
37 3 Anonyme
38
Define in it the ecosystem and the species in the right namespace as well as the needed interface:
39
<pre>
40 8 Anonyme
import tutorial2.logging.interfaces.ILog
41 3 Anonyme
42
namespace tutorial2.logging {
43 1 Anonyme
	
44 9 Anonyme
	ecosystem Logging {		
45
		provides create: ICreateLogger
46
47 3 Anonyme
		species Logger(name: String) {
48
			provides log: ILog
49
		}
50
	}
51
	
52
}
53
</pre>
54
55
<pre>
56 8 Anonyme
package tutorial2.logging.interfaces;
57 3 Anonyme
58
public interface ILog {
59
60
	public void addLine(String line);
61 1 Anonyme
}
62 9 Anonyme
63
public interface ICreateLogger {
64
65
	public Logging.Logger.Component createStandaloneLogger(String name);
66
}
67 3 Anonyme
</pre>
68
69
h3. Implementing the Ecosystem and the Species, First One
70
71 12 Anonyme
Create a new Java class in _tutorial2.logging.impl_ named _LoggingImplOneFile_ that extends _Logging_, that takes the a _File_ as a parameter to the constructor to store the logs, and resolve the error with the Quick Fixes of Eclipse:
72 3 Anonyme
<pre>
73
package tutorial2.logging.impl;
74
75
import java.io.File;
76
import java.io.FileNotFoundException;
77 5 Anonyme
import java.io.FileWriter;
78 3 Anonyme
import java.io.IOException;
79
import java.io.PrintWriter;
80
81 1 Anonyme
import tutorial2.logging.Logging;
82 9 Anonyme
import tutorial2.logging.interfaces.ICreateLogger;
83 3 Anonyme
84 12 Anonyme
public class LoggingImplOneFile extends Logging {
85 3 Anonyme
86
	private PrintWriter logWriter;
87
	
88 12 Anonyme
	public LoggingImplOneFile(File logFile) {
89 3 Anonyme
		// if an exception happens, nothing can be done about it
90
		// we just let logStream be null and
91
		// the operations of logging won't be done
92
		try {
93 5 Anonyme
			this.logWriter = new PrintWriter(new FileWriter(logFile), true);
94 3 Anonyme
		} catch (FileNotFoundException e) {
95 5 Anonyme
			System.err.println("An error happened with the file, nothing will be logged.");
96 1 Anonyme
			this.logWriter = null;
97 3 Anonyme
		} catch (IOException e) {
98 5 Anonyme
			System.err.println("An error happened with the file, nothing will be logged.");
99 3 Anonyme
			this.logWriter = null;
100
		}
101 1 Anonyme
	}
102 9 Anonyme
103
	@Override
104
	protected ICreateLogger make_create() {
105
		// TODO Auto-generated method stub
106
		return null;
107
	}
108 3 Anonyme
	
109
	@Override
110
	protected Logger make_Logger(String name) {
111
		// TODO Auto-generated method stub
112
		return null;
113
	}
114
}
115
</pre>
116
117
As we can see, the species we defined needs to be implemented and this implementation needs to be returned by the method _Logger make_Logger(String name)_.
118
119 12 Anonyme
Let's define an inner class inside _LoggingImplOneFile_ to do that, it will take as a parameter to the constructor the _name_ of the Logger and that will exploit the _logWriter_ to do the actual logging.
120 3 Anonyme
<pre>
121 12 Anonyme
public class LoggingImplOneFile extends Logging {
122 3 Anonyme
123
	private PrintWriter logWriter;
124
	
125
	// ...
126
	
127
	@Override
128
	protected Logger make_Logger(String name) {
129
		return new LoggerImpl(name);
130
	}
131
	
132
	private class LoggerImpl extends Logger implements ILog {
133
134
		private final String name;
135
		
136
		public LoggerImpl(String name) {
137
			this.name = name;
138
		}
139
		
140
		@Override
141
		protected ILog make_log() {
142
			return this;
143 1 Anonyme
		}
144
145
		@Override
146 5 Anonyme
		public void addLine(String line) {
147 1 Anonyme
			if (logWriter != null) {
148 5 Anonyme
				logWriter.println("["+name+"] "+ line);
149
			}
150
		}
151
	}
152
}
153
</pre>
154 1 Anonyme
155 9 Anonyme
Then let's implement the create port by exploiting the method *newLogger(String name)* present in the extended class that enables to instantiate a species:
156
<pre>
157 12 Anonyme
public class LoggingImplOneFile extends Logging {
158 9 Anonyme
159
	// ...
160
	
161
	@Override
162
	protected ICreateLogger make_create() {
163
		return new ICreateLogger() {
164
			@Override
165
			public Logger.Component createStandaloneLogger(String name) {
166
				return newLogger(name);
167
			}
168
		};
169
	}
170
171
	// ...
172
}
173 10 Anonyme
</pre>
174 9 Anonyme
175 5 Anonyme
We now have a complete implementation for the Logging ecosystem.
176 9 Anonyme
Let's test it with a very simple program that we put in the package _tutorial2.logging.tests_*:
177 5 Anonyme
<pre>
178
package tutorial2.logging.tests;
179
180 1 Anonyme
import java.io.File;
181
182 9 Anonyme
import tutorial2.logging.Logging;
183
import tutorial2.logging.Logging.Logger;
184 12 Anonyme
import tutorial2.logging.impl.LoggingImplOneFile;
185 5 Anonyme
186 9 Anonyme
public class LoggingTest {
187
	public static void main(String[] args) {
188 5 Anonyme
189 12 Anonyme
		Logging.Component logging = new LoggingImplOneFile(new File("/tmp/tutorial2-logging-test.txt")).newComponent();
190 5 Anonyme
191
		// create new Loggers
192 9 Anonyme
		Logger.Component l1 = logging.create().createStandaloneLogger("a");
193
		Logger.Component l2 = logging.create().createStandaloneLogger("b");
194
		Logger.Component l3 = logging.create().createStandaloneLogger("c");
195
196 5 Anonyme
		// log things to them
197
		l1.log().addLine("1 a says hi");
198
		l1.log().addLine("2 test test");
199
		l2.log().addLine("3 b says hoy");
200
		l1.log().addLine("4 blabla");
201
		l3.log().addLine("5 hop");
202 6 Anonyme
	}
203 5 Anonyme
}
204
</pre>
205
206
Execute it and confirm that the file _/tmp/tutorial2-logging-test.txt_ contains the following:
207
<pre>
208
[a] 1 a says hi
209 3 Anonyme
[a] 2 test test
210
[b] 3 b says hoy
211 1 Anonyme
[a] 4 blabla
212
[c] 5 hop
213 6 Anonyme
</pre>
214
215
h3. Implementing the Ecosystem and the Species, Second One
216
217
We can now define a second implementation that stores the logs of each Logger in its own file:
218
<pre>
219
package tutorial2.logging.impl;
220
221
import java.io.File;
222
import java.io.FileNotFoundException;
223
import java.io.FileWriter;
224
import java.io.IOException;
225
import java.io.PrintWriter;
226
227
import tutorial2.logging.Logging;
228 9 Anonyme
import tutorial2.logging.interfaces.ICreateLogger;
229 1 Anonyme
import tutorial2.logging.interfaces.ILog;
230
231 12 Anonyme
public class LoggingImplDirectory extends Logging {
232 1 Anonyme
233
	private final File logDir;
234
235 12 Anonyme
	public LoggingImplDirectory(File logDir) {
236 1 Anonyme
		this.logDir = logDir;
237
		this.logDir.mkdirs();
238 6 Anonyme
	}
239
	
240
	@Override
241
	protected Logger make_Logger(String name) {
242
		return new LoggerImpl(new File(logDir, name+".txt"));
243
	}
244 9 Anonyme
245
	@Override
246
	protected ICreateLogger make_create() {
247
		return new ICreateLogger() {
248
			@Override
249
			public Logger.Component createStandaloneLogger(String name) {
250
				return newLogger(name);
251
			}
252
		};
253
	}
254 6 Anonyme
	
255
	private class LoggerImpl extends Logger implements ILog {
256
257
		private PrintWriter logWriter;
258
		
259
		public LoggerImpl(File logFile) {
260
			// if an exception happens, nothing can be done about it
261
			// we just let logStream be null and
262
			// the operations of logging won't be done
263
			try {
264
				this.logWriter = new PrintWriter(new FileWriter(logFile), true);
265
			} catch (FileNotFoundException e) {
266
				System.err.println("An error happened with the file, nothing will be logged.");
267
				this.logWriter = null;
268
			} catch (IOException e) {
269
				System.err.println("An error happened with the file, nothing will be logged.");
270
				this.logWriter = null;
271
			}
272 1 Anonyme
		}
273
		
274
		@Override
275
		protected ILog make_log() {
276
			return this;
277
		}
278
279
		@Override
280
		public void addLine(String line) {
281
			if (logWriter != null) {
282
				logWriter.println(line);
283
			}
284
		}
285
	}
286
}
287
</pre>
288
289 9 Anonyme
It can be tested with the previous class by changing the first line instantiating the component:
290 1 Anonyme
<pre>
291 12 Anonyme
Logging.Component logging = new LoggingImplDirectory(new File("/tmp/tutorial2-logging-test/")).newComponent();
292 9 Anonyme
</pre>
293 1 Anonyme
294 9 Anonyme
Execute it and confirm that the _/tmp/tutorial2-logging-test/_ directory contains one file per Logger with the correct content.
295 1 Anonyme
296 9 Anonyme
h2. The Banking Ecosystem 
297 1 Anonyme
298 9 Anonyme
Banking will also be an ecosystem, it will contain Account that are species with a particularity: they have required ports!
299
Because of that, they can't simply be created but must be composed with other components or species to be usable.
300 1 Anonyme
301 9 Anonyme
h3. Defining the Ecosystem and the Species
302
303
Create a SpeADL file named _banking.speadl_ in the package _tutorial2.banking_ and define a _Banking_ ecosystem in _tutorial2.banking_ namespace:
304
<pre>
305
import tutorial2.banking.interfaces.IAccountOperations
306
import tutorial2.banking.interfaces.IAccountStatus
307
import tutorial2.logging.interfaces.ILog
308
309
namespace tutorial2.banking {
310 1 Anonyme
	
311 9 Anonyme
	ecosystem Banking {
312
		
313
		species Account(owner: String) {
314
			
315
			provides operations: IAccountOperations
316
			provides status: IAccountStatus
317
			
318
			requires log: ILog
319
		}
320 1 Anonyme
	}
321
}
322
</pre>
323
324 9 Anonyme
Then the interfaces in _tutorial2.banking.interfaces_:
325
<pre>
326
package tutorial2.banking.interfaces;
327 1 Anonyme
328 9 Anonyme
public interface IAccountOperations {
329 1 Anonyme
330 9 Anonyme
	public void deposit(int value);
331
	public void withdraw(int value);
332
}
333 1 Anonyme
334 9 Anonyme
public interface IAccountStatus {
335
336
	public int getBalance();
337
}
338
</pre>
339
340
h3. Implementing the Ecosystem and the Species
341
342
We now  can define an implementation named _BankingImpl_ in the package _tutorial2.banking.impl_.
343
It exploits the provided ports and the required ports of the species, but also the required port of the ecosystem:
344
<pre>
345
package tutorial2.banking.impl;
346
347
import java.util.concurrent.atomic.AtomicInteger;
348
349
import tutorial2.banking.Banking;
350
import tutorial2.banking.interfaces.IAccountOperations;
351
import tutorial2.banking.interfaces.IAccountStatus;
352
353
public class BankingImpl extends Banking {
354
	
355
	@Override
356
	protected Account make_Account(final String owner) {
357
		return new Account() {
358
			
359
			private final AtomicInteger balance = new AtomicInteger();
360
			
361
			@Override
362
			protected void start() {
363
				eco_requires().elog().addLine("Added a new account for "+owner);
364
			}
365
			
366
			@Override
367
			protected IAccountOperations make_operations() {
368
				return new IAccountOperations() {
369
					
370
					@Override
371
					public void withdraw(int value) {
372
						provides().operations().deposit(-value);
373
						requires().log().addLine(value+" were withdrawn, current balance: "+provides().status().getBalance());
374
					}
375
					
376
					@Override
377
					public void deposit(int value) {
378
						balance.addAndGet(value);
379
						requires().log().addLine(value+" were deposited, current balance: "+provides().status().getBalance());
380
					}
381
				};
382
			}
383
384
			@Override
385
			protected IAccountStatus make_status() {
386
				return new IAccountStatus() {
387
					@Override
388
					public int getBalance() {
389
						return balance.get();
390
					}
391
				};
392
			}
393
		};
394
	}
395
}
396 1 Anonyme
</pre>
397
398 11 Anonyme
Notice the calls to *provides()* and *requires()*.
399
400
Now let's add a bit more log for when a species is instantiated: it must be logged in a file specific to the ecosystem and not to the species.
401
Let's add a required port to the ecosystem _Banking_:
402
<pre>
403
requires elog: ILog
404
</pre>
405
406
Then let's add a *start()* method to the implementation of  _Account_ in _BankingImpl_:
407
<pre>
408
	@Override
409
	protected void start() {
410 1 Anonyme
		eco_requires().elog().addLine("Added a new account for "+owner);
411
	}
412 11 Anonyme
</pre>
413
414
Notice the use of  *eco_requires()* from within the species to access the ports of the ecosystem.
415
416
h2. Composing with Uses into a Bank Application
417
418
Now that we have the two functionality we need, we can build our application to compose them together.
419
In order to do that, we need to define an ecosystem with a species that "uses" the other two.
420
421 12 Anonyme
h3. Defining the Ecosystem and the Species
422
423 11 Anonyme
Let's define the ecosystem _Bank_ in a SpeADL file named _bank.speadl_ in the package and namespace _tutorial2.bank_:
424
<pre>
425
import tutorial2.banking.Banking
426
import tutorial2.banking.interfaces.IAccountOperations
427
import tutorial2.banking.interfaces.IAccountStatus
428
import tutorial2.logging.Logging
429
import tutorial2.logging.interfaces.ILog
430
431
namespace tutorial2.bank {
432
	
433
	ecosystem Bank {
434
		
435
		provides elog: ILog
436
		
437
		part l: Logging
438
		
439
		part b: Banking {
440
			bind elog to elog
441
		}
442
		
443
		species LoggedAccount(owner: String) {
444
			
445 1 Anonyme
			provides operations: IAccountOperations = ba.operations
446
			provides status: IAccountStatus = ba.status
447
			
448
			use ll: l.Logger(owner)
449
			use ba: b.Account(owner) {
450
				bind log to ll.log
451
			}
452
		}
453
	}
454
}
455
</pre>
456
457 12 Anonyme
Notice the following points:
458
* Each of the ecosystem that are needed are declared as parts of the _Bank_ ecosystem, and the species we defined in them are declared as uses of the species _LoggedAccount_.
459
* In order to bind the required port of _b: Banking_, the containing ecosystem needs to provide a port that will be used in the binding. This port is not meant to be used from the exterior but from inside the ecosystem.
460
* The required ports of the _Account_ species are provided by the _Logger_ species.
461
462
The idea behind such a composition is that when an instance of _LoggedAccount_ is created, then it implies that an instance of _Logger_ and an instance of _Account_ are created at the same time and used as parts of _LoggedAccount_.
463
Each of the species retains its links to its own ecosystem without leaking it to the outside.
464
465
h3. Implementing the Ecosystem and the Species
466
467
Implementing the ecosystem is quite straightforward as there is not so much things to add in the implementation.
468
Let's create _BankImpl_ in the package _tutorial2.bank.impl_:
469
<pre>
470
package tutorial2.bank.impl;
471
472
import tutorial2.bank.Bank;
473
import tutorial2.banking.Banking;
474
import tutorial2.logging.Logging;
475
import tutorial2.logging.interfaces.ILog;
476
477
public class BankImpl extends Bank {
478
479
	@Override
480
	protected ILog make_elog() {
481
		// TODO Auto-generated method stub
482
		return null;
483
	}
484
485
	@Override
486
	protected Logging make_l() {
487
		// TODO Auto-generated method stub
488
		return null;
489
	}
490
491
	@Override
492
	protected Banking make_b() {
493
		// TODO Auto-generated method stub
494
		return null;
495
	}
496
497
	@Override
498
	protected LoggedAccount make_LoggedAccount(String owner) {
499
		// TODO Auto-generated method stub
500
		return null;
501
	}
502
}
503
</pre>
504
505
First, let's fill the methods for the parts:
506
<pre>
507
public class BankImpl extends Bank {
508
509
	private final File logDir;
510
511
	public BankImpl(File logDir) {
512
		this.logDir = logDir;
513
	}
514
515
	@Override
516
	protected Logging make_l() {
517
		return new LoggingImplDirectory(logDir);
518
	}
519
520
	@Override
521
	protected Banking make_b() {
522
		return new BankingImpl();
523
	}
524
525
	// ...
526
}
527
</pre>
528
529
Then let's fill the method for the species.
530
As the species has nothing apart from uses and already delegated provided ports, there is no implementation to do:
531
<pre>
532
public class BankImpl extends Bank {
533
534
	// ...
535
536
	@Override
537
	protected LoggedAccount make_LoggedAccount(String owner) {
538
		return new LoggedAccount() {};
539
	}
540
541
	// ...
542
}
543
</pre>
544
545
Finally, let's use the _Logging_ component to get a special _Logger_ for the whole ecosystem:
546
<pre>
547
public class BankImpl extends Bank {
548
549
	// ...
550
551
	private Logging.Logger.Component eLogger;
552
	
553
	@Override
554
	protected void start() {
555
		eLogger = parts().l().create().createStandaloneLogger("BANK");
556
	}
557
558
	@Override
559
	protected ILog make_elog() {
560
		return new ILog() {
561
			@Override
562
			public void addLine(String line) {
563
				eLogger.log().addLine(line);
564
			}
565
		};
566
	}
567
568
	// ...
569
}
570
</pre>
571
572 13 Anonyme
Notice for that last one that because the _make_elog()_ method is called during initialisation of the component before the *start()* method, we have to explicitly delegate the methods of the _ILog_ interface and can't just return _eLogger.log()_ as the implementation of the port _elog_.
573
The _eLogger_ class member must be initialised in the *start()* method because *parts()* won't work properly before.
574
575
h2. Adding a GUI to the Bank Ecosystem
576
577
In order for the _Bank_ ecosystem to be usable, we need to be able to create new _LoggedAccount_ and interact with them.
578
We could add provided ports and interact with it, but here we are going to define another ecosystem encapsulating a GUI for managing the accounts.
579
This GUI could have been directly added to the _Bank_ ecosystem as it is quite empty, but for the sake of pedagogy, we create another ecosystem in order to show more examples and idioms.
580
581
h3. Preparing the Other Ecosystems
582
583
We need first to add a method to _IAccountStatus_ to be able to get the owner of an account:
584
<pre>
585
	public String getOwner();
586
</pre>
587
588
The implementation in the species of _BankingImpl_ just returns the owner:
589
<pre>
590
	@Override
591
	public String getOwner() {
592
		return owner;
593
	}
594
</pre>
595
596
597
Then we need to add a way to instantiate a new account in the _Bank_ ecosystem, let's add a port for that in the ecosystem:
598
<pre>
599
ecosystem Bank {		
600
	provides manage: IBankManage
601
	// ...
602
}
603
</pre>
604
605
<pre>
606
package tutorial2.bank.interfaces;
607
608
public interface IBankManage {
609
	public void instantiateAccount(String owner);
610
}
611
</pre>
612
613
Its implementation in _BankImpl_ simply calls _newLoggedAccount(owner)_:
614
<pre>
615
	@Override
616
	protected IBankManage make_manage() {
617
		return new IBankManage() {
618
			@Override
619
			public void instantiateAccount(String owner) {
620
				newLoggedAccount(owner);
621
			}
622
		};
623
	}
624
</pre>
625
626
Notice that we don't return the created instance because we won't need it in the GUI: everything will be done using bindings of ports between the uses.
627
628
h3. Defining the Ecosystem
629
630
Let's define a _BankGUI_ ecosystem in a SpeADL file named _gui.speadl_ in the package and namespace _tutorial2.gui_:
631 14 Anonyme
<pre>
632
import tutorial2.bank.interfaces.IBankManage
633
import tutorial2.banking.interfaces.IAccountOperations
634
import tutorial2.banking.interfaces.IAccountStatus
635
636
namespace tutorial2.gui {
637
	
638
	ecosystem BankGUI {
639
		
640
		requires manage: IBankManage
641
		
642
		species AccountGUI {
643
			requires operations: IAccountOperations
644
			requires status: IAccountStatus
645
		}
646
	}
647
}
648
</pre>
649
650
The species _AccountGUI_ is responsible of the part of the GUI related to one account, while the ecosystem itself is responsible of the whole frame.
651
In order to manipulate the account, the species has some required ports, and in order to trigger the instantiation of the species, the ecosystem has also some required ports.
652
653
We then need to update the _Bank_ ecosystem as follows in order to exploit _BankGUI_:
654
<pre>
655
namespace tutorial2.bank {
656
	
657
	ecosystem Bank {
658
		
659
		provides manage: IBankManage
660
		provides elog: ILog
661
		
662
		part l: Logging
663
		
664
		part b: Banking {
665
			bind elog to elog
666
		}
667
		
668
		part gui: BankGUI {
669
			bind manage to manage
670
		}
671
		
672
		species LoggedAccount(owner: String) {
673
			
674
			use ll: l.Logger(owner)
675
			use ba: b.Account(owner) {
676
				bind log to ll.log
677
			}
678
			use ga: gui.AccountGUI {
679
				bind operations to ba.operations
680
				bind status to ba.status
681
			}
682
		}
683
	}
684
}
685
</pre>
686
687
Notice that we removed the provided ports of _LoggedAccount_ because they were actually not needed.
688
689
Now, when a new _LoggedAccount_ is instantiated, the species _AccountGUI_ will also be along the other ones.
690
We can exploit that to define in the implementation what happens at that point.
691
692
h3. Implementing the Ecosystem and Species
693
694
The implementation relies on all these ports to instantiate the species when the user clicks on a button.
695
This instantiation will trigger the instantiation of the _AccountGUI_ species, and we will add a row in our GUI for this account.
696
Using the required ports, we can fill the row and call the operations on the account.
697
698
<pre>
699
package tutorial2.gui.impl;
700
701
import java.awt.BorderLayout;
702
import java.awt.event.ActionEvent;
703
import java.awt.event.ActionListener;
704
705
import javax.swing.BoxLayout;
706
import javax.swing.JButton;
707
import javax.swing.JFormattedTextField;
708
import javax.swing.JFrame;
709
import javax.swing.JLabel;
710
import javax.swing.JPanel;
711
import javax.swing.JTextField;
712
import javax.swing.SwingUtilities;
713
714
import tutorial2.gui.BankGUI;
715
716
public class BankGUIImpl extends BankGUI {
717
718
	private final JFrame f = new JFrame();
719
	private final JPanel accPanel = new JPanel();
720
	
721
	@Override
722
	protected void start() {
723
		SwingUtilities.invokeLater(new Runnable() {
724
			@Override
725
			public void run() {				
726
				final JTextField tfAccName = new JTextField("OwnerName");
727
				tfAccName.setColumns(15);
728
				final JButton bAddAccount = new JButton("Add");
729
				final JPanel addAccPanel = new JPanel();
730
				addAccPanel.add(tfAccName);
731
				addAccPanel.add(bAddAccount);								
732
				bAddAccount.addActionListener(new ActionListener() {
733
					@Override
734
					public void actionPerformed(ActionEvent e) {
735
						if (!tfAccName.getText().isEmpty()) {
736
							requires().manage().instantiateAccount(tfAccName.getText());
737
							tfAccName.setText("");
738
						}
739
					}
740
				});
741
				f.getContentPane().add(addAccPanel, BorderLayout.PAGE_START);
742
				accPanel.setLayout(new BoxLayout(accPanel, BoxLayout.Y_AXIS));
743
				f.getContentPane().add(accPanel, BorderLayout.CENTER);
744
			    
745
			    f.pack();
746
			    f.setVisible(true);
747
			    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
748
			}
749
		});
750
	}
751
	
752
	@Override
753
	protected AccountGUI make_AccountGUI() {
754
		return new AccountGUI() {
755
			
756
			private final JPanel panel = new JPanel();
757
			private final JLabel balance = new JLabel();
758
			
759
			@Override
760
			protected void start() {
761
				panel.add(new JLabel(requires().status().getOwner()));
762
				panel.add(balance);
763
				final JFormattedTextField amount = new JFormattedTextField(new Integer(0));
764
				amount.setColumns(5);
765
				panel.add(amount);
766
				final JButton bPlus = new JButton("+");
767
				bPlus.addActionListener(new ActionListener() {
768
					@Override
769
					public void actionPerformed(ActionEvent e) {
770
						final int toAdd = ((Number) amount.getValue()).intValue();
771
						requires().operations().deposit(toAdd);
772
						updateBalance();
773
					}
774
				});
775
				panel.add(bPlus);
776
				final JButton bMinus = new JButton("-");
777
				bMinus.addActionListener(new ActionListener() {
778
					@Override
779
					public void actionPerformed(ActionEvent e) {
780
						final int toRem = ((Number) amount.getValue()).intValue();
781
						requires().operations().withdraw(toRem);
782
						updateBalance();
783
					}
784
				});
785
				panel.add(bMinus);
786
				final JButton bRem = new JButton("Remove");
787
				bRem.addActionListener(new ActionListener() {
788
					@Override
789
					public void actionPerformed(ActionEvent e) {
790
						accPanel.remove(panel);
791
						f.pack();
792
					}
793
				});
794
				panel.add(bRem);
795
				updateBalance();
796
				accPanel.add(panel);
797
				f.pack();
798
			}
799
			
800
			private void updateBalance() {
801
				balance.setText(""+requires().status().getBalance());
802
			}
803
		};
804
	}
805
}
806
</pre>
807
808
We can notice that the remove button will simply remove the panel that contains references to the species.
809
Because the elements of the _LoggedAccount_ species and its sub-components are all related to each others but not at all with the exterior, the fact that this only reference between the GUI and the species disappear means  that the garbage collector of the JVM will remove the instance of the species and its content from the memory.
810 15 Anonyme
811
h3. Executing
812
813
The _Application_ class needs not to be changed and can be run to test the program.