├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── chapters
├── exercice1.adoc
├── exercice2.adoc
├── exercice3.adoc
├── exercice4.adoc
├── exercice5.adoc
└── introduction.adoc
├── lab1 solution
├── Lab1.txt
├── build.xml
├── nbproject
│ ├── ant-deploy.xml
│ ├── build-impl.xml
│ ├── genfiles.properties
│ ├── private
│ │ ├── private.properties
│ │ ├── private.xml
│ │ └── retriever
│ │ │ ├── catalog.xml
│ │ │ └── www.oracle.com
│ │ │ └── webfolder
│ │ │ └── technetwork
│ │ │ └── jsc
│ │ │ └── xml
│ │ │ └── ns
│ │ │ └── javaee
│ │ │ └── index.html
│ ├── project.properties
│ └── project.xml
├── src
│ ├── conf
│ │ └── MANIFEST.MF
│ └── java
│ │ └── org
│ │ └── glassfish
│ │ └── javaee7
│ │ └── batch
│ │ └── lab1
│ │ ├── BatchJobSubmitter.java
│ │ ├── NetPayProcessor.java
│ │ ├── PayrollDataHolderBean.java
│ │ ├── PayrollInputRecord.java
│ │ ├── PayrollInputRecordReader.java
│ │ ├── PayrollOutputRecord.java
│ │ └── PayrollOutputRecordWriter.java
└── web
│ ├── WEB-INF
│ ├── beans.xml
│ ├── classes
│ │ └── META-INF
│ │ │ └── batch-jobs
│ │ │ └── PayrollJob.xml
│ └── glassfish-web.xml
│ └── index.html
├── lab1-solution.zip
├── lab2-solution.zip
├── lab2.zip
├── lab3-solution.zip
├── lab3.zip
├── lab4-solution.zip
├── lab4.zip
├── lab5-solution.zip
├── lab5.zip
├── masterLab.adoc
├── masterLab.html
└── pic
├── E1.1.jpg
├── E1.1.png
├── E1.10.jpg
├── E1.10.png
├── E1.11.jpg
├── E1.11.png
├── E1.12.jpg
├── E1.12.png
├── E1.14.jpg
├── E1.14.png
├── E1.15.jpg
├── E1.15.png
├── E1.16.jpg
├── E1.16.png
├── E1.17.jpg
├── E1.17.png
├── E1.2.jpg
├── E1.2.png
├── E1.3.jpg
├── E1.3.png
├── E1.4.jpg
├── E1.4.png
├── E1.5.jpg
├── E1.5.png
├── E1.6.jpg
├── E1.6.png
├── E1.7.jpg
├── E1.7.png
├── E1.8.jpg
├── E1.8.png
├── E1.9.jpg
├── E1.9.png
├── E2.1.jpg
├── E2.1.png
├── E2.2.jpg
├── E2.2.png
├── E2.3.jpg
├── E2.3.png
├── E3.1.jpg
├── E3.1.png
├── E3.2.jpg
├── E3.2.png
├── cover.jpg
└── originals
├── E1.1.png
├── E1.10.png
├── E1.11.png
├── E1.12.png
├── E1.14.png
├── E1.15.png
├── E1.16.png
├── E1.17.png
├── E1.2.png
├── E1.3.png
├── E1.4.png
├── E1.5.png
├── E1.6.png
├── E1.7.png
├── E1.8.png
└── E1.9.png
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | ---
4 |
5 | # Source Code Submissions
6 | We welcome your contributions and look forward to collaborating with you. We can only accept source code repository
7 | submissions from users who have signed and returned the Oracle
8 | Contributor Agreement. You will find details and the agreement to sign at this OTN web page:
9 | [Oracle Contributor Agreement](http://www.oracle.com/technetwork/community/oca-486395.html).
10 |
11 | # Other Contrbutions
12 | For all project Submissions other than source code repository contributions, the following also applies: Oracle does
13 | not claim ownership of Your Submissions. However, in order to fulfill
14 | the purposes of this project, You must give Oracle and all Users
15 | the right to post, access, discuss, use, publish, disseminate, and refine
16 | Your Submissions.
17 |
18 | In legalese: *You hereby grant to Oracle and all
19 | Users a royalty-free, perpetual, irrevocable, worldwide, non-exclusive,
20 | and fully sub-licensable right and license, under Your intellectual
21 | property rights, to reproduce, modify, adapt, publish, translate, create
22 | derivative works from, distribute, perform, display, and use Your
23 | Submissions (in whole or part) and to incorporate or implement them in
24 | other works in any form, media, or technology now known or later
25 | developed, all subject to the obligation to retain any copyright notices
26 | included in Your Submissions. All Users, Oracle, and their
27 | sublicensees are responsible for any modifications they make to the
28 | Submissions of others.*
29 |
30 | Copyright © 2017 Oracle and/or its affiliates. All rights reserved
31 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1
2 |
3 | 1. Definitions.
4 |
5 | 1.1. "Contributor" means each individual or entity that creates or
6 | contributes to the creation of Modifications.
7 |
8 | 1.2. "Contributor Version" means the combination of the Original
9 | Software, prior Modifications used by a Contributor (if any), and
10 | the Modifications made by that particular Contributor.
11 |
12 | 1.3. "Covered Software" means (a) the Original Software, or (b)
13 | Modifications, or (c) the combination of files containing Original
14 | Software with files containing Modifications, in each case including
15 | portions thereof.
16 |
17 | 1.4. "Executable" means the Covered Software in any form other than
18 | Source Code.
19 |
20 | 1.5. "Initial Developer" means the individual or entity that first
21 | makes Original Software available under this License.
22 |
23 | 1.6. "Larger Work" means a work which combines Covered Software or
24 | portions thereof with code not governed by the terms of this License.
25 |
26 | 1.7. "License" means this document.
27 |
28 | 1.8. "Licensable" means having the right to grant, to the maximum
29 | extent possible, whether at the time of the initial grant or
30 | subsequently acquired, any and all of the rights conveyed herein.
31 |
32 | 1.9. "Modifications" means the Source Code and Executable form of
33 | any of the following:
34 |
35 | A. Any file that results from an addition to, deletion from or
36 | modification of the contents of a file containing Original Software
37 | or previous Modifications;
38 |
39 | B. Any new file that contains any part of the Original Software or
40 | previous Modification; or
41 |
42 | C. Any new file that is contributed or otherwise made available
43 | under the terms of this License.
44 |
45 | 1.10. "Original Software" means the Source Code and Executable form
46 | of computer software code that is originally released under this
47 | License.
48 |
49 | 1.11. "Patent Claims" means any patent claim(s), now owned or
50 | hereafter acquired, including without limitation, method, process,
51 | and apparatus claims, in any patent Licensable by grantor.
52 |
53 | 1.12. "Source Code" means (a) the common form of computer software
54 | code in which modifications are made and (b) associated
55 | documentation included in or with such code.
56 |
57 | 1.13. "You" (or "Your") means an individual or a legal entity
58 | exercising rights under, and complying with all of the terms of,
59 | this License. For legal entities, "You" includes any entity which
60 | controls, is controlled by, or is under common control with You. For
61 | purposes of this definition, "control" means (a) the power, direct
62 | or indirect, to cause the direction or management of such entity,
63 | whether by contract or otherwise, or (b) ownership of more than
64 | fifty percent (50%) of the outstanding shares or beneficial
65 | ownership of such entity.
66 |
67 | 2. License Grants.
68 |
69 | 2.1. The Initial Developer Grant.
70 |
71 | Conditioned upon Your compliance with Section 3.1 below and subject
72 | to third party intellectual property claims, the Initial Developer
73 | hereby grants You a world-wide, royalty-free, non-exclusive license:
74 |
75 | (a) under intellectual property rights (other than patent or
76 | trademark) Licensable by Initial Developer, to use, reproduce,
77 | modify, display, perform, sublicense and distribute the Original
78 | Software (or portions thereof), with or without Modifications,
79 | and/or as part of a Larger Work; and
80 |
81 | (b) under Patent Claims infringed by the making, using or selling of
82 | Original Software, to make, have made, use, practice, sell, and
83 | offer for sale, and/or otherwise dispose of the Original Software
84 | (or portions thereof).
85 |
86 | (c) The licenses granted in Sections 2.1(a) and (b) are effective on
87 | the date Initial Developer first distributes or otherwise makes the
88 | Original Software available to a third party under the terms of this
89 | License.
90 |
91 | (d) Notwithstanding Section 2.1(b) above, no patent license is
92 | granted: (1) for code that You delete from the Original Software, or
93 | (2) for infringements caused by: (i) the modification of the
94 | Original Software, or (ii) the combination of the Original Software
95 | with other software or devices.
96 |
97 | 2.2. Contributor Grant.
98 |
99 | Conditioned upon Your compliance with Section 3.1 below and subject
100 | to third party intellectual property claims, each Contributor hereby
101 | grants You a world-wide, royalty-free, non-exclusive license:
102 |
103 | (a) under intellectual property rights (other than patent or
104 | trademark) Licensable by Contributor to use, reproduce, modify,
105 | display, perform, sublicense and distribute the Modifications
106 | created by such Contributor (or portions thereof), either on an
107 | unmodified basis, with other Modifications, as Covered Software
108 | and/or as part of a Larger Work; and
109 |
110 | (b) under Patent Claims infringed by the making, using, or selling
111 | of Modifications made by that Contributor either alone and/or in
112 | combination with its Contributor Version (or portions of such
113 | combination), to make, use, sell, offer for sale, have made, and/or
114 | otherwise dispose of: (1) Modifications made by that Contributor (or
115 | portions thereof); and (2) the combination of Modifications made by
116 | that Contributor with its Contributor Version (or portions of such
117 | combination).
118 |
119 | (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective
120 | on the date Contributor first distributes or otherwise makes the
121 | Modifications available to a third party.
122 |
123 | (d) Notwithstanding Section 2.2(b) above, no patent license is
124 | granted: (1) for any code that Contributor has deleted from the
125 | Contributor Version; (2) for infringements caused by: (i) third
126 | party modifications of Contributor Version, or (ii) the combination
127 | of Modifications made by that Contributor with other software
128 | (except as part of the Contributor Version) or other devices; or (3)
129 | under Patent Claims infringed by Covered Software in the absence of
130 | Modifications made by that Contributor.
131 |
132 | 3. Distribution Obligations.
133 |
134 | 3.1. Availability of Source Code.
135 |
136 | Any Covered Software that You distribute or otherwise make available
137 | in Executable form must also be made available in Source Code form
138 | and that Source Code form must be distributed only under the terms
139 | of this License. You must include a copy of this License with every
140 | copy of the Source Code form of the Covered Software You distribute
141 | or otherwise make available. You must inform recipients of any such
142 | Covered Software in Executable form as to how they can obtain such
143 | Covered Software in Source Code form in a reasonable manner on or
144 | through a medium customarily used for software exchange.
145 |
146 | 3.2. Modifications.
147 |
148 | The Modifications that You create or to which You contribute are
149 | governed by the terms of this License. You represent that You
150 | believe Your Modifications are Your original creation(s) and/or You
151 | have sufficient rights to grant the rights conveyed by this License.
152 |
153 | 3.3. Required Notices.
154 |
155 | You must include a notice in each of Your Modifications that
156 | identifies You as the Contributor of the Modification. You may not
157 | remove or alter any copyright, patent or trademark notices contained
158 | within the Covered Software, or any notices of licensing or any
159 | descriptive text giving attribution to any Contributor or the
160 | Initial Developer.
161 |
162 | 3.4. Application of Additional Terms.
163 |
164 | You may not offer or impose any terms on any Covered Software in
165 | Source Code form that alters or restricts the applicable version of
166 | this License or the recipients' rights hereunder. You may choose to
167 | offer, and to charge a fee for, warranty, support, indemnity or
168 | liability obligations to one or more recipients of Covered Software.
169 | However, you may do so only on Your own behalf, and not on behalf of
170 | the Initial Developer or any Contributor. You must make it
171 | absolutely clear that any such warranty, support, indemnity or
172 | liability obligation is offered by You alone, and You hereby agree
173 | to indemnify the Initial Developer and every Contributor for any
174 | liability incurred by the Initial Developer or such Contributor as a
175 | result of warranty, support, indemnity or liability terms You offer.
176 |
177 | 3.5. Distribution of Executable Versions.
178 |
179 | You may distribute the Executable form of the Covered Software under
180 | the terms of this License or under the terms of a license of Your
181 | choice, which may contain terms different from this License,
182 | provided that You are in compliance with the terms of this License
183 | and that the license for the Executable form does not attempt to
184 | limit or alter the recipient's rights in the Source Code form from
185 | the rights set forth in this License. If You distribute the Covered
186 | Software in Executable form under a different license, You must make
187 | it absolutely clear that any terms which differ from this License
188 | are offered by You alone, not by the Initial Developer or
189 | Contributor. You hereby agree to indemnify the Initial Developer and
190 | every Contributor for any liability incurred by the Initial
191 | Developer or such Contributor as a result of any such terms You offer.
192 |
193 | 3.6. Larger Works.
194 |
195 | You may create a Larger Work by combining Covered Software with
196 | other code not governed by the terms of this License and distribute
197 | the Larger Work as a single product. In such a case, You must make
198 | sure the requirements of this License are fulfilled for the Covered
199 | Software.
200 |
201 | 4. Versions of the License.
202 |
203 | 4.1. New Versions.
204 |
205 | Oracle is the initial license steward and may publish revised and/or
206 | new versions of this License from time to time. Each version will be
207 | given a distinguishing version number. Except as provided in Section
208 | 4.3, no one other than the license steward has the right to modify
209 | this License.
210 |
211 | 4.2. Effect of New Versions.
212 |
213 | You may always continue to use, distribute or otherwise make the
214 | Covered Software available under the terms of the version of the
215 | License under which You originally received the Covered Software. If
216 | the Initial Developer includes a notice in the Original Software
217 | prohibiting it from being distributed or otherwise made available
218 | under any subsequent version of the License, You must distribute and
219 | make the Covered Software available under the terms of the version
220 | of the License under which You originally received the Covered
221 | Software. Otherwise, You may also choose to use, distribute or
222 | otherwise make the Covered Software available under the terms of any
223 | subsequent version of the License published by the license steward.
224 |
225 | 4.3. Modified Versions.
226 |
227 | When You are an Initial Developer and You want to create a new
228 | license for Your Original Software, You may create and use a
229 | modified version of this License if You: (a) rename the license and
230 | remove any references to the name of the license steward (except to
231 | note that the license differs from this License); and (b) otherwise
232 | make it clear that the license contains terms which differ from this
233 | License.
234 |
235 | 5. DISCLAIMER OF WARRANTY.
236 |
237 | COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
238 | WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
239 | INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE
240 | IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR
241 | NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF
242 | THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE
243 | DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY
244 | OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING,
245 | REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
246 | ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS
247 | AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
248 |
249 | 6. TERMINATION.
250 |
251 | 6.1. This License and the rights granted hereunder will terminate
252 | automatically if You fail to comply with terms herein and fail to
253 | cure such breach within 30 days of becoming aware of the breach.
254 | Provisions which, by their nature, must remain in effect beyond the
255 | termination of this License shall survive.
256 |
257 | 6.2. If You assert a patent infringement claim (excluding
258 | declaratory judgment actions) against Initial Developer or a
259 | Contributor (the Initial Developer or Contributor against whom You
260 | assert such claim is referred to as "Participant") alleging that the
261 | Participant Software (meaning the Contributor Version where the
262 | Participant is a Contributor or the Original Software where the
263 | Participant is the Initial Developer) directly or indirectly
264 | infringes any patent, then any and all rights granted directly or
265 | indirectly to You by such Participant, the Initial Developer (if the
266 | Initial Developer is not the Participant) and all Contributors under
267 | Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice
268 | from Participant terminate prospectively and automatically at the
269 | expiration of such 60 day notice period, unless if within such 60
270 | day period You withdraw Your claim with respect to the Participant
271 | Software against such Participant either unilaterally or pursuant to
272 | a written agreement with Participant.
273 |
274 | 6.3. If You assert a patent infringement claim against Participant
275 | alleging that the Participant Software directly or indirectly
276 | infringes any patent where such claim is resolved (such as by
277 | license or settlement) prior to the initiation of patent
278 | infringement litigation, then the reasonable value of the licenses
279 | granted by such Participant under Sections 2.1 or 2.2 shall be taken
280 | into account in determining the amount or value of any payment or
281 | license.
282 |
283 | 6.4. In the event of termination under Sections 6.1 or 6.2 above,
284 | all end user licenses that have been validly granted by You or any
285 | distributor hereunder prior to termination (excluding licenses
286 | granted to You by any distributor) shall survive termination.
287 |
288 | 7. LIMITATION OF LIABILITY.
289 |
290 | UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
291 | (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
292 | INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
293 | COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE
294 | TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
295 | CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
296 | LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER
297 | FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR
298 | LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE
299 | POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT
300 | APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
301 | PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
302 | LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
303 | LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION
304 | AND LIMITATION MAY NOT APPLY TO YOU.
305 |
306 | 8. U.S. GOVERNMENT END USERS.
307 |
308 | The Covered Software is a "commercial item," as that term is defined
309 | in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
310 | software" (as that term is defined at 48 C.F.R. §
311 | 252.227-7014(a)(1)) and "commercial computer software documentation"
312 | as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent
313 | with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4
314 | (June 1995), all U.S. Government End Users acquire Covered Software
315 | with only those rights set forth herein. This U.S. Government Rights
316 | clause is in lieu of, and supersedes, any other FAR, DFAR, or other
317 | clause or provision that addresses Government rights in computer
318 | software under this License.
319 |
320 | 9. MISCELLANEOUS.
321 |
322 | This License represents the complete agreement concerning subject
323 | matter hereof. If any provision of this License is held to be
324 | unenforceable, such provision shall be reformed only to the extent
325 | necessary to make it enforceable. This License shall be governed by
326 | the law of the jurisdiction specified in a notice contained within
327 | the Original Software (except to the extent applicable law, if any,
328 | provides otherwise), excluding such jurisdiction's conflict-of-law
329 | provisions. Any litigation relating to this License shall be subject
330 | to the jurisdiction of the courts located in the jurisdiction and
331 | venue specified in a notice contained within the Original Software,
332 | with the losing party responsible for costs, including, without
333 | limitation, court costs and reasonable attorneys' fees and expenses.
334 | The application of the United Nations Convention on Contracts for
335 | the International Sale of Goods is expressly excluded. Any law or
336 | regulation which provides that the language of a contract shall be
337 | construed against the drafter shall not apply to this License. You
338 | agree that You alone are responsible for compliance with the United
339 | States export administration regulations (and the export control
340 | laws and regulation of any other countries) when You use, distribute
341 | or otherwise make available any Covered Software.
342 |
343 | 10. RESPONSIBILITY FOR CLAIMS.
344 |
345 | As between Initial Developer and the Contributors, each party is
346 | responsible for claims and damages arising, directly or indirectly,
347 | out of its utilization of rights under this License and You agree to
348 | work with Initial Developer and Contributors to distribute such
349 | responsibility on an equitable basis. Nothing herein is intended or
350 | shall be deemed to constitute any admission of liability.
351 |
352 | ------------------------------------------------------------------------
353 |
354 | NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION
355 | LICENSE (CDDL)
356 |
357 | The code released under the CDDL shall be governed by the laws of the
358 | State of California (excluding conflict-of-law provisions). Any
359 | litigation relating to this License shall be subject to the jurisdiction
360 | of the Federal Courts of the Northern District of California and the
361 | state courts of the State of California, with venue lying in Santa Clara
362 | County, California.
363 |
364 |
365 |
366 | # The GNU General Public License (GPL) Version 2, June 1991
367 |
368 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.
369 | 51 Franklin Street, Fifth Floor
370 | Boston, MA 02110-1335
371 | USA
372 |
373 | Everyone is permitted to copy and distribute verbatim copies
374 | of this license document, but changing it is not allowed.
375 |
376 | Preamble
377 |
378 | The licenses for most software are designed to take away your freedom to
379 | share and change it. By contrast, the GNU General Public License is
380 | intended to guarantee your freedom to share and change free software--to
381 | make sure the software is free for all its users. This General Public
382 | License applies to most of the Free Software Foundation's software and
383 | to any other program whose authors commit to using it. (Some other Free
384 | Software Foundation software is covered by the GNU Library General
385 | Public License instead.) You can apply it to your programs, too.
386 |
387 | When we speak of free software, we are referring to freedom, not price.
388 | Our General Public Licenses are designed to make sure that you have the
389 | freedom to distribute copies of free software (and charge for this
390 | service if you wish), that you receive source code or can get it if you
391 | want it, that you can change the software or use pieces of it in new
392 | free programs; and that you know you can do these things.
393 |
394 | To protect your rights, we need to make restrictions that forbid anyone
395 | to deny you these rights or to ask you to surrender the rights. These
396 | restrictions translate to certain responsibilities for you if you
397 | distribute copies of the software, or if you modify it.
398 |
399 | For example, if you distribute copies of such a program, whether gratis
400 | or for a fee, you must give the recipients all the rights that you have.
401 | You must make sure that they, too, receive or can get the source code.
402 | And you must show them these terms so they know their rights.
403 |
404 | We protect your rights with two steps: (1) copyright the software, and
405 | (2) offer you this license which gives you legal permission to copy,
406 | distribute and/or modify the software.
407 |
408 | Also, for each author's protection and ours, we want to make certain
409 | that everyone understands that there is no warranty for this free
410 | software. If the software is modified by someone else and passed on, we
411 | want its recipients to know that what they have is not the original, so
412 | that any problems introduced by others will not reflect on the original
413 | authors' reputations.
414 |
415 | Finally, any free program is threatened constantly by software patents.
416 | We wish to avoid the danger that redistributors of a free program will
417 | individually obtain patent licenses, in effect making the program
418 | proprietary. To prevent this, we have made it clear that any patent must
419 | be licensed for everyone's free use or not licensed at all.
420 |
421 | The precise terms and conditions for copying, distribution and
422 | modification follow.
423 |
424 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
425 |
426 | 0. This License applies to any program or other work which contains a
427 | notice placed by the copyright holder saying it may be distributed under
428 | the terms of this General Public License. The "Program", below, refers
429 | to any such program or work, and a "work based on the Program" means
430 | either the Program or any derivative work under copyright law: that is
431 | to say, a work containing the Program or a portion of it, either
432 | verbatim or with modifications and/or translated into another language.
433 | (Hereinafter, translation is included without limitation in the term
434 | "modification".) Each licensee is addressed as "you".
435 |
436 | Activities other than copying, distribution and modification are not
437 | covered by this License; they are outside its scope. The act of running
438 | the Program is not restricted, and the output from the Program is
439 | covered only if its contents constitute a work based on the Program
440 | (independent of having been made by running the Program). Whether that
441 | is true depends on what the Program does.
442 |
443 | 1. You may copy and distribute verbatim copies of the Program's source
444 | code as you receive it, in any medium, provided that you conspicuously
445 | and appropriately publish on each copy an appropriate copyright notice
446 | and disclaimer of warranty; keep intact all the notices that refer to
447 | this License and to the absence of any warranty; and give any other
448 | recipients of the Program a copy of this License along with the Program.
449 |
450 | You may charge a fee for the physical act of transferring a copy, and
451 | you may at your option offer warranty protection in exchange for a fee.
452 |
453 | 2. You may modify your copy or copies of the Program or any portion of
454 | it, thus forming a work based on the Program, and copy and distribute
455 | such modifications or work under the terms of Section 1 above, provided
456 | that you also meet all of these conditions:
457 |
458 | a) You must cause the modified files to carry prominent notices
459 | stating that you changed the files and the date of any change.
460 |
461 | b) You must cause any work that you distribute or publish, that in
462 | whole or in part contains or is derived from the Program or any part
463 | thereof, to be licensed as a whole at no charge to all third parties
464 | under the terms of this License.
465 |
466 | c) If the modified program normally reads commands interactively
467 | when run, you must cause it, when started running for such
468 | interactive use in the most ordinary way, to print or display an
469 | announcement including an appropriate copyright notice and a notice
470 | that there is no warranty (or else, saying that you provide a
471 | warranty) and that users may redistribute the program under these
472 | conditions, and telling the user how to view a copy of this License.
473 | (Exception: if the Program itself is interactive but does not
474 | normally print such an announcement, your work based on the Program
475 | is not required to print an announcement.)
476 |
477 | These requirements apply to the modified work as a whole. If
478 | identifiable sections of that work are not derived from the Program, and
479 | can be reasonably considered independent and separate works in
480 | themselves, then this License, and its terms, do not apply to those
481 | sections when you distribute them as separate works. But when you
482 | distribute the same sections as part of a whole which is a work based on
483 | the Program, the distribution of the whole must be on the terms of this
484 | License, whose permissions for other licensees extend to the entire
485 | whole, and thus to each and every part regardless of who wrote it.
486 |
487 | Thus, it is not the intent of this section to claim rights or contest
488 | your rights to work written entirely by you; rather, the intent is to
489 | exercise the right to control the distribution of derivative or
490 | collective works based on the Program.
491 |
492 | In addition, mere aggregation of another work not based on the Program
493 | with the Program (or with a work based on the Program) on a volume of a
494 | storage or distribution medium does not bring the other work under the
495 | scope of this License.
496 |
497 | 3. You may copy and distribute the Program (or a work based on it,
498 | under Section 2) in object code or executable form under the terms of
499 | Sections 1 and 2 above provided that you also do one of the following:
500 |
501 | a) Accompany it with the complete corresponding machine-readable
502 | source code, which must be distributed under the terms of Sections 1
503 | and 2 above on a medium customarily used for software interchange; or,
504 |
505 | b) Accompany it with a written offer, valid for at least three
506 | years, to give any third party, for a charge no more than your cost
507 | of physically performing source distribution, a complete
508 | machine-readable copy of the corresponding source code, to be
509 | distributed under the terms of Sections 1 and 2 above on a medium
510 | customarily used for software interchange; or,
511 |
512 | c) Accompany it with the information you received as to the offer to
513 | distribute corresponding source code. (This alternative is allowed
514 | only for noncommercial distribution and only if you received the
515 | program in object code or executable form with such an offer, in
516 | accord with Subsection b above.)
517 |
518 | The source code for a work means the preferred form of the work for
519 | making modifications to it. For an executable work, complete source code
520 | means all the source code for all modules it contains, plus any
521 | associated interface definition files, plus the scripts used to control
522 | compilation and installation of the executable. However, as a special
523 | exception, the source code distributed need not include anything that is
524 | normally distributed (in either source or binary form) with the major
525 | components (compiler, kernel, and so on) of the operating system on
526 | which the executable runs, unless that component itself accompanies the
527 | executable.
528 |
529 | If distribution of executable or object code is made by offering access
530 | to copy from a designated place, then offering equivalent access to copy
531 | the source code from the same place counts as distribution of the source
532 | code, even though third parties are not compelled to copy the source
533 | along with the object code.
534 |
535 | 4. You may not copy, modify, sublicense, or distribute the Program
536 | except as expressly provided under this License. Any attempt otherwise
537 | to copy, modify, sublicense or distribute the Program is void, and will
538 | automatically terminate your rights under this License. However, parties
539 | who have received copies, or rights, from you under this License will
540 | not have their licenses terminated so long as such parties remain in
541 | full compliance.
542 |
543 | 5. You are not required to accept this License, since you have not
544 | signed it. However, nothing else grants you permission to modify or
545 | distribute the Program or its derivative works. These actions are
546 | prohibited by law if you do not accept this License. Therefore, by
547 | modifying or distributing the Program (or any work based on the
548 | Program), you indicate your acceptance of this License to do so, and all
549 | its terms and conditions for copying, distributing or modifying the
550 | Program or works based on it.
551 |
552 | 6. Each time you redistribute the Program (or any work based on the
553 | Program), the recipient automatically receives a license from the
554 | original licensor to copy, distribute or modify the Program subject to
555 | these terms and conditions. You may not impose any further restrictions
556 | on the recipients' exercise of the rights granted herein. You are not
557 | responsible for enforcing compliance by third parties to this License.
558 |
559 | 7. If, as a consequence of a court judgment or allegation of patent
560 | infringement or for any other reason (not limited to patent issues),
561 | conditions are imposed on you (whether by court order, agreement or
562 | otherwise) that contradict the conditions of this License, they do not
563 | excuse you from the conditions of this License. If you cannot distribute
564 | so as to satisfy simultaneously your obligations under this License and
565 | any other pertinent obligations, then as a consequence you may not
566 | distribute the Program at all. For example, if a patent license would
567 | not permit royalty-free redistribution of the Program by all those who
568 | receive copies directly or indirectly through you, then the only way you
569 | could satisfy both it and this License would be to refrain entirely from
570 | distribution of the Program.
571 |
572 | If any portion of this section is held invalid or unenforceable under
573 | any particular circumstance, the balance of the section is intended to
574 | apply and the section as a whole is intended to apply in other
575 | circumstances.
576 |
577 | It is not the purpose of this section to induce you to infringe any
578 | patents or other property right claims or to contest validity of any
579 | such claims; this section has the sole purpose of protecting the
580 | integrity of the free software distribution system, which is implemented
581 | by public license practices. Many people have made generous
582 | contributions to the wide range of software distributed through that
583 | system in reliance on consistent application of that system; it is up to
584 | the author/donor to decide if he or she is willing to distribute
585 | software through any other system and a licensee cannot impose that choice.
586 |
587 | This section is intended to make thoroughly clear what is believed to be
588 | a consequence of the rest of this License.
589 |
590 | 8. If the distribution and/or use of the Program is restricted in
591 | certain countries either by patents or by copyrighted interfaces, the
592 | original copyright holder who places the Program under this License may
593 | add an explicit geographical distribution limitation excluding those
594 | countries, so that distribution is permitted only in or among countries
595 | not thus excluded. In such case, this License incorporates the
596 | limitation as if written in the body of this License.
597 |
598 | 9. The Free Software Foundation may publish revised and/or new
599 | versions of the General Public License from time to time. Such new
600 | versions will be similar in spirit to the present version, but may
601 | differ in detail to address new problems or concerns.
602 |
603 | Each version is given a distinguishing version number. If the Program
604 | specifies a version number of this License which applies to it and "any
605 | later version", you have the option of following the terms and
606 | conditions either of that version or of any later version published by
607 | the Free Software Foundation. If the Program does not specify a version
608 | number of this License, you may choose any version ever published by the
609 | Free Software Foundation.
610 |
611 | 10. If you wish to incorporate parts of the Program into other free
612 | programs whose distribution conditions are different, write to the
613 | author to ask for permission. For software which is copyrighted by the
614 | Free Software Foundation, write to the Free Software Foundation; we
615 | sometimes make exceptions for this. Our decision will be guided by the
616 | two goals of preserving the free status of all derivatives of our free
617 | software and of promoting the sharing and reuse of software generally.
618 |
619 | NO WARRANTY
620 |
621 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
622 | WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
623 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
624 | OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
625 | EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
626 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
627 | ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
628 | YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
629 | NECESSARY SERVICING, REPAIR OR CORRECTION.
630 |
631 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
632 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
633 | AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
634 | DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
635 | DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
636 | (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
637 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
638 | THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR
639 | OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
640 |
641 | END OF TERMS AND CONDITIONS
642 |
643 | How to Apply These Terms to Your New Programs
644 |
645 | If you develop a new program, and you want it to be of the greatest
646 | possible use to the public, the best way to achieve this is to make it
647 | free software which everyone can redistribute and change under these terms.
648 |
649 | To do so, attach the following notices to the program. It is safest to
650 | attach them to the start of each source file to most effectively convey
651 | the exclusion of warranty; and each file should have at least the
652 | "copyright" line and a pointer to where the full notice is found.
653 |
654 | One line to give the program's name and a brief idea of what it does.
655 | Copyright (C)
656 |
657 | This program is free software; you can redistribute it and/or modify
658 | it under the terms of the GNU General Public License as published by
659 | the Free Software Foundation; either version 2 of the License, or
660 | (at your option) any later version.
661 |
662 | This program is distributed in the hope that it will be useful, but
663 | WITHOUT ANY WARRANTY; without even the implied warranty of
664 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
665 | General Public License for more details.
666 |
667 | You should have received a copy of the GNU General Public License
668 | along with this program; if not, write to the Free Software
669 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
670 |
671 | Also add information on how to contact you by electronic and paper mail.
672 |
673 | If the program is interactive, make it output a short notice like this
674 | when it starts in an interactive mode:
675 |
676 | Gnomovision version 69, Copyright (C) year name of author
677 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type
678 | `show w'. This is free software, and you are welcome to redistribute
679 | it under certain conditions; type `show c' for details.
680 |
681 | The hypothetical commands `show w' and `show c' should show the
682 | appropriate parts of the General Public License. Of course, the commands
683 | you use may be called something other than `show w' and `show c'; they
684 | could even be mouse-clicks or menu items--whatever suits your program.
685 |
686 | You should also get your employer (if you work as a programmer) or your
687 | school, if any, to sign a "copyright disclaimer" for the program, if
688 | necessary. Here is a sample; alter the names:
689 |
690 | Yoyodyne, Inc., hereby disclaims all copyright interest in the
691 | program `Gnomovision' (which makes passes at compilers) written by
692 | James Hacker.
693 |
694 | signature of Ty Coon, 1 April 1989
695 | Ty Coon, President of Vice
696 |
697 | This General Public License does not permit incorporating your program
698 | into proprietary programs. If your program is a subroutine library, you
699 | may consider it more useful to permit linking proprietary applications
700 | with the library. If this is what you want to do, use the GNU Library
701 | General Public License instead of this License.
702 |
703 | ---
704 |
705 | Certain source files distributed by Oracle America, Inc. and/or its
706 | affiliates are subject to the following clarification and special
707 | exception to the GPLv2, based on the GNU Project exception for its
708 | Classpath libraries, known as the GNU Classpath Exception, but only
709 | where Oracle has expressly included in the particular source file's
710 | header the words "Oracle designates this particular file as subject to
711 | the "Classpath" exception as provided by Oracle in the LICENSE file
712 | that accompanied this code."
713 |
714 | You should also note that Oracle includes multiple, independent
715 | programs in this software package. Some of those programs are provided
716 | under licenses deemed incompatible with the GPLv2 by the Free Software
717 | Foundation and others. For example, the package includes programs
718 | licensed under the Apache License, Version 2.0. Such programs are
719 | licensed to you under their original licenses.
720 |
721 | Oracle facilitates your further distribution of this package by adding
722 | the Classpath Exception to the necessary parts of its GPLv2 code, which
723 | permits you to use that code in combination with other independent
724 | modules not licensed under the GPLv2. However, note that this would
725 | not permit you to commingle code under an incompatible license with
726 | Oracle's GPLv2 licensed code by, for example, cutting and pasting such
727 | code into a file also containing Oracle's GPLv2 licensed code and then
728 | distributing the result. Additionally, if you were to remove the
729 | Classpath Exception from any of the files to which it applies and
730 | distribute the result, you would likely be required to license some or
731 | all of the other code in that distribution under the GPLv2 as well, and
732 | since the GPLv2 is incompatible with the license terms of some items
733 | included in the distribution by Oracle, removing the Classpath
734 | Exception could therefore effectively compromise your ability to
735 | further distribute the package.
736 |
737 | Proceed with caution and we recommend that you obtain the advice of a
738 | lawyer skilled in open source matters before removing the Classpath
739 | Exception or making modifications to this package which may
740 | subsequently be redistributed and/or involve the use of third party
741 | software.
742 |
743 | # CLASSPATH EXCEPTION
744 | Linking this library statically or dynamically with other modules is
745 | making a combined work based on this library. Thus, the terms and
746 | conditions of the GNU General Public License version 2 cover the whole
747 | combination.
748 |
749 | As a special exception, the copyright holders of this library give you
750 | permission to link this library with independent modules to produce an
751 | executable, regardless of the license terms of these independent
752 | modules, and to copy and distribute the resulting executable under
753 | terms of your choice, provided that you also meet, for each linked
754 | independent module, the terms and conditions of the license of that
755 | module. An independent module is a module which is not derived from or
756 | based on this library. If you modify this library, you may extend this
757 | exception to your version of the library, but you are not obligated to
758 | do so. If you do not wish to do so, delete this exception statement
759 | from your version.
760 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BatchLab
2 | Batch API (JSR 352) Hands-on Lab
3 |
4 | This Lab was developed for JavaOne 2014.
5 |
6 | It starts with introducing the core concepts of JSR 352 (Job, Chunk, etc.) and then add features and concpets such as Batchlet, Multi-steps Job, Checkpoints, the JobOperator interface, Listeners and Job Partitioning.
7 |
8 | This Lab has been tested on GlassFish 4.0 & 4.1 but should work on any Java EE 7 compatible application server (full platform).
9 |
10 | To get started, download the project and check the masterLab.html file (generated from the .adoc files).
11 |
--------------------------------------------------------------------------------
/chapters/exercice1.adoc:
--------------------------------------------------------------------------------
1 | //////////////////////////////////////////
2 | Author : David Delabassee
3 | License :
4 | //////////////////////////////////////////
5 |
6 |
7 | :imagesdir: ../pic
8 |
9 | == Lab: JSR 352 introduction
10 |
11 | This exercise will introduce you the main concepts of JSR 352 : Step, Job, Job Specification Language, batch runtime, etc. You will build a complete application that will run a simple batch job performing some hypothetical salary calculations. The application has been intentionally kept quite simple in order to focus on the key concepts of JSR 352.
12 |
13 |
14 | === Set the stage
15 |
16 | By nature Batch Job are long-lived and doesn't require human intervention. Nevertheless in our exercise, we will use a Servlet to interact with the Batch API (e.g. start the Job, get the status of the Job, etc.).
17 |
18 |
19 | ==== Create the project
20 |
21 | In the NetBeans Projects window, right click and select "New Project...".
22 |
23 | .NetBeans Project Windows
24 | image::E1.1.jpg[]
25 |
26 | ==== Create the Web Application
27 |
28 | We will now create a Web Application so select "Web Application" in the "Java Web" category. Note that a Web Application in NetBeans parlance is just the project structure of a typical Web Application.
29 | --
30 | TIP: You can use the filter option at the top of the "New Project" window to filter out options from NetBeans, e.g. type "web" to easily find the "Web Application" project type.
31 | --
32 |
33 | .Create a Project & NetBeans Filter
34 | image::E1.2.jpg[]
35 |
36 |
37 | Click "Next" and give your project a relevant name (e.g. "Lab1"). You can leave the other suggested values (Location & Folder) as they are. Click "Finish" and you should now have an empty Web Application (project structure and a single JSP page).
38 |
39 | .TO CHECK
40 | image::E1.3.jpg[]
41 |
42 | ==== Create the Package
43 |
44 | You should now create the package to host the application code. Right click in your project, select "New" and "Java Package" and name your package "org.glassfish.batch.lab1". All our codes will reside in this package.
45 |
46 | .Create a New Package
47 | image::E1.4.jpg[]
48 | --
49 | TIP: It is possible that your menu is slightly different. If you don't find the "Java Package..." option, just select "Other..." at the bottom of the menu and use the filter.
50 | --
51 |
52 | ==== Create the Servlet
53 |
54 | We will now create the Servlet itself. As usual, use NetBeans "New" menu and select "Servlet" from the "Web" category. Click "Next" and make sure to select, using the drop-down list, the package we have defined in the previous step (see Figure 6). You can click "Finish" as we are, for the rest, using the default values.
55 |
56 |
57 | .Create the Servlet
58 | image::E1.6.jpg[]
59 |
60 | .Select the right package for your Servlet
61 | image::E1.7.jpg[]
62 |
63 | --
64 | TIP: You can now right click on your Servlet class and select "Run File". If everything goes well, your Servlet will be compiled and deployed to GlassFish. NetBeans will then invoke your web browser to connect to your Servlet.
65 | --
66 |
67 |
68 | === Data and Data Store
69 |
70 | A typical enterprise application needs some data to consume. In real life, those data are high likely stored in a database, received over the network (eg. through a REST endpoint) or via a JMS Queue, etc.
71 |
72 | Our exercise also needs some data but for the sake of simplicity, we will mock a data producer behind a simple Singleton EJB as the focus of the Lab is really on the Batch API and not so much on other APIs such as JPA or JAX-RS.
73 |
74 | ==== Create the the Input Record
75 |
76 | Let's now create a simple class that will be used as input record for the application.
77 | This class is very simple, it holds an employee Id and some simple methods (e.g. get and set the employee salary).
78 |
79 | In the Project Window, select "New", "Java Class" from the "Java" category and click "Next". Name the class "PayrollInputRecord" and make sure it's in the correct package ("org.glassfish.batch.lab1"). Click "Finish" to actually create the class.
80 |
81 | .Create a new Java class
82 | image::E1.8.jpg[]
83 |
84 | Add the following code to the body of the class :
85 | [source, java]
86 | ----
87 | private final int id;
88 |
89 | private String salary;
90 |
91 | public PayrollInputRecord(int id) {
92 | this.id = id;
93 | }
94 |
95 | public int getId() {
96 | return id;
97 | }
98 |
99 | public String getSalary() {
100 | return salary;
101 | }
102 |
103 | public void setSalary(String salary) {
104 | this.salary = salary;
105 | }
106 |
107 | @Override
108 | public int hashCode() {
109 | return id;
110 | }
111 |
112 | @Override
113 | public boolean equals(Object object) {
114 | if (object == null || !(object instanceof PayrollInputRecord)) {
115 | return false;
116 | }
117 | PayrollInputRecord other = (PayrollInputRecord) object;
118 | return this.id == other.id;
119 | }
120 |
121 | @Override
122 | public String toString() {
123 | return "PayrollInputRecord[ id=" + id + " ]";
124 | }
125 | ----
126 |
127 | --
128 | TIP: When you save a class, NetBeans will try to recompile it. If it can't, you will easily then see where the errors are.
129 | --
130 |
131 | ==== Create the the Output Record
132 |
133 | Similarly, we will now create a simple class that will be used as output record.
134 | This class adds some capabilities (set and get the employee social security number, his/her bonus, etc.)
135 |
136 | In the Project Window, select "New", "Java Class" from the "Java" category and click "Next". Name the class "PayrollOutputRecord", check the package ("org.glassfish.batch.lab1") and click "Finish".
137 |
138 | Add this code to the class :
139 | [source, java]
140 | ----
141 | private final int empId;
142 |
143 | private float salary;
144 |
145 | private float socialSecurityTax;
146 |
147 | private float bonus = 0;
148 |
149 | private float net;
150 |
151 | public PayrollOutputRecord(int empID) {
152 | this.empId = empID;
153 | }
154 |
155 | public int getEmpId() {
156 | return empId;
157 | }
158 |
159 | public float getSalary() {
160 | return salary;
161 | }
162 |
163 | public void setSalary(float base) {
164 | this.salary = base;
165 | }
166 |
167 | public float getSocialSecurityTax() {
168 | return socialSecurityTax;
169 | }
170 |
171 | public void setSocialSecurityTax(float socialSecurityTax) {
172 | this.socialSecurityTax = socialSecurityTax;
173 | }
174 |
175 | public float getBonus() {
176 | return bonus;
177 | }
178 |
179 | public void setBonus(float bonus) {
180 | this.bonus = bonus;
181 | }
182 |
183 | public float getNet() {
184 | return net;
185 | }
186 |
187 | public void setNet(float net) {
188 | this.net = net;
189 | }
190 |
191 | @Override
192 | public int hashCode() {
193 | return getEmpId();
194 | }
195 |
196 | @Override
197 | public boolean equals(Object object) {
198 | if (object == null || !(object instanceof PayrollOutputRecord)) {
199 | return false;
200 | }
201 | PayrollOutputRecord other = (PayrollOutputRecord) object;
202 | return getEmpId() == other.getEmpId();
203 | }
204 |
205 | @Override
206 | public String toString() {
207 | return "PayrollOutputRecord[ id= [" + getEmpId() + "]";
208 | }
209 | ----
210 |
211 |
212 | ==== Create the EJB
213 |
214 | We will create a simple Java class. We will then use some annotations to turn this POJO (Plain Old Java Object) into the Enterprise Java Beans we need.
215 |
216 | In the Project Window, select "New", "Java Class" from the "Java" category and click "Next". Name the class "PayrollDataHolderBean" and make sure it's in the correct package ("org.glassfish.batch.lab1")
217 |
218 | .Create a java class
219 | image::E1.5.jpg[]
220 |
221 | Add the following 2 annotations at the class level : `@Singleton` & `@Startup` :
222 |
223 | * `@Singleton` is used to specify that this class will be implements a singleton session bean. You will have to import `javax.ejb.Singleton`.
224 | * `@Startup` is used to specify that this EJB will use eager initialization, i.e. the EJB container will initialise it upon application startup, before it can get any requests. This is useful, for example, to perform application startup tasks.
225 | ...
226 |
227 | .Notice the yellow light bulb on the left and the red waved underlined line of code.
228 | image::E1.9.jpg[]
229 |
230 | --
231 | TIP: A waved red underlined line of code means that NetBeans is unable to compile that particular line. A light bulb on the left side of the code means that NetBeans has suggestions that could fix the issue. Right click on the magnifier to see and eventually select one of the proposed fix.
232 | --
233 |
234 | Right click on the light bulb to fix the imports. Check to top of the class file and you should now see the that the classes corresponding to the 2 annotations have been added.
235 |
236 | [source, java]
237 | ----
238 | import javax.ejb.Singleton;
239 | import javax.ejb.Startup;
240 | ----
241 |
242 |
243 |
244 |
245 | Add the following code to the body of the class :
246 | [source, java]
247 | ----
248 | private List payrollInputRecords = new ArrayList<>();
249 |
250 | private Set payrollOutputRecords = new HashSet<>();
251 |
252 | public PayrollDataHolderBean() {
253 |
254 | }
255 |
256 | @PostConstruct
257 | public void onApplicationStartup() {
258 | for (int empID=1; empID<6; empID++) {
259 | payrollInputRecords.add("" + empID + ", " + (80000 + empID*10000));
260 | }
261 | }
262 |
263 | public List getPayrollInputData() {
264 | return Collections.unmodifiableList(payrollInputRecords);
265 | }
266 |
267 | public void addPayrollOutputRecord(PayrollOutputRecord data) {
268 | payrollOutputRecords.add(data);
269 | }
270 |
271 | public Set getPayrollOutputRecords() {
272 | return payrollOutputRecords;
273 | }
274 | ----
275 |
276 | In this code, we define a `payrollInputRecords` list of strings. We use the `@PostConstruct` annotation to specify to the Application Server that the `onApplicationStartup()` method should be invoked after all injection has occurred and after all initializers have been called, i.e. before the EJB can handle client requests. This method basically fills the `payrollInputRecords` list with dummy employees data (an employee ID and numeric value, stored in a simple string).
277 | We also define a `PayrollOutputRecord` collection and some related methods (add an element, get the collection).
278 |
279 | Make sure to resolve any missing imports. The class `PayrollDataHolderBean.java` should now compile and looks like this.
280 | [source, java]
281 | ----
282 | package org.glassfish.batch.lab1;
283 |
284 | import java.util.ArrayList;
285 | import java.util.Collections;
286 | import java.util.HashSet;
287 | import java.util.List;
288 | import java.util.Set;
289 | import javax.annotation.PostConstruct;
290 | import javax.ejb.Singleton;
291 | import javax.ejb.Startup;
292 |
293 | @Singleton
294 | @Startup
295 | public class PayrollDataHolderBean {
296 | private List payrollInputRecords = new ArrayList<>();
297 |
298 | private Set payrollOutputRecords = new HashSet<>();
299 |
300 | public PayrollDataHolderBean() {
301 |
302 | }
303 |
304 | @PostConstruct
305 | public void onApplicationStartup() {
306 | for (int empID=1; empID<6; empID++) {
307 | payrollInputRecords.add("" + empID + ", " + (80000 + empID*10000));
308 | }
309 | }
310 |
311 | public List getPayrollInputData() {
312 | return Collections.unmodifiableList(payrollInputRecords);
313 | }
314 |
315 | public void addPayrollOutputRecord(PayrollOutputRecord data) {
316 | payrollOutputRecords.add(data);
317 | }
318 |
319 | public Set getPayrollOutputRecords() {
320 | return payrollOutputRecords;
321 | }
322 |
323 | }
324 | ----
325 |
326 |
327 | === PayRoll Job : the Reader, the Processor, the Writer
328 |
329 | Now that we have everything set in place, we can tackle the main part of the exercise, i.e. create the batch job!
330 |
331 | A batch job uses a simple 'Read - Process - Write' pattern. A *Reader* is used to retrieve the input data, a *Processor* will then do some processing on those data and finally, a *Writer* will save the results somewhere. How the data are actually read (e.g. from a filesystem, from a database, from memory, etc.) is not specified so we are free to use, in a Reader, the mechanism we want. In our exercise, we will just read some data stored in an singleton EJB.
332 |
333 |
334 | The same is true for the output, for the Writer. The specification doesn't say how the output should be saved so we can use different approaches (e.g. send a mail, post to a JMS queue, update a Database via JPA or JBDC, etc.)
335 |
336 | --
337 | TIP: The fundamental unit of a *Job* is a *Step*. A job is made of one or more steps. JSR 352 defines 2 types of steps: *Chunk* step used to work on data using the Read-Process-Write pattern and *Batchlet* step used to perform task(s) within a job (e.g. send via FTP the final result of a Job).
338 | --
339 |
340 | A *chunk-style step* contains exactly one *ItemReader*, one *ItemProcessor*, and one *ItemWriter*. In this pattern, items are processed "chunk-size" at a time. The "chunk-size" is specified in the Job xml.
341 |
342 | --
343 | TIP: JSR 352 also defines a XML based language called *JSL* (Job Specification Language). JSL is used to assemble together different steps to form a job, defines the flow between the different steps and also configure the behaviour of the Job itself (e.g. what to do in case of error).
344 | --
345 |
346 | A chunk is processed as follows: The batch runtime starts a transaction and calls the ItemReader to read one item at a time. The batch runtime then passes this item to the ItemProcessor that processes the item based upon the business logic (such as "calculate net pay"), and returns the processed item to the batch runtime for aggregation. Once the "chunk-size" number of items are read and processed, they are given to an ItemWriter, which writes the data (for example, to a database table or a flat file). The transaction is then committed. The process repeats till the ItemReader finishes reading all items.
347 |
348 | To implement a batch Job, we will have implement at least one Chunked step. Implementing a Chunked step means developing in Java : a Reader, a Processor and a Writer. That is exactly what will do in the next few sections, we will develop a Reader, a Writer and a Processor. We will then define the Job itself using JSL.
349 |
350 |
351 | ==== Reader
352 |
353 | A Reader is class that extends the abstract `javax.batch.api.chunk.AbstractItemReader` class defined in JSR 352.
354 |
355 | Create, in the right package, a new class called PayrollInputRecordReader and in the class declaration, specify that this class should extends the `AbstractItemReader` class.
356 |
357 | .extends the `AbstractItemReader` class
358 | image::E1.11.jpg[]
359 |
360 | Make sure to fix the import for the `AbstractItemReader` class.
361 | You can see that NetBeans is still unable to compile the code, this is because the class we are extending is abstract. To fix this, just make sure to implements all the abstract methods (one in this case, the `readItem()` method).
362 |
363 | .Using NetBeans to implements the abstract methods
364 | image::E1.12.jpg[]
365 |
366 | The exercise data will be coming from the singleton EJB we have defined previously, so you can inject this EJB by adding the following declaration:
367 |
368 | [source, java]
369 | ----
370 | @EJB
371 | PayrollDataHolderBean payrollDataHolderBean;
372 | ----
373 |
374 | Let's create the `payrollInputRecordsIterator` Iterator
375 |
376 | [source, java]
377 | ----
378 | Iterator payrollInputRecordsIterator;
379 | ----
380 |
381 | Now we should initialize it with the data contained in the EJB. We will do this in the `open()` method defined in the `AbstractItemReader` class. As its name implies, this method is invoked by the Batch runtime to open ressources required by the Reader.
382 | [source, java]
383 | ----
384 | public void open(Serializable e) throws Exception {
385 | payrollInputRecordsIterator = payrollDataHolderBean.getPayrollInputData().iterator();
386 | }
387 | ----
388 |
389 | We will now rewrite the `readItem()` method as follow :
390 | [source, java]
391 | ----
392 | public Object readItem() throws Exception {
393 | String line = payrollInputRecordsIterator.hasNext() ? payrollInputRecordsIterator.next() : null;
394 | PayrollInputRecord record = null;
395 | if (line != null) {
396 | StringTokenizer tokenizer = new StringTokenizer(line, ", ");
397 | String empId = tokenizer.nextToken();
398 | String salary = tokenizer.nextToken();
399 | if (tokenizer.hasMoreTokens())
400 | throw new IllegalArgumentException("Extra characters in input data: " + line);
401 | record = new PayrollInputRecord(Integer.valueOf(empId));
402 | record.setSalary(salary);
403 | }
404 |
405 | return record;
406 | }
407 | ----
408 |
409 | The `readItem()` method is invoked by the Batch runtime, the method will then return the next item. If there is no more item, it will return `null` instead.
410 | The code is fairly easy to understand, it iterates over all the employees and for each of them, it creates a `PayrollInputRecord` object with his/her details, object which is then returned by the `readItem()` method.
411 |
412 |
413 | We can use the `open()` method to initialize any ressources that is required by the Reader. In our case, the initialization is limited to copy the `payrollDataHolderBean` data to the `payrollInputRecordsIterator`.
414 |
415 | [source, java]
416 | ----
417 | public void open(Serializable e) throws Exception {
418 | payrollInputRecordsIterator = payrollDataHolderBean.getPayrollInputData().iterator();
419 | }
420 | ----
421 |
422 | --
423 | TIP: You should now know how to detect any missing import and how to solve this.
424 | --
425 |
426 |
427 | We should also decorate the class with the `@Named` annotation.
428 |
429 |
430 | --
431 | TIP: When running in Java EE environment, the Batch runtime uses CDI (Context and Dependency Injection) to instantiate Job artifacts (like Item{Reader, Writer, Procesor} etc.). The `@Named` annotation allows us to access a bean by using its bean name (with the first letter in lowercase). So annotating the ItemReader with `@Named` will allow us to reference the Reader in our Job XML just by using its bean name.
432 | --
433 |
434 | Once you have resolved the missing imports, your `PayrollInputRecordReader.java` class should look similar to this:
435 | [source, java]
436 | ----
437 | package org.glassfish.batch.lab1;
438 |
439 | import java.io.Serializable;
440 | import java.util.Iterator;
441 | import java.util.StringTokenizer;
442 | import javax.batch.api.chunk.AbstractItemReader;
443 | import javax.ejb.EJB;
444 | import javax.inject.Named;
445 |
446 | @Named
447 | public class PayrollInputRecordReader extends AbstractItemReader {
448 |
449 | @EJB
450 | PayrollDataHolderBean payrollDataHolderBean;
451 |
452 | Iterator payrollInputRecordsIterator;
453 |
454 | public Object readItem() throws Exception {
455 | String line = payrollInputRecordsIterator.hasNext() ? payrollInputRecordsIterator.next() : null;
456 | PayrollInputRecord record = null;
457 | if (line != null) {
458 | StringTokenizer tokenizer = new StringTokenizer(line, ", ");
459 | String empId = tokenizer.nextToken();
460 | String salary = tokenizer.nextToken();
461 | if (tokenizer.hasMoreTokens())
462 | throw new IllegalArgumentException("Extra characters in input data: " + line);
463 | record = new PayrollInputRecord(Integer.valueOf(empId));
464 | record.setSalary(salary);
465 | }
466 |
467 | return record;
468 | }
469 |
470 | public void open(Serializable e) throws Exception {
471 | payrollInputRecordsIterator = payrollDataHolderBean.getPayrollInputData().iterator();
472 | }
473 |
474 | }
475 | ----
476 |
477 |
478 | ==== Processor
479 |
480 | As its name implies, a Processor will handle, within a batch step, the actual data processing, data that is provided by the Reader. Technically, a Processor is a class that implements the `javax.batch.api.chunk.ItemProcessor` interface defined in the JSR 352 specification and has a `processItem()` method. The argument to this method is the item that was read by the ItemReader. The method must return a processed item. The processed item need not be the same type as the item read by the ItemReader.
481 |
482 |
483 | So, create a new class called `NetPayProcessor` and specify that it implements the `ItemProcessor` interface. Decorate the class with the `@Named` annotation, resolve the missing imports and ask NetBeans to implement the abstract method.
484 |
485 | We should now change the `processItem()` method to perform the actual data processing, so change this method as follow:
486 | [source, java]
487 | ----
488 | public Object processItem(Object obj) throws Exception {
489 | PayrollInputRecord inputRecord = (PayrollInputRecord) obj;
490 | float salary = Integer.valueOf(inputRecord.getSalary());
491 | float socialSecurityTax =
492 | salary > 117000 ? 117000 * 6.2f / 100 : salary * 6.2f / 100;
493 |
494 | PayrollOutputRecord outputRecord = new PayrollOutputRecord(inputRecord.getId());
495 | outputRecord.setSalary(salary / 24.0f);
496 | outputRecord.setSocialSecurityTax(socialSecurityTax / 24.0f);
497 | outputRecord.setNet(outputRecord.getSalary() - outputRecord.getSocialSecurityTax());
498 |
499 | return outputRecord;
500 | }
501 | ----
502 |
503 | This method casts the received object to a `PayrollInputRecord`. It does some computations and then creates and initializes a `PayrollOutputRecord` object, compute and set a net salary. That `PayrollOutputRecord` object is then returned to the calling method.
504 |
505 |
506 | Your `NetPayProcessor.java` class should now look similar to this:
507 | [source, java]
508 | ----
509 | package org.glassfish.javaee7.batch.lab1;
510 |
511 | import javax.batch.api.chunk.ItemProcessor;
512 | import javax.batch.runtime.context.JobContext;
513 | import javax.inject.Inject;
514 | import javax.inject.Named;
515 |
516 | @Named
517 | public class NetPayProcessor
518 | implements ItemProcessor {
519 |
520 | @Inject
521 | private JobContext jobContext;
522 |
523 | public Object processItem(Object obj) throws Exception {
524 | PayrollInputRecord inputRecord = (PayrollInputRecord) obj;
525 | float salary = Integer.valueOf(inputRecord.getSalary());
526 | float socialSecurityTax =
527 | salary > 117000 ? 117000 * 6.2f / 100 : salary * 6.2f / 100;
528 |
529 | PayrollOutputRecord outputRecord = new PayrollOutputRecord(inputRecord.getId());
530 | outputRecord.setSalary(salary / 24.0f);
531 | outputRecord.setSocialSecurityTax(socialSecurityTax / 24.0f);
532 | outputRecord.setNet(outputRecord.getSalary() - outputRecord.getSocialSecurityTax());
533 |
534 | return outputRecord;
535 | }
536 |
537 | }
538 | ----
539 |
540 | ==== Writer
541 |
542 |
543 | After the Reader and the Processor, we now need to develop the Writer to save our results. A Writer is a class that extends the `javax.batch.api.chunk.AbstractItemWriter` interface and implements the `writeItems()` method. Do note that the ItemWriter is given a list of items processed by the ItemWriter.
544 |
545 | As usual, create a class named `PayrollOutputRecordWriter` in the right package. Resolve the import and ask NetBeans to implement the abstract method.
546 |
547 | Remember that for the sake of simplicity, we will save the results in the Bean we have created earlier, so you need to inject that bean with the following code.
548 |
549 | We should also decorate the class with the `@Named` annotation and resolve the missing import.
550 |
551 | [source, java]
552 | ----
553 | @EJB
554 | private PayrollDataHolderBean bean;
555 | ----
556 |
557 | Now, we will change the `writeItems()` method to save the results, that is, to add the results to our bean.
558 | [source, java]
559 | ----
560 | public void writeItems(List list) throws Exception {
561 | for (Object obj : list) {
562 | bean.addPayrollOutputRecord((PayrollOutputRecord) obj);
563 | }
564 | }
565 | ----
566 |
567 | Your `PayrollOutputRecordWriter.java` class should now look similar to this:
568 | [source, java]
569 | ----
570 | package org.glassfish.batch.lab1;
571 |
572 | import java.util.List;
573 | import javax.batch.api.chunk.AbstractItemWriter;
574 | import javax.ejb.EJB;
575 | import javax.inject.Named;
576 |
577 | @Named
578 | public class PayrollOutputRecordWriter extends AbstractItemWriter {
579 | @EJB
580 | private PayrollDataHolderBean bean;
581 |
582 | public void writeItems(List list) throws Exception {
583 | for (Object obj : list) {
584 | bean.addPayrollOutputRecord((PayrollOutputRecord) obj);
585 | }
586 | }
587 |
588 | }
589 | ----
590 |
591 | === Putting all the pieces together : JSL
592 |
593 | In the previous section, we have defined a Chunk step with a Reader, a Processor and a Writer. Now, we need to wire together those elements to actually form a Job that will be executable by the JSR 352 runtime. For that, we will use a XML based language defined by the JSR 352 specification : the *Job Specification Language (JSL)*.
594 |
595 |
596 | Go to Files tab (usually, it is next to the Project tab). Expand your project "WEB-INF" directory ("web/WEB-INF") and with the NetBeans wizard (New "Folder" in the "Other" Category) create the following directory hierarchy : "classes/META-INF/batch-jobs"
597 |
598 | In the "batch-jobs" directory, create a XML file named `PayrollJob.xml` (New "XML Document" from the "XML" category).
599 |
600 | .Create the JSL file
601 | image::E1.14.jpg[]
602 |
603 | --
604 | TIP: This XML file will be the JSL that will describe our Job. It will be needed to control the Batch itself in the next step so make sure to note its name.
605 | --
606 |
607 | Edit the `PayrollJob.xml` as follow :
608 | [source, xml]
609 | ----
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 | ----
621 |
622 | We are defining a Job called "PayrollJob" made of a single chunk step called "process".
623 | We then define the Reader, the Processor and the Writer of the "process" step. Execution of the job commences by executing the first step listed in the Job XML. Our first step is a chunk style step with "chunk size" (item-count) of 3. The step also lists an ItemReader identified by the CDI bean name `payRollInputRecordReader`. Similarly, the step lists an ItemProcessor and a ItemWriter by the beans names `netPayProcessor` and `payRollOutputRecordWriter` respectively. In order to execute the step, the Batch runtime uses CDI to instantiate the specified ItemReader, ItemProcessor and ItemWriter. It then calls the ItemReader's `readItem()` and ItemProcessor's `processItem()` "item-count" times (3 in our sample). These processed items are then collected and passed to the ItemWriter's `writeItems()` method.
624 |
625 |
626 | === Executing the Job
627 |
628 | In the previous section, we have defined the implementations of our Step (Reader, Processor and Writer). Using JSL, we have then referenced those implementations to define the batch job. The last thing we need to do is to submit the job for execution.
629 |
630 | --
631 | TIP: JSR 352 defines the `javax.batch.operations.JobOperator` interface to control jobs. Via this interface, it is possible to start, stop, and restart jobs. It is also possible to inspect job history, to discover what jobs are currently running, what jobs have previously run, etc. For more details, check the http://docs.oracle.com/javaee/7/api/javax/batch/operations/JobOperator.html[javadoc].
632 | --
633 |
634 | ==== Submitting the job for execution
635 | Edit the the `BatchJobSubmitter.java` servlet we have defined earlier, insert the following method:
636 | [source, java]
637 | ----
638 | private long submitJobFromXML(String jobName) throws Exception {
639 | JobOperator jobOperator = BatchRuntime.getJobOperator();
640 | Properties props = new Properties();
641 | return jobOperator.start(jobName, props);
642 | }
643 | ----
644 | This method gets a `jobOperator` instance using the `BatchRuntime.getJobOperator()` method. It then invokes the `jobOperator.start()` method to start the job. The first parameter passed to the `jobOperator.start()` method is the job xml name. This xml must reside under the "WEB-INF/classes/META-INF/batch-jobs" directory.
645 |
646 | --
647 | TIP: Putting the JSL in a wrong directory or using a different name are frequent errors when starting with JSR 352.
648 | --
649 |
650 |
651 |
652 | ==== Get the job details
653 |
654 | We will again leverage the `jobOperator` interface to get runtime details of job. We will write a few utility methods to gather data and display the results. First, add the following method to the servlet:
655 |
656 | [source, java]
657 | ----
658 | private void displayJobDetails(PrintWriter pw, long executionId) {
659 | pw.println("");
660 | pw.println("Status of Submitted Jobs |
");
661 | pw.println("");
662 | pw.println("Job Name | Instance Id | ExecutionID | "
663 | + "Batch Status | Exit Status | "
664 | + "Start Time Status | End Time | "
665 | + "
");
666 |
667 | JobOperator jobOperator = BatchRuntime.getJobOperator();
668 | try {
669 | for (JobInstance jobInstance : jobOperator.getJobInstances("PayrollJob", 0, Integer.MAX_VALUE-1)) {
670 | for (JobExecution jobExecution : jobOperator.getJobExecutions(jobInstance)) {
671 | StringBuilder sb = new StringBuilder();
672 | if (executionId == jobExecution.getExecutionId()) {
673 | sb.append("");
674 | } else {
675 | sb.append("
");
676 | }
677 | sb.append("").append(jobExecution.getJobName()).append(" | ");
678 | sb.append("").append(jobInstance.getInstanceId()).append(" | ");
679 | sb.append("").append(jobExecution.getExecutionId()).append(" | ");
680 | sb.append("").append(jobExecution.getBatchStatus()).append(" | ");
681 | sb.append("").append(jobExecution.getExitStatus()).append(" | ");
682 | sb.append("").append(jobExecution.getStartTime()).append(" | ");
683 | sb.append("").append(jobExecution.getEndTime()).append(" |
");
684 | pw.println(sb.toString());
685 | }
686 | }
687 | } catch (Exception ex) {
688 | pw.println(ex.toString());
689 | }
690 | pw.println("
");
691 | pw.println("
");
692 | }
693 | ----
694 |
695 |
696 | We use the `BatchRuntime.getJobOperator()` method to get a `JobOperator` instance.
697 | We then invoke the `getJobInstances()` method on this `JobOperator` instance to get the different job instances.
698 | And for all the job instances, we pass each instances to the `jobOperator.getJobExecutions()` method and get in return a `JobExecution` object. Once we have that object, we can query the different values we need (e.g. start time, etc.).
699 | The rest (and bulk) of this method generate HTML.
700 |
701 |
702 | --
703 | IMPORTANT: Hard coding HTML directly in a servlet is not recommended for any serious application.
704 | --
705 |
706 | You can also add the following method to display the input data used by the job:
707 | [source, java]
708 | ----
709 | private void displayPayrollForm(PrintWriter pw)
710 | throws Exception {
711 |
712 | pw.println("Payroll Input Records (Comma Separated Values) |
");
713 | for (String line : payrollDataHolderBean.getPayrollInputData()) {
714 | pw.println("" + line + " |
");
715 | }
716 | pw.println("
");
717 | }
718 | ----
719 |
720 | NetBeans will complain about `payrollDataHolderBean` bean that is supposed to hold the data, so you should inject it:
721 |
722 | [source, java]
723 | ----
724 | @EJB
725 | PayrollDataHolderBean payrollDataHolderBean;
726 | ----
727 |
728 | You can now add the `displayProcessedPayrollRecords()` method:
729 | [source, java]
730 | ----
731 | private void displayProcessedPayrollRecords(PrintWriter pw, long executionId) throws Exception {
732 | pw.println("");
747 | }
748 | ----
749 |
750 | This method displays, in a HTML form, a table containing the job results using the `payrollDataHolderBean` bean. Towards the end, you can also see that the method print raw HTML with the 2 buttons that the end user will use to control the application (e.g. "Calculate Payroll" & "Refresh").
751 |
752 |
753 | Finally, we will rewrite the existing `processRequest()` servlet method to use those utilities methods:
754 | [source, java]
755 | ----
756 | protected void processRequest(HttpServletRequest request, HttpServletResponse response)
757 | throws ServletException, IOException {
758 | response.setContentType("text/html;charset=UTF-8");
759 | try (PrintWriter pw = response.getWriter()) {
760 | pw.println("");
761 | pw.println("Servlet BatchJobSubmitter");
762 |
763 | long executionId = -1;
764 | if (request.getParameter("executionId") != null) {
765 | executionId = Long.valueOf(request.getParameter("executionId"));
766 | }
767 |
768 | try {
769 | if (request.getParameter("calculatePayroll") != null) {
770 | executionId = submitJobFromXML("PayrollJob");
771 | }
772 | pw.println("");
773 | pw.println("");
774 | displayPayrollForm(pw);
775 | pw.println(" | ");
776 | displayProcessedPayrollRecords(pw, executionId);
777 | pw.println(" |
");
778 | pw.println("
");
779 | displayJobDetails(pw, executionId);
780 | } catch (Exception ex) {
781 | throw new ServletException(ex);
782 | }
783 | pw.println("");
784 | pw.println("");
785 | }
786 | }
787 | ----
788 |
789 | --
790 | TIP: Make sure the string parameter you pass to the `submitJobFromXML()` method corresponds to the name of the JSL file describing your Job (without the .xml extension)!
791 | --
792 |
793 | In this case, we are working with Explicit CDI Beans Archive so we need to create a bean.xml. For a Web Application, this beans.xml has to be in the WEB-INF directory so right click on the WEB-INF directory and create an empty file called "beans.xml".
794 |
795 | --
796 | TIP: The CDI container is looking for a "beans.xml" file in the WEB-INF directory. If it's not there or present under a different name, the application will not work as it rely on some CDI features.
797 | --
798 |
799 |
800 |
801 | === Testing the Payroll application
802 |
803 | To test the application, right click on the `BatchJobSubmitter.java` servlet in the "Project" tab and select "Run". This action will compile and deploy the application and invoke your local browser with the Servlet URL. The first time, you should will see the following screen.
804 |
805 | .Initial screen : no job submitted yet
806 | image::E1.15.jpg[]
807 |
808 | Now click on the "Calculate Payroll" button to submit a job for execution to the batch runtime. You can see that a job has been started but not yet completed (e.g. it has no end time). You can also see that the right column is empty at this stage.
809 |
810 | .A job has been started
811 | image::E1.16.jpg[]
812 |
813 | Finally, if you click on "refresh" the job will have had enough time to run completely. The results are displayed in the right column. You can also notice the end time of the job execution.
814 | Since the data set is minimal and the processing trivial, the batch execution is almost instantaneous.
815 |
816 | .The job is now completed
817 | image::E1.17.jpg[]
818 |
819 | === Summary
820 |
821 | In this Lab, we have learnt the core components of the batch processing architecture.
822 |
823 | * A job encapsulates the entire batch process. A job contains one or more steps. A job is put together using a *Job Specification Language* (JSL) that specifies the sequence in which the steps must be executed. In JSR 352, JSL is specified in an XML file called the job XML file. In short, *a job (with JSR 352) is basically a container for steps*.
824 |
825 | * A *step* is a domain object that encapsulates an *independent, sequential phase of the job*. A step contains all the necessary logic and data to perform the actual processing. The batch specification deliberately leaves the definition of a step vague because the content of a step is purely application-specific and can be as complex or simple as the developer desires. There are *two kinds of steps: chunk and batchlet*.
826 |
827 | * A *chunk-style* step contains exactly one *ItemReader*, *one ItemProcessor*, and *one ItemWriter*. In this pattern, ItemReader reads one item at a time, ItemProcessor processes the item based upon the business logic (such as "calculate account balance"), and hands it to the batch runtime for aggregation. Once the "chunk-size" number of items are read and processed, they are given to an ItemWriter, which writes the data (for example, to a database table or a flat file). The transaction is then committed.
828 |
829 | * JSR 352 also defines a roll-your-own kind of a step called a *batchlet*. A batchlet is free to use anything to accomplish the step, such as sending an e-mail. Batchlet will be discussed in the next section.
830 |
831 | * *JobOperator* provides an interface to manage all aspects of job processing, including operational commands, such as start, restart, and stop, as well as job repository commands, such as retrieval of job and step executions. See section 10.4 of the JSR 352 specification for more details about JobOperator.
832 |
833 | * *JobRepository* holds information about jobs currently running and jobs that ran in the past. JobOperator provides APIs to access this repository. A JobRepository could be implemented using, say, a database or a file system.
834 |
835 |
836 | //////////////////////////////////////////
837 |
838 | icon:tags[role="black"] Test
839 |
840 | icon:taxi[role="black"] Taxi
841 |
842 | icon:star[role="black"] Star
843 |
844 | icon:comment[role="black"] Comment
845 |
846 | tip - icon-pushpin (or icon-star or icon-plus)
847 | note - icon-info-sign
848 | warning - icon-warning-sign
849 | important - icon-exclamation-sign
850 | caution - icon-bolt (or icon-minus)
851 |
852 |
853 | //////////////////////////////////////////
854 |
855 |
856 |
857 |
--------------------------------------------------------------------------------
/chapters/exercice2.adoc:
--------------------------------------------------------------------------------
1 | :imagesdir: ../pic
2 |
3 | == Lab: Batchlet and Multi-steps Job
4 |
5 | In the first exercise, we have developed a simple job made of a single step, a Chunk step. This exercise will introduce you to *Batchlet*, the second type of step supported by JSR 352. Chunk step are used to work on data while Batchlets are useful for performing a variety of tasks that are not item-oriented, such as executing a command or performing a task (like copying files, preparing reports etc.).
6 |
7 | To illustrate this, we will define a multi-steps job that combine 2 steps: a Chunk step and a Batchlet step.
8 |
9 |
10 |
11 | === Set the stage
12 |
13 | Open the "lab2" project in NetBeans ("File" , "Open Project" and select the "lab2" directory). If you run the project and access the "BatchJobSubmitter" servlet, you will see that it is very similar to what we have done in the previous exercise.
14 |
15 | It is a simple batch job made of a single Chunk step, the "prepare" step (check the JSL file describing the batch job).
16 |
17 | === Implement the Batchlet step
18 |
19 | A Batchlet is a class that extends and implements the `javax.batch.api.AbstractBatchlet` interface. So create, in the source package, a new Java class called "SummaryProcessor" that extends the `AbstractBatchlet` interface. Use NetBeans to resolve the missing import and implement the abstract `process()` method.
20 |
21 | Decorate the class with the `@Named` annotation and inject the `PayrollDataHolderBean` bean as follow :
22 |
23 | [source, java]
24 | ----
25 | @EJB
26 | PayrollDataHolderBean payrollDataHolderBean;
27 | ----
28 |
29 | The `process()` method is doing the work of the Batchlet is supposed to do so let's re-write it as follow :
30 |
31 | [source, java]
32 | ----
33 | public String process() throws Exception {
34 | SummaryRecord summaryRecord = new SummaryRecord();
35 |
36 | try {
37 | for (PayrollOutputRecord outputRecord : payrollDataHolderBean.getPayrollOutputRecords()) {
38 | summaryRecord.addBonus(outputRecord.getBonus());
39 | summaryRecord.addNet(outputRecord.getNet());
40 | summaryRecord.addSalary(outputRecord.getSalary());
41 | summaryRecord.addSocialSecurityTax(outputRecord.getSocialSecurityTax());
42 | }
43 | } catch (Exception ex) {
44 | return "FAILED";
45 | }
46 |
47 | payrollDataHolderBean.setSummaryRecord(summaryRecord);
48 | return "COMPLETED";
49 | }
50 | ----
51 |
52 | This Batchlet computes the total net, total salary and total socialsecurity of all the payroll records processed by first step. Once the imports have been fixed, the final `SummaryProcessor` Batchlet should looks like this:
53 | [source, java]
54 | ----
55 | package org.glassfish.javaee7.batch.lab2;
56 | // imports omitted !
57 |
58 | @Named
59 | public class SummaryProcessor extends AbstractBatchlet {
60 |
61 | @EJB
62 | PayrollDataHolderBean payrollDataHolderBean;
63 |
64 | public String process() throws Exception {
65 | SummaryRecord summaryRecord = new SummaryRecord();
66 |
67 | try {
68 | for (PayrollOutputRecord outputRecord : payrollDataHolderBean.getPayrollOutputRecords()) {
69 | summaryRecord.addBonus(outputRecord.getBonus());
70 | summaryRecord.addNet(outputRecord.getNet());
71 | summaryRecord.addSalary(outputRecord.getSalary());
72 | summaryRecord.addSocialSecurityTax(outputRecord.getSocialSecurityTax());
73 | }
74 | } catch (Exception ex) {
75 | return "FAILED";
76 | }
77 |
78 | payrollDataHolderBean.setSummaryRecord(summaryRecord);
79 | return "COMPLETED";
80 | }
81 |
82 | }
83 | ----
84 |
85 | --
86 | TIP: The return type of the `process()` method of a batchlet is the exit status of the Batchlet.
87 | --
88 |
89 |
90 | === Update the JSL
91 |
92 | We now need to update the JSL file to make sure the Batchlet is part of the job. Open "PayRollJob.xml" (in "web/WEB-INF/classes/META-INF/batch-jobs") and add the Batch "summary" step to the job as follow:
93 | [source, xml]
94 | ----
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | ----
111 |
112 | As mentioned before, the execution commences by executing the first step listed in the job xml. If the step completes normally, then the step specified in the "next" attrinute will be executed.
113 | --
114 | TIP: Be aware that if you don't specify the next attribute, the execution stops after the first step!
115 | --
116 |
117 | === Testing the Payroll application
118 |
119 | If you run the job again, you should now see an additional "TOTAL" line in the right table. Those data are computed in in the Batchlet and displayed by the `displayProcessedPayrollRecords()` method when `summaryRecord` is not null.
120 |
121 | .Total values computed by the Batchlet step
122 | image::E2.3.jpg[]
123 |
124 |
125 | === Summary
126 |
127 | In this Lab, we learnt
128 |
129 | * how to write a Batchlet step
130 | * how to combine multiple steps within a single Job
131 |
132 |
133 |
--------------------------------------------------------------------------------
/chapters/exercice3.adoc:
--------------------------------------------------------------------------------
1 | :imagesdir: ../pic
2 |
3 | == Lab: Checkpoints and the JobOperator interface
4 |
5 | This exercise is focusing on two additional JSR 352 aspects: checkpoint and the JobOperator interface.
6 |
7 | *JobOperator* provides an interface to manage all aspects of job processing, including operational commands, such as start, restart, and stop, as well as job repository commands. We have already used it in previous exercises to start jobs and also to get their execution status. In this exercise, we will see how we can resume the execution of a failed job.
8 |
9 | To avoid having to restart a failed job from the beginning, JSR 352 support the concept of checkpoint. A *checkpoint* allows a step to periodically bookmark its current progress to enable restart from the last point of consistency should this job be stopped (intentionally or unintentionally).
10 |
11 |
12 | === Set the stage
13 |
14 | Open and run the "Lab 3" project. This PayRoll application is again very similar. It has a single Chunk step. The only real difference is that this application let you update, delete and add Input Records. We will use this feature to intentionally introduce corrupt data to force our job to fail. We will finally use the JobOperator interface to resume the job execution where it has failed.
15 |
16 |
17 | The GlassFish console is a useful tool to understand what is going on. Go in the "Services" tab and locate the GlassFish instance (it's probably called "GlassFish 4.1" or "GlassFish Server"). Right click on it and select "View Domain Server Log", this action will open the GlassFish Logs in the NetBeans "Output" window.
18 |
19 | .GlassFish Server Log
20 | image::E2.2.jpg[]
21 |
22 | === Start a job
23 |
24 | Locate the `displayPayrollForm()` method in the `BatchJobSubmitter` servlet. This method uses a `switch` to handle the different commands: start a job to calculate a payroll, add, update and delete input records.
25 |
26 | If you look at the `submitJobFromXML()` method that is invoked via the "calculatePayroll" command, you will notice that starting a job is easy.
27 | [source, java]
28 | ----
29 | JobOperator jobOperator = BatchRuntime.getJobOperator(); // get a jobOperator instance
30 | Properties props = new Properties(); // set some properties
31 | id = jobOperator.start(jobName, props); // and start to job
32 | ----
33 |
34 |
35 | A `jobOperator` instance is used to interact with the batch runtime. Once you have that instance, all you have to do is to invoke its `start()` method and pass it the jobNanme and eventually some properties (see http://docs.oracle.com/javaee/7/api/javax/batch/operations/JobOperator.html#start[javadoc]). Note that the jobName parameter is the actual name of the JSL file describing the job (without the XML extension). The 'start()' method will return an execution ID that we can use to continue to interact with the job via the batch runtime (e.g. stop the job, query the status of the job, etc.).
36 |
37 | --
38 | TIP: The location of the job xml is spec defined. It must be defined under "WEB-INF/classes/META-INF/batch-jobs" (for war files) or under "META-INF/batch-jobs" (for ejb jar files).
39 | --
40 |
41 |
42 | === Break the job!
43 |
44 | We will now introduce some corrupt data to force our job to fail. For example, you can update the 5th record by replacing the "," with a space and click "update". You can now start the job and "if everything goes well", your job will fail with an "Exit status: FAILED". A "restart" button should also appear on the right side of the last failed job.
45 |
46 | .Break the job
47 | image::E3.1.jpg[]
48 |
49 | In the log, we can see that the Job fails at the fifth record and that there is a checkpoint every *2* records. This is defined in the Chunk step element in the JSL file.
50 | The "item-count" attribue (the size) of the "chunk" element specify the number of items to process per chunk (10 per default). At the end, a checkpoint will be performed since this is an obvious place for such action.
51 |
52 | [source]
53 | ----
54 | ...
55 | ...[INFO]...[ ** Calculating net pay for empId: 1 ]
56 | ...[INFO]...[ ** Calculating net pay for empId: 2 ]
57 | ...[INFO]...[ PayrollInputRecordReader: Checkpointing reader position: 2 ]
58 | ...[INFO]...[ ** Calculating net pay for empId: 3 ]
59 | ...[INFO]...[ ** Calculating net pay for empId: 4 ]
60 | ...[INFO]...[ PayrollInputRecordReader: Checkpointing reader position: 4 ]
61 | ...[SEVERE]...[[ Failure in Read-Process-Write Loop com.ibm.jbatch.container.exception.BatchContainerRuntimeException: java.util.NoSuchElementException]]
62 | ...
63 | ----
64 |
65 | .Defining the size of the chunk step
66 | image::E3.2.jpg[]
67 |
68 | --
69 | TIP: Any real application would obviously implement more severe validation strategies. We haven't because it's not the purpose of this exercise and we are also using that weaknesses to demonstrate some of the JSR5352 features.
70 | --
71 |
72 |
73 | === Resume a failed job
74 |
75 | We will now update the `displayPayrollForm()` method to also handle the "restart" command. In `switch' construction, add an extra `case` with the following logic to handle the "restart" command with the following logic.
76 |
77 | [source, java]
78 | ----
79 | case "restart":
80 | executionId = restartJob(executionId);
81 | session.setAttribute("executionId", executionId);
82 | break;
83 | ----
84 | Restarting a failed job is also done via the jobOperator interface and more particularly via its `restart()` method. We pass, to this method, the execution ID of the failed job and we get in return a new execution ID.
85 |
86 | --
87 | TIP: JSR 352 allows only the most recent execution id to the restart method. Thats why our application attaches the restart button to the most recent job!
88 | --
89 |
90 | If you fix and update the wrong input record and "restart" the job, the job should now exit with a "COMPLETED" status.
91 |
92 | If you check the GlassFish log, you will notice that job is restarted from the last known checkpint (i.e. 4) so it read and process the next item (5 in this case). A final checkpoint is performed after the last record.
93 |
94 | [source]
95 | ----
96 | ...[INFO]...[ PayrollInputRecordReader: resuming from: 4 ]
97 | ...[INFO]...[ ** Calculating net pay for empId: 5 ]
98 | ...[INFO]...[ PayrollInputRecordReader: Checkpointing reader position: 5 ]
99 | ----
100 |
101 |
102 |
103 | === Summary
104 |
105 | Job restarts (resumption of jobs rather) is possible due to the checkpointing mechanism. Execution of a check style step commences by the batch runtime calling the ItemReader's `open()` method. If the step is not due to a re-start (meaning a the job is being executed using `jobOperator.start()`) then a `null` value is passed to the `open()` method (else the previous checkpointed data is passed).
106 | Once every "item-count" (chunk size) number of items have been written out by the ItemWriter, the Batch runtime calls the `checkpointInfo()` method on the ItemReader. The item reader can return any Serializable data that captures its current state (like number of items read etc.). This Serializable data will be saved by the batch runtime in the JobRepository and allows the batch runtime to track the last known checkpointed state.
107 | If the job were to fail now (or before the next checkpoint), the Job can be resumed by calling the `JobOperator.restart()` method. Job restart processing begins by the batch runtime calling the ItemReader's `open()` method with the previous run's checkpointed data. This allows the ItemReader to resume reading from the previous successful point and thus allows the Job to resume rather than start from the beginning.
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/chapters/exercice4.adoc:
--------------------------------------------------------------------------------
1 | :imagesdir: ../pic
2 |
3 | == Lab: Listeners
4 |
5 | In the first exercise, we have created the simple batch application from scratch.
6 | This exercise will build on that initial application and will introduce listeners.
7 | *Listeners* are used to intervene, at the different levels, during the life-cylcle of a batch job.
8 |
9 | A listener is configured to receive the execution control at some well defined phases during the execution of the job.
10 | They can be configured at different level (step level before or after, job level, ...)
11 | Technically, a listener is a class that that implements one of the listener interfaces defined in the JSR 352 specification.
12 |
13 | === Set the stage
14 |
15 | We will now start from a NetBeans project that already contains a simple batch application. So just open the "Lab4" project in NetBeans.
16 | As you explore the project files, you will notice the servlet that is used to control the batch, the reader, the processor and the writer, the JSL that defines the job, etc.
17 | In short, this application does almost what we developed in the first exercise.
18 | The only real difference is that it is now possible to add Payroll input records in the UI and restart the last executed job. Run the job and check the result in the GlassFish console.
19 |
20 | [source]
21 | ----
22 | ... PayrollInputRecordReader: resuming from: 0
23 | ... ** Calculating net pay for empId: 1
24 | ... ** Calculating net pay for empId: 2
25 | ... ** Calculating net pay for empId: 3
26 | ... PayrollInputRecordReader: Checkpointing reader position: 3
27 | ... ** Calculating net pay for empId: 4
28 | ... ** Calculating net pay for empId: 5
29 | ... PayrollInputRecordReader: Checkpointing reader position: 5
30 | ----
31 |
32 |
33 | === Defining a listener at the Job level
34 |
35 | Let's define a listener at the job level.
36 | For that, you should create a class called "PayrollJobListener" that implements the `javax.batch.api.listener.JobListener` interface.
37 | Make sure to decorate the class with the `@Named` annotation.
38 | NetBeans will help you to resolve the missing import and implement the abstract methods : `beforeJob()` and `afterJob()`.
39 |
40 | To use, in the listener, information related to the job instance, we need to inject the job context object.
41 |
42 | [source,java]
43 | ----
44 | @Inject
45 | JobContext jobContext;
46 | ----
47 |
48 | --
49 | TIP: Since this is a Job level listener, there is no Step context.
50 | --
51 |
52 | Rewrite the 2 methods as follow :
53 | [source,java]
54 | ----
55 | @Override
56 | public void beforeJob() throws Exception {
57 | System.out.println("** PayrollJobListener:: Job started at: " + (new Date()));
58 | }
59 |
60 | @Override
61 | public void afterJob() throws Exception {
62 | System.out.println("** PayrollJobListener:: Job completed at: " + (new Date())
63 | + "; exitStatus : " + jobContext.getExitStatus() + "; " + jobContext.getBatchStatus());
64 | }
65 | ----
66 |
67 | The last thing we need to do is to update the JSL to include this listener ans since it is a Job level listener, we should make sure to define it at the job level!
68 | [source,xml]
69 | ----
70 |
71 |
72 |
73 |
74 |
75 | ...
76 | ----
77 |
78 | If we run the batch once again, we can observer in the console that the job level listener has been invoked at the beginning (`beforeJob()` method) and at the end (`afterJob()` method).
79 | [source]
80 | ----
81 | Info: ** PayrollJobListener:: Job started at: Tue Aug 12
82 | Info: ** PayrollStepListener:: Step started at: Tue Aug 12; stepContext: STARTED
83 | Info: PayrollInputRecordReader: resuming from: 0
84 | Info: ** Calculating net pay for empId: 1
85 | Info: ** Calculating net pay for empId: 2
86 | Info: ** Calculating net pay for empId: 3
87 | Info: PayrollInputRecordReader: Checkpointing reader position: 3
88 | Info: ** Calculating net pay for empId: 4
89 | Info: ** Calculating net pay for empId: 5
90 | Info: PayrollInputRecordReader: Checkpointing reader position: 5
91 | Info: ** PayrollStepListener:: Step ended at: Tue Aug 12; stepContext: STARTED
92 | Info: ** PayrollJobListener:: Job completed at: Tue Aug 12; exitStatus : null; STARTED
93 | ----
94 |
95 | === Defining listener(s) at the Step level
96 |
97 | Setting listeners at the level of the job might be, in some cases, too coarse grained.
98 | Luckily, JSR 352 allows us to define listeners at the step level.
99 |
100 | In the project source directory, create a new java class called "PayrollStepListener".
101 | This class needs to implement the `javax.batch.api.listener.StepListener` interface.
102 | Use NetBeans to resolve the import and implements the abstract methods.
103 |
104 | You should now have 2 methods : `beforeStep()` and `afterStep()`
105 |
106 | In the previous listener, we used the Job context but this time, we have also the step context at our disposal.
107 | You can inject the step context in your listener.
108 |
109 | [source,java]
110 | ----
111 | @Inject
112 | StepContext stepContext;
113 | ----
114 |
115 | We will use this context to gather some information.
116 | Update the `beforeStep()` and `afterStep()` methods as follow (make the necessary changes for the 2nd method).
117 |
118 | [source,java]
119 | ----
120 | System.out.println("\t** PayrollStepListener:: Step started at: " + (new Date())
121 | + "; stepContext: " + stepContext.getBatchStatus());
122 | ----
123 |
124 | --
125 | TIP: Make sure to annotate the class declaration with the `@Named` annotation.
126 | --
127 |
128 | Now that we have defined the implementation of the listener, we need to update the batch JSL to reference it.
129 | Update the step defined in the JSL as follow:
130 |
131 | [source,xml]
132 | ----
133 | ...
134 |
135 |
136 |
137 |
138 | ...
139 | ----
140 |
141 | If you run the batch, you will see that our 2 listeners are correctly invoked.
142 | You can also notice the listener invokation chain order : _job before_, _step before_, _step after_, _job after_.
143 | [source]
144 | ----
145 | Info: ** PayrollJobListener:: Job started at: Thu Jul 31 04:06:39 CEST 2014
146 | Info: ** PayrollStepListener:: Step started at: Thu Jul 31 04:06:39 CEST 2014; stepContext: STARTED
147 | Info: ** Calculating net pay for empId: 1
148 | ...
149 | Info: ** Calculating net pay for empId: 5
150 | Info: ** PayrollStepListener:: Step completed at: Thu Jul 31 04:06:39 CEST 2014; stepContext: STARTED
151 | Info: ** PayrollJobListener:: Job completed at: Thu Jul 31 04:06:39 CEST 2014; exitStatus : null; STARTED
152 | ----
153 |
154 | === Defining listener(s) within a Step
155 |
156 | We saw that we can define listeners at the level of a Job and at the level of a Step but this might still be too coarse grained.
157 | JSR 352 also allows to define listeners within a step itself.
158 |
159 | Before adding this listener, let's simulate a use case in the application by adding a record.
160 | Make sure to respect the format expected by the application : int,salary.
161 | For example, fill in "6,10000" and click "add".
162 | You can now launch the job. After you have hit "refresh", the displayed results should includes the record you have just added.
163 |
164 | .Adding a record
165 | image::E2.1.png[]
166 |
167 | Let's now pretend we did a mistake and add a record using an incorrect format (e.g. "61000").
168 | If you now run the batch again, GlassFish will throw some exceptions as clearly the application can only handle record correctly formated.
169 |
170 | [source]
171 | ----
172 | Info: ** Calculating net pay for empId: 4
173 | Info: ** Calculating net pay for empId: 5
174 | Severe: Failure in Read-Process-Write Loop
175 | com.ibm.jbatch.container.exception.BatchContainerRuntimeException: java.lang.IllegalArgumentException: Salary cannot be null
176 | ...
177 | Warning: Caught throwable in chunk processing. Attempting to close all readers and writers.
178 | Warning: Caught exception executing step: com.ibm.jbatch.container.exception.BatchContainerRuntimeException: Failure in Read-Process-Write Loop
179 | ...
180 | Caused by: com.ibm.jbatch.container.exception.BatchContainerRuntimeException: java.lang.IllegalArgumentException: Salary cannot be null
181 | ...
182 | Caused by: java.lang.IllegalArgumentException: Salary cannot be null
183 | ...
184 | ----
185 |
186 | Our step is made of a reader, a processor and a writer.
187 | JSR 352 allows to also define listener at this level, i.e. within a step.
188 | In this example, we will define a listener at the reader level.
189 | Typically, such a listener would be used to intervene and handle any misread data by the reader.
190 |
191 | In the source directory, create a new java class called "PayrollInputRecordReadListener" and decorate it with the `@Named` annotation.
192 | As we want a reader at the reader level, we need to implements the `javax.batch.api.chunk.listener.ItemReadListener` interface, so update your class definition accordingly.
193 | Use NetBeans to implement the abstract methods of the interface.
194 |
195 | We can inject, in our listener, contexts: the job and the step context.
196 |
197 | [source,java]
198 | ----
199 | @Inject
200 | JobContext jobContext;
201 |
202 | @Inject
203 | StepContext stepContext;
204 | ----
205 |
206 | You can remove the body of the `beforeRead()` and the `afterRead()` methods as we won't use them.
207 | Change the `onReadError()` method as follows:
208 | [source,java]
209 | ----
210 | @Override
211 | public void onReadError(Exception ex) throws Exception {
212 | System.out.println("\t** PayrollInputRecordReadListener:: onReadError : "
213 | + stepContext.getTransientUserData() + "; Exception: " + ex);
214 | }
215 | ----
216 |
217 | Your `PayrollInputRecordReadListener.java` listener should now looks like this.
218 | [source,java]
219 | ----
220 | package org.glassfish.javaee7.batch.lab4;
221 | import javax.batch.api.chunk.listener.ItemReadListener;
222 | import javax.batch.runtime.context.JobContext;
223 | import javax.batch.runtime.context.StepContext;
224 | import javax.inject.Inject;
225 | import javax.inject.Named;
226 |
227 | @Named
228 | public class PayrollInputRecordReadListener
229 | implements ItemReadListener {
230 |
231 | @Inject
232 | JobContext jobContext;
233 |
234 | @Inject
235 | StepContext stepContext;
236 |
237 | @Override
238 | public void beforeRead() throws Exception {
239 | }
240 |
241 | @Override
242 | public void afterRead(Object item) throws Exception {
243 | }
244 |
245 | @Override
246 | public void onReadError(Exception ex) throws Exception {
247 | System.out.println("\t** PayrollInputRecordReadListener:: onReadError : "
248 | + stepContext.getTransientUserData() + "; Exception: " + ex);
249 | }
250 | }
251 | ----
252 |
253 | Now that we have defined the listener implementation, we need to configure our job JSL file as follow:
254 |
255 | [source,xml]
256 | ----
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 | ----
270 |
271 | If you test the batch with a incorrect record, you will notice that the Listener is invoked but you can also see that exceptions are still thrown.
272 | [source]
273 | ----
274 | ...
275 | Info: ** Calculating net pay for empId: 4
276 | Info: ** Calculating net pay for empId: 5
277 | Info: ** PayrollInputRecordReadListener:: onReadError : null; Exception: java.lang.IllegalArgumentException
278 | Severe: Failure in Read-Process-Write Loop
279 | com.ibm.jbatch.container.exception.BatchContainerRuntimeException: java.util.NoSuchElementException...
280 | ...
281 | ----
282 |
283 | To avoid that, we can define a set of exceptions that can be skipped if they are thrown during the execution of the step.
284 | To do that, define at the step level in the JSL which exception(s) can be skipped.
285 | [source,xml]
286 | ----
287 |
288 |
289 |
290 |
291 | ----
292 |
293 |
294 | The updated JSL should now looks like this (previous listeners have been removed for shortness, you can keep them):
295 | [source,xml]
296 | ----
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 | ----
315 |
316 | If you try again to run the batch job with an incorrect record, you should get the following output in the GlassFish console.
317 | [source]
318 | ----
319 | Info: ** Calculating net pay for empId: 1
320 | Info: ** Calculating net pay for empId: 2
321 | Info: ** Calculating net pay for empId: 3
322 | Info: ** Calculating net pay for empId: 4
323 | Info: ** Calculating net pay for empId: 5
324 | Info: ** PayrollInputRecordReadListener:: onReadError : null; Exception: java.lang.IllegalArgumentException: Salary cannot be null
325 | ----
326 |
327 | === Summary
328 |
329 | In this Lab, we learnt how to define and use listener to intervene within the life-cycle of a batch job.
330 |
--------------------------------------------------------------------------------
/chapters/exercice5.adoc:
--------------------------------------------------------------------------------
1 | :imagesdir: ../pic
2 |
3 | == Lab: Job Partitioning
4 |
5 | By default, all steps in a job run on the same thread. Multi-threading can be leveraged to increase throughput and better utilize underlying hardware, that is what *partitioned step* brings. A serially processed step can be broken it into *partitions* that will run on different threads. Once we have defined the partition strategy, the batch runtime will manage the threads and will handle all aspects of checkpoints.
6 |
7 |
8 | === Set the stage
9 |
10 | We will start from an usual payroll batch job and will enhance it to support partition. Open Lab 5 and launch the `PartitionedJobSubmitterServlet.java` servlet. In this application, you can select for which month the payroll should be calculated. Don't run a batch job at this stage, as it will fails.
11 |
12 |
13 |
14 | === Define the partition strategy
15 |
16 | JSR 352 defines an interface called `PartitionMapper` (http://docs.oracle.com/javaee/7/api/javax/batch/api/partition/PartitionMapper.html[javadoc]) that provides a programmatic means for calculating the number of partitions and threads for a partitioned step.
17 |
18 | So create a java classes called "PayrollPartitionMapper", implements the PartitionMapper interface. And as usual, decorate the class with the `@Named("PayrollPartitionMapper)` annotation, resolve any missing imports and implements the abstract methods imposed by the interface.
19 |
20 |
21 | Inject the JobConext and the SampleDataHolderBean as we will need them.
22 |
23 | [source, java]
24 | ----
25 | @Inject
26 | private JobContext jobContext;
27 |
28 | @EJB
29 | private SampleDataHolderBean bean;
30 | ----
31 |
32 |
33 | The `mapPartitions()` method return a `PartitionPlan` object, so let's modify the body of the method as follow :
34 | [source, java]
35 | ----
36 | @Override
37 | public PartitionPlan mapPartitions() throws Exception {
38 |
39 | return new PartitionPlanImpl() {
40 | @Override
41 | public int getPartitions() {
42 | return 5;
43 | }
44 |
45 | @Override
46 | public Properties[] getPartitionProperties() {
47 | Properties jobParameters = BatchRuntime.getJobOperator().getParameters(jobContext.getExecutionId());
48 |
49 | String monthYear = (String) jobParameters.get("monthYear");
50 | int partitionSize = bean.getMaxEmployees() / getPartitions();
51 |
52 | System.out.println("**[PayrollPartitionMapper] jobParameters: " + jobParameters
53 | + "; executionId: " + jobContext.getExecutionId() + "; partitionSize = " + partitionSize);
54 |
55 | Properties[] props = new Properties[getPartitions()];
56 | for (int i=0; i
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | ----
128 |
129 |
130 |
131 | === Test the partitioned execution
132 |
133 | If you now run the job for a particular month, you will see in the GlassFish logs that data are spread across 5 threads as defined by the `getPartitions()` method of the partition mapper. You can also see the data range that each partition is assigned.
134 |
135 | [source]
136 | ----
137 | Info: ** JobSubmitterServlet: JAN-2013
138 | Info: **[PayrollPartitionMapper] jobParameters: {monthYear=JAN-2013}; executionId: 79; partitionSize = 6
139 | Info: **[PayrollPartitionMapper[0/5] : {endEmpID=6, partitionNumber=0, startEmpID=0, monthYear=JAN-2013}
140 | Info: **[PayrollPartitionMapper[1/5] : {endEmpID=12, partitionNumber=1, startEmpID=6, monthYear=JAN-2013}
141 | Info: **[PayrollPartitionMapper[2/5] : {endEmpID=18, partitionNumber=2, startEmpID=12, monthYear=JAN-2013}
142 | Info: **[PayrollPartitionMapper[3/5] : {endEmpID=24, partitionNumber=3, startEmpID=18, monthYear=JAN-2013}
143 | Info: **[PayrollPartitionMapper[4/5] : {endEmpID=30, partitionNumber=4, startEmpID=24, monthYear=JAN-2013}
144 | Info: SimpleItemReader[partition #2 will process from employeeId: 12 to 18 for the month of JAN-2013
145 | Info: SimpleItemReader[partition #0 will process from employeeId: 0 to 6 for the month of JAN-2013
146 | Info: SimpleItemReader[partition #1 will process from employeeId: 6 to 12 for the month of JAN-2013
147 | Info: SimpleItemReader[partition #4 will process from employeeId: 24 to 30 for the month of JAN-2013
148 | Info: SimpleItemReader[partition #3 will process from employeeId: 18 to 24 for the month of JAN-2013
149 | ----
150 |
151 |
152 |
153 |
154 |
155 | === Summary
156 |
157 | In this Lab, we learnt how to use Partition Mapper to distribute batch processing on different threads.
158 |
159 |
160 | ////////////////////////////
--------------------------------------------------------------------------------
/chapters/introduction.adoc:
--------------------------------------------------------------------------------
1 | :imagesdir: ../pic
2 |
3 | == Introduction
4 |
5 | Batch processing is used in many industries for tasks ranging from payroll processing; statement generation; end-of-day jobs such as interest calculation, ETL (extract, load, and transform) in a data warehouse; and many more. Typically, batch processing is bulk-oriented, non-interactive, and long running and might be data or computation-intensive. Batch jobs can be run on schedule or initiated on demand. Also, since batch jobs are typically long-running jobs, check-pointing and restarting are common features found in batch jobs.
6 |
7 | JSR 352 (Batch Processing for Java Platform), part of the Java EE 7 platform, defines the programming model for batch applications and the runtime to run and manage batch jobs. This Hands-on Lab will take you through the key concepts of JSR352.
8 |
9 | === Software Requirements
10 |
11 | The following software are needed for this Lab.
12 |
13 | --
14 | TIP: JavaOne attendees, everything has been installed and pre-configured for you!
15 | --
16 |
17 | * *Java SE*: JDK 7 or JDK 8 is required. The JDK can be downloaded from
18 | http://www.oracle.com/technetwork/java/javase/downloads/index.html[http://www.oracle.com/technetwork/java/javase/downloads/index.html].
19 | * *Java EE 7 Application Server*: This Lab uses the latest release of GlassFish, i.e. GlassFish Server Open Source Edition 4.1 (GF 4.0 should also work). Any other Java EE 7 (Full Platform) Application Server should work as well. Since JSR 352 is part of the Full Platform, this lab will not run on a Java EE 7 Web Profile Application Server.
20 |
21 | * *IDE*: This Lab uses NetBeans 8.0 but any IDE supporting Java EE 7 should work.
22 |
23 |
24 | === Lab Overview
25 |
26 | This Lab is divided in 5 exercises :
27 |
28 | * *Lab 1* will introduce you the main concepts of JSR 352 such as Step, Job, JSL, etc. In this exercise, you will be guided to build from scratch a complete application that will run a simple batch job to perform some hypothetical payroll calculations.
29 |
30 | * *Lab 2* will enhance the first exercise and introduce mutli-steps jobs combining Chunk step with a Batchlet step..
31 |
32 | * *Lab 3* will cover checkpoint and the JobOperator interface which can be used to resume failed job.
33 |
34 | * *Lab 4* will build introduce you to listeners, a mechanism that can be used to intervene within the life-cycle of a batch job (e.g. to catch errors).
35 |
36 | * *Lab 5* will introduce the concept of Job Partitioning, a more advanced feature of JSR 352.
37 |
38 | Unless you are already familiar with the Batch API, it is recommended to follow the suggested exercises order.
39 |
40 |
41 | === Where to get help
42 |
43 | Here are some advices if you are stuck during the Lab...
44 |
45 | * Check that your imports are correct, e.g. a `java.util.list` is not really a `java.awt.list` !
46 |
47 | * Make sure that the code you have copy/pasted is correct and complete.
48 |
49 | * If your code doesn't compile, NetBeans will show where the error is and will also provide some suggestions on how it could be fixed.
50 |
51 | * It is sometime useful to re-read a section from the beginning.
52 |
53 | * The solutions should be used as a final resort to to pinpoints hard to find issues.
54 |
55 |
56 | At any time, feel free to ask a JavaOne Proctor, they are here to help you!
57 |
58 | === Important note
59 |
60 | WARNING: The sample applications and the code may not always be following best practices (e.g. data validation, correct error handling, leverage the lastest Java SE features, etc.). This is intentional such as to stay focused on explaining JSR 352. It is highly recommended to make sure that the code copied from this lab is updated to meet the requirements of any production application!
61 |
62 | ////
63 | === TO DO
64 |
65 | * Copyright / License to use?
66 | * How to start GF
67 | * Add a key map in the Help (Fix import, Reformat, ...)
68 | * Add info about expected audience, assumptions and timing
69 | ////
70 |
--------------------------------------------------------------------------------
/lab1 solution/Lab1.txt:
--------------------------------------------------------------------------------
1 | Objective:
2 |
3 | To Learn:
4 |
5 | Structure of a Batch Job
6 | ItemReader, ItemProcessor, ItemWriter
7 | Job XML
8 | Steps
9 | Specifying the Item{Reader, Processor, Writer} for a Step.
10 |
11 | Packaging requirements
12 | Placing Job XMl under META-INF/batch-jobs
13 | Multiple Job xmls can be placed under this directory.
14 |
15 | Using JobOperator APIs
16 | How to submit a Batch Job
17 | Using JobOperator APIs to query Job status
18 |
19 | Difference between executionId and instanceId
20 |
21 |
22 | About the application used in lab1
23 |
24 | Mimics a rudimentary Payroll processing system.
25 | Input data comes from a EJB Singleton as coma separated records.
26 | The Job XML has only one step.
27 | ItemReader:
28 | Reads list of CSV from the Singleton bean and converts each line into a
29 | PayrollInputRecord. This shields the rest of the application from
30 | knowing the source of the input data. By providing appropriate ItemReader
31 | the rest of the application need not worry about the source of input data.
32 | ItemProcessor:
33 | Processes the input data (PayrollInputRecord) and computes the social security
34 | tax and net pay. It produces a PayrollOutputRecord for each processed
35 | input record.
36 | ItemWriter:
37 | Writes / Saves the processed data into the Singleton bean itself. Different
38 | ItemWriters can be written to store the processed data in a variety of
39 | stores.
40 |
41 | Summary:
42 |
43 | We learnt about Job XML structure and packaging requirements.
44 |
45 | We learnt about how to write Item{Reader, Processor, Writer} for a Step.
46 |
47 | We learnt how to: Start and Query the Batch jobs using JobOperator APIs.
48 |
--------------------------------------------------------------------------------
/lab1 solution/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Builds, tests, and runs the project lab1 solution.
12 |
13 |
71 |
72 |
--------------------------------------------------------------------------------
/lab1 solution/nbproject/ant-deploy.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
102 |
103 |
104 |
105 |
106 |
107 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/lab1 solution/nbproject/genfiles.properties:
--------------------------------------------------------------------------------
1 | build.xml.data.CRC32=90c7a06d
2 | build.xml.script.CRC32=eb434d5d
3 | build.xml.stylesheet.CRC32=651128d4@1.69.0.1
4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
6 | nbproject/build-impl.xml.data.CRC32=90c7a06d
7 | nbproject/build-impl.xml.script.CRC32=0f48d970
8 | nbproject/build-impl.xml.stylesheet.CRC32=99ea4b56@1.69.0.1
9 |
--------------------------------------------------------------------------------
/lab1 solution/nbproject/private/private.properties:
--------------------------------------------------------------------------------
1 | deploy.ant.properties.file=/Users/davidd/Library/Application Support/NetBeans/dev/config/GlassFishEE6/Properties/gfv3743454947.properties
2 | j2ee.platform.is.jsr109=true
3 | j2ee.server.domain=/work/gf/41/08-10/glassfish4/glassfish/domains/domain1
4 | j2ee.server.home=/work/gf/41/08-10/glassfish4/glassfish
5 | j2ee.server.instance=[/work/gf/41/08-10/glassfish4/glassfish:/work/gf/41/08-10/glassfish4/glassfish/domains/domain1]deployer:gfv3ee6wc:localhost:4848
6 | j2ee.server.middleware=/work/gf/41/08-10/glassfish4
7 | javac.debug=true
8 | javadoc.preview=true
9 | selected.browser=default
10 | user.properties.file=/Users/davidd/Library/Application Support/NetBeans/dev/build.properties
11 |
--------------------------------------------------------------------------------
/lab1 solution/nbproject/private/private.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | file:/work/j1/hol/dd/lab1/src/java/org/glassfish/javaee7/batch/lab1/BatchJobSubmitter.java
7 | file:/work/j1/hol/dd/lab1/web/WEB-INF/classes/META-INF/batch-jobs/PayrollJob.xml
8 | file:/work/j1/hol/dd/lab1/src/java/org/glassfish/javaee7/batch/lab1/NetPayProcessor.java
9 | file:/work/j1/hol/dd/lab1/src/java/org/glassfish/javaee7/batch/lab1/PayrollDataHolderBean.java
10 | file:/work/j1/hol/dd/lab1/src/java/org/glassfish/javaee7/batch/lab1/PayrollInputRecord.java
11 | file:/work/j1/hol/dd/lab1/src/java/org/glassfish/javaee7/batch/lab1/PayrollInputRecordReader.java
12 | file:/work/j1/hol/dd/lab1/src/java/org/glassfish/javaee7/batch/lab1/PayrollOutputRecord.java
13 | file:/work/j1/hol/dd/lab1/src/java/org/glassfish/javaee7/batch/lab1/PayrollOutputRecordWriter.java
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/lab1 solution/nbproject/private/retriever/catalog.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/lab1 solution/nbproject/private/retriever/www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Java EE: XML Schemas for Java EE Deployment Descriptors
6 |
20 |
21 |
22 |
23 |
24 |

25 |
26 |
27 |
28 |
29 | Java EE: XML Schemas for Java EE Deployment Descriptors
30 |
31 |
32 |
33 |
34 |
35 |
36 | By Bill Shannon,
37 | Java EE Spec Lead, Oracle, April 30, 2013
38 | |
39 |
40 |
41 | Latest Version: http://xmlns.jcp.org/xml/ns/javaee/
42 | Contents
43 |
44 |
54 |
55 |
56 | Introduction
57 |
58 |
59 |
60 | This document lists the document formats that will be used by the
61 |
62 | Java Platform, Enterprise Edition (Java EE)
63 | deployment descriptors described by Java EE 5 and later specifications.
64 | Prior to the J2EE 1.4 specifications, each Deployment Descriptor was required
65 | to be valid with respect to a specific DTD
66 | that describes the Deployment Descriptor.
67 | The DTDs are found in the J2EE section of
68 | this document.
69 | Starting with
70 | the J2EE 1.4 specification, each specification requires its Deployment
71 | Descriptor be validated with respect to an XML Schema that is listed in
72 | the J2EE 1.4 document
73 | and this document.
74 | Note that deployment descriptors defined by previous
75 | versions of the Java EE specification must also be supported by all current
76 | Java EE products, and must
77 | continue to be validated against the corresponding DTD or schema.
78 | Note that not all deployment descriptors are updated for every
79 | release of Java EE, in which case the deployment descriptor from
80 | the previous version is used.
81 |
82 |
83 | The Java EE specification also requires support for the Java Persistence API.
84 | The Java Persistence API Schemas are available at
85 | http://xmlns.jcp.org/xml/ns/persistence/
86 |
87 |
88 | This document describes how to use the Java EE schemas
89 | and provides a list of XML Schemas for each
90 | deployment descriptor.
91 |
92 |
93 | Using Java EE Schemas
94 |
95 |
96 | All Java EE 7 and newer Deployment Descriptor Schemas share the namespace
97 | http://xmlns.jcp.org/xml/ns/javaee/.
98 | Each schema
99 | document contains a version attribute that contains the version of the
100 | specification. For example, the XML Schema document for the Servlet
101 | specification contains the version attribute value "3.1", pertaining to
102 | the specific version of the specification as well as the schema
103 | document itself.
104 |
105 |
106 | Each Java EE XML Schema document's file name contains the specific version
107 | of the related specification. This is introduced for convenience to
108 | locate specific versions of the schema documents. However, Deployment
109 | Descriptor instances are not required to refer to a specific file.
110 | Instead, an instance must specify the version of the corresponding
111 | specification by using the version attribute. For example, servlet
112 | Deployment Descriptor instances that must be processed with the
113 | servlet
114 | 3.1 version must indicate the version within the version attribute of
115 | the instance document, for example, "3.1". The Deployment Descriptor
116 | processors use the version information to choose the appropriate
117 | version of the schema document(s) to process the Deployment Descriptor
118 | instances.
119 |
120 |
121 | A specific version of the Java EE specification contains a set of
122 | deployment descriptor schemas to constitute the Java EE Schema. The common
123 | definitions are contained in the javaee_<version>.xsd
124 | document that may be included by several Java EE Deployment Descriptor
125 | schemas.
126 |
127 |
128 | Java EE 7 Schema Resources
129 |
130 |
131 |
132 | This table contains the XML Schema components for Java EE 7 schema.
133 | All new schemas are in the
134 | http://xmlns.jcp.org/xml/ns/javaee/
135 | namespace.
136 | Most older schemas remain in the
137 | http://java.sun.com/xml/ns/javaee/
138 | namespace.
139 |
140 |
141 |
142 |
143 |
144 | Date Published |
145 | File Name |
146 | Description |
147 | Status |
148 |
149 |
150 | April 30, 2013 |
151 | application_7.xsd |
152 | Application schema |
153 | Final Release |
154 |
155 |
156 | April 30, 2013 |
157 | application-client_7.xsd |
158 | Application Client schema |
159 | Final Release |
160 |
161 |
162 | April 30, 2013 |
163 | batchXML_1_0.xsd |
164 | Schema for batch.xml-based artifact loading in Java Batch |
165 | Final Release |
166 |
167 |
168 | April 30, 2013 |
169 | beans_1_1.xsd |
170 | Contexts and Dependency Injection schema |
171 | Final Release |
172 |
173 |
174 | April 30, 2013 |
175 | connector_1_7.xsd |
176 | Java EE Connector schema |
177 | Final Release |
178 |
179 |
180 | April 30, 2013 |
181 | ejb-jar_3_2.xsd |
182 | Enterprise JavaBeans Deployment Descriptor Schema |
183 | Final Release |
184 |
185 |
186 | April 30, 2013 |
187 | javaee_7.xsd |
188 | Java EE 7 definitions file that contains common schema components |
189 | Final Release |
190 |
191 |
192 | April 30, 2013 |
193 | javaee_web_services_1_4.xsd |
194 | Web services schema |
195 | Final Release |
196 |
197 |
198 | April 30, 2013 |
199 | javaee_web_services_client_1_4.xsd |
200 | Web services client schema |
201 | Final Release |
202 |
203 |
204 | April 30, 2013 |
205 | jobXML_1_0.xsd |
206 | Batch Job Specification Language (JSL) schema |
207 | Final Release |
208 |
209 |
210 | April 30, 2013 |
211 | jsp_2_3.xsd |
212 | JavaServer Pages Deployment Descriptor schema |
213 | Final Release |
214 |
215 |
216 | April 30, 2013 |
217 | permissions_7.xsd |
218 | Java EE application permissions schema |
219 | Final Release |
220 |
221 |
222 | April 30, 2013 |
223 | web-app_3_1.xsd |
224 | Web Application Deployment Descriptor schema |
225 | Final Release |
226 |
227 |
228 | April 30, 2013 |
229 | web-common_3_1.xsd |
230 | Web Application Deployment Descriptor common definitions schema |
231 | Final Release |
232 |
233 |
234 | April 30, 2013 |
235 | web-fragment_3_1.xsd |
236 | Web Application Deployment Descriptor fragment schema |
237 | Final Release |
238 |
239 |
240 | April 30, 2013 |
241 | web-facelettaglibrary_2_2.xsd |
242 | JavaServer Faces Facelet Tag Library schema
243 | |
244 | Final Release |
245 |
246 |
247 | April 30, 2013 |
248 | web-facesconfig_2_2.xsd |
249 | JavaServer Faces Application Configuration File schema |
250 | Final Release |
251 |
252 |
253 | April 30, 2013 |
254 | web-partialresponse_2_2.xsd |
255 | JavaServer Faces partial response schema |
256 | Final Release |
257 |
258 |
259 | July 1, 2009 |
260 | web-facesuicomponent_2_0.xsd |
261 | JavaServer Faces UI Component Configuration schema |
262 | Final Release |
263 |
264 |
265 | December 10, 2009 |
266 | web-jsptaglibrary_2_1.xsd |
267 | JSP Taglibrary Deployment Descriptor schema |
268 | Final Release |
269 |
270 |
271 | November 21, 2007 |
272 | javaee_web_services_metadata_handler_2_0.xsd |
273 | Web services schema |
274 | Final Release |
275 |
276 |
277 | - |
278 | http://www.w3.org/2001/xml.xsd |
279 | The Java EE schemas use some common definitions provided and published by W3C |
280 | - |
281 |
282 |
283 |
284 |
285 |
286 |
287 | Java EE 6 Schema Resources
288 |
289 |
290 |
291 | This table contains the XML Schema components for Java EE 6 schema.
292 | All of these schemas are in the
293 | http://java.sun.com/xml/ns/javaee
294 | namespace.
295 |
296 |
297 |
298 |
299 |
300 |
301 | Date Published |
302 | File Name |
303 | Description |
304 | Status |
305 |
306 |
307 | December 10, 2009 |
308 | application_6.xsd |
309 | Application schema
310 | |
311 | Final Release |
312 |
313 |
314 | December 10, 2009 |
315 | application-client_6.xsd |
317 | Application Client schema
318 | |
319 | Final Release |
320 |
321 |
322 | December 10, 2009 |
323 | beans_1_0.xsd |
325 | Contexts and Dependency Injection schema
326 | |
327 | Final Release |
328 |
329 |
330 | December 10, 2009 |
331 | connector_1_6.xsd |
333 | Java EE Connector schema
334 | |
335 | Final Release |
336 |
337 |
338 | December 10, 2009 |
339 | ejb-jar_3_1.xsd | Enterprise JavaBeans Deployment Descriptor
340 | Schema |
341 | Final Release |
342 |
343 |
344 | December 10, 2009 |
345 | javaee_6.xsd |
346 | Java EE 6 definitions file that
347 | contains common schema components
348 | |
349 | Final Release |
350 |
351 |
352 | December 10, 2009 |
353 | javaee_web_services_1_3.xsd |
355 | Web services schema
356 | |
357 | Final Release |
358 |
359 |
360 | December 10, 2009 |
361 | javaee_web_services_client_1_3.xsd |
363 | Web services client schema
364 | |
365 | Final Release |
366 |
367 | December 10, 2009 |
368 | jsp_2_2.xsd |
369 | JavaServer Pages Deployment Descriptor schema |
370 | Final Release |
371 |
372 |
373 | December 10, 2009 |
374 | web-app_3_0.xsd |
375 | Web Application Deployment Descriptor schema |
376 | Final Release |
377 |
378 |
379 | December 10, 2009 |
380 | web-common_3_0.xsd |
381 | Web Application Deployment Descriptor common definitions schema |
382 | Final Release |
383 |
384 |
385 | December 10, 2009 |
386 | web-fragment_3_0.xsd |
387 | Web Application Deployment Descriptor fragment schema |
388 | Final Release |
389 |
390 |
391 | July 1, 2009 |
392 | web-facelettaglibrary_2_0.xsd |
393 | JavaServer Faces Facelet Tag Library schema
394 | |
395 | Final Release |
396 |
397 |
398 | July 1, 2009 |
399 | web-facesconfig_2_0.xsd |
400 | JavaServer Faces Application Configuration File schema
401 | |
402 | Final Release |
403 |
404 |
405 | July 1, 2009 |
406 | web-facesuicomponent_2_0.xsd |
407 | JavaServer Faces UI Component Configuration schema
408 | |
409 | Final Release |
410 |
411 |
412 | July 1, 2009 |
413 | web-partialresponse_2_0.xsd |
414 | JavaServer Faces partial response schema
415 | |
416 | Final Release |
417 |
418 |
419 | December 10, 2009 |
420 | web-jsptaglibrary_2_1.xsd |
422 | JSP Taglibrary Deployment Descriptor schema |
423 | Final Release |
424 |
425 |
426 | November 21, 2007 |
427 | javaee_web_services_metadata_handler_2_0.xsd |
429 | Web services schema
430 | |
431 | Final Release |
432 |
433 |
434 | - |
435 | http://www.w3.org/2001/xml.xsd |
436 | The Java EE schemas use some
437 | common definitions provided and published by W3C
438 | |
439 | - |
440 |
441 |
442 |
443 |
444 |
445 |
446 | Java EE 5 Schema Resources
447 |
448 |
449 |
450 | This table contains the XML Schema components for Java EE 5 schema.
451 | All of these schemas are in the
452 | http://java.sun.com/xml/ns/javaee
453 | namespace.
454 |
455 |
456 |
457 |
458 |
459 |
460 | Date Published |
461 | File Name |
462 | Description |
463 | Status |
464 |
465 |
466 | May 2, 2006 |
467 | application_5.xsd |
468 | Application schema
469 | |
470 | Final Release |
471 |
472 |
473 | May 2, 2006 |
474 | application-client_5.xsd |
476 | Application Client schema
477 | |
478 | Final Release |
479 |
480 |
481 | May 2, 2006 |
482 | ejb-jar_3_0.xsd | Enterprise JavaBeans Deployment Descriptor
483 | Schema |
484 | Final Release |
485 |
486 |
487 | May 2, 2006 |
488 | javaee_5.xsd |
489 | Java EE 5 definitions file that
490 | contains common schema components
491 | |
492 | Final Release |
493 |
494 |
495 | May 2, 2006 |
496 | javaee_web_services_1_2.xsd |
498 | Web services schema
499 | |
500 | Final Release |
501 |
502 |
503 | May 2, 2006 |
504 | javaee_web_services_client_1_2.xsd |
506 | Web services client schema
507 | |
508 | Final Release |
509 |
510 | May 2, 2006 |
511 | jsp_2_1.xsd |
512 | JavaServer Pages Deployment Descriptor
513 | Schema |
514 | Final Release |
515 |
516 |
517 | May 2, 2006 |
518 | web-app_2_5.xsd | Servlet Deployment Descriptor Schema |
519 | Final Release |
520 |
521 |
522 | July 1, 2008 |
523 | web-facesconfig_1_2.xsd |
524 | JavaServer Faces Application Configuration File schema
525 | |
526 | Final Release |
527 |
528 |
529 | May 2, 2006 |
530 | web-jsptaglibrary_2_1.xsd |
532 | JSP Taglibrary Deployment Descriptor Schema |
533 | Final Release |
534 |
535 |
536 | November 21, 2007 |
537 | javaee_web_services_metadata_handler_2_0.xsd |
539 | Java EE Web Services Metadata Handler Chain Schema |
540 | Final Release |
541 |
542 |
543 | - |
544 | http://www.w3.org/2001/xml.xsd |
545 | The Java EE schemas use some
546 | common definitions provided and published by W3C
547 | |
548 | - |
549 |
550 |
551 |
552 |
553 |
554 |
555 | J2EE 1.4 XML Schemas
556 |
557 |
558 | XML Schemas specified by the J2EE 1.4 specification are
559 | available at http://java.sun.com/xml/ns/j2ee/.
560 |
561 | J2EE 1.3 DTDs
562 |
563 |
564 | DTDs specified by the J2EE 1.3 specification are
565 | available at http://java.sun.com/dtd/.
566 |
567 | J2EE 1.2 DTDs
568 |
569 |
570 | DTDs specified by the J2EE 1.2 specification are
571 | available at http://java.sun.com/j2ee/dtds/.
572 |
573 |
574 |
575 |
576 |
577 |
--------------------------------------------------------------------------------
/lab1 solution/nbproject/project.properties:
--------------------------------------------------------------------------------
1 | annotation.processing.enabled=true
2 | annotation.processing.enabled.in.editor=true
3 | annotation.processing.processors.list=
4 | annotation.processing.run.all.processors=true
5 | annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
6 | build.classes.dir=${build.web.dir}/WEB-INF/classes
7 | build.classes.excludes=**/*.java,**/*.form
8 | build.dir=build
9 | build.generated.dir=${build.dir}/generated
10 | build.generated.sources.dir=${build.dir}/generated-sources
11 | build.test.classes.dir=${build.dir}/test/classes
12 | build.test.results.dir=${build.dir}/test/results
13 | build.web.dir=${build.dir}/web
14 | build.web.excludes=${build.classes.excludes}
15 | client.urlPart=
16 | compile.jsps=false
17 | conf.dir=${source.root}/conf
18 | debug.classpath=${build.classes.dir}:${javac.classpath}
19 | debug.test.classpath=\
20 | ${run.test.classpath}
21 | display.browser=true
22 | # Files to be excluded from distribution war
23 | dist.archive.excludes=
24 | dist.dir=dist
25 | dist.ear.war=${dist.dir}/${war.ear.name}
26 | dist.javadoc.dir=${dist.dir}/javadoc
27 | dist.war=${dist.dir}/${war.name}
28 | endorsed.classpath=\
29 | ${libs.javaee-endorsed-api-6.0.classpath}
30 | excludes=
31 | includes=**
32 | j2ee.compile.on.save=true
33 | j2ee.copy.static.files.on.save=true
34 | j2ee.deploy.on.save=true
35 | j2ee.platform=1.7-web
36 | j2ee.platform.classpath=${j2ee.server.home}/modules/endorsed/javax.annotation-api.jar:${j2ee.server.home}/modules/endorsed/jaxb-api.jar:${j2ee.server.home}/modules/endorsed/webservices-api-osgi.jar:${j2ee.server.home}/modules/bean-validator.jar:${j2ee.server.home}/modules/javax.batch-api.jar:${j2ee.server.home}/modules/javax.ejb-api.jar:${j2ee.server.home}/modules/javax.el.jar:${j2ee.server.home}/modules/javax.enterprise.concurrent-api.jar:${j2ee.server.home}/modules/javax.enterprise.concurrent.jar:${j2ee.server.home}/modules/javax.enterprise.deploy-api.jar:${j2ee.server.home}/modules/javax.faces.jar:${j2ee.server.home}/modules/javax.inject.jar:${j2ee.server.home}/modules/javax.interceptor-api.jar:${j2ee.server.home}/modules/javax.jms-api.jar:${j2ee.server.home}/modules/javax.json.jar:${j2ee.server.home}/modules/javax.mail.jar:${j2ee.server.home}/modules/javax.management.j2ee-api.jar:${j2ee.server.home}/modules/javax.persistence.jar:${j2ee.server.home}/modules/javax.resource-api.jar:${j2ee.server.home}/modules/javax.security.auth.message-api.jar:${j2ee.server.home}/modules/javax.security.jacc-api.jar:${j2ee.server.home}/modules/javax.servlet-api.jar:${j2ee.server.home}/modules/javax.servlet.jsp-api.jar:${j2ee.server.home}/modules/javax.servlet.jsp.jar:${j2ee.server.home}/modules/javax.servlet.jsp.jstl-api.jar:${j2ee.server.home}/modules/javax.servlet.jsp.jstl.jar:${j2ee.server.home}/modules/javax.transaction-api.jar:${j2ee.server.home}/modules/javax.websocket-api.jar:${j2ee.server.home}/modules/javax.ws.rs-api.jar:${j2ee.server.home}/modules/javax.xml.registry-api.jar:${j2ee.server.home}/modules/javax.xml.rpc-api.jar:${j2ee.server.home}/modules/jaxb-osgi.jar:${j2ee.server.home}/modules/webservices-osgi.jar:${j2ee.server.home}/modules/weld-osgi-bundle.jar:${j2ee.server.middleware}/mq/lib/jaxm-api.jar
37 | j2ee.platform.embeddableejb.classpath=${j2ee.server.home}/lib/embedded/glassfish-embedded-static-shell.jar
38 | j2ee.platform.wscompile.classpath=${j2ee.server.home}/modules/webservices-osgi.jar
39 | j2ee.platform.wsgen.classpath=${j2ee.server.home}/modules/webservices-osgi.jar:${j2ee.server.home}/modules/endorsed/webservices-api-osgi.jar:${j2ee.server.home}/modules/jaxb-osgi.jar:${j2ee.server.home}/modules/endorsed/jaxb-api.jar
40 | j2ee.platform.wsimport.classpath=${j2ee.server.home}/modules/webservices-osgi.jar:${j2ee.server.home}/modules/endorsed/webservices-api-osgi.jar:${j2ee.server.home}/modules/jaxb-osgi.jar:${j2ee.server.home}/modules/endorsed/jaxb-api.jar
41 | j2ee.platform.wsit.classpath=
42 | j2ee.server.type=gfv3ee6
43 | jar.compress=false
44 | javac.classpath=
45 | # Space-separated list of extra javac options
46 | javac.compilerargs=
47 | javac.debug=true
48 | javac.deprecation=false
49 | javac.processorpath=\
50 | ${javac.classpath}
51 | javac.source=1.7
52 | javac.target=1.7
53 | javac.test.classpath=\
54 | ${javac.classpath}:\
55 | ${build.classes.dir}
56 | javac.test.processorpath=\
57 | ${javac.test.classpath}
58 | javadoc.additionalparam=
59 | javadoc.author=false
60 | javadoc.encoding=${source.encoding}
61 | javadoc.noindex=false
62 | javadoc.nonavbar=false
63 | javadoc.notree=false
64 | javadoc.preview=true
65 | javadoc.private=false
66 | javadoc.splitindex=true
67 | javadoc.use=true
68 | javadoc.version=false
69 | javadoc.windowtitle=
70 | lib.dir=${web.docbase.dir}/WEB-INF/lib
71 | persistence.xml.dir=${conf.dir}
72 | platform.active=default_platform
73 | resource.dir=setup
74 | run.test.classpath=\
75 | ${javac.test.classpath}:\
76 | ${build.test.classes.dir}
77 | # Space-separated list of JVM arguments used when running a class with a main method or a unit test
78 | # (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value):
79 | runmain.jvmargs=
80 | source.encoding=UTF-8
81 | source.root=src
82 | src.dir=${source.root}/java
83 | test.src.dir=test
84 | war.content.additional=
85 | war.ear.name=${war.name}
86 | war.name=lab1_solution.war
87 | web.docbase.dir=web
88 | webinf.dir=web/WEB-INF
89 |
--------------------------------------------------------------------------------
/lab1 solution/nbproject/project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.netbeans.modules.web.project
4 |
5 |
6 | lab1 solution
7 | 1.6.5
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/lab1 solution/src/conf/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 |
3 |
--------------------------------------------------------------------------------
/lab1 solution/src/java/org/glassfish/javaee7/batch/lab1/BatchJobSubmitter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 | *
4 | * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
5 | *
6 | * The contents of this file are subject to the terms of either the GNU
7 | * General Public License Version 2 only ("GPL") or the Common Development
8 | * and Distribution License("CDDL") (collectively, the "License"). You
9 | * may not use this file except in compliance with the License. You can
10 | * obtain a copy of the License at
11 | * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
12 | * or packager/legal/LICENSE.txt. See the License for the specific
13 | * language governing permissions and limitations under the License.
14 | *
15 | * When distributing the software, include this License Header Notice in each
16 | * file and include the License file at packager/legal/LICENSE.txt.
17 | *
18 | * GPL Classpath Exception:
19 | * Oracle designates this particular file as subject to the "Classpath"
20 | * exception as provided by Oracle in the GPL Version 2 section of the License
21 | * file that accompanied this code.
22 | *
23 | * Modifications:
24 | * If applicable, add the following below the License Header, with the fields
25 | * enclosed by brackets [] replaced by your own identifying information:
26 | * "Portions Copyright [year] [name of copyright owner]"
27 | *
28 | * Contributor(s):
29 | * If you wish your version of this file to be governed by only the CDDL or
30 | * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 | * elects to include this software in this distribution under the [CDDL or GPL
32 | * Version 2] license." If you don't indicate a single choice of license, a
33 | * recipient has the option to distribute your version of this file under
34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 | * its licensees as provided above. However, if you add GPL Version 2 code
36 | * and therefore, elected the GPL Version 2 license, then the option applies
37 | * only if the new code is made subject to such option by the copyright
38 | * holder.
39 | */
40 | package org.glassfish.javaee7.batch.lab1;
41 |
42 | import java.io.IOException;
43 | import java.io.PrintWriter;
44 | import java.util.Properties;
45 | import javax.batch.operations.JobOperator;
46 | import javax.batch.runtime.BatchRuntime;
47 | import javax.batch.runtime.JobExecution;
48 | import javax.batch.runtime.JobInstance;
49 | import javax.ejb.EJB;
50 | import javax.servlet.ServletException;
51 | import javax.servlet.annotation.WebServlet;
52 | import javax.servlet.http.HttpServlet;
53 | import javax.servlet.http.HttpServletRequest;
54 | import javax.servlet.http.HttpServletResponse;
55 |
56 | /**
57 | *
58 | * @author makannan
59 | */
60 | @WebServlet(urlPatterns = {"/BatchJobSubmitter"})
61 | public class BatchJobSubmitter extends HttpServlet {
62 |
63 | @EJB
64 | PayrollDataHolderBean payrollDataHolderBean;
65 |
66 | /**
67 | * Processes requests for both HTTP GET
and POST
68 | * methods.
69 | *
70 | * @param request servlet request
71 | * @param response servlet response
72 | * @throws ServletException if a servlet-specific error occurs
73 | * @throws IOException if an I/O error occurs
74 | */
75 | protected void processRequest(HttpServletRequest request, HttpServletResponse response)
76 | throws ServletException, IOException {
77 | response.setContentType("text/html;charset=UTF-8");
78 | try (PrintWriter pw = response.getWriter()) {
79 | /* TODO output your page here. You may use following sample code. */
80 | pw.println("");
81 | pw.println("");
82 | pw.println("");
83 | pw.println("TEST Servlet BatchJobSubmitter");
84 | pw.println("");
85 | pw.println("");
86 |
87 | long executionId = -1;
88 | if (request.getParameter("executionId") != null) {
89 | executionId = Long.valueOf(request.getParameter("executionId"));
90 | }
91 |
92 | try {
93 | if (request.getParameter("calculatePayroll") != null) {
94 | executionId = submitJobFromXML("PayrollJob");
95 | }
96 | pw.println("");
97 | pw.println("");
98 | displayPayrollForm(pw);
99 | pw.println(" | ");
100 | displayProcessedPayrollRecords(pw, executionId);
101 | pw.println(" |
");
102 | pw.println("
");
103 |
104 | displayJobDetails(pw, executionId);
105 | } catch (Exception ex) {
106 | throw new ServletException(ex);
107 | }
108 |
109 | pw.println("");
110 | pw.println("");
111 | }
112 | }
113 |
114 | private void displayProcessedPayrollRecords(PrintWriter pw, long executionId)
115 | throws Exception {
116 |
117 | pw.println("");
132 | }
133 | private void displayPayrollForm(PrintWriter pw)
134 | throws Exception {
135 |
136 | pw.println("Payroll Input Records (Comma Separated Values) |
");
137 | for (String line : payrollDataHolderBean.getPayrollInputData()) {
138 | pw.println("" + line + " |
");
139 | }
140 | pw.println("
");
141 | }
142 |
143 | private long submitJobFromXML(String jobName)
144 | throws Exception {
145 | JobOperator jobOperator = BatchRuntime.getJobOperator();
146 |
147 | Properties props = new Properties();
148 | return jobOperator.start(jobName, props);
149 | }
150 |
151 | private void displayJobDetails(PrintWriter pw, long executionId) {
152 | pw.println("");
153 | pw.println("Status of Submitted Jobs |
");
154 | pw.println("");
155 | pw.println("Job Name | Instance Id | ExecutionID | "
156 | + "Batch Status | Exit Status | "
157 | + "Start Time Status | End Time | "
158 | + "
");
159 |
160 |
161 | JobOperator jobOperator = BatchRuntime.getJobOperator();
162 | try {
163 | for (JobInstance jobInstance : jobOperator.getJobInstances("PayrollJob", 0, Integer.MAX_VALUE-1)) {
164 | for (JobExecution jobExecution : jobOperator.getJobExecutions(jobInstance)) {
165 | StringBuilder sb = new StringBuilder();
166 | if (executionId == jobExecution.getExecutionId()) {
167 | sb.append("");
168 | } else {
169 | sb.append("
");
170 | }
171 | sb.append("").append(jobExecution.getJobName()).append(" | ");
172 | sb.append("").append(jobInstance.getInstanceId()).append(" | ");
173 | sb.append("").append(jobExecution.getExecutionId()).append(" | ");
174 | sb.append("").append(jobExecution.getBatchStatus()).append(" | ");
175 | sb.append("").append(jobExecution.getExitStatus()).append(" | ");
176 | sb.append("").append(jobExecution.getStartTime()).append(" | ");
177 | sb.append("").append(jobExecution.getEndTime()).append(" |
");
178 | pw.println(sb.toString());
179 | }
180 | }
181 | } catch (Exception ex) {
182 | pw.println(ex.toString());
183 | }
184 | pw.println("
");
185 | pw.println("
");
186 | }
187 |
188 | //
189 | /**
190 | * Handles the HTTP GET
method.
191 | *
192 | * @param request servlet request
193 | * @param response servlet response
194 | * @throws ServletException if a servlet-specific error occurs
195 | * @throws IOException if an I/O error occurs
196 | */
197 | @Override
198 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
199 | throws ServletException, IOException {
200 | processRequest(request, response);
201 | }
202 |
203 | /**
204 | * Handles the HTTP POST
method.
205 | *
206 | * @param request servlet request
207 | * @param response servlet response
208 | * @throws ServletException if a servlet-specific error occurs
209 | * @throws IOException if an I/O error occurs
210 | */
211 | @Override
212 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
213 | throws ServletException, IOException {
214 | processRequest(request, response);
215 | }
216 |
217 | /**
218 | * Returns a short description of the servlet.
219 | *
220 | * @return a String containing servlet description
221 | */
222 | @Override
223 | public String getServletInfo() {
224 | return "Short description";
225 | }//
226 |
227 | }
228 |
--------------------------------------------------------------------------------
/lab1 solution/src/java/org/glassfish/javaee7/batch/lab1/NetPayProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 | *
4 | * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
5 | *
6 | * The contents of this file are subject to the terms of either the GNU
7 | * General Public License Version 2 only ("GPL") or the Common Development
8 | * and Distribution License("CDDL") (collectively, the "License"). You
9 | * may not use this file except in compliance with the License. You can
10 | * obtain a copy of the License at
11 | * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
12 | * or packager/legal/LICENSE.txt. See the License for the specific
13 | * language governing permissions and limitations under the License.
14 | *
15 | * When distributing the software, include this License Header Notice in each
16 | * file and include the License file at packager/legal/LICENSE.txt.
17 | *
18 | * GPL Classpath Exception:
19 | * Oracle designates this particular file as subject to the "Classpath"
20 | * exception as provided by Oracle in the GPL Version 2 section of the License
21 | * file that accompanied this code.
22 | *
23 | * Modifications:
24 | * If applicable, add the following below the License Header, with the fields
25 | * enclosed by brackets [] replaced by your own identifying information:
26 | * "Portions Copyright [year] [name of copyright owner]"
27 | *
28 | * Contributor(s):
29 | * If you wish your version of this file to be governed by only the CDDL or
30 | * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 | * elects to include this software in this distribution under the [CDDL or GPL
32 | * Version 2] license." If you don't indicate a single choice of license, a
33 | * recipient has the option to distribute your version of this file under
34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 | * its licensees as provided above. However, if you add GPL Version 2 code
36 | * and therefore, elected the GPL Version 2 license, then the option applies
37 | * only if the new code is made subject to such option by the copyright
38 | * holder.
39 | */
40 | package org.glassfish.javaee7.batch.lab1;
41 |
42 | import javax.batch.api.chunk.ItemProcessor;
43 | import javax.batch.runtime.context.JobContext;
44 | import javax.inject.Inject;
45 | import javax.inject.Named;
46 |
47 | @Named
48 | public class NetPayProcessor
49 | implements ItemProcessor {
50 |
51 | @Inject
52 | private JobContext jobContext;
53 |
54 |
55 | public Object processItem(Object obj) throws Exception {
56 | PayrollInputRecord inputRecord = (PayrollInputRecord) obj;
57 | float salary = Integer.valueOf(inputRecord.getSalary());
58 | float socialSecurityTax =
59 | salary > 117000 ? 117000 * 6.2f / 100 : salary * 6.2f / 100;
60 |
61 | PayrollOutputRecord outputRecord = new PayrollOutputRecord(inputRecord.getId());
62 | outputRecord.setSalary(salary / 24.0f);
63 | outputRecord.setSocialSecurityTax(socialSecurityTax / 24.0f);
64 | outputRecord.setNet(outputRecord.getSalary() - outputRecord.getSocialSecurityTax());
65 |
66 | return outputRecord;
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/lab1 solution/src/java/org/glassfish/javaee7/batch/lab1/PayrollDataHolderBean.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 | *
4 | * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
5 | *
6 | * The contents of this file are subject to the terms of either the GNU
7 | * General Public License Version 2 only ("GPL") or the Common Development
8 | * and Distribution License("CDDL") (collectively, the "License"). You
9 | * may not use this file except in compliance with the License. You can
10 | * obtain a copy of the License at
11 | * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
12 | * or packager/legal/LICENSE.txt. See the License for the specific
13 | * language governing permissions and limitations under the License.
14 | *
15 | * When distributing the software, include this License Header Notice in each
16 | * file and include the License file at packager/legal/LICENSE.txt.
17 | *
18 | * GPL Classpath Exception:
19 | * Oracle designates this particular file as subject to the "Classpath"
20 | * exception as provided by Oracle in the GPL Version 2 section of the License
21 | * file that accompanied this code.
22 | *
23 | * Modifications:
24 | * If applicable, add the following below the License Header, with the fields
25 | * enclosed by brackets [] replaced by your own identifying information:
26 | * "Portions Copyright [year] [name of copyright owner]"
27 | *
28 | * Contributor(s):
29 | * If you wish your version of this file to be governed by only the CDDL or
30 | * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 | * elects to include this software in this distribution under the [CDDL or GPL
32 | * Version 2] license." If you don't indicate a single choice of license, a
33 | * recipient has the option to distribute your version of this file under
34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 | * its licensees as provided above. However, if you add GPL Version 2 code
36 | * and therefore, elected the GPL Version 2 license, then the option applies
37 | * only if the new code is made subject to such option by the copyright
38 | * holder.
39 | */
40 | package org.glassfish.javaee7.batch.lab1;
41 |
42 | import java.util.ArrayList;
43 | import java.util.Collections;
44 | import java.util.HashSet;
45 | import java.util.List;
46 | import java.util.Set;
47 | import javax.annotation.PostConstruct;
48 | import javax.ejb.Singleton;
49 | import javax.ejb.Startup;
50 |
51 | /**
52 | * Note: In a typical payroll processing system, the payroll records would come
53 | * from a database, But for simplicity we are using this singleton bean to
54 | * cache the payroll records.
55 | */
56 | @Singleton
57 | @Startup
58 | public class PayrollDataHolderBean {
59 |
60 | private List payrollInputRecords
61 | = new ArrayList<>();
62 |
63 | private Set payrollOutputRecords
64 | = new HashSet<>();
65 |
66 | public PayrollDataHolderBean() {
67 |
68 | }
69 |
70 | @PostConstruct
71 | public void onApplicationStartup() {
72 | for (int empID=1; empID<6; empID++) {
73 | payrollInputRecords.add("" + empID + ", " + (80000 + empID*10000));
74 | }
75 | }
76 |
77 | public List getPayrollInputData() {
78 | return Collections.unmodifiableList(payrollInputRecords);
79 | }
80 |
81 | public void addPayrollOutputRecord(PayrollOutputRecord data) {
82 | payrollOutputRecords.add(data);
83 | }
84 |
85 | public Set getPayrollOutputRecords() {
86 | return payrollOutputRecords;
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/lab1 solution/src/java/org/glassfish/javaee7/batch/lab1/PayrollInputRecord.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 | *
4 | * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
5 | *
6 | * The contents of this file are subject to the terms of either the GNU
7 | * General Public License Version 2 only ("GPL") or the Common Development
8 | * and Distribution License("CDDL") (collectively, the "License"). You
9 | * may not use this file except in compliance with the License. You can
10 | * obtain a copy of the License at
11 | * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
12 | * or packager/legal/LICENSE.txt. See the License for the specific
13 | * language governing permissions and limitations under the License.
14 | *
15 | * When distributing the software, include this License Header Notice in each
16 | * file and include the License file at packager/legal/LICENSE.txt.
17 | *
18 | * GPL Classpath Exception:
19 | * Oracle designates this particular file as subject to the "Classpath"
20 | * exception as provided by Oracle in the GPL Version 2 section of the License
21 | * file that accompanied this code.
22 | *
23 | * Modifications:
24 | * If applicable, add the following below the License Header, with the fields
25 | * enclosed by brackets [] replaced by your own identifying information:
26 | * "Portions Copyright [year] [name of copyright owner]"
27 | *
28 | * Contributor(s):
29 | * If you wish your version of this file to be governed by only the CDDL or
30 | * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 | * elects to include this software in this distribution under the [CDDL or GPL
32 | * Version 2] license." If you don't indicate a single choice of license, a
33 | * recipient has the option to distribute your version of this file under
34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 | * its licensees as provided above. However, if you add GPL Version 2 code
36 | * and therefore, elected the GPL Version 2 license, then the option applies
37 | * only if the new code is made subject to such option by the copyright
38 | * holder.
39 | */
40 | package org.glassfish.javaee7.batch.lab1;
41 |
42 | /**
43 | * A class that serves as input record for a simple payroll
44 | * processing system
45 | */
46 | public class PayrollInputRecord {
47 |
48 | private final int id;
49 |
50 | private String salary;
51 |
52 | public PayrollInputRecord(int id) {
53 | this.id = id;
54 | }
55 |
56 | public int getId() {
57 | return id;
58 | }
59 |
60 | public String getSalary() {
61 | return salary;
62 | }
63 |
64 | public void setSalary(String salary) {
65 | this.salary = salary;
66 | }
67 |
68 | @Override
69 | public int hashCode() {
70 | return id;
71 | }
72 |
73 | @Override
74 | public boolean equals(Object object) {
75 | if (object == null || !(object instanceof PayrollInputRecord)) {
76 | return false;
77 | }
78 | PayrollInputRecord other = (PayrollInputRecord) object;
79 | return this.id == other.id;
80 | }
81 |
82 | @Override
83 | public String toString() {
84 | return "PayrollInputRecord[ id=" + id + " ]";
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/lab1 solution/src/java/org/glassfish/javaee7/batch/lab1/PayrollInputRecordReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 | *
4 | * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
5 | *
6 | * The contents of this file are subject to the terms of either the GNU
7 | * General Public License Version 2 only ("GPL") or the Common Development
8 | * and Distribution License("CDDL") (collectively, the "License"). You
9 | * may not use this file except in compliance with the License. You can
10 | * obtain a copy of the License at
11 | * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
12 | * or packager/legal/LICENSE.txt. See the License for the specific
13 | * language governing permissions and limitations under the License.
14 | *
15 | * When distributing the software, include this License Header Notice in each
16 | * file and include the License file at packager/legal/LICENSE.txt.
17 | *
18 | * GPL Classpath Exception:
19 | * Oracle designates this particular file as subject to the "Classpath"
20 | * exception as provided by Oracle in the GPL Version 2 section of the License
21 | * file that accompanied this code.
22 | *
23 | * Modifications:
24 | * If applicable, add the following below the License Header, with the fields
25 | * enclosed by brackets [] replaced by your own identifying information:
26 | * "Portions Copyright [year] [name of copyright owner]"
27 | *
28 | * Contributor(s):
29 | * If you wish your version of this file to be governed by only the CDDL or
30 | * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 | * elects to include this software in this distribution under the [CDDL or GPL
32 | * Version 2] license." If you don't indicate a single choice of license, a
33 | * recipient has the option to distribute your version of this file under
34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 | * its licensees as provided above. However, if you add GPL Version 2 code
36 | * and therefore, elected the GPL Version 2 license, then the option applies
37 | * only if the new code is made subject to such option by the copyright
38 | * holder.
39 | */
40 | package org.glassfish.javaee7.batch.lab1;
41 |
42 | import java.io.Serializable;
43 | import java.util.Iterator;
44 | import java.util.StringTokenizer;
45 | import javax.batch.api.chunk.AbstractItemReader;
46 | import javax.ejb.EJB;
47 | import javax.inject.Named;
48 |
49 | /**
50 | * Reads PayrollInputRecords. In a typical payroll processing system, the data
51 | * would come come from a database, but for this lab this ItemReader will
52 | * simply retrieve data records from the EJB Singleton bean.
53 | *
54 | * This also demonstrates that an ItemReader can read data from any source.
55 | *
56 | */
57 | @Named
58 | public class PayrollInputRecordReader
59 | extends AbstractItemReader {
60 |
61 | @EJB
62 | PayrollDataHolderBean payrollDataHolderBean;
63 |
64 | Iterator payrollInputRecordsIterator;
65 |
66 | public void open(Serializable e) throws Exception {
67 | payrollInputRecordsIterator = payrollDataHolderBean.getPayrollInputData().iterator();
68 | }
69 |
70 | public Object readItem() throws Exception {
71 | String line = payrollInputRecordsIterator.hasNext() ? payrollInputRecordsIterator.next() : null;
72 | PayrollInputRecord record = null;
73 | if (line != null) {
74 | StringTokenizer tokenizer = new StringTokenizer(line, ", ");
75 | String empId = tokenizer.nextToken();
76 | String salary = tokenizer.nextToken();
77 | if (tokenizer.hasMoreTokens())
78 | throw new IllegalArgumentException("Extra characters in input data: " + line);
79 | record = new PayrollInputRecord(Integer.valueOf(empId));
80 | record.setSalary(salary);
81 | }
82 |
83 | return record;
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/lab1 solution/src/java/org/glassfish/javaee7/batch/lab1/PayrollOutputRecord.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 | *
4 | * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
5 | *
6 | * The contents of this file are subject to the terms of either the GNU
7 | * General Public License Version 2 only ("GPL") or the Common Development
8 | * and Distribution License("CDDL") (collectively, the "License"). You
9 | * may not use this file except in compliance with the License. You can
10 | * obtain a copy of the License at
11 | * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
12 | * or packager/legal/LICENSE.txt. See the License for the specific
13 | * language governing permissions and limitations under the License.
14 | *
15 | * When distributing the software, include this License Header Notice in each
16 | * file and include the License file at packager/legal/LICENSE.txt.
17 | *
18 | * GPL Classpath Exception:
19 | * Oracle designates this particular file as subject to the "Classpath"
20 | * exception as provided by Oracle in the GPL Version 2 section of the License
21 | * file that accompanied this code.
22 | *
23 | * Modifications:
24 | * If applicable, add the following below the License Header, with the fields
25 | * enclosed by brackets [] replaced by your own identifying information:
26 | * "Portions Copyright [year] [name of copyright owner]"
27 | *
28 | * Contributor(s):
29 | * If you wish your version of this file to be governed by only the CDDL or
30 | * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 | * elects to include this software in this distribution under the [CDDL or GPL
32 | * Version 2] license." If you don't indicate a single choice of license, a
33 | * recipient has the option to distribute your version of this file under
34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 | * its licensees as provided above. However, if you add GPL Version 2 code
36 | * and therefore, elected the GPL Version 2 license, then the option applies
37 | * only if the new code is made subject to such option by the copyright
38 | * holder.
39 | */
40 | package org.glassfish.javaee7.batch.lab1;
41 |
42 | public class PayrollOutputRecord {
43 | private final int empId;
44 |
45 | private float salary;
46 |
47 | private float socialSecurityTax;
48 |
49 | private float bonus = 0;
50 |
51 | private float net;
52 |
53 | public PayrollOutputRecord(int empID) {
54 | this.empId = empID;
55 | }
56 |
57 | public int getEmpId() {
58 | return empId;
59 | }
60 |
61 | public float getSalary() {
62 | return salary;
63 | }
64 |
65 | public void setSalary(float base) {
66 | this.salary = base;
67 | }
68 |
69 | public float getSocialSecurityTax() {
70 | return socialSecurityTax;
71 | }
72 |
73 | public void setSocialSecurityTax(float socialSecurityTax) {
74 | this.socialSecurityTax = socialSecurityTax;
75 | }
76 |
77 | public float getBonus() {
78 | return bonus;
79 | }
80 |
81 | public void setBonus(float bonus) {
82 | this.bonus = bonus;
83 | }
84 |
85 | public float getNet() {
86 | return net;
87 | }
88 |
89 | public void setNet(float net) {
90 | this.net = net;
91 | }
92 |
93 | @Override
94 | public int hashCode() {
95 | return getEmpId();
96 | }
97 |
98 | @Override
99 | public boolean equals(Object object) {
100 | // TODO: Warning - this method won't work in the case the id fields are not set
101 | if (object == null || !(object instanceof PayrollOutputRecord)) {
102 | return false;
103 | }
104 | PayrollOutputRecord other = (PayrollOutputRecord) object;
105 | return getEmpId() == other.getEmpId();
106 | }
107 |
108 | @Override
109 | public String toString() {
110 | return "PayrollOutputRecord[ id= [" + getEmpId() + "]";
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/lab1 solution/src/java/org/glassfish/javaee7/batch/lab1/PayrollOutputRecordWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 | *
4 | * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
5 | *
6 | * The contents of this file are subject to the terms of either the GNU
7 | * General Public License Version 2 only ("GPL") or the Common Development
8 | * and Distribution License("CDDL") (collectively, the "License"). You
9 | * may not use this file except in compliance with the License. You can
10 | * obtain a copy of the License at
11 | * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
12 | * or packager/legal/LICENSE.txt. See the License for the specific
13 | * language governing permissions and limitations under the License.
14 | *
15 | * When distributing the software, include this License Header Notice in each
16 | * file and include the License file at packager/legal/LICENSE.txt.
17 | *
18 | * GPL Classpath Exception:
19 | * Oracle designates this particular file as subject to the "Classpath"
20 | * exception as provided by Oracle in the GPL Version 2 section of the License
21 | * file that accompanied this code.
22 | *
23 | * Modifications:
24 | * If applicable, add the following below the License Header, with the fields
25 | * enclosed by brackets [] replaced by your own identifying information:
26 | * "Portions Copyright [year] [name of copyright owner]"
27 | *
28 | * Contributor(s):
29 | * If you wish your version of this file to be governed by only the CDDL or
30 | * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 | * elects to include this software in this distribution under the [CDDL or GPL
32 | * Version 2] license." If you don't indicate a single choice of license, a
33 | * recipient has the option to distribute your version of this file under
34 | * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 | * its licensees as provided above. However, if you add GPL Version 2 code
36 | * and therefore, elected the GPL Version 2 license, then the option applies
37 | * only if the new code is made subject to such option by the copyright
38 | * holder.
39 | */
40 | package org.glassfish.javaee7.batch.lab1;
41 |
42 | import java.io.Serializable;
43 | import java.util.List;
44 | import javax.batch.api.chunk.AbstractItemWriter;
45 | import javax.ejb.EJB;
46 | import javax.inject.Named;
47 |
48 | @Named
49 | public class PayrollOutputRecordWriter
50 | extends AbstractItemWriter {
51 |
52 | @EJB
53 | private PayrollDataHolderBean bean;
54 |
55 | @Override
56 | public void open(Serializable checkpoint) throws Exception {
57 |
58 | }
59 |
60 | public void writeItems(List list) throws Exception {
61 | for (Object obj : list) {
62 | bean.addPayrollOutputRecord((PayrollOutputRecord) obj);
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/lab1 solution/web/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab1 solution/web/WEB-INF/beans.xml
--------------------------------------------------------------------------------
/lab1 solution/web/WEB-INF/classes/META-INF/batch-jobs/PayrollJob.xml:
--------------------------------------------------------------------------------
1 |
2 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/lab1 solution/web/WEB-INF/glassfish-web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /dd_lab1
5 |
6 |
7 |
8 | Keep a copy of the generated servlet class' java code.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lab1 solution/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | Lab 1
10 |
11 |
12 |
13 |
14 | Lab 1
15 |
16 |
17 |
--------------------------------------------------------------------------------
/lab1-solution.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab1-solution.zip
--------------------------------------------------------------------------------
/lab2-solution.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab2-solution.zip
--------------------------------------------------------------------------------
/lab2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab2.zip
--------------------------------------------------------------------------------
/lab3-solution.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab3-solution.zip
--------------------------------------------------------------------------------
/lab3.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab3.zip
--------------------------------------------------------------------------------
/lab4-solution.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab4-solution.zip
--------------------------------------------------------------------------------
/lab4.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab4.zip
--------------------------------------------------------------------------------
/lab5-solution.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab5-solution.zip
--------------------------------------------------------------------------------
/lab5.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/lab5.zip
--------------------------------------------------------------------------------
/masterLab.adoc:
--------------------------------------------------------------------------------
1 | = Introduction to the Batch API (JSR 352)
2 | David Delabassee
3 | v1.0, Aug 27, 2014
4 | :doctype: book
5 | :toc:
6 | :toc-placement: preamble
7 | :toclevels: 2
8 | :icons: font
9 |
10 | image::cover.jpg[]
11 |
12 | :numbered!:
13 | include::chapters/introduction.adoc[]
14 | :numbered:
15 | include::chapters/exercice1.adoc[]
16 | include::chapters/exercice2.adoc[]
17 | include::chapters/exercice3.adoc[]
18 | include::chapters/exercice4.adoc[]
19 | include::chapters/exercice5.adoc[]
20 |
--------------------------------------------------------------------------------
/pic/E1.1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.1.jpg
--------------------------------------------------------------------------------
/pic/E1.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.1.png
--------------------------------------------------------------------------------
/pic/E1.10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.10.jpg
--------------------------------------------------------------------------------
/pic/E1.10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.10.png
--------------------------------------------------------------------------------
/pic/E1.11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.11.jpg
--------------------------------------------------------------------------------
/pic/E1.11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.11.png
--------------------------------------------------------------------------------
/pic/E1.12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.12.jpg
--------------------------------------------------------------------------------
/pic/E1.12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.12.png
--------------------------------------------------------------------------------
/pic/E1.14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.14.jpg
--------------------------------------------------------------------------------
/pic/E1.14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.14.png
--------------------------------------------------------------------------------
/pic/E1.15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.15.jpg
--------------------------------------------------------------------------------
/pic/E1.15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.15.png
--------------------------------------------------------------------------------
/pic/E1.16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.16.jpg
--------------------------------------------------------------------------------
/pic/E1.16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.16.png
--------------------------------------------------------------------------------
/pic/E1.17.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.17.jpg
--------------------------------------------------------------------------------
/pic/E1.17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.17.png
--------------------------------------------------------------------------------
/pic/E1.2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.2.jpg
--------------------------------------------------------------------------------
/pic/E1.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.2.png
--------------------------------------------------------------------------------
/pic/E1.3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.3.jpg
--------------------------------------------------------------------------------
/pic/E1.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.3.png
--------------------------------------------------------------------------------
/pic/E1.4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.4.jpg
--------------------------------------------------------------------------------
/pic/E1.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.4.png
--------------------------------------------------------------------------------
/pic/E1.5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.5.jpg
--------------------------------------------------------------------------------
/pic/E1.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.5.png
--------------------------------------------------------------------------------
/pic/E1.6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.6.jpg
--------------------------------------------------------------------------------
/pic/E1.6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.6.png
--------------------------------------------------------------------------------
/pic/E1.7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.7.jpg
--------------------------------------------------------------------------------
/pic/E1.7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.7.png
--------------------------------------------------------------------------------
/pic/E1.8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.8.jpg
--------------------------------------------------------------------------------
/pic/E1.8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.8.png
--------------------------------------------------------------------------------
/pic/E1.9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.9.jpg
--------------------------------------------------------------------------------
/pic/E1.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E1.9.png
--------------------------------------------------------------------------------
/pic/E2.1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E2.1.jpg
--------------------------------------------------------------------------------
/pic/E2.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E2.1.png
--------------------------------------------------------------------------------
/pic/E2.2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E2.2.jpg
--------------------------------------------------------------------------------
/pic/E2.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E2.2.png
--------------------------------------------------------------------------------
/pic/E2.3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E2.3.jpg
--------------------------------------------------------------------------------
/pic/E2.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E2.3.png
--------------------------------------------------------------------------------
/pic/E3.1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E3.1.jpg
--------------------------------------------------------------------------------
/pic/E3.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E3.1.png
--------------------------------------------------------------------------------
/pic/E3.2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E3.2.jpg
--------------------------------------------------------------------------------
/pic/E3.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/E3.2.png
--------------------------------------------------------------------------------
/pic/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/cover.jpg
--------------------------------------------------------------------------------
/pic/originals/E1.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.1.png
--------------------------------------------------------------------------------
/pic/originals/E1.10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.10.png
--------------------------------------------------------------------------------
/pic/originals/E1.11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.11.png
--------------------------------------------------------------------------------
/pic/originals/E1.12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.12.png
--------------------------------------------------------------------------------
/pic/originals/E1.14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.14.png
--------------------------------------------------------------------------------
/pic/originals/E1.15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.15.png
--------------------------------------------------------------------------------
/pic/originals/E1.16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.16.png
--------------------------------------------------------------------------------
/pic/originals/E1.17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.17.png
--------------------------------------------------------------------------------
/pic/originals/E1.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.2.png
--------------------------------------------------------------------------------
/pic/originals/E1.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.3.png
--------------------------------------------------------------------------------
/pic/originals/E1.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.4.png
--------------------------------------------------------------------------------
/pic/originals/E1.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.5.png
--------------------------------------------------------------------------------
/pic/originals/E1.6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.6.png
--------------------------------------------------------------------------------
/pic/originals/E1.7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.7.png
--------------------------------------------------------------------------------
/pic/originals/E1.8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.8.png
--------------------------------------------------------------------------------
/pic/originals/E1.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaee/batchlab/ed95ed5c245fefab8cb721ab8f256350bf414270/pic/originals/E1.9.png
--------------------------------------------------------------------------------