]> git.mxchange.org Git - pizzaservice-war.git/blob - src/java/org/mxchange/pizzaapplication/application/PizzaServiceApplication.java
e32f4556cf24de8150ddc769b7067b7d04aa3c81
[pizzaservice-war.git] / src / java / org / mxchange / pizzaapplication / application / PizzaServiceApplication.java
1 /*
2  * Copyright (C) 2015 Roland Haeder
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 package org.mxchange.pizzaapplication.application;
18
19 import org.mxchange.pizzaapplication.exceptions.CategoryTitleAlreadyUsedException;
20 import java.io.IOException;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.InvocationTargetException;
23 import java.sql.SQLException;
24 import java.text.MessageFormat;
25 import java.util.Iterator;
26 import java.util.Map;
27 import javax.servlet.ServletContext;
28 import javax.servlet.ServletException;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpSession;
31 import org.mxchange.jcore.contact.Gender;
32 import org.mxchange.jcore.exceptions.BadTokenException;
33 import org.mxchange.jcore.exceptions.UnsupportedDatabaseBackendException;
34 import org.mxchange.pizzaapplication.BasePizzaServiceSystem;
35 import org.mxchange.pizzaapplication.category.Category;
36 import org.mxchange.pizzaapplication.customer.Customer;
37 import org.mxchange.pizzaapplication.customer.PizzaServiceCustomer;
38 import org.mxchange.pizzaapplication.database.category.PizzaCategoryDatabaseConstants;
39 import org.mxchange.pizzaapplication.database.frontend.category.CategoryFrontend;
40 import org.mxchange.pizzaapplication.database.frontend.category.PizzaCategoryDatabaseFrontend;
41 import org.mxchange.pizzaapplication.database.frontend.product.PizzaProductDatabaseFrontend;
42 import org.mxchange.pizzaapplication.database.frontend.product.ProductFrontend;
43 import org.mxchange.pizzaapplication.database.product.PizzaProductDatabaseConstants;
44 import org.mxchange.pizzaapplication.exceptions.ProductTitleAlreadyUsedException;
45 import org.mxchange.pizzaapplication.product.Product;
46
47 /**
48  * Main application class
49  *
50  * @author Roland Haeder
51  */
52 public class PizzaServiceApplication extends BasePizzaServiceSystem implements PizzaApplication {
53         /**
54          * Main title
55          */
56         public static final String MAIN_TITLE = "Pizza-Service";
57
58         /**
59          * Frontend for products
60          */
61         private ProductFrontend productFrontend;
62
63         /**
64          * Frontend for categories
65          */
66         private CategoryFrontend categoryFrontend;
67
68         /**
69          * Some singleton getter for this instance. If the instance is not set in
70          * given application, it will be created.
71          *
72          * @param context Servlet context
73          * @return This instance
74          * @throws javax.servlet.ServletException If object is not set correctly
75          */
76         public static final PizzaApplication getInstance (final ServletContext context) throws ServletException {
77                 // Check application instance
78                 if (context == null) {
79                         // Not set
80                         throw new NullPointerException("application is null"); //NOI18N
81                 }
82
83                 // Init instance
84                 PizzaApplication instance = null;
85
86                 // Get instance from servlet application (aka. "application scope")
87                 Object object = context.getAttribute("app"); //NOI18N
88
89                 // Is it set?
90                 if (object instanceof PizzaApplication) {
91                         // Instance is set, so casting should work
92                         instance = (PizzaApplication) object;
93                 } else if (object instanceof Object) {
94                         // Not correct instance
95                         throw new ServletException("app is not set correctly"); //NOI18N
96                 } else {
97                         try {
98                                 // "service" is null, so initialize it
99                                 instance = new PizzaServiceApplication(context);
100                         } catch (final UnsupportedDatabaseBackendException | SQLException | IOException | BadTokenException ex) {
101                                 throw new ServletException(ex);
102                         }
103
104                         // And set it here
105                         context.setAttribute("app", instance); //NOI18N
106                 }
107
108                 // Trace message
109                 instance.getLogger().trace(MessageFormat.format("instance={0} - EXIT!", instance)); //NOI18N
110
111                 // Return it
112                 return instance;
113         }
114
115         /**
116          * For debugging purpose
117          *
118          * @param args Arguments
119          */
120         public static void main (String[] args) {
121                 // Get instance and start it
122                 new PizzaServiceApplication().start();
123         }
124
125         /**
126          * Constructor with servet configuration
127          *
128          * @param context Servlet context
129          */
130         private PizzaServiceApplication (final ServletContext context) throws UnsupportedDatabaseBackendException, SQLException, IOException, BadTokenException {
131                 // Temporary initialize default bundle
132                 // @TODO The JSF may have better internatialization support
133                 this.initBundle();
134
135                 // Initialize properties from config
136                 this.initProperties(context);
137
138                 // Init database frontends
139                 this.initDatabaseFrontends();
140         }
141
142         /**
143          * Default constructor
144          */
145         private PizzaServiceApplication () {
146         }
147
148         /**
149          * Calculates total amount of all choosen products
150          *
151          * @param request Request instance
152          * @param session Session instance
153          * @return Total amount of all choosen products
154          */
155         @Override
156         public int calculateTotalAmount (final HttpServletRequest request, final HttpSession session) throws ServletException {
157                 // Trace message
158                 this.getLogger().trace(MessageFormat.format("request={0},session={1} - CALLED!", request, session)); //NOI18N
159
160                 // Is product and session set?
161                 if (request == null) {
162                         // Not set
163                         throw new NullPointerException("request is null"); //NOI18N
164                 } else if (session == null) {
165                         // Not set
166                         throw new NullPointerException("session is null"); //NOI18N
167                 }
168
169                 // Init/declare total price and iterator
170                 int totalAmount = 0;
171                 Iterator<Product> iterator = this.getAvailableProducts();
172
173                 // "Walk" over all products
174                 while (iterator.hasNext()) {
175                         // Get next product
176                         Product product = iterator.next();
177
178                         // Is this choosen?
179                         if (this.isProductChoosen(product, request, session)) {
180                                 // Then add ordered amount
181                                 this.getLogger().debug(MessageFormat.format("Counting {0} ...", product.getId())); //NOI18N
182
183                                 // Getting amount
184                                 String amount = this.getAmountFromSession(product, session);
185
186                                 // Add it up
187                                 this.getLogger().debug(MessageFormat.format("amount={0}", amount)); //NOI18N
188                                 totalAmount += Integer.valueOf(amount);
189                         }
190                         this.getLogger().debug(MessageFormat.format("product={0},totalAmount={1}", product.getId(), totalAmount)); //NOI18N
191                 }
192
193                 // Trace message
194                 this.getLogger().trace(MessageFormat.format("totalAmount={0} - EXIT!", totalAmount)); //NOI18N
195
196                 // Return total price
197                 return totalAmount;
198         }
199
200         /**
201          * Calculates total price of all choosen products
202          *
203          * @param request Request instance
204          * @param session Session instance
205          * @return Total price of all choosen products
206          */
207         @Override
208         public float calculateTotalPrice (final HttpServletRequest request, final HttpSession session) throws ServletException {
209                 // Trace message
210                 this.getLogger().trace(MessageFormat.format("request={0},session={1} - CALLED!", request, session)); //NOI18N
211
212                 // Is product and session set?
213                 if (request == null) {
214                         // Not set
215                         throw new NullPointerException("request is null"); //NOI18N
216                 } else if (session == null) {
217                         // Not set
218                         throw new NullPointerException("session is null"); //NOI18N
219                 }
220
221                 // Init total price
222                 float totalPrice = 0.00f;
223
224                 // Get iterator
225                 Iterator<Product> iterator = this.getAvailableProducts();
226
227                 // "Walk" over all products
228                 while (iterator.hasNext()) {
229                         // Get next product
230                         Product product = iterator.next();
231
232                         // Is this choosen?
233                         if (this.isProductChoosen(product, request, session)) {
234                                 // Then add product's total price
235                                 this.getLogger().debug(MessageFormat.format("Calling getTotalPositionPriceFromRequestSession({0},request,session) ...", product.getId())); //NOI18N
236                                 totalPrice += this.getTotalPositionPriceFromRequestSession(product, request, session);
237                         }
238                         this.getLogger().debug(MessageFormat.format("product={0},totalPrice={1}", product.getId(), totalPrice)); //NOI18N
239                 }
240
241                 // Trace message
242                 this.getLogger().trace(MessageFormat.format(" totalPrice={0} - EXIT!", totalPrice)); //NOI18N
243
244                 // Return total price
245                 return totalPrice;
246         }
247
248         @Override
249         public void doBootstrap () {
250                 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
251         }
252
253         @Override
254         public void doMainLoop () {
255                 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
256         }
257
258         @Override
259         public void doShutdown () {
260                 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
261         }
262
263         /**
264          * Some "getter" for amount from session
265          *
266          * @param product Product instance
267          * @param session Session instance
268          * @return Amount as string
269          */
270         @Override
271         public String getAmountFromSession (final Product product, final HttpSession session) {
272                 // Trace message
273                 this.getLogger().trace(MessageFormat.format("product={0},session={1} - CALLED!", product, session)); //NOI18N
274
275                 // Is product and session set?
276                 if (product == null) {
277                         // Not set
278                         throw new NullPointerException("product is null"); //NOI18N
279                 } else if (session == null) {
280                         // Not set
281                         throw new NullPointerException("session is null"); //NOI18N
282                 }
283
284                 // Get attribute
285                 Object object = this.getValueFromSession(product, session, HTTP_PARAM_AMOUNT);
286
287                 // Is the object null?
288                 if (object == null) {
289                         // Trace message
290                         this.getLogger().trace("Returning 0 - EXIT!"); //NOI18N
291
292                         // Not found
293                         return "0"; //NOI18N
294                 }
295
296                 // Trace message
297                 this.getLogger().trace(MessageFormat.format("object={0} - EXIT!", object)); //NOI18N
298
299                 // Cast to string and return it
300                 return (String) object;
301         }
302
303         /**
304          * Some "getter" for HTML code 'checked="checked"' if the product is choosen
305          * 
306          * @param product Product instance
307          * @param request Request instance
308          * @param session Session instance
309          * @return Whether the product is choosen
310          */
311         @Override
312         public String getCheckedHtmlFromProduct (final Product product, final HttpServletRequest request, final HttpSession session) {
313                 // Trace message
314                 this.getLogger().trace(MessageFormat.format("product={0},request={1},session={2} - CALLED!", product, request, session)); //NOI18N
315
316                 // Is product and session set?
317                 if (product == null) {
318                         // Not set
319                         throw new NullPointerException("product is null"); //NOI18N
320                 } else if (request == null) {
321                         // Not set
322                         throw new NullPointerException("request is null"); //NOI18N
323                 } else if (session == null) {
324                         // Not set
325                         throw new NullPointerException("session is null"); //NOI18N
326                 }
327
328                 // First let's check if the product is choosen
329                 if (this.isProductChoosen(product, request, session)) {
330                         // Trace message
331                         this.getLogger().trace("Returning checked=\"checked\" - EXIT!"); //NOI18N
332
333                         // Is choosen
334                         return "checked=\"checked\""; //NOI18N
335                 } else {
336                         // Trace message
337                         this.getLogger().trace("Returning empty string - EXIT!"); //NOI18N
338
339                         // Not choosen
340                         return ""; //NOI18N
341                 }
342         }
343
344         /**
345          * Some "getter" for choose from session
346          * 
347          * @param product Product instance
348          * @param session Session instance
349          * @return Choose as string
350          */
351         @Override
352         public String getChooseFromSession (final Product product, final HttpSession session) {
353                 // Trace message
354                 this.getLogger().trace(MessageFormat.format("product={0},session={1} - CALLED!", product, session)); //NOI18N
355
356                 // Is product and session set?
357                 if (product == null) {
358                         // Not set
359                         throw new NullPointerException("product is null"); //NOI18N
360                 } else if (session == null) {
361                         // Not set
362                         throw new NullPointerException("session is null"); //NOI18N
363                 }
364
365                 // Get attribute
366                 Object object = this.getValueFromSession(product, session, HTTP_PARAM_CHOOSE);
367
368                 // Is the object null?
369                 if (object == null) {
370                         // Not found
371                         this.getLogger().debug(MessageFormat.format("Returning empty string for product={0} ...", product.getId())); //NOI18N
372                         return ""; //NOI18N
373                 }
374
375                 // Trace message
376                 this.getLogger().trace(MessageFormat.format("object={0} - CALLED!", object)); //NOI18N
377
378                 // Cast to string and return it
379                 return (String) object;
380         }
381
382         /**
383          * Some "getter" for HTML code 'disabled="disabled"' for e.g. submit buttons
384          *
385          * @param request Request instance
386          * @param session Session instance
387          * @return Whether the product is choosen
388          */
389         @Override
390         public String getDisabledHtmlFromSession (final HttpServletRequest request, final HttpSession session) throws ServletException {
391                 // Trace message
392                 this.getLogger().trace(MessageFormat.format("request={0},session={1} - CALLED!", request, session)); //NOI18N
393
394                 // Is product and session set?
395                 if (request == null) {
396                         // Not set
397                         throw new NullPointerException("request is null"); //NOI18N
398                 } else if (session == null) {
399                         // Not set
400                         throw new NullPointerException("session is null"); //NOI18N
401                 }
402
403                 // Is something selected?
404                 if (this.calculateTotalAmount(request, session) > 0) {
405                         // Trace message
406                         this.getLogger().trace("Returning empty string - EXIT!"); //NOI18N
407
408                         // Something has been choosen
409                         return ""; //NOI18N
410                 } else {
411                         // Trace message
412                         this.getLogger().trace("Returning disabled=\"disabled\" - EXIT!"); //NOI18N
413
414                         // Nothing choosen yet
415                         return "disabled=\"disabled\""; //NOI18N
416                 }
417         }
418
419         /**
420          * Some "getter" for choosen (checkbox) from session
421          *
422          * @param product Product instance
423          * @param request Request instance
424          * @param session Session instance
425          * @return Amount as string
426          */
427         @Override
428         public String getPrintableChoosenFromRequestSession (final Product product, final HttpServletRequest request, final HttpSession session) {
429                 // Trace message
430                 this.getLogger().trace(MessageFormat.format("product={0},request={1},session={2} - CALLED!", product, request, session)); //NOI18N
431
432                 // Is product and session set?
433                 if (product == null) {
434                         // Not set
435                         throw new NullPointerException("product is null"); //NOI18N
436                 } else if (request == null) {
437                         // Not set
438                         throw new NullPointerException("request is null"); //NOI18N
439                 } else if (session == null) {
440                         // Not set
441                         throw new NullPointerException("session is null"); //NOI18N
442                 }
443
444                 // Get element
445                 this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getId(), request, session)); //NOI18N
446                 String choosen = this.handleChooseFromRequestSession(product, request, session);
447                 this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getId(), choosen)); //NOI18N
448
449                 // Must not be null
450                 assert(choosen instanceof String): "choosen is null"; //NOI18N
451
452                 // Is it empty?
453                 if (choosen.isEmpty()) {
454                         // Not choosen
455                         return "Nein";
456                 }
457
458                 // Get amount
459                 String amount = this.handleAmountFromRequestSession(product, request, session);
460                 this.getLogger().debug(MessageFormat.format("product={0},amount={1}", product.getId(), amount)); //NOI18N
461
462                 // Must not be null
463                 assert(amount instanceof String): "amount is null"; //NOI18N
464
465                 // Is it empty?
466                 if (amount.isEmpty() || "0".equals(amount)) { //NOI18N
467                         // Choosen, but no amount
468                         return "Nein";
469                 } else {
470                         // Is choosen
471                         return "Ja";
472                 }
473         }
474
475         /**
476          * Checks if given Product instance is available and returns a printable
477          * (human-readable) string.
478          * 
479          * @param product Product instance to check
480          * @return Human-readable version of product availability
481          */
482         @Override
483         public String getPrintableProduktAvailability (final Product product) {
484                 // Trace message
485                 this.getLogger().trace(MessageFormat.format("product={0} - CALLED!", product));
486
487                 // Is it null?
488                 if (product == null) {
489                         // Should not be null
490                         throw new NullPointerException("product is null");
491                 }
492
493                 // Get availability
494                 if (product.getAvailable() == true) {
495                         // Is available
496                         return "Ja";
497                 } else {
498                         // Not, not for public
499                         return "Nein";
500                 }
501         }
502
503         /**
504          * Some getter for printable value from session or an empty string for null.
505          *
506          * @param session Session instance
507          * @param key Key to get
508          * @return Value from key, empty string for null
509          */
510         @Override
511         public Object getPrintableValeFromSession (final HttpSession session, final String key) {
512                 // Trace message
513                 this.getLogger().trace(MessageFormat.format("session={0},key={1} - CALLED", session, key)); //NOI18N
514
515                 // Are both parameter not null?
516                 if (session == null) {
517                         // Abort here
518                         throw new NullPointerException("session is null"); //NOI18N
519                 } else  if (key == null) {
520                         // Abort here
521                         throw new NullPointerException("key is null"); //NOI18N
522                 }
523
524                 // Now get it
525                 Object value = this.getValueFromSession(session, key);
526
527                 // Debug message
528                 this.getLogger().debug(MessageFormat.format("value={0}", value)); //NOI18N
529
530                 // Trace message
531                 this.getLogger().trace(MessageFormat.format("Calling this.convertNullToEmpty({0}) ... - EXIT!", value)); //NOI18N
532
533                 // Return actual value
534                 return this.convertNullToEmpty(value);
535         }
536
537         /**
538          * Some "getter" for a an array of only available products
539          *
540          * @return All products
541          */
542         @Override
543         public Iterator<Product> getAvailableProducts () throws ServletException {
544                 try {
545                         // Ask frontend for a list of products
546                         return this.productFrontend.getAvailableProducts();
547                 } catch (final IOException | BadTokenException | SQLException ex) {
548                         throw new ServletException(ex);
549                 }
550         }
551
552         /**
553          * Some "getter" for a an array of all products
554          *
555          * @return All products
556          */
557         @Override
558         public Iterator<Product> getAllProducts () throws ServletException {
559                 try {
560                         // Ask frontend for a list of products
561                         return this.productFrontend.getAllProducts();
562                 } catch (final IOException | BadTokenException | SQLException ex) {
563                         throw new ServletException(ex);
564                 }
565         }
566
567         /**
568          * Some "getter" for a an array of all categories
569          *
570          * @return All categories
571          */
572         @Override
573         public Iterator<Category> getCategories () throws ServletException {
574                 try {
575                         // Ask frontend for a list of categories
576                         return this.categoryFrontend.getCategories();
577                 } catch (final IOException | BadTokenException | SQLException ex) {
578                         throw new ServletException(ex);
579                 }
580         }
581
582         /**
583          * Some "getter" for total price of position from request or session.
584          * Single price and amount is multiplyed.
585          *
586          * @param product Product instance
587          * @param request Request instance
588          * @param session Session instance
589          * @return Amount as string
590          */
591         @Override
592         public float getTotalPositionPriceFromRequestSession (final Product product, final HttpServletRequest request, final HttpSession session) {
593                 // Trace message
594                 this.getLogger().trace(MessageFormat.format("product={0},request={1},session={2} - CALLED!", product, request, session)); //NOI18N
595
596                 // Is product and session set?
597                 if (product == null) {
598                         // Not set
599                         throw new NullPointerException("product is null"); //NOI18N
600                 } else if (request == null) {
601                         // Not set
602                         throw new NullPointerException("request is null"); //NOI18N
603                 } else if (session == null) {
604                         // Not set
605                         throw new NullPointerException("session is null"); //NOI18N
606                 }
607
608                 // Get choosen
609                 this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getId(), request, session)); //NOI18N
610                 String choosen = this.handleChooseFromRequestSession(product, request, session);
611                 this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getId(), choosen)); //NOI18N
612
613                 // Must not be null
614                 assert(choosen instanceof String): "choosen is null"; //NOI18N
615
616                 // Is it set?
617                 if (choosen.isEmpty()) {
618                         // Is empty
619                         this.getLogger().debug(MessageFormat.format("product={0},choosen={1} - returning zero ...", product.getId(), choosen)); //NOI18N
620                         return 0.00f;
621                 }
622
623                 // Get amount
624                 String amount = this.handleAmountFromRequestSession(product, request, session);
625                 this.getLogger().debug(MessageFormat.format("product={0},amount={1}", product.getId(), amount)); //NOI18N
626
627                 // Must not be null
628                 assert(amount instanceof String): "amount is null"; //NOI18N
629
630                 // Is it empty?
631                 if (amount.isEmpty() || "0".equals(amount)) { //NOI18N
632                         // Is empty
633                         this.getLogger().debug(MessageFormat.format("product={0},amount={1} - returning zero ...", product.getId(), amount)); //NOI18N
634                         return 0.00f;
635                 }
636
637                 // Init variable
638                 Integer value = null;
639
640                 // Try it
641                 try {
642                         // Get amount as integer
643                         value = Integer.valueOf(amount);
644                 } catch (final NumberFormatException e) {
645                         // Bat input
646                         throw new IllegalArgumentException(e);
647                 }
648
649                 // Calculate price
650                 float price = (product.getPrice() * value);
651
652                 // Trace message
653                 this.getLogger().trace(MessageFormat.format("product={0},price={1} - EXIT!", product.getId(), price)); //NOI18N
654
655                 // Then multiply it with price
656                 return price;
657         }
658
659         /**
660          * Handler for amount from request or session
661          *
662          * @param product Product instance
663          * @param request Request instance
664          * @param session Session instance
665          * @return Amount as string
666          */
667         @Override
668         public String handleAmountFromRequestSession (final Product product, final HttpServletRequest request, final HttpSession session) {
669                 // Trace message
670                 this.getLogger().trace(MessageFormat.format("product={0},request={1},session={2} - CALLED!", product, request, session)); //NOI18N
671
672                 // Is product and session set?
673                 if (product == null) {
674                         // Not set
675                         throw new NullPointerException("product is null"); //NOI18N
676                 } else if (request == null) {
677                         // Not set
678                         throw new NullPointerException("request is null"); //NOI18N
679                 } else if (session == null) {
680                         // Not set
681                         throw new NullPointerException("session is null"); //NOI18N
682                 }
683
684                 // Init variabke
685                 Object object;
686
687                 // Check request method
688                 if (!"POST".equals(request.getMethod())) { //NOI18N
689                         // Not POST, so get from session
690                         return this.getAmountFromSession(product, session);
691                 } else if (this.handleChooseFromRequestSession(product, request, session).isEmpty()) {
692                         // Not choosen
693                         this.clearSessionAttribute(product, session, HTTP_PARAM_AMOUNT);
694                         this.getLogger().debug(MessageFormat.format("Unsetting for product={0} in session, returning zero ...", product.getId())); //NOI18N
695                         return "0"; //NOI18N
696                 }
697
698                 // Get attribute from request
699                 object = request.getParameter(String.format(HTTP_PARAM_MASK, HTTP_PARAM_AMOUNT, product.getId()));
700
701                 // Is it set?
702                 if (object instanceof String) {
703                         // Try to parse it to integer
704                         try {
705                                 Integer value = Integer.valueOf((String) object);
706                         } catch (final NumberFormatException ex) {
707                                 // Not valid input
708                                 this.getLogger().warn(ex);
709                                 return "0"; //NOI18N
710                         }
711
712                         // Then set it in session
713                         this.setValueInSession(product, session, HTTP_PARAM_AMOUNT, object);
714
715                         // And return it
716                         return (String) object;
717                 }
718
719                 // Trace message
720                 this.getLogger().trace("Calling getAmountFromSession() ..."); //NOI18N
721
722                 // Get attribute from session
723                 return this.getAmountFromSession(product, session);
724         }
725
726         /**
727          * Checks whether the given product is choosen, request overules session.
728          *
729          * @param product Product instance
730          * @param request Request instance
731          * @param session Session instance
732          * @return Whether the product is choosen
733          */
734         @Override
735         public boolean isProductChoosen (final Product product, final HttpServletRequest request, final HttpSession session) {
736                 // Trace message
737                 this.getLogger().trace(MessageFormat.format("product={0},request={1},session={2} - CALLED!", product, request, session)); //NOI18N
738
739                 // Is product and session set?
740                 if (product == null) {
741                         // Not set
742                         throw new NullPointerException("product is null"); //NOI18N
743                 } else if (request == null) {
744                         // Not set
745                         throw new NullPointerException("request is null"); //NOI18N
746                 } else if (session == null) {
747                         // Not set
748                         throw new NullPointerException("session is null"); //NOI18N
749                 }
750
751                 // Get choosen
752                 this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getId(), request, session)); //NOI18N
753                 String choosen = this.handleChooseFromRequestSession(product, request, session);
754                 this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getId(), choosen)); //NOI18N
755
756                 // Must not be null
757                 assert(choosen instanceof String): "choosen is null"; //NOI18N
758
759                 // Is it not choosen?
760                 if (choosen.isEmpty()) {
761                         // Not choosen
762                         return false;
763                 }
764
765                 // Get amount
766                 String amount = this.handleAmountFromRequestSession(product, request, session);
767
768                 // Must not be null
769                 assert(amount instanceof String): "amount is not set"; //NOI18N
770
771                 // Trace message
772                 this.getLogger().trace(MessageFormat.format("amount={0} - EXIT!", amount)); //NOI18N
773
774                 // Must not be empty and not 0
775                 return (!amount.isEmpty() && !"0".equals(amount)); //NOI18N
776         }
777
778         /**
779          * Marks all choosen products as ordered
780          *
781          * @param request Request instance
782          * @param session Session instance
783          */
784         @Override
785         public void markAllChoosenProductsAsOrdered (final HttpServletRequest request, final HttpSession session) throws ServletException {
786                 // Trace message
787                 this.getLogger().trace(MessageFormat.format("request={0},session={1} - CALLED!", request, session)); //NOI18N
788
789                 // Init iterator
790                 Iterator<Product> iterator = this.getAvailableProducts();
791
792                 // "Walk" over all products
793                 while (iterator.hasNext()) {
794                         // Get next product
795                         Product product = iterator.next();
796
797                         // Debug message
798                         this.getLogger().debug(MessageFormat.format("product={0}", product)); //NOI18N
799
800                         // Is it choosen?
801                         if (this.isProductChoosen(product, request, session)) {
802                                 // Mark product as ordered
803                                 this.markProductAsOrdered(product, session);
804                         }
805                 }
806
807                 // Trace message
808                 this.getLogger().trace("EXIT!"); //NOI18N
809         }
810
811         /**
812          * Marks given product as choosen in session
813          *
814          * @param product Product to mark as ordered
815          * @param session Session instance
816          */
817         @Override
818         public void markProductAsChoosen (final Product product, final HttpSession session) {
819                 // Trace message
820                 this.getLogger().trace(MessageFormat.format("product={0},session={1} - CALLED!", product, session)); //NOI18N
821
822                 // Is product and session set?
823                 if (product == null) {
824                         // Not set
825                         throw new NullPointerException("product is null"); //NOI18N
826                 } else if (session == null) {
827                         // Not set
828                         throw new NullPointerException("session is null"); //NOI18N
829                 }
830
831                 // Mark it as ordered by setting flag
832                 this.getLogger().debug(MessageFormat.format("Marking product={0} as choosen.", product.getId())); //NOI18N
833                 this.setValueInSession(product, session, HTTP_PARAM_CHOOSE, "1"); //NOI18N
834
835                 // Trace message
836                 this.getLogger().trace("EXIT!"); //NOI18N
837         }
838
839         /**
840          * Marks given product as ordered in session
841          *
842          * @param product Product to mark as ordered
843          * @param session Session instance
844          */
845         @Override
846         public void markProductAsOrdered (final Product product, final HttpSession session) {
847                 // Trace message
848                 this.getLogger().trace(MessageFormat.format("product={0},session={1} - CALLED!", product, session)); //NOI18N
849
850                 // Is product and session set?
851                 if (product == null) {
852                         // Not set
853                         throw new NullPointerException("product is null"); //NOI18N
854                 } else if (session == null) {
855                         // Not set
856                         throw new NullPointerException("session is null"); //NOI18N
857                 }
858
859                 // Mark it as ordered by setting flag
860                 this.getLogger().debug(MessageFormat.format("Marking product={0} as ordered.", product.getId())); //NOI18N
861                 this.setValueInSession(product, session, SESSION_ORDERED, "true"); //NOI18N
862
863                 // Trace message
864                 this.getLogger().trace("EXIT!"); //NOI18N
865         }
866
867         /**
868          * Somewhat setter in session
869          *
870          * @param session Session instance
871          * @param key Session key to set
872          * @param value Value to set
873          */
874         @Override
875         public void setValueInSession (final HttpSession session, final String key, final Object value) {
876                 // Trace message
877                 this.getLogger().trace(MessageFormat.format("session={0},key={1},value={2} - CALLED!", session, key, value)); //NOI18N
878
879                 synchronized(session) {
880                         // Set it synced
881                         session.setAttribute(key, value);
882                 }
883
884                 // Trace message
885                 this.getLogger().trace("EXIT!"); //NOI18N
886         }
887
888         /**
889          * Unmarks given product as choosen in session
890          *
891          * @param product Product to unmark as choosen
892          * @param session Session instance
893          */
894         @Override
895         public void unmarkProductAsChoosen (final Product product, final HttpSession session) {
896                 // Trace message
897                 this.getLogger().trace(MessageFormat.format("product={0},session={1} - CALLED!", product, session)); //NOI18N
898
899                 // Is product and session set?
900                 if (product == null) {
901                         // Not set
902                         throw new NullPointerException("product is null"); //NOI18N
903                 } else if (session == null) {
904                         // Not set
905                         throw new NullPointerException("session is null"); //NOI18N
906                 }
907
908                 // Mark it as ordered by setting flag
909                 this.getLogger().debug(MessageFormat.format("Unmarking product={0} as choosen.", product.getId())); //NOI18N
910                 this.clearSessionAttribute(product, session, HTTP_PARAM_CHOOSE);
911
912                 // Trace message
913                 this.getLogger().trace("EXIT!"); //NOI18N
914         }
915
916         /**
917          * Unmarks given product as ordered in session
918          *
919          * @param product Product to unmark as ordered
920          * @param session Session instance
921          */
922         @Override
923         public void unmarkProductAsOrdered (final Product product, final HttpSession session) {
924                 // Trace message
925                 this.getLogger().trace(MessageFormat.format("product={0},session={1} - CALLED!", product, session)); //NOI18N
926
927                 // Is product and session set?
928                 if (product == null) {
929                         // Not set
930                         throw new NullPointerException("product is null"); //NOI18N
931                 } else if (session == null) {
932                         // Not set
933                         throw new NullPointerException("session is null"); //NOI18N
934                 }
935
936                 // Mark it as ordered by setting flag
937                 this.getLogger().debug(MessageFormat.format("Unmarking product={0} as ordered.", product.getId())); //NOI18N
938                 this.clearSessionAttribute(product, session, SESSION_ORDERED);
939
940                 // Trace message
941                 this.getLogger().trace("EXIT!"); //NOI18N
942         }
943
944         /**
945          * Clears given parameter for product in session
946          *
947          * @param product Product instance
948          * @param session Session instance
949          * @param parameter Parameter to clear
950          */
951         private void clearSessionAttribute (final Product product, final HttpSession session, final String parameter) {
952                 // Trace message
953                 this.getLogger().trace(MessageFormat.format("produce={0},parameter={1},session={2} - CALLED!", product, parameter, session)); //NOI18N
954
955                 // Clear in session
956                 this.getLogger().debug(MessageFormat.format("Clearing product={0},parameter={1} ...", product.getId(), parameter)); //NOI18N
957                 this.setValueInSession(product, session, parameter, null);
958
959                 // Trace message
960                 this.getLogger().trace("EXIT!"); //NOI18N
961         }
962
963         /**
964          * Some getter for value from session
965          *
966          * @param product Product instance
967          * @param session Session instance
968          * @param attribute Attribute to get value from
969          * @return Value from session
970          */
971         private Object getValueFromSession (final Product product, final HttpSession session, final String attribute) {
972                 // Trace message
973                 this.getLogger().trace(MessageFormat.format("product={0},session={1},attribute={2} - CALLED!", product, session, attribute)); //NOI18N
974
975                 // Init variable
976                 Object value = this.getValueFromSession(session, String.format(HTTP_PARAM_MASK, attribute, product.getId()));
977                 
978                 this.getLogger().debug(MessageFormat.format("product={0},attribute={1},value={2}", product.getId(), attribute, value)); //NOI18N
979
980                 // Trace message
981                 this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value)); //NOI18N
982
983                 // Return it
984                 return value;
985         }
986
987         /**
988          * Some getter for value from session
989          *
990          * @param session Session instance
991          * @param key Key to get value from
992          * @return Value from session
993          */
994         private Object getValueFromSession (final HttpSession session, final String key) {
995                 // Trace message
996                 this.getLogger().trace(MessageFormat.format("session={0},key={1} - CALLED!", session, key)); //NOI18N
997
998                 // Init value
999                 Object value = null;
1000
1001                 // Get it synchronized from session
1002                 synchronized (session) {
1003                         value = session.getAttribute(key);
1004                 }
1005
1006                 // Trace message
1007                 this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value)); //NOI18N
1008
1009                 // Return it
1010                 return value;
1011         }
1012
1013         /**
1014          * Handler for choosen (checkbox) from request or session
1015          *
1016          * @param product Product instance
1017          * @param request Request instance
1018          * @param session Session instance
1019          * @return Amount as string
1020          */
1021         private String handleChooseFromRequestSession(final Product product, final HttpServletRequest request, final HttpSession session) {
1022                 // Trace message
1023                 this.getLogger().trace(MessageFormat.format("product={0},request={1},session={2} - CALLED!", product, request, session)); //NOI18N
1024
1025                 // Is product and session set?
1026                 if (product == null) {
1027                         // Not set
1028                         throw new NullPointerException("product is null"); //NOI18N
1029                 } else if (request == null) {
1030                         // Not set
1031                         throw new NullPointerException("request is null"); //NOI18N
1032                 } else if (session == null) {
1033                         // Not set
1034                         throw new NullPointerException("session is null"); //NOI18N
1035                 }
1036
1037                 // Init variabke
1038                 Object object;
1039
1040                 // Check request method
1041                 if (!"POST".equals(request.getMethod())) { //NOI18N
1042                         // Not POST, so get from session
1043                         this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getId(), session)); //NOI18N
1044                         return this.getChooseFromSession(product, session);
1045                 } else if (this.isProductOrdered(product, session)) {
1046                         // Product is ordered
1047                         this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getId(), session)); //NOI18N
1048                         return this.getChooseFromSession(product, session);
1049                 } else if (!this.getChooseFromSession(product, session).isEmpty()) {
1050                         // Found in session
1051                         this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getId(), session)); //NOI18N
1052                         return this.getChooseFromSession(product, session);
1053                 }
1054
1055                 // Get reqzest element
1056                 object = request.getParameter(String.format(HTTP_PARAM_MASK, HTTP_PARAM_CHOOSE, product.getId()));
1057                 this.getLogger().debug(MessageFormat.format("product={0},object={1}", product.getId(), object)); //NOI18N
1058
1059                 // Is it null?
1060                 if (object == null) {
1061                         // Unset session
1062                         this.getLogger().debug(MessageFormat.format("Unsetting session for product={0} ...", product.getId())); //NOI18N
1063                         this.clearSessionAttribute(product, session, HTTP_PARAM_CHOOSE);
1064                         this.clearSessionAttribute(product, session, HTTP_PARAM_AMOUNT);
1065
1066                         // Return empty string
1067                         return ""; //NOI18N
1068                 }
1069
1070                 // Then set it in session
1071                 this.setValueInSession(product, session, HTTP_PARAM_CHOOSE, object);
1072
1073                 // Cast to string and return it
1074                 this.getLogger().debug(MessageFormat.format("product={0} - Returning {1} ...", product.getId(), object)); //NOI18N
1075                 return (String) object;
1076         }
1077
1078         /**
1079          * Initializes database frontends.
1080          */
1081         private void initDatabaseFrontends () throws UnsupportedDatabaseBackendException, SQLException {
1082                 // Product frontend
1083                 this.productFrontend = new PizzaProductDatabaseFrontend();
1084
1085                 // Category frontend
1086                 this.categoryFrontend = new PizzaCategoryDatabaseFrontend();
1087         }
1088
1089         /**
1090          * Checks whether given category title is already used
1091          *
1092          * @param title Title of category to check
1093          * @return Whether it has been found
1094          */
1095         private boolean isCategoryTitleUsed (final String title) throws IOException, SQLException, BadTokenException {
1096                 // Delegate to frontend
1097                 return this.categoryFrontend.isCategoryTitleUsed(title);
1098         }
1099
1100         /**
1101          * Checks if given product title is already used
1102          * @param title Product title to check
1103          * @return Whether the product title has already been used
1104          */
1105         private boolean isProductTitleUsed (final String title) throws IOException, SQLException, BadTokenException {
1106                 // Delegate to frontend
1107                 return this.productFrontend.isProductTitleUsed(title);
1108         }
1109
1110         /**
1111          * Checks if the product ordered?
1112          *
1113          * @param product Product instance
1114          * @param session HttpSession instance
1115          * @return
1116          */
1117         private boolean isProductOrdered(final Product product, final HttpSession session) {
1118                 // Trace message
1119                 this.getLogger().trace(MessageFormat.format("product={0},session={1} - CALLED!", product, session)); //NOI18N
1120
1121                 // Get session
1122                 Object isOrdered = this.getValueFromSession(product, session, SESSION_ORDERED);
1123                 this.getLogger().debug(MessageFormat.format("product={0},isOrdered={1}", product.getId(), isOrdered)); //NOI18N
1124
1125                 // Return result
1126                 return ("true".equals(isOrdered)); //NOI18N
1127         }
1128
1129         /**
1130          * Somewhat setter in session
1131          *
1132          * @param product Product instance
1133          * @param session Session instance
1134          * @param keyPart Key part to include in final key
1135          * @param value Value to set
1136          */
1137         private void setValueInSession (final Product product, final HttpSession session, final String keyPart, final Object value) {
1138                 // Trace message
1139                 this.getLogger().trace(MessageFormat.format("product={0},session={1},keyPart={2},value={3} - CALLED!", product, session, keyPart, value)); //NOI18N
1140
1141                 // Set it synced
1142                 this.getLogger().debug(MessageFormat.format("Setting value={0} for product={1},keyPart={2}", value, product.getId(), keyPart)); //NOI18N
1143                 this.setValueInSession(session, String.format(HTTP_PARAM_MASK, keyPart, product.getId()), value);
1144
1145                 // Trace message
1146                 this.getLogger().trace("EXIT!"); //NOI18N
1147         }
1148         
1149         /**
1150          * Application starter
1151          */
1152         private void start () {
1153                 // Init bundle
1154                 this.initBundle();
1155
1156                 try {
1157                         // Init properties
1158                         this.initProperties();
1159                 } catch (final IOException ex) {
1160                         // Abort here
1161                         this.abortProgramWithException(ex);
1162                 }
1163
1164                 // Init instance
1165                 Iterator<Product> iterator = null;
1166
1167                 try {
1168                         // Get iterator
1169                         iterator = this.getAvailableProducts();
1170                 } catch (final ServletException ex) {
1171                         this.abortProgramWithException(ex);
1172                 }
1173
1174                 // "Walk" over all products
1175                 while ((iterator instanceof Iterator) && (iterator.hasNext())) {
1176                         // Get next product
1177                         Product product = iterator.next();
1178
1179                         // Output data
1180                         this.getLogger().debug(MessageFormat.format("Product {0}, {1}: {2}", product.getId(), product.getTitle(), product.getPrice())); //NOI18N
1181                 }
1182
1183                 // Generate fake Customer instance
1184                 Customer customer = new PizzaServiceCustomer();
1185
1186                 /*
1187                  * Need a least a gender ... :( See, that is why I don't like default
1188                  * constructors, you can easily miss something important and bam! You
1189                  * get an NPE. The fix here is, to have construtors (or factories) which
1190                  * requires all required instances that needs to be set to get a
1191                  * consitent object back.
1192                  */
1193
1194                 // Gender is MALE now
1195                 customer.setGender(Gender.MALE);
1196
1197                 // Init iterator
1198                 Iterator<Map.Entry<Field, Object>> it = null;
1199
1200                 try {
1201                         // Get iterator on all its fields
1202                         it = customer.iterator();
1203                 } catch (final NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
1204                         this.abortProgramWithException(ex);
1205                 }
1206
1207                 // Output it
1208                 while ((it instanceof Iterator) && (it.hasNext())) {
1209                         Map.Entry<Field, Object> entry = it.next();
1210                         this.getLogger().debug(MessageFormat.format("entry {0}={1}", entry.getKey(), entry.getValue())); //NOI18N
1211                 }
1212         }
1213
1214         /**
1215          * Adds given category data from request to database
1216          *
1217          * @param request Request instance
1218          */
1219         @Override
1220         public void doAdminAddCategory (final HttpServletRequest request) throws ServletException, CategoryTitleAlreadyUsedException {
1221                 // Trace message
1222                 this.getLogger().trace(MessageFormat.format("request={0} - CALLED!", request)); //NOI18N
1223
1224                 // request must not be null
1225                 if (request == null) {
1226                         // Is null
1227                         throw new NullPointerException("request is null");
1228                 }
1229
1230                 // Get all fields
1231                 String title = request.getParameter(PizzaCategoryDatabaseConstants.COLUMN_TITLE);
1232                 String parent = request.getParameter(PizzaCategoryDatabaseConstants.COLUMN_PARENT);
1233                 Integer id = null;
1234
1235                 // Check all fields
1236                 if (title == null) {
1237                         // "title" not set
1238                         throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaCategoryDatabaseConstants.COLUMN_TITLE));
1239                 } else if (title.isEmpty()) {
1240                         // Is left empty
1241                         throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaCategoryDatabaseConstants.COLUMN_TITLE));
1242                 } else if ((parent != null) && (!parent.isEmpty())) {
1243                         // "parent" is set, so check it
1244                         try {
1245                                 id = Integer.parseInt(parent);
1246                         } catch (final NumberFormatException e) {
1247                                 // Not valid number
1248                                 throw new IllegalArgumentException(e);
1249                         }
1250                 }
1251                 try {
1252                         // Try to check if title is used already
1253                         if (this.isCategoryTitleUsed(title)) {
1254                                 // Title already used
1255                                 throw new CategoryTitleAlreadyUsedException(request);
1256                         }
1257                 } catch (final IOException | SQLException | BadTokenException ex) {
1258                         throw new ServletException(ex);
1259                 }
1260
1261                 try {
1262                         // The category is not found, so add it to database
1263                         this.categoryFrontend.addCategory(title, id);
1264                 } catch (final SQLException ex) {
1265                         // Continue to throw it
1266                         throw new ServletException(ex);
1267                 }
1268
1269                 // Trace message
1270                 this.getLogger().trace("EXIT!"); //NOI18N
1271         }
1272
1273         /**
1274          * Adds given product data from request to database
1275          *
1276          * @param request Request instance
1277          */
1278         @Override
1279         public void doAdminAddProduct (final HttpServletRequest request) throws ServletException, ProductTitleAlreadyUsedException {
1280                 // Trace message
1281                 this.getLogger().trace(MessageFormat.format("request={0} - CALLED!", request)); //NOI18N
1282
1283                 // request must not be null
1284                 if (request == null) {
1285                         // Is null
1286                         throw new NullPointerException("request is null");
1287                 }
1288
1289                 // Get title, price and category id
1290                 String title = request.getParameter(PizzaProductDatabaseConstants.COLUMN_TITLE);
1291                 String price = request.getParameter(PizzaProductDatabaseConstants.COLUMN_PRICE);
1292                 String category = request.getParameter(PizzaProductDatabaseConstants.COLUMN_CATEGORY);
1293                 String available = request.getParameter(PizzaProductDatabaseConstants.COLUMN_AVAILABLE);
1294
1295                 Long id = null;
1296                 Float p = null;
1297                 Boolean a = null;
1298
1299                 // Check all fields
1300                 if (title == null) {
1301                         // "title" not set
1302                         throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_TITLE));
1303                 } else if (title.isEmpty()) {
1304                         // Is left empty
1305                         throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_TITLE));
1306                 } else if (price == null) {
1307                         // "price" not set
1308                         throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_PRICE));
1309                 } else if (price.isEmpty()) {
1310                         // Is left empty
1311                         throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_PRICE));
1312                 } else if (category == null) {
1313                         // "title" not set
1314                         throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_CATEGORY));
1315                 } else if (category.isEmpty()) {
1316                         // Is left empty
1317                         throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_CATEGORY));
1318                 } else if (available == null) {
1319                         // "title" not set
1320                         throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_AVAILABLE));
1321                 } else if (available.isEmpty()) {
1322                         // Is left empty
1323                         throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_AVAILABLE));
1324                 } else if ((!"true".equals(available)) && (!"false".equals(available))) {
1325                         // Invalid value
1326                         throw new IllegalArgumentException(MessageFormat.format("{0} is invalid: {1}", PizzaProductDatabaseConstants.COLUMN_AVAILABLE, available));
1327                 }
1328
1329                 // Parse numbers
1330                 try {
1331                         id = Long.parseLong(category);
1332                         p = Float.parseFloat(price);
1333                 } catch (final NumberFormatException e) {
1334                         // Not valid number
1335                         throw new IllegalArgumentException(e);
1336                 }
1337
1338                 // Parse boolean
1339                 a = Boolean.parseBoolean(available);
1340
1341                 // Test on product title
1342                 try {
1343                         // Try to check if title is used already
1344                         if (this.isProductTitleUsed(title)) {
1345                                 // Title already used
1346                                 throw new ProductTitleAlreadyUsedException(request);
1347                         }
1348                 } catch (final IOException | SQLException | BadTokenException ex) {
1349                         throw new ServletException(ex);
1350                 }
1351
1352                 try {
1353                         // The product is not found, so add it to database
1354                         this.productFrontend.addProduct(title, p, id, a);
1355                 } catch (final SQLException ex) {
1356                         // Continue to throw it
1357                         throw new ServletException(ex);
1358                 }
1359
1360                 // Trace message
1361                 this.getLogger().trace("EXIT!"); //NOI18N
1362         }
1363
1364         /**
1365          * Generates link HTML code for given category's parent id, if set. This
1366          * link then points to products.jsp?category_id=x
1367          *
1368          * @param category Category instance
1369          * @return HTML code
1370          */
1371         @Override
1372         public String generateLinkForParent (final Category category) {
1373                 // Trace message
1374                 this.getLogger().trace(MessageFormat.format("category={0} - CALLED!", category));
1375
1376                 // category must not be null
1377                 if (category == null) {
1378                         // Is null
1379                         throw new NullPointerException("category is null");
1380                 }
1381
1382                 // Get parent id
1383                 Integer parent = category.getParent();
1384
1385                 // Is the id set?
1386                 if (parent > 0) {
1387                         // Product HTML code for link
1388                         throw new UnsupportedOperationException(MessageFormat.format("parent={0} - Unfinished!", parent));
1389                 }
1390
1391                 // No parent set
1392                 return "Keine";
1393         }
1394 }