]> git.mxchange.org Git - pizzaservice-war.git/blobdiff - src/java/org/mxchange/pizzaapplication/application/PizzaServiceApplication.java
Converted private constructor to public init() method with context, still this cannot...
[pizzaservice-war.git] / src / java / org / mxchange / pizzaapplication / application / PizzaServiceApplication.java
index 09b73e05bd612f87ad8473b4c1ca0d9331ade053..d8253814c2c7a000741ccc59f10bb1774ccbd29c 100644 (file)
 package org.mxchange.pizzaapplication.application;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.sql.SQLException;
 import java.text.MessageFormat;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import org.mxchange.jcore.contact.Gender;
 import org.mxchange.jcore.exceptions.BadTokenException;
+import org.mxchange.jcore.exceptions.CorruptedDatabaseFileException;
 import org.mxchange.jcore.exceptions.UnsupportedDatabaseBackendException;
 import org.mxchange.pizzaapplication.BasePizzaServiceSystem;
+import org.mxchange.pizzaapplication.category.Category;
 import org.mxchange.pizzaapplication.customer.Customer;
 import org.mxchange.pizzaapplication.customer.PizzaServiceCustomer;
+import org.mxchange.pizzaapplication.database.category.PizzaCategoryDatabaseConstants;
+import org.mxchange.pizzaapplication.database.frontend.category.CategoryFrontend;
+import org.mxchange.pizzaapplication.database.frontend.category.PizzaCategoryDatabaseFrontend;
 import org.mxchange.pizzaapplication.database.frontend.product.PizzaProductDatabaseFrontend;
 import org.mxchange.pizzaapplication.database.frontend.product.ProductFrontend;
+import org.mxchange.pizzaapplication.database.product.PizzaProductDatabaseConstants;
+import org.mxchange.pizzaapplication.exceptions.CategoryTitleAlreadyUsedException;
+import org.mxchange.pizzaapplication.exceptions.ProductTitleAlreadyUsedException;
 import org.mxchange.pizzaapplication.product.Product;
 
 /**
+ * Main application class
  *
  * @author Roland Haeder
  */
@@ -49,6 +58,16 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
         */
        public static final String MAIN_TITLE = "Pizza-Service";
 
