Projet

Général

Profil

SpeADL Dynamic Tutorial » Historique » Version 14

Anonyme, 15/10/2014 10:33

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