Projet

Général

Profil

SpeADL Dynamic Tutorial » Historique » Version 35

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