+       /**
+        * Frontend for products
+        */
+       private ProductFrontend productFrontend;
+
+       /**
+        * Frontend for categories
+        */
+       private CategoryFrontend categoryFrontend;
+
        /**
         * Some singleton getter for this instance. If the instance is not set in
         * given application, it will be created.
@@ -74,13 +93,20 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                if (object instanceof PizzaApplication) {
                        // Instance is set, so casting should work
                        instance = (PizzaApplication) object;
+
+                       // Debug message
+                       instance.getLogger().debug(MessageFormat.format("Using existing instance {0} ...", object)); //NOI18N
                } else if (object instanceof Object) {
                        // Not correct instance
                        throw new ServletException("app is not set correctly"); //NOI18N
                } else {
                        try {
                                // "service" is null, so initialize it
-                               instance = new PizzaServiceApplication(context);
+                               instance = new PizzaServiceApplication();
+                               instance.init(context);
+
+                       // Debug message
+                       instance.getLogger().debug(MessageFormat.format("Created new instance {0} ...", object)); //NOI18N
                        } catch (final UnsupportedDatabaseBackendException | SQLException | IOException | BadTokenException ex) {
                                throw new ServletException(ex);
                        }
@@ -106,28 +132,8 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                new PizzaServiceApplication().start();
        }
 
-       /**
-        * Product list 
-        */
-       private final SortedMap<String, Product> products;
-
-       /**
-        * Private constructor
-        */
-       private PizzaServiceApplication () {
-               // Init products instance
-               this.products = new TreeMap<>();
-       }
-
-       /**
-        * Constructor with servet configuration
-        *
-        * @param context Servlet context
-        */
-       private PizzaServiceApplication (final ServletContext context) throws UnsupportedDatabaseBackendException, SQLException, IOException, BadTokenException {
-               // Call other constructor first
-               this();
-
+       @Override
+       public void init (final ServletContext context) throws UnsupportedDatabaseBackendException, SQLException, IOException, BadTokenException {
                // Temporary initialize default bundle
                // @TODO The JSF may have better internatialization support
                this.initBundle();
@@ -135,8 +141,14 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                // Initialize properties from config
                this.initProperties(context);
 
-               // Load available products
-               this.fillProductsList();
+               // Init database frontends
+               this.initDatabaseFrontends();
+       }
+
+       /**
+        * Default constructor
+        */
+       private PizzaServiceApplication () {
        }
 
        /**
@@ -147,7 +159,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
         * @return Total amount of all choosen products
         */
        @Override
-       public int calculateTotalAmount (final HttpServletRequest request, final HttpSession session) {
+       public int calculateTotalAmount (final HttpServletRequest request, final HttpSession session) throws ServletException {
                // Trace message
                this.getLogger().trace(MessageFormat.format("request={0},session={1} - CALLED!", request, session)); //NOI18N
 
@@ -160,15 +172,19 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                        throw new NullPointerException("session is null"); //NOI18N
                }
 
-               // Init total price
+               // Init/declare total price and iterator
                int totalAmount = 0;
+               Iterator<Product> iterator = this.getAvailableProducts();
 
                // "Walk" over all products
-               for (final Product product : this.getProducts()) {
+               while (iterator.hasNext()) {
+                       // Get next product
+                       Product product = iterator.next();
+
                        // Is this choosen?
                        if (this.isProductChoosen(product, request, session)) {
                                // Then add ordered amount
-                               this.getLogger().debug(MessageFormat.format("Counting {0} ...", product.getName())); //NOI18N
+                               this.getLogger().debug(MessageFormat.format("Counting {0} ...", product.getId())); //NOI18N
 
                                // Getting amount
                                String amount = this.getAmountFromSession(product, session);
@@ -177,7 +193,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                                this.getLogger().debug(MessageFormat.format("amount={0}", amount)); //NOI18N
                                totalAmount += Integer.valueOf(amount);
                        }
-                       this.getLogger().debug(MessageFormat.format("product={0},totalAmount={1}", product.getName(), totalAmount)); //NOI18N
+                       this.getLogger().debug(MessageFormat.format("product={0},totalAmount={1}", product.getId(), totalAmount)); //NOI18N
                }
 
                // Trace message
@@ -195,7 +211,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
         * @return Total price of all choosen products
         */
        @Override
-       public float calculateTotalPrice (final HttpServletRequest request, final HttpSession session) {
+       public float calculateTotalPrice (final HttpServletRequest request, final HttpSession session) throws ServletException {
                // Trace message
                this.getLogger().trace(MessageFormat.format("request={0},session={1} - CALLED!", request, session)); //NOI18N
 
@@ -211,15 +227,21 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                // Init total price
                float totalPrice = 0.00f;
 
+               // Get iterator
+               Iterator<Product> iterator = this.getAvailableProducts();
+
                // "Walk" over all products
-               for (final Product product : this.getProducts()) {
+               while (iterator.hasNext()) {
+                       // Get next product
+                       Product product = iterator.next();
+
                        // Is this choosen?
                        if (this.isProductChoosen(product, request, session)) {
                                // Then add product's total price
-                               this.getLogger().debug(MessageFormat.format("Calling getTotalPositionPriceFromRequestSession({0},request,session) ...", product.getName())); //NOI18N
+                               this.getLogger().debug(MessageFormat.format("Calling getTotalPositionPriceFromRequestSession({0},request,session) ...", product.getId())); //NOI18N
                                totalPrice += this.getTotalPositionPriceFromRequestSession(product, request, session);
                        }
-                       this.getLogger().debug(MessageFormat.format("product={0},totalPrice={1}", product.getName(), totalPrice)); //NOI18N
+                       this.getLogger().debug(MessageFormat.format("product={0},totalPrice={1}", product.getId(), totalPrice)); //NOI18N
                }
 
                // Trace message
@@ -231,17 +253,17 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
 
        @Override
        public void doBootstrap () {
-               throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+               throw new UnsupportedOperationException("Not supported yet."); //NOI18N
        }
 
        @Override
        public void doMainLoop () {
-               throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+               throw new UnsupportedOperationException("Not supported yet."); //NOI18N
        }
 
        @Override
        public void doShutdown () {
-               throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+               throw new UnsupportedOperationException("Not supported yet."); //NOI18N
        }
 
        /**
@@ -347,12 +369,12 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Get attribute
-               Object object = this.getValueFromSession(product, session, HTTP_PARAM_CHOOSE);
+               Object object = this.getValueFromSession(product, session, HTTP_PARAM_ITEM_ID);
 
                // Is the object null?
                if (object == null) {
                        // Not found
-                       this.getLogger().debug(MessageFormat.format("Returning empty string for product={0} ...", product.getName())); //NOI18N
+                       this.getLogger().debug(MessageFormat.format("Returning empty string for product={0} ...", product.getId())); //NOI18N
                        return ""; //NOI18N
                }
 
@@ -371,7 +393,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
         * @return Whether the product is choosen
         */
        @Override
-       public String getDisabledHtmlFromSession (final HttpServletRequest request, final HttpSession session) {
+       public String getDisabledHtmlFromSession (final HttpServletRequest request, final HttpSession session) throws ServletException {
                // Trace message
                this.getLogger().trace(MessageFormat.format("request={0},session={1} - CALLED!", request, session)); //NOI18N
 
@@ -384,8 +406,14 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                        throw new NullPointerException("session is null"); //NOI18N
                }
 
+               // Get "enabled" from request scope
+               Boolean enabled = Boolean.parseBoolean((String) request.getAttribute("enabled")); //NOI18N
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("enabled={0}", enabled)); //NOI18N
+
                // Is something selected?
-               if (this.calculateTotalAmount(request, session) > 0) {
+               if ((enabled) || (this.calculateTotalAmount(request, session) > 0)) {
                        // Trace message
                        this.getLogger().trace("Returning empty string - EXIT!"); //NOI18N
 
@@ -426,9 +454,9 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Get element
-               this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getName(), request, session)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getId(), request, session)); //NOI18N
                String choosen = this.handleChooseFromRequestSession(product, request, session);
-               this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getName(), choosen)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getId(), choosen)); //NOI18N
 
                // Must not be null
                assert(choosen instanceof String): "choosen is null"; //NOI18N
@@ -441,7 +469,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
 
                // Get amount
                String amount = this.handleAmountFromRequestSession(product, request, session);
-               this.getLogger().debug(MessageFormat.format("product={0},amount={1}", product.getName(), amount)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("product={0},amount={1}", product.getId(), amount)); //NOI18N
 
                // Must not be null
                assert(amount instanceof String): "amount is null"; //NOI18N
@@ -456,6 +484,34 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
        }
 
+       /**
+        * Checks if given Product instance is available and returns a printable
+        * (human-readable) string.
+        * 
+        * @param product Product instance to check
+        * @return Human-readable version of product availability
+        */
+       @Override
+       public String getPrintableProduktAvailability (final Product product) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("product={0} - CALLED!", product)); //NOI18N
+
+               // Is it null?
+               if (product == null) {
+                       // Should not be null
+                       throw new NullPointerException("product is null"); //NOI18N
+               }
+
+               // Get availability
+               if (product.getAvailable() == true) {
+                       // Is available
+                       return "Ja";
+               } else {
+                       // Not, not for public
+                       return "Nein";
+               }
+       }
+
        /**
         * Some getter for printable value from session or an empty string for null.
         *
@@ -490,14 +546,49 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                return this.convertNullToEmpty(value);
        }
 
+       /**
+        * Some "getter" for a an array of only available products
+        *
+        * @return All products
+        */
+       @Override
+       public Iterator<Product> getAvailableProducts () throws ServletException {
+               try {
+                       // Ask frontend for a list of products
+                       return this.productFrontend.getAvailableProducts();
+               } catch (final IOException | BadTokenException | SQLException | CorruptedDatabaseFileException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+                       throw new ServletException(ex);
+               }
+       }
+
        /**
         * Some "getter" for a an array of all products
         *
-        * @return Unmarked products
+        * @return All products
+        */
+       @Override
+       public Iterator<Product> getAllProducts () throws ServletException {
+               try {
+                       // Ask frontend for a list of products
+                       return this.productFrontend.getAllProducts();
+               } catch (final IOException | BadTokenException | SQLException | CorruptedDatabaseFileException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+                       throw new ServletException(ex);
+               }
+       }
+
+       /**
+        * Some "getter" for a an array of all categories
+        *
+        * @return All categories
         */
        @Override
