Projet

Général

Profil

SpeADL Dynamic Tutorial » Historique » Version 24

Anonyme, 16/10/2014 12:52

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