Projet

Général

Profil

SpeADL Dynamic Tutorial » Historique » Version 37

Anonyme, 31/10/2014 15:26

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