-       public Product[] getProducts () {
-               return this.products.values().toArray(new Product[this.products.size()]);
+       public Iterator<Category> getCategories () throws ServletException {
+               try {
+                       // Ask frontend for a list of categories
+                       return this.categoryFrontend.getCategories();
+               } catch (final IOException | BadTokenException | SQLException | CorruptedDatabaseFileException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+                       throw new ServletException(ex);
+               }
        }
 
        /**
@@ -527,9 +618,9 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Get choosen
-               this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getName(), request, session)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getId(), request, session)); //NOI18N
                String choosen = this.handleChooseFromRequestSession(product, request, session);
-               this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getName(), choosen)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getId(), choosen)); //NOI18N
 
                // Must not be null
                assert(choosen instanceof String): "choosen is null"; //NOI18N
@@ -537,13 +628,13 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                // Is it set?
                if (choosen.isEmpty()) {
                        // Is empty
-                       this.getLogger().debug(MessageFormat.format("product={0},choosen={1} - returning zero ...", product.getName(), choosen)); //NOI18N
+                       this.getLogger().debug(MessageFormat.format("product={0},choosen={1} - returning zero ...", product.getId(), choosen)); //NOI18N
                        return 0.00f;
                }
 
                // Get amount
                String amount = this.handleAmountFromRequestSession(product, request, session);
-               this.getLogger().debug(MessageFormat.format("product={0},amount={1}", product.getName(), amount)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("product={0},amount={1}", product.getId(), amount)); //NOI18N
 
                // Must not be null
                assert(amount instanceof String): "amount is null"; //NOI18N
@@ -551,7 +642,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                // Is it empty?
                if (amount.isEmpty() || "0".equals(amount)) { //NOI18N
                        // Is empty
-                       this.getLogger().debug(MessageFormat.format("product={0},amount={1} - returning zero ...", product.getName(), amount)); //NOI18N
+                       this.getLogger().debug(MessageFormat.format("product={0},amount={1} - returning zero ...", product.getId(), amount)); //NOI18N
                        return 0.00f;
                }
 
@@ -571,32 +662,12 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                float price = (product.getPrice() * value);
 
                // Trace message
-               this.getLogger().trace(MessageFormat.format("product={0},price={1} - EXIT!", product.getName(), price)); //NOI18N
+               this.getLogger().trace(MessageFormat.format("product={0},price={1} - EXIT!", product.getId(), price)); //NOI18N
 
                // Then multiply it with price
                return price;
        }
 
-       /**
-        * Gets an array of products from product iterator and unmarks them as ordered
-        *
-        * @param session HttpSession instance
-        * @return Unmarked products
-        */
-       @Override
-       public Product[] getUnmarkedProducts (final HttpSession session) {
-               // Init array
-               Product[] array = this.getProducts();
-
-               // Unmark are all as ordered
-               for (final Product product : array) {
-                       this.unmarkProductAsOrdered(product, session);
-               }
-
-               // Return finished array
-               return array;
-       }
-
        /**
         * Handler for amount from request or session
         *
@@ -632,12 +703,12 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                } else if (this.handleChooseFromRequestSession(product, request, session).isEmpty()) {
                        // Not choosen
                        this.clearSessionAttribute(product, session, HTTP_PARAM_AMOUNT);
-                       this.getLogger().debug(MessageFormat.format("Unsetting for product={0} in session, returning zero ...", product.getName())); //NOI18N
+                       this.getLogger().debug(MessageFormat.format("Unsetting for product={0} in session, returning zero ...", product.getId())); //NOI18N
                        return "0"; //NOI18N
                }
 
                // Get attribute from request
-               object = request.getParameter(String.format(HTTP_PARAM_MASK, HTTP_PARAM_AMOUNT, product.getName()));
+               object = request.getParameter(String.format(HTTP_PARAM_MASK, HTTP_PARAM_AMOUNT, product.getId()));
 
                // Is it set?
                if (object instanceof String) {
@@ -690,9 +761,9 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Get choosen
-               this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getName(), request, session)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("Calling handleChooseFromRequestSession({0},{1},{2}) ...", product.getId(), request, session)); //NOI18N
                String choosen = this.handleChooseFromRequestSession(product, request, session);
-               this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getName(), choosen)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("product={0},choosen={1}", product.getId(), choosen)); //NOI18N
 
                // Must not be null
                assert(choosen instanceof String): "choosen is null"; //NOI18N
@@ -716,6 +787,39 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                return (!amount.isEmpty() && !"0".equals(amount)); //NOI18N
        }
 
+       /**
+        * Marks all choosen products as ordered
+        *
+        * @param request Request instance
+        * @param session Session instance
+        */
+       @Override
+       public void markAllChoosenProductsAsOrdered (final HttpServletRequest request, final HttpSession session) throws ServletException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("request={0},session={1} - CALLED!", request, session)); //NOI18N
+
+               // Init iterator
+               Iterator<Product> iterator = this.getAvailableProducts();
+
+               // "Walk" over all products
+               while (iterator.hasNext()) {
+                       // Get next product
+                       Product product = iterator.next();
+
+                       // Debug message
+                       this.getLogger().debug(MessageFormat.format("product={0}", product)); //NOI18N
+
+                       // Is it choosen?
+                       if (this.isProductChoosen(product, request, session)) {
+                               // Mark product as ordered
+                               this.markProductAsOrdered(product, session);
+                       }
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
        /**
         * Marks given product as choosen in session
         *
@@ -737,8 +841,8 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Mark it as ordered by setting flag
-               this.getLogger().debug(MessageFormat.format("Marking product={0} as choosen.", product.getName())); //NOI18N
-               this.setValueInSession(product, session, HTTP_PARAM_CHOOSE, "1"); //NOI18N
+               this.getLogger().debug(MessageFormat.format("Marking product={0} as choosen.", product.getId())); //NOI18N
+               this.setValueInSession(product, session, HTTP_PARAM_ITEM_ID, "1"); //NOI18N
 
                // Trace message
                this.getLogger().trace("EXIT!"); //NOI18N
@@ -765,7 +869,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Mark it as ordered by setting flag
-               this.getLogger().debug(MessageFormat.format("Marking product={0} as ordered.", product.getName())); //NOI18N
+               this.getLogger().debug(MessageFormat.format("Marking product={0} as ordered.", product.getId())); //NOI18N
                this.setValueInSession(product, session, SESSION_ORDERED, "true"); //NOI18N
 
                // Trace message
@@ -814,8 +918,8 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Mark it as ordered by setting flag
-               this.getLogger().debug(MessageFormat.format("Unmarking product={0} as choosen.", product.getName())); //NOI18N
-               this.clearSessionAttribute(product, session, HTTP_PARAM_CHOOSE);
+               this.getLogger().debug(MessageFormat.format("Unmarking product={0} as choosen.", product.getId())); //NOI18N
+               this.clearSessionAttribute(product, session, HTTP_PARAM_ITEM_ID);
 
                // Trace message
                this.getLogger().trace("EXIT!"); //NOI18N
@@ -842,41 +946,13 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Mark it as ordered by setting flag
-               this.getLogger().debug(MessageFormat.format("Unmarking product={0} as ordered.", product.getName())); //NOI18N
+               this.getLogger().debug(MessageFormat.format("Unmarking product={0} as ordered.", product.getId())); //NOI18N
                this.clearSessionAttribute(product, session, SESSION_ORDERED);
 
                // Trace message
                this.getLogger().trace("EXIT!"); //NOI18N
        }
 
-       /**
-        * Adds given product to list or throws an exception if name is already found
-        *
-        * @param product Product instance to add
-        */
-       private void addProduct (final Product product) {
-               // Trace message
-               this.getLogger().trace(MessageFormat.format("product={0} - CALLED!", product)); //NOI18N
-
-               // Get all data from it
-               String name = product.getName();
-
-               // Is the name already used?
-               if (this.isProductNameUsed(name)) {
-                       // Something went wrong
-                       throw new IllegalArgumentException(MessageFormat.format("product {0} is already used.", name)); //NOI18N
-               }
-
-               // Debug message
-               this.getLogger().debug(MessageFormat.format("Adding product={0} ...", product)); //NOI18N
-
-               // Add it
-               this.products.put(product.getName(), product);
-
-               // Trace message
-               this.getLogger().trace("EXIT!"); //NOI18N
-       }
-
        /**
         * Clears given parameter for product in session
         *
@@ -889,40 +965,13 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                this.getLogger().trace(MessageFormat.format("produce={0},parameter={1},session={2} - CALLED!", product, parameter, session)); //NOI18N
 
                // Clear in session
-               this.getLogger().debug(MessageFormat.format("Clearing product={0},parameter={1} ...", product.getName(), parameter)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("Clearing product={0},parameter={1} ...", product.getId(), parameter)); //NOI18N
                this.setValueInSession(product, session, parameter, null);
 
                // Trace message
                this.getLogger().trace("EXIT!"); //NOI18N
        }
 
-       /**
-        * Fills products list
-        * @todo Very hard-coded stuff ...
-        */
-       private void fillProductsList () throws UnsupportedDatabaseBackendException, SQLException, IOException, BadTokenException {
-               // Trace message
-               this.getLogger().trace("CALLED!"); //NOI18N
-
-               // Get a product frontend
-               ProductFrontend frontend = new PizzaProductDatabaseFrontend();
-
-               // Get iterator
-               Iterator<Product> iterator = frontend.getProducts();
-
-               // Get all products
-               while (iterator.hasNext()) {
-                       // Get it
-                       Product product = iterator.next();
-
-                       // Add it
-                       this.addProduct(product);
-               }
-
-               // Trace message
-               this.getLogger().trace("EXIT!"); //NOI18N
-       }
-
        /**
         * Some getter for value from session
         *
@@ -936,9 +985,9 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                this.getLogger().trace(MessageFormat.format("product={0},session={1},attribute={2} - CALLED!", product, session, attribute)); //NOI18N
 
                // Init variable
-               Object value = this.getValueFromSession(session, String.format(HTTP_PARAM_MASK, attribute, product.getName()));
+               Object value = this.getValueFromSession(session, String.format(HTTP_PARAM_MASK, attribute, product.getId()));
                
-               this.getLogger().debug(MessageFormat.format("product={0},attribute={1},value={2}", product.getName(), attribute, value)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("product={0},attribute={1},value={2}", product.getId(), attribute, value)); //NOI18N
 
                // Trace message
                this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value)); //NOI18N
@@ -959,7 +1008,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                this.getLogger().trace(MessageFormat.format("session={0},key={1} - CALLED!", session, key)); //NOI18N
 
                // Init value
-               Object value = null;
+               Object value;
 
                // Get it synchronized from session
                synchronized (session) {
@@ -981,7 +1030,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
         * @param session Session instance
         * @return Amount as string
         */
-       private String handleChooseFromRequestSession(final Product product, final HttpServletRequest request, final HttpSession session) {
+       private String handleChooseFromRequestSession (final Product product, final HttpServletRequest request, final HttpSession session) {
                // Trace message
                this.getLogger().trace(MessageFormat.format("product={0},request={1},session={2} - CALLED!", product, request, session)); //NOI18N
 
@@ -1003,27 +1052,27 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                // Check request method
                if (!"POST".equals(request.getMethod())) { //NOI18N
                        // Not POST, so get from session
-                       this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getName(), session));
+                       this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getId(), session)); //NOI18N
                        return this.getChooseFromSession(product, session);
                } else if (this.isProductOrdered(product, session)) {
                        // Product is ordered
-                       this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getName(), session));
+                       this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getId(), session)); //NOI18N
                        return this.getChooseFromSession(product, session);
                } else if (!this.getChooseFromSession(product, session).isEmpty()) {
                        // Found in session
-                       this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getName(), session));
+                       this.getLogger().trace(MessageFormat.format("Calling this.getChooseFromSession({0},{1}) ... - EXIT!", product.getId(), session)); //NOI18N
                        return this.getChooseFromSession(product, session);
                }
 
                // Get reqzest element
-               object = request.getParameter(String.format(HTTP_PARAM_MASK, HTTP_PARAM_CHOOSE, product.getName()));
-               this.getLogger().debug(MessageFormat.format("product={0},object={1}", product.getName(), object)); //NOI18N
+               object = request.getParameter(String.format(HTTP_PARAM_MASK, HTTP_PARAM_ITEM_ID, product.getId()));
+               this.getLogger().debug(MessageFormat.format("product={0},object={1}", product.getId(), object)); //NOI18N
 
                // Is it null?
                if (object == null) {
                        // Unset session
-                       this.getLogger().debug(MessageFormat.format("Unsetting session for product={0} ...", product.getName())); //NOI18N
-                       this.clearSessionAttribute(product, session, HTTP_PARAM_CHOOSE);
+                       this.getLogger().debug(MessageFormat.format("Unsetting session for product={0} ...", product.getId())); //NOI18N
+                       this.clearSessionAttribute(product, session, HTTP_PARAM_ITEM_ID);
                        this.clearSessionAttribute(product, session, HTTP_PARAM_AMOUNT);
 
                        // Return empty string
@@ -1031,41 +1080,59 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                }
 
                // Then set it in session
-               this.setValueInSession(product, session, HTTP_PARAM_CHOOSE, object);
+               this.setValueInSession(product, session, HTTP_PARAM_ITEM_ID, object);
 
                // Cast to string and return it
-               this.getLogger().debug(MessageFormat.format("product={0} - Returning {1} ...", product.getName(), object)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("product={0} - Returning {1} ...", product.getId(), object)); //NOI18N
                return (String) object;
        }
 
        /**
-        * Checks whether given product is already used
+        * Initializes database frontends.
+        */
+       private void initDatabaseFrontends () throws UnsupportedDatabaseBackendException, SQLException {
+               // Product frontend
+               this.productFrontend = new PizzaProductDatabaseFrontend();
+
+               // Category frontend
+               this.categoryFrontend = new PizzaCategoryDatabaseFrontend();
+       }
+
+       /**
+        * Checks whether given category title is already used
         *
-        * @param name Name of product
-        * @return Whether the given product's name is already used
+        * @param title Title of category to check
+        * @return Whether it has been found
         */
-       private boolean isProductNameUsed(final String name) {
-               // Trace message
-               this.getLogger().trace(MessageFormat.format("name={0} - CALLED!", name)); //NOI18N
+       private boolean isCategoryTitleUsed(final String title) throws IOException, SQLException, BadTokenException, CorruptedDatabaseFileException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+               // Delegate to frontend
+               return this.categoryFrontend.isCategoryTitleUsed(title);
+       }
 
-               // Is it found?
-               return this.products.containsKey(name);
+       /**
+        * Checks if given product title is already used
+        * @param title Product title to check
+        * @return Whether the product title has already been used
+        */
+       private boolean isProductTitleUsed (final String title) throws IOException, SQLException, BadTokenException, CorruptedDatabaseFileException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+               // Delegate to frontend
+               return this.productFrontend.isProductTitleUsed(title);
        }
 
        /**
         * Checks if the product ordered?
         *
-        * @param product
-        * @param session
-        * @return
+        * @param product Product instance
+        * @param session HttpSession instance
+        * @return Whether the product has been ordered
         */
-       private boolean isProductOrdered(final Product product, final HttpSession session) {
+       private boolean isProductOrdered (final Product product, final HttpSession session) {
                // Trace message
                this.getLogger().trace(MessageFormat.format("product={0},session={1} - CALLED!", product, session)); //NOI18N
 
                // Get session
                Object isOrdered = this.getValueFromSession(product, session, SESSION_ORDERED);
-               this.getLogger().debug(MessageFormat.format("product={0},isOrdered={1}", product.getName(), isOrdered)); //NOI18N
+               this.getLogger().debug(MessageFormat.format("product={0},isOrdered={1}", product.getId(), isOrdered)); //NOI18N
 
                // Return result
                return ("true".equals(isOrdered)); //NOI18N
@@ -1084,8 +1151,8 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                this.getLogger().trace(MessageFormat.format("product={0},session={1},keyPart={2},value={3} - CALLED!", product, session, keyPart, value)); //NOI18N
 
                // Set it synced
-               this.getLogger().debug(MessageFormat.format("Setting value={0} for product={1},keyPart={2}", value, product.getName(), keyPart)); //NOI18N
-               this.setValueInSession(session, String.format(HTTP_PARAM_MASK, keyPart, product.getName()), value);
+               this.getLogger().debug(MessageFormat.format("Setting value={0} for product={1},keyPart={2}", value, product.getId(), keyPart)); //NOI18N
+               this.setValueInSession(session, String.format(HTTP_PARAM_MASK, keyPart, product.getId()), value);
 
                // Trace message
                this.getLogger().trace("EXIT!"); //NOI18N
@@ -1094,7 +1161,7 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
        /**
         * Application starter
         */
-       private void start () {
+       private void start() {
                // Init bundle
                this.initBundle();
 
@@ -1102,30 +1169,43 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                        // Init properties
                        this.initProperties();
 
-                       // Fill products list
-                       this.fillProductsList();
-               } catch (final IOException | UnsupportedDatabaseBackendException | SQLException | BadTokenException ex) {
+                       // And frontends
+                       this.initDatabaseFrontends();
+               } catch (final IOException | UnsupportedDatabaseBackendException | SQLException ex) {
                        // Abort here
                        this.abortProgramWithException(ex);
                }
 
+               // Init instance
+               Iterator<Product> iterator = null;
+
+               try {
+                       // Get iterator
+                       iterator = this.getAvailableProducts();
+               } catch (final ServletException ex) {
+                       this.abortProgramWithException(ex);
+               }
+
                // "Walk" over all products
-               for (final Product product : this.getProducts()) {
+               while ((iterator instanceof Iterator) && (iterator.hasNext())) {
+                       // Get next product
+                       Product product = iterator.next();
+
                        // Output data
-                       this.getLogger().debug(MessageFormat.format("Product {0}, {1}: {2}", product.getName(), product.getTitle(), product.getPrice())); //NOI18N
+                       this.getLogger().debug(MessageFormat.format("Product {0}, {1}: {2}", product.getId(), product.getTitle(), product.getPrice())); //NOI18N
                }
 
                // Generate fake Customer instance
                Customer customer = new PizzaServiceCustomer();
 
                /*
-                * Need a least a gender ... :( See, that is why I don't like default
-                * constructors, you can easily miss something important and bam! You
-                * get an NPE. The fix here is, to have construtors (or factories) which
-                * requires all required instances that needs to be set to get a
-                * consitent object back.
-                */
-
+               * Need a least a gender ... :( See, that is why I don't like default
+               * constructors, you can easily miss something important and bam! You
+               * get an NPE. The fix here is, to have construtors (or factories) which
+               * requires all required instances that needs to be set to get a
+               * consitent object back.
+               */
+               
                // Gender is MALE now
                customer.setGender(Gender.MALE);
 
@@ -1145,4 +1225,430 @@ public class PizzaServiceApplication extends BasePizzaServiceSystem implements P
                        this.getLogger().debug(MessageFormat.format("entry {0}={1}", entry.getKey(), entry.getValue())); //NOI18N
                }
        }
+
+       /**
+        * Adds given category data from request to database
+        *
+        * @param request Request instance
+        */
+       @Override
+       public void doAdminAddCategory (final HttpServletRequest request) throws ServletException, CategoryTitleAlreadyUsedException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("request={0} - CALLED!", request)); //NOI18N
+
+               // request must not be null
+               if (request == null) {
+                       // Is null
+                       throw new NullPointerException("request is null"); //NOI18N
+               }
+
+               // Get all fields
+               String title = request.getParameter(PizzaCategoryDatabaseConstants.COLUMN_TITLE);
+               String parent = request.getParameter(PizzaCategoryDatabaseConstants.COLUMN_PARENT);
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("title={0},parent={1}", title, parent)); //NOI18N
+
+               // Init variables for casting
+               Integer id = 0;
+
+               // Check all fields
+               if (title == null) {
+                       // "title" not set
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaCategoryDatabaseConstants.COLUMN_TITLE)); //NOI18N
+               } else if (title.isEmpty()) {
+                       // Is left empty
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaCategoryDatabaseConstants.COLUMN_TITLE)); //NOI18N
+               } else if ((parent != null) && (!parent.isEmpty())) {
+                       // "parent" is set, so check it
+                       try {
+                               id = Integer.parseInt(parent);
+                       } catch (final NumberFormatException e) {
+                               // Not valid number
+                               throw new IllegalArgumentException(e);
+                       }
+               }
+
+               try {
+                       // Try to check if title is used already
+                       if (this.isCategoryTitleUsed(title)) {
+                               // Title already used
+                               throw new CategoryTitleAlreadyUsedException(request);
+                       }
+               } catch (final IOException | SQLException | BadTokenException | CorruptedDatabaseFileException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+                       throw new ServletException(ex);
+               }
+
+               try {
+                       // The category is not found, so add it to database
+                       this.categoryFrontend.addCategory(title, id);
+               } catch (final SQLException | IOException ex) {
+                       // Continue to throw it
+                       throw new ServletException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Adds given product data from request to database
+        *
+        * @param request Request instance
+        */
+       @Override
+       public void doAdminAddProduct (final HttpServletRequest request) throws ServletException, ProductTitleAlreadyUsedException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("request={0} - CALLED!", request)); //NOI18N
+
+               // request must not be null
+               if (request == null) {
+                       // Is null
+                       throw new NullPointerException("request is null"); //NOI18N
+               }
+
+               // Get title, price and category id
+               String title = request.getParameter(PizzaProductDatabaseConstants.COLUMN_TITLE);
+               String price = request.getParameter(PizzaProductDatabaseConstants.COLUMN_PRICE);
+               String category = request.getParameter(PizzaProductDatabaseConstants.COLUMN_CATEGORY);
+               String available = request.getParameter(PizzaProductDatabaseConstants.COLUMN_AVAILABLE);
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("title={0},price={1},category={2},available={3}", title, price, category, available)); //NOI18N
+
+               // Variables for converting
+               Long id = null;
+               Float p = null;
+
+               // Check all fields
+               if (title == null) {
+                       // "title" not set
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_TITLE)); //NOI18N
+               } else if (title.isEmpty()) {
+                       // Is left empty
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_TITLE)); //NOI18N
+               } else if (price == null) {
+                       // "price" not set
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_PRICE)); //NOI18N
+               } else if (price.isEmpty()) {
+                       // Is left empty
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_PRICE)); //NOI18N
+               } else if (category == null) {
+                       // "title" not set
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_CATEGORY)); //NOI18N
+               } else if (category.isEmpty()) {
+                       // Is left empty
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_CATEGORY)); //NOI18N
+               } else if (available == null) {
+                       // "title" not set
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_AVAILABLE)); //NOI18N
+               } else if (available.isEmpty()) {
+                       // Is left empty
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_AVAILABLE)); //NOI18N
+               } else if ((!"true".equals(available)) && (!"false".equals(available))) { //NOI18N
+                       // Invalid value
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is invalid: {1}", PizzaProductDatabaseConstants.COLUMN_AVAILABLE, available)); //NOI18N
+               }
+
+               // Parse numbers
+               try {
+                       id = Long.parseLong(category);
+                       p = Float.parseFloat(price);
+               } catch (final NumberFormatException e) {
+                       // Not valid number
+                       throw new IllegalArgumentException(e);
+               }
+
+               // Parse boolean
+               Boolean a = Boolean.parseBoolean(available);
+
+               // Test on product title
+               try {
+                       // Try to check if title is used already
+                       if (this.isProductTitleUsed(title)) {
+                               // Title already used
+                               throw new ProductTitleAlreadyUsedException(request);
+                       }
+               } catch (final IOException | SQLException | BadTokenException | CorruptedDatabaseFileException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+                       throw new ServletException(ex);
+               }
+
+               try {
+                       // The product is not found, so add it to database
+                       this.productFrontend.addProduct(title, p, id, a);
+               } catch (final SQLException | IOException ex) {
+                       // Continue to throw it
+                       throw new ServletException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Generates link HTML code for given category's parent id, if set. This
+        * link then points to products.jsp?category_id=x
+        *
+        * @param category Category instance
+        * @return HTML code
+        */
+       @Override
+       public String generateLinkForParent (final Category category) {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("category={0} - CALLED!", category)); //NOI18N
+
+               // category must not be null
+               if (category == null) {
+                       // Is null
+                       throw new NullPointerException("category is null"); //NOI18N
+               }
+
+               // Get parent id
+               Long parent = category.getParent();
+
+               // Is the id set?
+               if (parent > 0) {
+                       // Product HTML code for link
+                       throw new UnsupportedOperationException(MessageFormat.format("parent={0} - Unfinished!", parent)); //NOI18N
+               }
+
+               // No parent set
+               return "Keine";
+       }
+
+       @Override
+       public String getPrintableProduktCategory (final Product product) throws ServletException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("product={0} - CALLED!", product)); //NOI18N
+
+               // product must not be null
+               if (product == null) {
+                       // Abort here
+                       throw new NullPointerException("product is null"); //NOI18N
+               }
+
+               // Declare category
+               Category category;
+
+               try {
+                       // Get Category instance from product over the frontend
+                       category = this.categoryFrontend.getCategory(product);
+               } catch (final IOException | SQLException | BadTokenException | CorruptedDatabaseFileException | NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+                       throw new ServletException(ex);
+               }
+
+               // Debug message
+               this.getLogger().debug(MessageFormat.format("category={0}", category)); //NOI18N
+
+               String title = null;
+               try {
+                       // Now get title from it and return it
+                       title = category.decodedTitle();
+               } catch (final UnsupportedEncodingException ex) {
+                       // Continue to throw as cause
+                       throw new ServletException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("title={0} - EXIT!", title)); //NOI18N
+
+               // Return it
+               return title;
+       }
+
+       /**
+        * Checks if product's title is already used.
+        * 
+        * @param request Request instance
+        * @return Whether the product title is already used
+        * @throws java.io.IOException If any IO error occurs
+        * @throws org.mxchange.jcore.exceptions.BadTokenException If a bad token was found in a file-based database backend's file ... ;-)
+        * @throws java.sql.SQLException If any SQL error occurs
+        * @throws org.mxchange.jcore.exceptions.CorruptedDatabaseFileException If the database file is damaged
+        * @throws java.lang.NoSuchMethodException If a method was not found
+        * @throws java.lang.IllegalAccessException If the method cannot be accessed
+        * @throws java.lang.reflect.InvocationTargetException Any other problems?
+        */
+       private boolean isProductTitleUsed (final HttpServletRequest request) throws IOException, SQLException, BadTokenException, CorruptedDatabaseFileException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("request={0} - CALLED!", request)); //NOI18N
+
+               // Init title
+               String title = request.getParameter(PizzaProductDatabaseConstants.COLUMN_TITLE);
+
+               // request must not be null and "title" must be found and non-empty
+               if (request == null) {
+                       // Abort here
+                       throw new NullPointerException("request is null"); //NOI18N
+               } else if (title == null) {
+                       // title is not set
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaProductDatabaseConstants.COLUMN_TITLE)); //NOI18N
+               } else if (title.isEmpty()) {
+                       // Is left empty
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaProductDatabaseConstants.COLUMN_TITLE)); //NOI18N
+               }
+
+               // Default is not used
+               boolean isUsed = this.isProductTitleUsed(title);
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("isUsed={0} - EXIT!", isUsed)); //NOI18N
+
+               // Return it
+               return isUsed;
+       }
+
+       /**
+        * Handles admin form requests
+        * @param request Request instance
+        * @param response Response instance
+        * @throws ServletException If something unexpected happened
+        */
+       @Override
+       public void doAdminHandleProductForms (final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("request={0},response={1} - CALLED!", request, response)); //NOI18N
+
+               // request and response must both be set
+               if (request == null) {
+                       // request is null
+                       throw new NullPointerException("request is null"); //NOI18N
+               } else if (response == null) {
+                       // response is null
+                       throw new NullPointerException("response is null"); //NOI18N
+               }
+
+               // Try this operations
+               try {
+                       // Is it post?
+                       if ("POST".equals(request.getMethod())) { //NOI18N
+                               // Is "add/edit/delete" set?
+                               if (request.getParameter("add") != null) { //NOI18N
+                                       // Is it already added?
+                                       if (this.isProductTitleUsed(request)) {
+                                               // Debug message
+                                               this.getLogger().debug("Already used, redirecting ..."); //NOI18N
+
+                                               // Already added, so redirect here, else a ServletException will be thrown
+                                               response.sendRedirect(String.format("%s/admin/product.jsp?already=1", request.getContextPath())); //NOI18N
+                                       } else {
+                                               // Add new product
+                                               this.doAdminAddProduct(request);
+                                       }
+                               } else if (request.getParameter("edit") != null) { //NOI18N
+                                       // @TODO
+                               } else if (request.getParameter("delete") != null) { //NOI18N
+                                       // @TODO
+                               }
+
+                               // Redirect to proper URL
+                               // @TODO Commented out for developing:
+                               //response.sendRedirect(request.getContextPath() + "/finished.jsp");
+                       }
+               } catch (final IOException | SQLException | BadTokenException | CorruptedDatabaseFileException | ProductTitleAlreadyUsedException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) {
+                       // Throw it as cause
+                       throw new ServletException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Handles admin form requests
+        * @param request Request instance
+        * @param response Response instance
+        * @throws ServletException If something unexpected happened
+        */
+       @Override
+       public void doAdminHandleCategoryForms (final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("request={0},response={1} - CALLED!", request, response)); //NOI18N
+
+               // request and response must both be set
+               if (request == null) {
+                       // request is null
+                       throw new NullPointerException("request is null"); //NOI18N
+               } else if (response == null) {
+                       // response is null
+                       throw new NullPointerException("response is null"); //NOI18N
+               }
+
+               // Try this operations
+               try {
+                       // Is it post?
+                       if ("POST".equals(request.getMethod())) { //NOI18N
+                               // Is "add/edit/delete" set?
+                               if (request.getParameter("add") != null) { //NOI18N
+                                       // Is the category title already used?
+                                       if (this.isCategoryTitleUsed(request)) {
+                                               // Debug message
+                                               this.getLogger().debug("Already used, redirecting ..."); //NOI18N
+
+                                               // Already added, so redirect here, else a ServletException will be thrown
+                                               response.sendRedirect(String.format("%s/admin/category.jsp?already=1", request.getContextPath())); //NOI18N
+                                       } else {
+                                               // Add new category
+                                               this.doAdminAddCategory(request);
+                                       }
+                               } else if (request.getParameter("edit") != null) { //NOI18N
+                                       // @TODO
+                               } else if (request.getParameter("delete") != null) { //NOI18N
+                                       // @TODO
+                               }
+
+                               // Redirect to proper URL
+                               // @TODO Commented out for developing:
+                               //response.sendRedirect(request.getContextPath() + "/finished.jsp");
+                       }
+               } catch (final IOException | SQLException | BadTokenException | CorruptedDatabaseFileException | CategoryTitleAlreadyUsedException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) {
+                       // Throw it as cause
+                       throw new ServletException(ex);
+               }
+
+               // Trace message
+               this.getLogger().trace("EXIT!"); //NOI18N
+       }
+
+       /**
+        * Checks if category's title is already used.
+        * 
+        * @param request Request instance
+        * @return Whether the product title is already used
+        * @throws java.io.IOException If any IO error occurs
+        * @throws org.mxchange.jcore.exceptions.BadTokenException If a bad token was found in a file-based database backend's file ... ;-)
+        * @throws java.sql.SQLException If any SQL error occurs
+        * @throws org.mxchange.jcore.exceptions.CorruptedDatabaseFileException If the database file is damaged
+        * @throws java.lang.NoSuchMethodException If a method was not found
+        * @throws java.lang.IllegalAccessException If the method cannot be accessed
+        * @throws java.lang.reflect.InvocationTargetException Any other problems?
+        */
+       private boolean isCategoryTitleUsed (final HttpServletRequest request) throws IOException, SQLException, BadTokenException, CorruptedDatabaseFileException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("request={0} - CALLED!", request)); //NOI18N
+
+               // Init title
+               String title = request.getParameter(PizzaCategoryDatabaseConstants.COLUMN_TITLE);
+
+               // request must not be null and "title" must be found and non-empty
+               if (request == null) {
+                       // Abort here
+                       throw new NullPointerException("request is null"); //NOI18N
+               } else if (title == null) {
+                       // title is not set
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is not set.", PizzaCategoryDatabaseConstants.COLUMN_TITLE)); //NOI18N
+               } else if (title.isEmpty()) {
+                       // Is left empty
+                       throw new IllegalArgumentException(MessageFormat.format("{0} is empty.", PizzaCategoryDatabaseConstants.COLUMN_TITLE)); //NOI18N
+               }
+
+               // Default is not used
+               boolean isUsed = this.isCategoryTitleUsed(title);
+
+               // Trace message
+               this.getLogger().trace(MessageFormat.format("isUsed={0} - EXIT!", isUsed)); //NOI18N
+
+               // Return it
+               return isUsed;
+       }
 }