]> git.mxchange.org Git - jfinancials-war.git/commitdiff
Maybe cherry-pick:
authorRoland Häder <roland@mxchange.org>
Tue, 31 Oct 2017 19:04:59 +0000 (20:04 +0100)
committerRoland Häder <roland@mxchange.org>
Tue, 31 Oct 2017 19:06:04 +0000 (20:06 +0100)
- renamed "category" path -> "product_category"
- renamed "product" path -> "generic_product"

Signed-off-by: Roland Häder <roland@mxchange.org>
29 files changed:
src/java/org/mxchange/jfinancials/beans/category/FinancialAdminCategoryWebRequestBean.java [deleted file]
src/java/org/mxchange/jfinancials/beans/category/FinancialAdminCategoryWebRequestController.java [deleted file]
src/java/org/mxchange/jfinancials/beans/category/FinancialCategoryWebRequestBean.java [deleted file]
src/java/org/mxchange/jfinancials/beans/category/FinancialCategoryWebRequestController.java [deleted file]
src/java/org/mxchange/jfinancials/beans/generic_product/FinancialAdminProductWebRequestBean.java [new file with mode: 0644]
src/java/org/mxchange/jfinancials/beans/generic_product/FinancialAdminProductWebRequestController.java [new file with mode: 0644]
src/java/org/mxchange/jfinancials/beans/generic_product/FinancialProductWebRequestBean.java [new file with mode: 0644]
src/java/org/mxchange/jfinancials/beans/generic_product/FinancialProductWebRequestController.java [new file with mode: 0644]
src/java/org/mxchange/jfinancials/beans/product/FinancialAdminProductWebRequestBean.java [deleted file]
src/java/org/mxchange/jfinancials/beans/product/FinancialAdminProductWebRequestController.java [deleted file]
src/java/org/mxchange/jfinancials/beans/product/FinancialProductWebRequestBean.java [deleted file]
src/java/org/mxchange/jfinancials/beans/product/FinancialProductWebRequestController.java [deleted file]
src/java/org/mxchange/jfinancials/beans/product_category/FinancialAdminCategoryWebRequestBean.java [new file with mode: 0644]
src/java/org/mxchange/jfinancials/beans/product_category/FinancialAdminCategoryWebRequestController.java [new file with mode: 0644]
src/java/org/mxchange/jfinancials/beans/product_category/FinancialCategoryWebRequestBean.java [new file with mode: 0644]
src/java/org/mxchange/jfinancials/beans/product_category/FinancialCategoryWebRequestController.java [new file with mode: 0644]
src/java/org/mxchange/jfinancials/converter/generic_product/FinancialsGenericProductConverter.java
src/java/org/mxchange/jfinancials/converter/product_category/FinancialsProductCategoryConverter.java
web/WEB-INF/faces-config.xml
web/WEB-INF/product-links.jsf.taglib.xml
web/WEB-INF/product.jsf.taglib.xml
web/WEB-INF/templates/admin/category/admin_form_category_data.tpl [deleted file]
web/WEB-INF/templates/admin/generic_product/admin_form_product_data.tpl [new file with mode: 0644]
web/WEB-INF/templates/admin/product/admin_form_product_data.tpl [deleted file]
web/WEB-INF/templates/admin/product_category/admin_form_category_data.tpl [new file with mode: 0644]
web/admin/category/admin_product_category_list.xhtml [deleted file]
web/admin/generic_product/admin_generic_product_list.xhtml [new file with mode: 0644]
web/admin/product/admin_generic_product_list.xhtml [deleted file]
web/admin/product_category/admin_product_category_list.xhtml [new file with mode: 0644]

diff --git a/src/java/org/mxchange/jfinancials/beans/category/FinancialAdminCategoryWebRequestBean.java b/src/java/org/mxchange/jfinancials/beans/category/FinancialAdminCategoryWebRequestBean.java
deleted file mode 100644 (file)
index 1764c64..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2016, 2017 Roland Häder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package org.mxchange.jfinancials.beans.category;
-
-import javax.ejb.EJB;
-import javax.enterprise.context.RequestScoped;
-import javax.enterprise.event.Event;
-import javax.enterprise.inject.Any;
-import javax.faces.view.facelets.FaceletException;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.mxchange.jfinancials.beans.BaseFinancialsBean;
-import org.mxchange.jproduct.events.category.AddedCategoryEvent;
-import org.mxchange.jproduct.events.category.CategoryAddedEvent;
-import org.mxchange.jproduct.exceptions.category.CategoryAlreadyAddedException;
-import org.mxchange.jproduct.model.category.AdminCategorySessionBeanRemote;
-import org.mxchange.jproduct.model.category.Category;
-import org.mxchange.jproduct.model.category.ProductCategory;
-
-/**
- * Main application class
- * <p>
- * @author Roland Häder<roland@mxchange.org>
- */
-@Named ("adminCategoryController")
-@RequestScoped
-public class FinancialAdminCategoryWebRequestBean extends BaseFinancialsBean implements FinancialAdminCategoryWebRequestController {
-
-       /**
-        * Serial number
-        */
-       private static final long serialVersionUID = 5_819_375_183_472_871L;
-
-       /**
-        * Event for added shop categories
-        */
-       @Inject
-       @Any
-       private Event<AddedCategoryEvent> categoryAddedEvent;
-
-       /**
-        * Remote bean for categories
-        */
-       @EJB (lookup = "java:global/jfinancials-ejb/adminCategory!org.mxchange.jproduct.model.category.AdminCategorySessionBeanRemote")
-       private AdminCategorySessionBeanRemote categoryBean;
-
-       /**
-        * Whether this category is shown in statistics
-        */
-       private Boolean categoryShownInStatistics;
-
-       /**
-        * Category categoryI18nKey
-        */
-       private String categoryI18nKey;
-
-       /**
-        * Parent category
-        */
-       private Category parentCategory;
-
-       /**
-        * Default constructor
-        */
-       public FinancialAdminCategoryWebRequestBean () {
-               // Call super constructor
-               super();
-       }
-
-       /**
-        * Adds given category data from request to database
-        * <p>
-        * @throws javax.faces.view.facelets.FaceletException If something
-        * unexpected happened
-        */
-       public void addCategory () throws FaceletException {
-               // Create category
-               final Category category = this.createCategoryInstance();
-
-               // Declare updated category instance
-               final Category updatedCategory;
-
-               try {
-                       // Deligate to remote bean
-                       updatedCategory = this.categoryBean.addProductCategory(category);
-               } catch (final CategoryAlreadyAddedException ex) {
-                       // Continue to throw
-                       throw new FaceletException(ex);
-               }
-
-               // Fire event
-               this.categoryAddedEvent.fire(new CategoryAddedEvent(updatedCategory));
-
-               // Unset all older values
-               this.clear();
-       }
-
-       /**
-        * Getter for whether category is shown in statistics
-        * <p>
-        * @return Whether category is shown in statistics
-        */
-       public Boolean getCategoryShownInStatistics () {
-               return this.categoryShownInStatistics;
-       }
-
-       /**
-        * Setter for whether category is shown in statistics
-        * <p>
-        * @param categoryShownInStatistics Whether category is shown in statistics
-        */
-       public void setCategoryShownInStatistics (final Boolean categoryShownInStatistics) {
-               this.categoryShownInStatistics = categoryShownInStatistics;
-       }
-
-       /**
-        * Getter for category i18n key
-        * <p>
-        * @return Category i18n key
-        */
-       public String getCategoryI18nKey () {
-               return this.categoryI18nKey;
-       }
-
-       /**
-        * Setter for category i18n key
-        * <p>
-        * @param categoryI18nKey Category i18n key
-        */
-       public void setCategoryI18nKey (final String categoryI18nKey) {
-               this.categoryI18nKey = categoryI18nKey;
-       }
-
-       /**
-        * Getter for parent id
-        * <p>
-        * @return Parent id
-        */
-       public Category getParentCategory () {
-               return this.parentCategory;
-       }
-
-       /**
-        * Setter for parent category
-        * <p>
-        * @param parentCategory Parent category to set
-        */
-       public void setParentCategory (final Category parentCategory) {
-               this.parentCategory = parentCategory;
-       }
-
-       /**
-        * Clears this bean (example: when category has been added)
-        */
-       private void clear () {
-               // Clear all fields
-               this.setCategoryI18nKey(null);
-               this.setParentCategory(null);
-       }
-
-       /**
-        * Creates a category instance with all fields (except primary key)
-        * <p>
-        * @return Category instance
-        */
-       private Category createCategoryInstance () {
-               // Create category
-               final Category category = new ProductCategory(this.getCategoryI18nKey(), this.getParentCategory(), this.getCategoryShownInStatistics());
-
-               // Return it
-               return category;
-       }
-
-}
diff --git a/src/java/org/mxchange/jfinancials/beans/category/FinancialAdminCategoryWebRequestController.java b/src/java/org/mxchange/jfinancials/beans/category/FinancialAdminCategoryWebRequestController.java
deleted file mode 100644 (file)
index 6a292c2..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016, 2017 Roland Häder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package org.mxchange.jfinancials.beans.category;
-
-import java.io.Serializable;
-
-/**
- * An interface for product controllers for "ADMIN" role
- * <p>
- * @author Roland Häder<roland@mxchange.org>
- */
-public interface FinancialAdminCategoryWebRequestController extends Serializable {
-
-}
diff --git a/src/java/org/mxchange/jfinancials/beans/category/FinancialCategoryWebRequestBean.java b/src/java/org/mxchange/jfinancials/beans/category/FinancialCategoryWebRequestBean.java
deleted file mode 100644 (file)
index e45879a..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2016, 2017 Roland Häder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package org.mxchange.jfinancials.beans.category;
-
-import fish.payara.cdi.jsr107.impl.NamedCache;
-import java.text.MessageFormat;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import javax.annotation.PostConstruct;
-import javax.cache.Cache;
-import javax.ejb.EJB;
-import javax.enterprise.context.RequestScoped;
-import javax.enterprise.event.Observes;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.mxchange.jfinancials.beans.BaseFinancialsBean;
-import org.mxchange.jproduct.events.category.AddedCategoryEvent;
-import org.mxchange.jproduct.exceptions.category.CategoryNotFoundException;
-import org.mxchange.jproduct.model.category.Category;
-import org.mxchange.jproduct.model.category.CategorySessionBeanRemote;
-
-/**
- * General (product) category controller
- * <p>
- * @author Roland Häder<roland@mxchange.org>
- */
-@Named ("categoryController")
-@RequestScoped
-public class FinancialCategoryWebRequestBean extends BaseFinancialsBean implements FinancialCategoryWebRequestController {
-
-       /**
-        * Serial number
-        */
-       private static final long serialVersionUID = 58_137_539_530_279L;
-
-       /**
-        * List of all categories
-        */
-       private final List<Category> allCategories;
-
-       /**
-        * EJB for general category stuff
-        */
-       @EJB (lookup = "java:global/jfinancials-ejb/category!org.mxchange.jproduct.model.category.CategorySessionBeanRemote")
-       private CategorySessionBeanRemote categoryBean;
-
-       /**
-        * Cache for all product categories
-        */
-       @Inject
-       @NamedCache (cacheName = "categoryCache")
-       private Cache<Long, Category> categoryCache;
-
-       /**
-        * A list of filtered categories
-        */
-       private List<Category> filteredCategories;
-
-       /**
-        * Default constructor
-        */
-       public FinancialCategoryWebRequestBean () {
-               // Call super constructor
-               super();
-
-               // Init list
-               this.allCategories = new LinkedList<>();
-       }
-
-       /**
-        * Observes events fired after a new product category has been added
-        * <p>
-        * @param event Event to be observed
-        */
-       public void afterShopCategoryAdded (@Observes final AddedCategoryEvent event) {
-               // Is all valid?
-               if (null == event) {
-                       // Throw NPE
-                       throw new NullPointerException("event is null"); //NOI18N
-               } else if (event.getAddedCategory() == null) {
-                       // Throw again ...
-                       throw new NullPointerException("event.addedCategory is null"); //NOI18N
-               } else if (event.getAddedCategory().getCategoryId() == null) {
-                       // And again ...
-                       throw new NullPointerException("event.addedCategory.categoryId is null"); //NOI18N
-               } else if (event.getAddedCategory().getCategoryId() < 1) {
-                       // Id is invalid
-                       throw new IllegalArgumentException(MessageFormat.format("event.addedCategory.categoryId={0} is not valid.", event.getAddedCategory().getCategoryId())); //NOI18N
-               }
-
-               // Add the category
-               this.allCategories.add(event.getAddedCategory());
-       }
-
-       /**
-        * Getter for a list of all categories
-        * <p>
-        * @return All categories
-        */
-       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
-       public List<Category> allCategories () {
-               // Return it
-               return this.allCategories;
-       }
-
-       @Override
-       public Category findCategoryById (final Long categoryId) throws CategoryNotFoundException {
-               // Validate parameter
-               if (null == categoryId) {
-                       // Throw NPE
-                       throw new NullPointerException("categoryId is null"); //NOI18N
-               } else if (categoryId < 1) {
-                       // Throw IAE
-                       throw new IllegalArgumentException("categoryId=" + categoryId + " is invalid"); //NOI18N
-               } else if (!this.categoryCache.containsKey(categoryId)) {
-                       // Not found
-                       throw new CategoryNotFoundException(categoryId);
-               }
-
-               // Get it from cache
-               final Category category = this.categoryCache.get(categoryId);
-
-               // Return it
-               return category;
-       }
-
-       /**
-        * Getter for filtered category list
-        * <p>
-        * @return Filtered category list
-        */
-       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
-       public List<Category> getFilteredCategories () {
-               return this.filteredCategories;
-       }
-
-       /**
-        * Setter for filtered category list
-        * <p>
-        * @param filteredCategories Filtered category list
-        */
-       @SuppressWarnings ("AssignmentToCollectionOrArrayFieldFromParameter")
-       public void setFilteredCategories (final List<Category> filteredCategories) {
-               this.filteredCategories = filteredCategories;
-       }
-
-       /**
-        * Initialization of this bean
-        */
-       @PostConstruct
-       public void init () {
-               // Is cache there?
-               if (!this.categoryCache.iterator().hasNext()) {
-                       // Get whole list
-                       final List<Category> categories = this.categoryBean.allCategories();
-
-                       // "Walk" through all entries and add to cache
-                       for (final Category category : categories) {
-                               // Add it by primary key
-                               this.categoryCache.put(category.getCategoryId(), category);
-                       }
-               }
-
-               // Is the list empty, but filled cache?
-               if (this.allCategories.isEmpty() && this.categoryCache.iterator().hasNext()) {
-                       // Get iterator
-                       final Iterator<Cache.Entry<Long, Category>> iterator = this.categoryCache.iterator();
-
-                       // Build up list
-                       while (iterator.hasNext()) {
-                               // GEt next element
-                               final Cache.Entry<Long, Category> next = iterator.next();
-
-                               // Add to list
-                               this.allCategories.add(next.getValue());
-                       }
-
-                       // Sort list
-                       this.allCategories.sort(new Comparator<Category>() {
-                               @Override
-                               public int compare (final Category o1, final Category o2) {
-                                       return o1.getCategoryId() > o2.getCategoryId() ? 1 : o1.getCategoryId() < o2.getCategoryId() ? -1 : 0;
-                               }
-                       }
-                       );
-               }
-       }
-
-}
diff --git a/src/java/org/mxchange/jfinancials/beans/category/FinancialCategoryWebRequestController.java b/src/java/org/mxchange/jfinancials/beans/category/FinancialCategoryWebRequestController.java
deleted file mode 100644 (file)
index c8caa54..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016, 2017 Roland Häder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package org.mxchange.jfinancials.beans.category;
-
-import java.io.Serializable;
-import org.mxchange.jproduct.exceptions.category.CategoryNotFoundException;
-import org.mxchange.jproduct.model.category.Category;
-
-/**
- * An interface for (product) categories
- * <p>
- * @author Roland Häder<roland@mxchange.org>
- */
-public interface FinancialCategoryWebRequestController extends Serializable {
-
-       /**
-        * Returns a category instance (entity) for given primary key. If not found,
-        * a proper exception is thrown.
-        * <p>
-        * @param categoryId Category id (primary key)
-        * <p>
-        * @return Category entity matching to primary key
-        * <p>
-        * @throws CategoryNotFoundException If a category with given primary key
-        * could not be found
-        */
-       Category findCategoryById (final Long categoryId) throws CategoryNotFoundException;
-
-}
diff --git a/src/java/org/mxchange/jfinancials/beans/generic_product/FinancialAdminProductWebRequestBean.java b/src/java/org/mxchange/jfinancials/beans/generic_product/FinancialAdminProductWebRequestBean.java
new file mode 100644 (file)
index 0000000..14ee0cc
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2016, 2017 Roland Häder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jfinancials.beans.generic_product;
+
+import javax.ejb.EJB;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.event.Event;
+import javax.enterprise.inject.Any;
+import javax.faces.view.facelets.FaceletException;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.mxchange.jfinancials.beans.BaseFinancialsBean;
+import org.mxchange.jproduct.events.product.AddedProductEvent;
+import org.mxchange.jproduct.events.product.ProductAddedEvent;
+import org.mxchange.jproduct.exceptions.product.ProductAlreadyAddedException;
+import org.mxchange.jproduct.model.category.Category;
+import org.mxchange.jproduct.model.product.AdminProductSessionBeanRemote;
+import org.mxchange.jproduct.model.product.GenericProduct;
+import org.mxchange.jproduct.model.product.Product;
+
+/**
+ * Main application class
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+@Named ("adminProductController")
+@RequestScoped
+public class FinancialAdminProductWebRequestBean extends BaseFinancialsBean implements FinancialAdminProductWebRequestController {
+
+       /**
+        * Serial number
+        */
+       private static final long serialVersionUID = 5_819_375_183_472_871L;
+
+       /**
+        * Event for added product
+        */
+       @Inject
+       @Any
+       private Event<AddedProductEvent> addedProductEvent;
+
+       /**
+        * Available
+        */
+       private Boolean productAvailability;
+
+       /**
+        * Category instance
+        */
+       private Category productCategory;
+
+       /**
+        * Product's price currency code like EUR or USD
+        */
+       private String productCurrencyCode;
+
+       /**
+        * Product's gross price
+        */
+       private Float productGrossPrice;
+
+       /**
+        * Product's net price
+        */
+       private Float productNetPrice;
+
+       /**
+        * Remote bean for products
+        */
+       @EJB (lookup = "java:global/jfinancials-ejb/adminProduct!org.mxchange.jproduct.model.product.AdminProductSessionBeanRemote")
+       private AdminProductSessionBeanRemote adminProductBean;
+
+       /**
+        * Product's tax rate
+        */
+       private Float productTaxRate;
+
+       /**
+        * I18n key of product
+        */
+       private String productI18nKey;
+
+       /**
+        * Product's unit amount
+        */
+       private Float productUnitAmount;
+
+       /**
+        * Product's unit type
+        */
+       private String productUnitType;
+
+       /**
+        * Default constructor
+        */
+       public FinancialAdminProductWebRequestBean () {
+               // Call super constructor
+               super();
+       }
+
+       /**
+        * Adds given product data from request to database
+        * <p>
+        * @throws FaceletException If something unexpected happened
+        */
+       public void addProduct () throws FaceletException {
+               // Create product instance
+               final Product product = this.createProductInstance();
+
+               // Declare updated product instance
+               final Product updatedProduct;
+
+               try {
+                       // Call bean
+                       updatedProduct = this.adminProductBean.addGenericProduct(product);
+               } catch (final ProductAlreadyAddedException ex) {
+                       // Continue to throw
+                       throw new FaceletException(ex);
+               }
+
+               // Fire event
+               this.addedProductEvent.fire(new ProductAddedEvent(updatedProduct));
+
+               // Set all to null
+               this.clear();
+       }
+
+       /**
+        * Getter for product's available
+        * <p>
+        * @return Product's available
+        */
+       public Boolean getProductAvailability () {
+               return this.productAvailability;
+       }
+
+       /**
+        * Setter for product's available
+        * <p>
+        * @param productAvailability Product's available
+        */
+       public void setProductAvailability (final Boolean productAvailability) {
+               this.productAvailability = productAvailability;
+       }
+
+       /**
+        * Getter for product's category
+        * <p>
+        * @return Product's category
+        */
+       public Category getProductCategory () {
+               return this.productCategory;
+       }
+
+       /**
+        * Setter for product's category instance
+        * <p>
+        * @param productCategory Product's category instance
+        */
+       public void setProductCategory (final Category productCategory) {
+               this.productCategory = productCategory;
+       }
+
+       /**
+        * Getter for product's price currency code
+        * <p>
+        * @return Product's price currency code
+        */
+       public String getProductCurrencyCode () {
+               return this.productCurrencyCode;
+       }
+
+       /**
+        * Setter for product's price currency code
+        * <p>
+        * @param productCurrencyCode Product's price currency code
+        */
+       public void setProductCurrencyCode (final String productCurrencyCode) {
+               this.productCurrencyCode = productCurrencyCode;
+       }
+
+       /**
+        * Getter for product's gross price
+        * <p>
+        * @return Product's gross price
+        */
+       public Float getProductGrossPrice () {
+               return this.productGrossPrice;
+       }
+
+       /**
+        * Setter for product's gross price
+        * <p>
+        * @param productGrossPrice Product's gross price
+        */
+       public void setProductGrossPrice (final Float productGrossPrice) {
+               this.productGrossPrice = productGrossPrice;
+       }
+
+       /**
+        * Getter for product's net price
+        * <p>
+        * @return Product's net price
+        */
+       public Float getProductNetPrice () {
+               return this.productNetPrice;
+       }
+
+       /**
+        * Setter for product's net price
+        * <p>
+        * @param productNetPrice Product's net price
+        */
+       public void setProductNetPrice (final Float productNetPrice) {
+               this.productNetPrice = productNetPrice;
+       }
+
+       /**
+        * Getter for product's tax rate
+        * <p>
+        * @return Product's tax rate
+        */
+       public Float getProductTaxRate () {
+               return this.productTaxRate;
+       }
+
+       /**
+        * Setter for product's tax rate
+        * <p>
+        * @param productTaxRate Product's tax rate
+        */
+       public void setProductTaxRate (final Float productTaxRate) {
+               this.productTaxRate = productTaxRate;
+       }
+
+       /**
+        * Getter for product's i18n key
+        * <p>
+        * @return Product's i18n key
+        */
+       public String getProductI18nKey () {
+               return this.productI18nKey;
+       }
+
+       /**
+        * Setter for product's i18n key
+        * <p>
+        * @param productI18nKey Product's i18n key
+        */
+       public void setProductI18nKey (final String productI18nKey) {
+               this.productI18nKey = productI18nKey;
+       }
+
+       /**
+        * Getter for product's unit amount
+        * <p>
+        * @return Product's unit amount
+        */
+       public Float getProductUnitAmount () {
+               return this.productUnitAmount;
+       }
+
+       /**
+        * Setter for product's unit amount
+        * <p>
+        * @param productUnitAmount Product's unit amount
+        */
+       public void setProductUnitAmount (final Float productUnitAmount) {
+               this.productUnitAmount = productUnitAmount;
+       }
+
+       /**
+        * Getter for product's unit type
+        * <p>
+        * @return Product's unit type
+        */
+       public String getProductUnitType () {
+               return this.productUnitType;
+       }
+
+       /**
+        * Setter for product's unit type
+        * <p>
+        * @param productUnitType Product's unit type
+        */
+       public void setProductUnitType (final String productUnitType) {
+               this.productUnitType = productUnitType;
+       }
+
+       /**
+        * Clears this bean (example: product has been added)
+        */
+       private void clear () {
+               this.setProductAvailability(Boolean.FALSE);
+               this.setProductCategory(null);
+               this.setProductNetPrice(null);
+               this.setProductTaxRate(null);
+               this.setProductGrossPrice(null);
+               this.setProductI18nKey(null);
+               this.setProductUnitAmount(null);
+               this.setProductUnitType(null);
+       }
+
+       /**
+        * Creates a product instance with all fields
+        * <p>
+        * @return Product instance
+        */
+       private Product createProductInstance () {
+               // Create product instance
+               final Product product = new GenericProduct(this.getProductI18nKey(), this.getProductGrossPrice(), this.getProductCurrencyCode(), this.getProductCategory(), this.getProductAvailability());
+
+               // Set all optional fields
+               product.setProductNetPrice(this.getProductNetPrice());
+               product.setProductTaxRate(this.getProductTaxRate());
+               product.setProductUnitAmount(this.getProductUnitAmount());
+               product.setProductUnitType(this.getProductUnitType());
+
+               // Return it
+               return product;
+       }
+
+}
diff --git a/src/java/org/mxchange/jfinancials/beans/generic_product/FinancialAdminProductWebRequestController.java b/src/java/org/mxchange/jfinancials/beans/generic_product/FinancialAdminProductWebRequestController.java
new file mode 100644 (file)
index 0000000..c419bae
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016, 2017 Roland Häder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jfinancials.beans.generic_product;
+
+import java.io.Serializable;
+
+/**
+ * An interface for product controllers for "ADMIN" role
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+public interface FinancialAdminProductWebRequestController extends Serializable {
+
+}
diff --git a/src/java/org/mxchange/jfinancials/beans/generic_product/FinancialProductWebRequestBean.java b/src/java/org/mxchange/jfinancials/beans/generic_product/FinancialProductWebRequestBean.java
new file mode 100644 (file)
index 0000000..55ec532
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016, 2017 Roland Häder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jfinancials.beans.generic_product;
+
+import fish.payara.cdi.jsr107.impl.NamedCache;
+import java.text.MessageFormat;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.cache.Cache;
+import javax.ejb.EJB;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.event.Observes;
+import javax.faces.FacesException;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.mxchange.jfinancials.beans.BaseFinancialsBean;
+import org.mxchange.jproduct.events.product.AddedProductEvent;
+import org.mxchange.jproduct.exceptions.product.ProductNotFoundException;
+import org.mxchange.jproduct.model.product.Product;
+import org.mxchange.jproduct.model.product.ProductSessionBeanRemote;
+
+/**
+ * General product controller
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+@Named ("productController")
+@RequestScoped
+public class FinancialProductWebRequestBean extends BaseFinancialsBean implements FinancialProductWebRequestController {
+
+       /**
+        * Serial number
+        */
+       private static final long serialVersionUID = 58_137_539_530_279L;
+
+       /**
+        * List for all products
+        */
+       private List<Product> allProducts;
+
+       /**
+        * List for filtered products
+        */
+       private List<Product> filteredProducts;
+
+       /**
+        * EJB for general product purposes
+        */
+       @EJB (lookup = "java:global/jfinancials-ejb/product!org.mxchange.jproduct.model.product.ProductSessionBeanRemote")
+       private ProductSessionBeanRemote productBean;
+
+       /**
+        * Cached products
+        */
+       @Inject
+       @NamedCache (cacheName = "productCache")
+       private Cache<Long, Product> productCache;
+
+       /**
+        * Default constructor
+        */
+       public FinancialProductWebRequestBean () {
+               // Call super constructor
+               super();
+
+               // Init list
+               this.allProducts = new LinkedList<>();
+       }
+
+       /**
+        * Observes events fired after a new product has been added
+        * <p>
+        * @param event Event to be observed
+        * <p>
+        * @todo Move this to own controller
+        */
+       public void afterProductAdded (@Observes final AddedProductEvent event) {
+               // Is all valid?
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getAddedProduct() == null) {
+                       // Throw again ...
+                       throw new NullPointerException("event.addedProduct is null"); //NOI18N
+               } else if (event.getAddedProduct().getProductId() == null) {
+                       // And again ...
+                       throw new NullPointerException("event.addedProduct.productId is null"); //NOI18N
+               } else if (event.getAddedProduct().getProductId() < 1) {
+                       // Id is invalid
+                       throw new IllegalArgumentException(MessageFormat.format("event.addedProduct.productId={0} is not valid.", event.getAddedProduct().getProductId())); //NOI18N
+               }
+
+               // Is the product available?
+               if (event.getAddedProduct().getProductAvailability()) {
+                       // Add it
+                       this.allProducts.add(event.getAddedProduct());
+               }
+       }
+
+       @Override
+       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
+       public List<Product> allProducts () throws FacesException {
+               // Return it
+               return this.allProducts;
+       }
+
+       @Override
+       public Product findProductById (final Long productId) throws ProductNotFoundException {
+               // Validate parameter
+               if (null == productId) {
+                       // Throw NPE
+                       throw new NullPointerException("productId is null"); //NOI18N
+               } else if (productId < 1) {
+                       // Throw IAE
+                       throw new IllegalArgumentException("productId=" + productId + " is invalid"); //NOI18N
+               } else if (!this.productCache.containsKey(productId)) {
+                       // Not found
+                       throw new ProductNotFoundException(productId);
+               }
+
+               // Get it from cache
+               final Product product = this.productCache.get(productId);
+
+               // Return it
+               return product;
+       }
+
+       /**
+        * Getter for filtered product list
+        * <p>
+        * @return Filtered product list
+        */
+       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
+       public List<Product> getFilteredProducts () {
+               return this.filteredProducts;
+       }
+
+       /**
+        * Setter for filtered product list
+        * <p>
+        * @param filteredProducts Filtered product list
+        */
+       @SuppressWarnings ("AssignmentToCollectionOrArrayFieldFromParameter")
+       public void setFilteredProducts (final List<Product> filteredProducts) {
+               this.filteredProducts = filteredProducts;
+       }
+
+       /**
+        * Initialization of this bean
+        */
+       @PostConstruct
+       public void init () {
+               // Is cache there?
+               if (!this.productCache.iterator().hasNext()) {
+                       // Get whole list
+                       final List<Product> products = this.productBean.allProducts();
+
+                       // "Walk" through all entries and add to cache
+                       for (final Product product : products) {
+                               // Add it by primary key
+                               this.productCache.put(product.getProductId(), product);
+                       }
+               }
+
+               // Is the list empty, but filled cache?
+               if (this.allProducts.isEmpty() && this.productCache.iterator().hasNext()) {
+                       // Get iterator
+                       final Iterator<Cache.Entry<Long, Product>> iterator = this.productCache.iterator();
+
+                       // Build up list
+                       while (iterator.hasNext()) {
+                               // GEt next element
+                               final Cache.Entry<Long, Product> next = iterator.next();
+
+                               // Add to list
+                               this.allProducts.add(next.getValue());
+                       }
+
+                       // Sort list
+                       this.allProducts.sort(new Comparator<Product>() {
+                               @Override
+                               public int compare (final Product o1, final Product o2) {
+                                       return o1.getProductId() > o2.getProductId() ? 1 : o1.getProductId() < o2.getProductId() ? -1 : 0;
+                               }
+                       }
+                       );
+               }
+       }
+
+}
diff --git a/src/java/org/mxchange/jfinancials/beans/generic_product/FinancialProductWebRequestController.java b/src/java/org/mxchange/jfinancials/beans/generic_product/FinancialProductWebRequestController.java
new file mode 100644 (file)
index 0000000..7dbe48c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016, 2017 Roland Häder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jfinancials.beans.generic_product;
+
+import java.io.Serializable;
+import java.util.List;
+import javax.ejb.Local;
+import javax.faces.view.facelets.FaceletException;
+import org.mxchange.jproduct.exceptions.product.ProductNotFoundException;
+import org.mxchange.jproduct.model.product.Product;
+
+/**
+ * An interface for products
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+@Local
+public interface FinancialProductWebRequestController extends Serializable {
+
+       /**
+        * Some "getter" for a linked list of only available products
+        * <p>
+        * @return Only available products
+        * <p>
+        * @throws javax.faces.view.facelets.FaceletException If anything went wrong
+        */
+       List<Product> allProducts () throws FaceletException;
+
+       /**
+        * Returns a product instance (entity) for given primary key. If not found,
+        * a proper exception is thrown.
+        * <p>
+        * @param productId Product id (primary key)
+        * <p>
+        * @return Product entity matching to primary key
+        * <p>
+        * @throws ProductNotFoundException If a product with given primary key
+        * could not be found
+        */
+       Product findProductById (final Long productId) throws ProductNotFoundException;
+
+}
diff --git a/src/java/org/mxchange/jfinancials/beans/product/FinancialAdminProductWebRequestBean.java b/src/java/org/mxchange/jfinancials/beans/product/FinancialAdminProductWebRequestBean.java
deleted file mode 100644 (file)
index 842d3b1..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (C) 2016, 2017 Roland Häder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package org.mxchange.jfinancials.beans.product;
-
-import javax.ejb.EJB;
-import javax.enterprise.context.RequestScoped;
-import javax.enterprise.event.Event;
-import javax.enterprise.inject.Any;
-import javax.faces.view.facelets.FaceletException;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.mxchange.jfinancials.beans.BaseFinancialsBean;
-import org.mxchange.jproduct.events.product.AddedProductEvent;
-import org.mxchange.jproduct.events.product.ProductAddedEvent;
-import org.mxchange.jproduct.exceptions.product.ProductAlreadyAddedException;
-import org.mxchange.jproduct.model.category.Category;
-import org.mxchange.jproduct.model.product.AdminProductSessionBeanRemote;
-import org.mxchange.jproduct.model.product.GenericProduct;
-import org.mxchange.jproduct.model.product.Product;
-
-/**
- * Main application class
- * <p>
- * @author Roland Häder<roland@mxchange.org>
- */
-@Named ("adminProductController")
-@RequestScoped
-public class FinancialAdminProductWebRequestBean extends BaseFinancialsBean implements FinancialAdminProductWebRequestController {
-
-       /**
-        * Serial number
-        */
-       private static final long serialVersionUID = 5_819_375_183_472_871L;
-
-       /**
-        * Event for added product
-        */
-       @Inject
-       @Any
-       private Event<AddedProductEvent> addedProductEvent;
-
-       /**
-        * Available
-        */
-       private Boolean productAvailability;
-
-       /**
-        * Category instance
-        */
-       private Category productCategory;
-
-       /**
-        * Product's price currency code like EUR or USD
-        */
-       private String productCurrencyCode;
-
-       /**
-        * Product's gross price
-        */
-       private Float productGrossPrice;
-
-       /**
-        * Product's net price
-        */
-       private Float productNetPrice;
-
-       /**
-        * Remote bean for products
-        */
-       @EJB (lookup = "java:global/jfinancials-ejb/adminProduct!org.mxchange.jproduct.model.product.AdminProductSessionBeanRemote")
-       private AdminProductSessionBeanRemote adminProductBean;
-
-       /**
-        * Product's tax rate
-        */
-       private Float productTaxRate;
-
-       /**
-        * I18n key of product
-        */
-       private String productI18nKey;
-
-       /**
-        * Product's unit amount
-        */
-       private Float productUnitAmount;
-
-       /**
-        * Product's unit type
-        */
-       private String productUnitType;
-
-       /**
-        * Default constructor
-        */
-       public FinancialAdminProductWebRequestBean () {
-               // Call super constructor
-               super();
-       }
-
-       /**
-        * Adds given product data from request to database
-        * <p>
-        * @throws FaceletException If something unexpected happened
-        */
-       public void addProduct () throws FaceletException {
-               // Create product instance
-               final Product product = this.createProductInstance();
-
-               // Declare updated product instance
-               final Product updatedProduct;
-
-               try {
-                       // Call bean
-                       updatedProduct = this.adminProductBean.addGenericProduct(product);
-               } catch (final ProductAlreadyAddedException ex) {
-                       // Continue to throw
-                       throw new FaceletException(ex);
-               }
-
-               // Fire event
-               this.addedProductEvent.fire(new ProductAddedEvent(updatedProduct));
-
-               // Set all to null
-               this.clear();
-       }
-
-       /**
-        * Getter for product's available
-        * <p>
-        * @return Product's available
-        */
-       public Boolean getProductAvailability () {
-               return this.productAvailability;
-       }
-
-       /**
-        * Setter for product's available
-        * <p>
-        * @param productAvailability Product's available
-        */
-       public void setProductAvailability (final Boolean productAvailability) {
-               this.productAvailability = productAvailability;
-       }
-
-       /**
-        * Getter for product's category
-        * <p>
-        * @return Product's category
-        */
-       public Category getProductCategory () {
-               return this.productCategory;
-       }
-
-       /**
-        * Setter for product's category instance
-        * <p>
-        * @param productCategory Product's category instance
-        */
-       public void setProductCategory (final Category productCategory) {
-               this.productCategory = productCategory;
-       }
-
-       /**
-        * Getter for product's price currency code
-        * <p>
-        * @return Product's price currency code
-        */
-       public String getProductCurrencyCode () {
-               return this.productCurrencyCode;
-       }
-
-       /**
-        * Setter for product's price currency code
-        * <p>
-        * @param productCurrencyCode Product's price currency code
-        */
-       public void setProductCurrencyCode (final String productCurrencyCode) {
-               this.productCurrencyCode = productCurrencyCode;
-       }
-
-       /**
-        * Getter for product's gross price
-        * <p>
-        * @return Product's gross price
-        */
-       public Float getProductGrossPrice () {
-               return this.productGrossPrice;
-       }
-
-       /**
-        * Setter for product's gross price
-        * <p>
-        * @param productGrossPrice Product's gross price
-        */
-       public void setProductGrossPrice (final Float productGrossPrice) {
-               this.productGrossPrice = productGrossPrice;
-       }
-
-       /**
-        * Getter for product's net price
-        * <p>
-        * @return Product's net price
-        */
-       public Float getProductNetPrice () {
-               return this.productNetPrice;
-       }
-
-       /**
-        * Setter for product's net price
-        * <p>
-        * @param productNetPrice Product's net price
-        */
-       public void setProductNetPrice (final Float productNetPrice) {
-               this.productNetPrice = productNetPrice;
-       }
-
-       /**
-        * Getter for product's tax rate
-        * <p>
-        * @return Product's tax rate
-        */
-       public Float getProductTaxRate () {
-               return this.productTaxRate;
-       }
-
-       /**
-        * Setter for product's tax rate
-        * <p>
-        * @param productTaxRate Product's tax rate
-        */
-       public void setProductTaxRate (final Float productTaxRate) {
-               this.productTaxRate = productTaxRate;
-       }
-
-       /**
-        * Getter for product's i18n key
-        * <p>
-        * @return Product's i18n key
-        */
-       public String getProductI18nKey () {
-               return this.productI18nKey;
-       }
-
-       /**
-        * Setter for product's i18n key
-        * <p>
-        * @param productI18nKey Product's i18n key
-        */
-       public void setProductI18nKey (final String productI18nKey) {
-               this.productI18nKey = productI18nKey;
-       }
-
-       /**
-        * Getter for product's unit amount
-        * <p>
-        * @return Product's unit amount
-        */
-       public Float getProductUnitAmount () {
-               return this.productUnitAmount;
-       }
-
-       /**
-        * Setter for product's unit amount
-        * <p>
-        * @param productUnitAmount Product's unit amount
-        */
-       public void setProductUnitAmount (final Float productUnitAmount) {
-               this.productUnitAmount = productUnitAmount;
-       }
-
-       /**
-        * Getter for product's unit type
-        * <p>
-        * @return Product's unit type
-        */
-       public String getProductUnitType () {
-               return this.productUnitType;
-       }
-
-       /**
-        * Setter for product's unit type
-        * <p>
-        * @param productUnitType Product's unit type
-        */
-       public void setProductUnitType (final String productUnitType) {
-               this.productUnitType = productUnitType;
-       }
-
-       /**
-        * Clears this bean (example: product has been added)
-        */
-       private void clear () {
-               this.setProductAvailability(Boolean.FALSE);
-               this.setProductCategory(null);
-               this.setProductNetPrice(null);
-               this.setProductTaxRate(null);
-               this.setProductGrossPrice(null);
-               this.setProductI18nKey(null);
-               this.setProductUnitAmount(null);
-               this.setProductUnitType(null);
-       }
-
-       /**
-        * Creates a product instance with all fields
-        * <p>
-        * @return Product instance
-        */
-       private Product createProductInstance () {
-               // Create product instance
-               final Product product = new GenericProduct(this.getProductI18nKey(), this.getProductGrossPrice(), this.getProductCurrencyCode(), this.getProductCategory(), this.getProductAvailability());
-
-               // Set all optional fields
-               product.setProductNetPrice(this.getProductNetPrice());
-               product.setProductTaxRate(this.getProductTaxRate());
-               product.setProductUnitAmount(this.getProductUnitAmount());
-               product.setProductUnitType(this.getProductUnitType());
-
-               // Return it
-               return product;
-       }
-
-}
diff --git a/src/java/org/mxchange/jfinancials/beans/product/FinancialAdminProductWebRequestController.java b/src/java/org/mxchange/jfinancials/beans/product/FinancialAdminProductWebRequestController.java
deleted file mode 100644 (file)
index 768ed80..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016, 2017 Roland Häder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package org.mxchange.jfinancials.beans.product;
-
-import java.io.Serializable;
-
-/**
- * An interface for product controllers for "ADMIN" role
- * <p>
- * @author Roland Häder<roland@mxchange.org>
- */
-public interface FinancialAdminProductWebRequestController extends Serializable {
-
-}
diff --git a/src/java/org/mxchange/jfinancials/beans/product/FinancialProductWebRequestBean.java b/src/java/org/mxchange/jfinancials/beans/product/FinancialProductWebRequestBean.java
deleted file mode 100644 (file)
index 635cbe8..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2016, 2017 Roland Häder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package org.mxchange.jfinancials.beans.product;
-
-import fish.payara.cdi.jsr107.impl.NamedCache;
-import java.text.MessageFormat;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import javax.annotation.PostConstruct;
-import javax.cache.Cache;
-import javax.ejb.EJB;
-import javax.enterprise.context.RequestScoped;
-import javax.enterprise.event.Observes;
-import javax.faces.FacesException;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.mxchange.jfinancials.beans.BaseFinancialsBean;
-import org.mxchange.jproduct.events.product.AddedProductEvent;
-import org.mxchange.jproduct.exceptions.product.ProductNotFoundException;
-import org.mxchange.jproduct.model.product.Product;
-import org.mxchange.jproduct.model.product.ProductSessionBeanRemote;
-
-/**
- * General product controller
- * <p>
- * @author Roland Häder<roland@mxchange.org>
- */
-@Named ("productController")
-@RequestScoped
-public class FinancialProductWebRequestBean extends BaseFinancialsBean implements FinancialProductWebRequestController {
-
-       /**
-        * Serial number
-        */
-       private static final long serialVersionUID = 58_137_539_530_279L;
-
-       /**
-        * List for all products
-        */
-       private List<Product> allProducts;
-
-       /**
-        * List for filtered products
-        */
-       private List<Product> filteredProducts;
-
-       /**
-        * EJB for general product purposes
-        */
-       @EJB (lookup = "java:global/jfinancials-ejb/product!org.mxchange.jproduct.model.product.ProductSessionBeanRemote")
-       private ProductSessionBeanRemote productBean;
-
-       /**
-        * Cached products
-        */
-       @Inject
-       @NamedCache (cacheName = "productCache")
-       private Cache<Long, Product> productCache;
-
-       /**
-        * Default constructor
-        */
-       public FinancialProductWebRequestBean () {
-               // Call super constructor
-               super();
-
-               // Init list
-               this.allProducts = new LinkedList<>();
-       }
-
-       /**
-        * Observes events fired after a new product has been added
-        * <p>
-        * @param event Event to be observed
-        * <p>
-        * @todo Move this to own controller
-        */
-       public void afterProductAdded (@Observes final AddedProductEvent event) {
-               // Is all valid?
-               if (null == event) {
-                       // Throw NPE
-                       throw new NullPointerException("event is null"); //NOI18N
-               } else if (event.getAddedProduct() == null) {
-                       // Throw again ...
-                       throw new NullPointerException("event.addedProduct is null"); //NOI18N
-               } else if (event.getAddedProduct().getProductId() == null) {
-                       // And again ...
-                       throw new NullPointerException("event.addedProduct.productId is null"); //NOI18N
-               } else if (event.getAddedProduct().getProductId() < 1) {
-                       // Id is invalid
-                       throw new IllegalArgumentException(MessageFormat.format("event.addedProduct.productId={0} is not valid.", event.getAddedProduct().getProductId())); //NOI18N
-               }
-
-               // Is the product available?
-               if (event.getAddedProduct().getProductAvailability()) {
-                       // Add it
-                       this.allProducts.add(event.getAddedProduct());
-               }
-       }
-
-       @Override
-       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
-       public List<Product> allProducts () throws FacesException {
-               // Return it
-               return this.allProducts;
-       }
-
-       @Override
-       public Product findProductById (final Long productId) throws ProductNotFoundException {
-               // Validate parameter
-               if (null == productId) {
-                       // Throw NPE
-                       throw new NullPointerException("productId is null"); //NOI18N
-               } else if (productId < 1) {
-                       // Throw IAE
-                       throw new IllegalArgumentException("productId=" + productId + " is invalid"); //NOI18N
-               } else if (!this.productCache.containsKey(productId)) {
-                       // Not found
-                       throw new ProductNotFoundException(productId);
-               }
-
-               // Get it from cache
-               final Product product = this.productCache.get(productId);
-
-               // Return it
-               return product;
-       }
-
-       /**
-        * Getter for filtered product list
-        * <p>
-        * @return Filtered product list
-        */
-       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
-       public List<Product> getFilteredProducts () {
-               return this.filteredProducts;
-       }
-
-       /**
-        * Setter for filtered product list
-        * <p>
-        * @param filteredProducts Filtered product list
-        */
-       @SuppressWarnings ("AssignmentToCollectionOrArrayFieldFromParameter")
-       public void setFilteredProducts (final List<Product> filteredProducts) {
-               this.filteredProducts = filteredProducts;
-       }
-
-       /**
-        * Initialization of this bean
-        */
-       @PostConstruct
-       public void init () {
-               // Is cache there?
-               if (!this.productCache.iterator().hasNext()) {
-                       // Get whole list
-                       final List<Product> products = this.productBean.allProducts();
-
-                       // "Walk" through all entries and add to cache
-                       for (final Product product : products) {
-                               // Add it by primary key
-                               this.productCache.put(product.getProductId(), product);
-                       }
-               }
-
-               // Is the list empty, but filled cache?
-               if (this.allProducts.isEmpty() && this.productCache.iterator().hasNext()) {
-                       // Get iterator
-                       final Iterator<Cache.Entry<Long, Product>> iterator = this.productCache.iterator();
-
-                       // Build up list
-                       while (iterator.hasNext()) {
-                               // GEt next element
-                               final Cache.Entry<Long, Product> next = iterator.next();
-
-                               // Add to list
-                               this.allProducts.add(next.getValue());
-                       }
-
-                       // Sort list
-                       this.allProducts.sort(new Comparator<Product>() {
-                               @Override
-                               public int compare (final Product o1, final Product o2) {
-                                       return o1.getProductId() > o2.getProductId() ? 1 : o1.getProductId() < o2.getProductId() ? -1 : 0;
-                               }
-                       }
-                       );
-               }
-       }
-
-}
diff --git a/src/java/org/mxchange/jfinancials/beans/product/FinancialProductWebRequestController.java b/src/java/org/mxchange/jfinancials/beans/product/FinancialProductWebRequestController.java
deleted file mode 100644 (file)
index 8543d3c..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2016, 2017 Roland Häder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package org.mxchange.jfinancials.beans.product;
-
-import java.io.Serializable;
-import java.util.List;
-import javax.ejb.Local;
-import javax.faces.view.facelets.FaceletException;
-import org.mxchange.jproduct.exceptions.product.ProductNotFoundException;
-import org.mxchange.jproduct.model.product.Product;
-
-/**
- * An interface for products
- * <p>
- * @author Roland Häder<roland@mxchange.org>
- */
-@Local
-public interface FinancialProductWebRequestController extends Serializable {
-
-       /**
-        * Some "getter" for a linked list of only available products
-        * <p>
-        * @return Only available products
-        * <p>
-        * @throws javax.faces.view.facelets.FaceletException If anything went wrong
-        */
-       List<Product> allProducts () throws FaceletException;
-
-       /**
-        * Returns a product instance (entity) for given primary key. If not found,
-        * a proper exception is thrown.
-        * <p>
-        * @param productId Product id (primary key)
-        * <p>
-        * @return Product entity matching to primary key
-        * <p>
-        * @throws ProductNotFoundException If a product with given primary key
-        * could not be found
-        */
-       Product findProductById (final Long productId) throws ProductNotFoundException;
-
-}
diff --git a/src/java/org/mxchange/jfinancials/beans/product_category/FinancialAdminCategoryWebRequestBean.java b/src/java/org/mxchange/jfinancials/beans/product_category/FinancialAdminCategoryWebRequestBean.java
new file mode 100644 (file)
index 0000000..fb45265
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016, 2017 Roland Häder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jfinancials.beans.product_category;
+
+import javax.ejb.EJB;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.event.Event;
+import javax.enterprise.inject.Any;
+import javax.faces.view.facelets.FaceletException;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.mxchange.jfinancials.beans.BaseFinancialsBean;
+import org.mxchange.jproduct.events.category.AddedCategoryEvent;
+import org.mxchange.jproduct.events.category.CategoryAddedEvent;
+import org.mxchange.jproduct.exceptions.category.CategoryAlreadyAddedException;
+import org.mxchange.jproduct.model.category.AdminCategorySessionBeanRemote;
+import org.mxchange.jproduct.model.category.Category;
+import org.mxchange.jproduct.model.category.ProductCategory;
+
+/**
+ * Main application class
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+@Named ("adminCategoryController")
+@RequestScoped
+public class FinancialAdminCategoryWebRequestBean extends BaseFinancialsBean implements FinancialAdminCategoryWebRequestController {
+
+       /**
+        * Serial number
+        */
+       private static final long serialVersionUID = 5_819_375_183_472_871L;
+
+       /**
+        * Event for added shop categories
+        */
+       @Inject
+       @Any
+       private Event<AddedCategoryEvent> categoryAddedEvent;
+
+       /**
+        * Remote bean for categories
+        */
+       @EJB (lookup = "java:global/jfinancials-ejb/adminCategory!org.mxchange.jproduct.model.category.AdminCategorySessionBeanRemote")
+       private AdminCategorySessionBeanRemote categoryBean;
+
+       /**
+        * Whether this category is shown in statistics
+        */
+       private Boolean categoryShownInStatistics;
+
+       /**
+        * Category categoryI18nKey
+        */
+       private String categoryI18nKey;
+
+       /**
+        * Parent category
+        */
+       private Category parentCategory;
+
+       /**
+        * Default constructor
+        */
+       public FinancialAdminCategoryWebRequestBean () {
+               // Call super constructor
+               super();
+       }
+
+       /**
+        * Adds given category data from request to database
+        * <p>
+        * @throws javax.faces.view.facelets.FaceletException If something
+        * unexpected happened
+        */
+       public void addCategory () throws FaceletException {
+               // Create category
+               final Category category = this.createCategoryInstance();
+
+               // Declare updated category instance
+               final Category updatedCategory;
+
+               try {
+                       // Deligate to remote bean
+                       updatedCategory = this.categoryBean.addProductCategory(category);
+               } catch (final CategoryAlreadyAddedException ex) {
+                       // Continue to throw
+                       throw new FaceletException(ex);
+               }
+
+               // Fire event
+               this.categoryAddedEvent.fire(new CategoryAddedEvent(updatedCategory));
+
+               // Unset all older values
+               this.clear();
+       }
+
+       /**
+        * Getter for whether category is shown in statistics
+        * <p>
+        * @return Whether category is shown in statistics
+        */
+       public Boolean getCategoryShownInStatistics () {
+               return this.categoryShownInStatistics;
+       }
+
+       /**
+        * Setter for whether category is shown in statistics
+        * <p>
+        * @param categoryShownInStatistics Whether category is shown in statistics
+        */
+       public void setCategoryShownInStatistics (final Boolean categoryShownInStatistics) {
+               this.categoryShownInStatistics = categoryShownInStatistics;
+       }
+
+       /**
+        * Getter for category i18n key
+        * <p>
+        * @return Category i18n key
+        */
+       public String getCategoryI18nKey () {
+               return this.categoryI18nKey;
+       }
+
+       /**
+        * Setter for category i18n key
+        * <p>
+        * @param categoryI18nKey Category i18n key
+        */
+       public void setCategoryI18nKey (final String categoryI18nKey) {
+               this.categoryI18nKey = categoryI18nKey;
+       }
+
+       /**
+        * Getter for parent id
+        * <p>
+        * @return Parent id
+        */
+       public Category getParentCategory () {
+               return this.parentCategory;
+       }
+
+       /**
+        * Setter for parent category
+        * <p>
+        * @param parentCategory Parent category to set
+        */
+       public void setParentCategory (final Category parentCategory) {
+               this.parentCategory = parentCategory;
+       }
+
+       /**
+        * Clears this bean (example: when category has been added)
+        */
+       private void clear () {
+               // Clear all fields
+               this.setCategoryI18nKey(null);
+               this.setParentCategory(null);
+       }
+
+       /**
+        * Creates a category instance with all fields (except primary key)
+        * <p>
+        * @return Category instance
+        */
+       private Category createCategoryInstance () {
+               // Create category
+               final Category category = new ProductCategory(this.getCategoryI18nKey(), this.getParentCategory(), this.getCategoryShownInStatistics());
+
+               // Return it
+               return category;
+       }
+
+}
diff --git a/src/java/org/mxchange/jfinancials/beans/product_category/FinancialAdminCategoryWebRequestController.java b/src/java/org/mxchange/jfinancials/beans/product_category/FinancialAdminCategoryWebRequestController.java
new file mode 100644 (file)
index 0000000..be18989
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016, 2017 Roland Häder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jfinancials.beans.product_category;
+
+import java.io.Serializable;
+
+/**
+ * An interface for product controllers for "ADMIN" role
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+public interface FinancialAdminCategoryWebRequestController extends Serializable {
+
+}
diff --git a/src/java/org/mxchange/jfinancials/beans/product_category/FinancialCategoryWebRequestBean.java b/src/java/org/mxchange/jfinancials/beans/product_category/FinancialCategoryWebRequestBean.java
new file mode 100644 (file)
index 0000000..3dac53b
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2016, 2017 Roland Häder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jfinancials.beans.product_category;
+
+import fish.payara.cdi.jsr107.impl.NamedCache;
+import java.text.MessageFormat;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.cache.Cache;
+import javax.ejb.EJB;
+import javax.enterprise.context.RequestScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.mxchange.jfinancials.beans.BaseFinancialsBean;
+import org.mxchange.jproduct.events.category.AddedCategoryEvent;
+import org.mxchange.jproduct.exceptions.category.CategoryNotFoundException;
+import org.mxchange.jproduct.model.category.Category;
+import org.mxchange.jproduct.model.category.CategorySessionBeanRemote;
+
+/**
+ * General (product) category controller
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+@Named ("categoryController")
+@RequestScoped
+public class FinancialCategoryWebRequestBean extends BaseFinancialsBean implements FinancialCategoryWebRequestController {
+
+       /**
+        * Serial number
+        */
+       private static final long serialVersionUID = 58_137_539_530_279L;
+
+       /**
+        * List of all categories
+        */
+       private final List<Category> allCategories;
+
+       /**
+        * EJB for general category stuff
+        */
+       @EJB (lookup = "java:global/jfinancials-ejb/category!org.mxchange.jproduct.model.category.CategorySessionBeanRemote")
+       private CategorySessionBeanRemote categoryBean;
+
+       /**
+        * Cache for all product categories
+        */
+       @Inject
+       @NamedCache (cacheName = "categoryCache")
+       private Cache<Long, Category> categoryCache;
+
+       /**
+        * A list of filtered categories
+        */
+       private List<Category> filteredCategories;
+
+       /**
+        * Default constructor
+        */
+       public FinancialCategoryWebRequestBean () {
+               // Call super constructor
+               super();
+
+               // Init list
+               this.allCategories = new LinkedList<>();
+       }
+
+       /**
+        * Observes events fired after a new product category has been added
+        * <p>
+        * @param event Event to be observed
+        */
+       public void afterShopCategoryAdded (@Observes final AddedCategoryEvent event) {
+               // Is all valid?
+               if (null == event) {
+                       // Throw NPE
+                       throw new NullPointerException("event is null"); //NOI18N
+               } else if (event.getAddedCategory() == null) {
+                       // Throw again ...
+                       throw new NullPointerException("event.addedCategory is null"); //NOI18N
+               } else if (event.getAddedCategory().getCategoryId() == null) {
+                       // And again ...
+                       throw new NullPointerException("event.addedCategory.categoryId is null"); //NOI18N
+               } else if (event.getAddedCategory().getCategoryId() < 1) {
+                       // Id is invalid
+                       throw new IllegalArgumentException(MessageFormat.format("event.addedCategory.categoryId={0} is not valid.", event.getAddedCategory().getCategoryId())); //NOI18N
+               }
+
+               // Add the category
+               this.allCategories.add(event.getAddedCategory());
+       }
+
+       /**
+        * Getter for a list of all categories
+        * <p>
+        * @return All categories
+        */
+       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
+       public List<Category> allCategories () {
+               // Return it
+               return this.allCategories;
+       }
+
+       @Override
+       public Category findCategoryById (final Long categoryId) throws CategoryNotFoundException {
+               // Validate parameter
+               if (null == categoryId) {
+                       // Throw NPE
+                       throw new NullPointerException("categoryId is null"); //NOI18N
+               } else if (categoryId < 1) {
+                       // Throw IAE
+                       throw new IllegalArgumentException("categoryId=" + categoryId + " is invalid"); //NOI18N
+               } else if (!this.categoryCache.containsKey(categoryId)) {
+                       // Not found
+                       throw new CategoryNotFoundException(categoryId);
+               }
+
+               // Get it from cache
+               final Category category = this.categoryCache.get(categoryId);
+
+               // Return it
+               return category;
+       }
+
+       /**
+        * Getter for filtered category list
+        * <p>
+        * @return Filtered category list
+        */
+       @SuppressWarnings ("ReturnOfCollectionOrArrayField")
+       public List<Category> getFilteredCategories () {
+               return this.filteredCategories;
+       }
+
+       /**
+        * Setter for filtered category list
+        * <p>
+        * @param filteredCategories Filtered category list
+        */
+       @SuppressWarnings ("AssignmentToCollectionOrArrayFieldFromParameter")
+       public void setFilteredCategories (final List<Category> filteredCategories) {
+               this.filteredCategories = filteredCategories;
+       }
+
+       /**
+        * Initialization of this bean
+        */
+       @PostConstruct
+       public void init () {
+               // Is cache there?
+               if (!this.categoryCache.iterator().hasNext()) {
+                       // Get whole list
+                       final List<Category> categories = this.categoryBean.allCategories();
+
+                       // "Walk" through all entries and add to cache
+                       for (final Category category : categories) {
+                               // Add it by primary key
+                               this.categoryCache.put(category.getCategoryId(), category);
+                       }
+               }
+
+               // Is the list empty, but filled cache?
+               if (this.allCategories.isEmpty() && this.categoryCache.iterator().hasNext()) {
+                       // Get iterator
+                       final Iterator<Cache.Entry<Long, Category>> iterator = this.categoryCache.iterator();
+
+                       // Build up list
+                       while (iterator.hasNext()) {
+                               // GEt next element
+                               final Cache.Entry<Long, Category> next = iterator.next();
+
+                               // Add to list
+                               this.allCategories.add(next.getValue());
+                       }
+
+                       // Sort list
+                       this.allCategories.sort(new Comparator<Category>() {
+                               @Override
+                               public int compare (final Category o1, final Category o2) {
+                                       return o1.getCategoryId() > o2.getCategoryId() ? 1 : o1.getCategoryId() < o2.getCategoryId() ? -1 : 0;
+                               }
+                       }
+                       );
+               }
+       }
+
+}
diff --git a/src/java/org/mxchange/jfinancials/beans/product_category/FinancialCategoryWebRequestController.java b/src/java/org/mxchange/jfinancials/beans/product_category/FinancialCategoryWebRequestController.java
new file mode 100644 (file)
index 0000000..69fde5e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016, 2017 Roland Häder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.mxchange.jfinancials.beans.product_category;
+
+import java.io.Serializable;
+import org.mxchange.jproduct.exceptions.category.CategoryNotFoundException;
+import org.mxchange.jproduct.model.category.Category;
+
+/**
+ * An interface for (product) categories
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+public interface FinancialCategoryWebRequestController extends Serializable {
+
+       /**
+        * Returns a category instance (entity) for given primary key. If not found,
+        * a proper exception is thrown.
+        * <p>
+        * @param categoryId Category id (primary key)
+        * <p>
+        * @return Category entity matching to primary key
+        * <p>
+        * @throws CategoryNotFoundException If a category with given primary key
+        * could not be found
+        */
+       Category findCategoryById (final Long categoryId) throws CategoryNotFoundException;
+
+}
index 5af8d5fd0808c73ed5fa228d7b9a5bea4f7043c9..4c78bd34719ca3196c38d6b3e989acde730346cd 100644 (file)
@@ -22,8 +22,8 @@ import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
 import javax.faces.convert.ConverterException;
 import javax.faces.convert.FacesConverter;
-import org.mxchange.jfinancials.beans.product.FinancialProductWebRequestBean;
-import org.mxchange.jfinancials.beans.product.FinancialProductWebRequestController;
+import org.mxchange.jfinancials.beans.generic_product.FinancialProductWebRequestBean;
+import org.mxchange.jfinancials.beans.generic_product.FinancialProductWebRequestController;
 import org.mxchange.jproduct.exceptions.product.ProductNotFoundException;
 import org.mxchange.jproduct.model.product.Product;
 
index 983e8b3f4a3da15e5266d2be96dc259cb9da0fa5..4978f233a3e28205580cce3f858a601b2a5ba559 100644 (file)
@@ -22,8 +22,8 @@ import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
 import javax.faces.convert.ConverterException;
 import javax.faces.convert.FacesConverter;
-import org.mxchange.jfinancials.beans.category.FinancialCategoryWebRequestBean;
-import org.mxchange.jfinancials.beans.category.FinancialCategoryWebRequestController;
+import org.mxchange.jfinancials.beans.product_category.FinancialCategoryWebRequestBean;
+import org.mxchange.jfinancials.beans.product_category.FinancialCategoryWebRequestController;
 import org.mxchange.jproduct.exceptions.category.CategoryNotFoundException;
 import org.mxchange.jproduct.model.category.Category;
 
index b6471e276e24a5c99d54dd03676aa0f06cc5e08b..81a63726235f55ccb9cd64368ff6222fd2503e3c 100644 (file)
                </navigation-case>
                <navigation-case>
                        <from-outcome>admin_list_category</from-outcome>
-                       <to-view-id>/admin/category/admin_product_category_list.xhtml</to-view-id>
+                       <to-view-id>/admin/product_category/admin_product_category_list.xhtml</to-view-id>
                </navigation-case>
                <navigation-case>
                        <from-outcome>admin_list_product</from-outcome>
-                       <to-view-id>/admin/product/admin_generic_product_list.xhtml</to-view-id>
+                       <to-view-id>/admin/generic_product/admin_generic_product_list.xhtml</to-view-id>
                </navigation-case>
                <navigation-case>
                        <from-outcome>admin_list_user</from-outcome>
                </navigation-case>
        </navigation-rule>
        <navigation-rule>
-               <from-view-id>/admin/category/admin_product_category_list.xhtml</from-view-id>
+               <from-view-id>/admin/product_category/admin_product_category_list.xhtml</from-view-id>
                <navigation-case>
                        <from-outcome>admin_show_product_category</from-outcome>
-                       <to-view-id>/admin/category/admin_product_category_show.xhtml</to-view-id>
+                       <to-view-id>/admin/product_category/admin_product_category_show.xhtml</to-view-id>
                </navigation-case>
                <navigation-case>
                        <from-outcome>admin_edit_product_category</from-outcome>
-                       <to-view-id>/admin/category/admin_product_category_edit.xhtml</to-view-id>
+                       <to-view-id>/admin/product_category/admin_product_category_edit.xhtml</to-view-id>
                </navigation-case>
                <navigation-case>
                        <from-outcome>admin_delete_product_category</from-outcome>
-                       <to-view-id>/admin/category/admin_product_category_delete.xhtml</to-view-id>
+                       <to-view-id>/admin/product_category/admin_product_category_delete.xhtml</to-view-id>
                </navigation-case>
                <navigation-case>
                        <from-outcome>admin_assign_parent_category</from-outcome>
-                       <to-view-id>/admin/category/admin_product_category_assign_parent.xhtml</to-view-id>
+                       <to-view-id>/admin/product_category/admin_product_category_assign_parent.xhtml</to-view-id>
                </navigation-case>
        </navigation-rule>
        <navigation-rule>
-               <from-view-id>/admin/product/admin_generic_product_list.xhtml</from-view-id>
+               <from-view-id>/admin/generic_product/admin_generic_product_list.xhtml</from-view-id>
                <navigation-case>
                        <from-outcome>admin_show_generic_product</from-outcome>
-                       <to-view-id>/admin/product/admin_generic_product_show.xhtml</to-view-id>
+                       <to-view-id>/admin/generic_product/admin_generic_product_show.xhtml</to-view-id>
                </navigation-case>
                <navigation-case>
                        <from-outcome>admin_edit_generic_product</from-outcome>
-                       <to-view-id>/admin/product/admin_generic_product_edit.xhtml</to-view-id>
+                       <to-view-id>/admin/generic_product/admin_generic_product_edit.xhtml</to-view-id>
                </navigation-case>
                <navigation-case>
                        <from-outcome>admin_delete_generic_product</from-outcome>
-                       <to-view-id>/admin/product/admin_generic_product_delete.xhtml</to-view-id>
+                       <to-view-id>/admin/generic_product/admin_generic_product_delete.xhtml</to-view-id>
                </navigation-case>
        </navigation-rule>
        <!--
index 637991ce505c61fad0a7a99e591e6ea0d4142b15..e7a9fc1c9976002e2115292d4585e66dc44ae9e0 100644 (file)
@@ -23,7 +23,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
        <tag>
                <tag-name>outputProductCategoryAdminMiniLinks</tag-name>
                <description>This tag renders administrative "mini-links" for given category instance.</description>
-               <source>resources/tags/admin/links/mini/category/admin_product_category_links.tpl</source>
+               <source>resources/tags/admin/links/mini/product_category/admin_product_category_links.tpl</source>
                <attribute>
                        <name>category</name>
                        <description>The product category instance that provides the data for this tag.</description>
@@ -46,7 +46,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
        <tag>
                <tag-name>outputGenericProductAdminMiniLinks</tag-name>
                <description>This tag renders administrative "mini-links" for given product instance.</description>
-               <source>resources/tags/admin/links/mini/product/admin_generic_product_links.tpl</source>
+               <source>resources/tags/admin/links/mini/generic_product/admin_generic_product_links.tpl</source>
                <attribute>
                        <name>product</name>
                        <description>The generic product instance that provides the data for this tag.</description>
index c59492d0953a9a165aa8502070b1ed629347f04b..609ca8398d3218bcacca031a69a958170061931c 100644 (file)
@@ -23,7 +23,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
        <tag>
                <tag-name>inputProductPricePanelGrid</tag-name>
                <description>This tag renders input fields for creating a price panel grid for product prices.</description>
-               <source>resources/tags/input/panel_grid/product/product_price_input_panel_grid.tpl</source>
+               <source>resources/tags/input/panel_grid/generic_product/product_price_input_panel_grid.tpl</source>
                <attribute>
                        <name>rendered</name>
                        <description>Whether this tag is being rendered by JSF engine (default: true).</description>
diff --git a/web/WEB-INF/templates/admin/category/admin_form_category_data.tpl b/web/WEB-INF/templates/admin/category/admin_form_category_data.tpl
deleted file mode 100644 (file)
index c4d265c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
-@TODO: title="#{project.ADMIN_PRODUCT_CATEGORY_DATA_LEGEND_TITLE}"
--->
-<ui:composition
-       xmlns="http://www.w3.org/1999/xhtml"
-       xmlns:f="http://xmlns.jcp.org/jsf/core"
-       xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
-       xmlns:p="http://primefaces.org/ui">
-
-       <p:fieldset legend="#{project.ADMIN_PRODUCT_CATEGORY_DATA_LEGEND}">
-               <p:panelGrid layout="grid" columns="2" columnClasses="ui-grid-col-4,ui-grid-col-8" styleClass="table table-full ui-noborder">
-                       <p:outputLabel for="parentCategory" value="#{project.ADMIN_ASSIGN_PARENT_CATEGORY}" />
-                       <p:selectOneMenu
-                               id="parentCategory"
-                               value="#{adminCategoryController.parentCategory}"
-                               filter="true"
-                               filterMatchMode="contains"
-                               title="#{project.ADMIN_ASSIGN_PARENT_CATEGORY_TITLE}"
-                               >
-                               <f:converter converterId="ProductCategoryConverter" />
-                               <f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
-                               <f:selectItems value="#{categoryController.allCategories()}" var="category" itemValue="#{category}" itemLabel="#{beanHelper.renderProductCategory(category)}" />
-                       </p:selectOneMenu>
-
-                       <p:outputLabel for="categoryI18nKey" value="#{project.ADMIN_ENTER_CATEGORY_I18N_KEY}" />
-                       <p:inputText
-                               id="categoryI18nKey"
-                               value="#{adminCategoryController.categoryI18nKey}"
-                               size="10"
-                               maxlength="255"
-                               required="true"
-                               requiredMessage="#{project.ADMIN_CATEGORY_I18N_KEY_REQUIRED}"
-                               title="#{project.ADMIN_ENTER_CATEGORY_I18N_KEY_TITLE}"
-                               />
-
-                       <p:outputLabel for="categoryShownInStatistics" value="#{project.ADMIN_ENABLE_CATEGORY_IN_STATISTICS}" />
-                       <p:selectBooleanCheckbox
-                               id="categoryShownInStatistics"
-                               value="#{adminCategoryController.categoryShownInStatistics}"
-                               required="true"
-                               requiredMessage="#{project.ADMIN_ENABLE_CATEGORY_IN_STATISTICS_REQUIRED}"
-                               title="#{project.ADMIN_ENABLE_CATEGORY_IN_STATISTICS_TITLE}"
-                               />
-               </p:panelGrid>
-       </p:fieldset>
-</ui:composition>
diff --git a/web/WEB-INF/templates/admin/generic_product/admin_form_product_data.tpl b/web/WEB-INF/templates/admin/generic_product/admin_form_product_data.tpl
new file mode 100644 (file)
index 0000000..2587060
--- /dev/null
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+@TODO: title="#{project.ADMIN_GENERIC_PRODUCT_DATA_LEGEND_TITLE}"
+-->
+<ui:composition
+       xmlns="http://www.w3.org/1999/xhtml"
+       xmlns:product="http://mxchange.org/jsf/jproduct/widgets"
+       xmlns:f="http://xmlns.jcp.org/jsf/core"
+       xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+       xmlns:p="http://primefaces.org/ui">
+
+       <p:fieldset legend="#{project.ADMIN_GENERIC_PRODUCT_DATA_LEGEND}">
+               <p:panelGrid layout="grid" columns="2" columnClasses="ui-grid-col-4,ui-grid-col-8" styleClass="table table-full ui-noborder">
+                       <p:outputLabel for="productCategory" value="#{project.ADMIN_ASSIGN_PRODUCT_CATEGORY}" />
+                       <p:selectOneMenu
+                               id="productCategory"
+                               value="#{adminProductController.productCategory}"
+                               filter="true"
+                               filterMatchMode="contains"
+                               required="true"
+                               requiredMessage="#{project.ADMIN_PRODUCT_CATEGORY_REQUIRED}"
+                               title="#{project.ADMIN_ASSIGN_PRODUCT_CATEGORY_TITLE}"
+                               >
+                               <f:converter converterId="ProductCategoryConverter" />
+                               <f:selectItem itemValue="#{null}" itemLabel="#{msg.PLEASE_SELECT}" noSelectionOption="true" itemDisabled="true" />
+                               <f:selectItems value="#{categoryController.allCategories()}" var="category" itemValue="#{category}" itemLabel="#{beanHelper.renderProductCategory(category)}" />
+                       </p:selectOneMenu>
+
+                       <p:outputLabel for="productI18nKey" value="#{project.ADMIN_ENTER_PRODUCT_I18N_KEY}" />
+                       <p:inputText
+                               id="productI18nKey"
+                               value="#{adminProductController.productI18nKey}"
+                               size="10"
+                               maxlength="255"
+                               required="true"
+                               requiredMessage="#{project.ADMIN_PRODUCT_I18N_KEY_REQUIRED}"
+                               title="#{project.ADMIN_ENTER_PRODUCT_I18N_KEY_TITLE}"
+                               />
+
+                       <p:outputLabel for="productAvailability" value="#{project.ADMIN_ENABLE_PRODUCT_AVAILABILITY}" />
+                       <p:selectBooleanCheckbox
+                               id="productAvailability"
+                               value="#{adminProductController.productAvailability}"
+                               required="true"
+                               requiredMessage="#{project.ADMIN_GENERIC_PROJECT_AVAILABILITY_REQUIRED}"
+                               title="#{project.ADMIN_ENABLE_PRODUCT_AVAILABILITY_TITLE}"
+                               />
+
+                       <p:outputLabel value="#{project.ADMIN_ENTER_PRODUCT_PRICE}" />
+                       <product:inputProductPricePanelGrid targetController="#{adminProductController}" />
+
+                       <p:outputLabel for="productCurrencyCode" value="#{project.ADMIN_ENTER_PRODUCT_CURRENCY_CODE}" />
+                       <p:inputText
+                               id="productCurrencyCode"
+                               value="#{adminProductController.productCurrencyCode}"
+                               size="3"
+                               maxlength="3"
+                               title="#{project.ADMIN_ENTER_PRODUCT_CURRENCY_CODE_TITLE}"
+                               />
+
+                       <p:outputLabel for="productUnitAmount" value="#{project.ADMIN_ENTER_PRODUCT_UNIT_AMOUNT}" />
+                       <p:inputNumber
+                               id="productUnitAmount"
+                               value="#{adminProductController.productUnitAmount}"
+                               decimalSeparator=","
+                               thousandSeparator="."
+                               title="#{project.ADMIN_ENTER_PRODUCT_UNIT_AMOUNT_TITLE}"
+                               />
+
+                       <p:outputLabel for="productUnitType" value="#{project.ADMIN_ENTER_PRODUCT_UNIT_TYPE}" />
+                       <p:inputText
+                               id="productUnitType"
+                               value="#{adminProductController.productUnitType}"
+                               size="10"
+                               maxlength="255"
+                               title="#{project.ADMIN_ENTER_PRODUCT_UNIT_TYPE_TITLE}"
+                               />
+               </p:panelGrid>
+       </p:fieldset>
+</ui:composition>
diff --git a/web/WEB-INF/templates/admin/product/admin_form_product_data.tpl b/web/WEB-INF/templates/admin/product/admin_form_product_data.tpl
deleted file mode 100644 (file)
index 2587060..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
-@TODO: title="#{project.ADMIN_GENERIC_PRODUCT_DATA_LEGEND_TITLE}"
--->
-<ui:composition
-       xmlns="http://www.w3.org/1999/xhtml"
-       xmlns:product="http://mxchange.org/jsf/jproduct/widgets"
-       xmlns:f="http://xmlns.jcp.org/jsf/core"
-       xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
-       xmlns:p="http://primefaces.org/ui">
-
-       <p:fieldset legend="#{project.ADMIN_GENERIC_PRODUCT_DATA_LEGEND}">
-               <p:panelGrid layout="grid" columns="2" columnClasses="ui-grid-col-4,ui-grid-col-8" styleClass="table table-full ui-noborder">
-                       <p:outputLabel for="productCategory" value="#{project.ADMIN_ASSIGN_PRODUCT_CATEGORY}" />
-                       <p:selectOneMenu
-                               id="productCategory"
-                               value="#{adminProductController.productCategory}"
-                               filter="true"
-                               filterMatchMode="contains"
-                               required="true"
-                               requiredMessage="#{project.ADMIN_PRODUCT_CATEGORY_REQUIRED}"
-                               title="#{project.ADMIN_ASSIGN_PRODUCT_CATEGORY_TITLE}"
-                               >
-                               <f:converter converterId="ProductCategoryConverter" />
-                               <f:selectItem itemValue="#{null}" itemLabel="#{msg.PLEASE_SELECT}" noSelectionOption="true" itemDisabled="true" />
-                               <f:selectItems value="#{categoryController.allCategories()}" var="category" itemValue="#{category}" itemLabel="#{beanHelper.renderProductCategory(category)}" />
-                       </p:selectOneMenu>
-
-                       <p:outputLabel for="productI18nKey" value="#{project.ADMIN_ENTER_PRODUCT_I18N_KEY}" />
-                       <p:inputText
-                               id="productI18nKey"
-                               value="#{adminProductController.productI18nKey}"
-                               size="10"
-                               maxlength="255"
-                               required="true"
-                               requiredMessage="#{project.ADMIN_PRODUCT_I18N_KEY_REQUIRED}"
-                               title="#{project.ADMIN_ENTER_PRODUCT_I18N_KEY_TITLE}"
-                               />
-
-                       <p:outputLabel for="productAvailability" value="#{project.ADMIN_ENABLE_PRODUCT_AVAILABILITY}" />
-                       <p:selectBooleanCheckbox
-                               id="productAvailability"
-                               value="#{adminProductController.productAvailability}"
-                               required="true"
-                               requiredMessage="#{project.ADMIN_GENERIC_PROJECT_AVAILABILITY_REQUIRED}"
-                               title="#{project.ADMIN_ENABLE_PRODUCT_AVAILABILITY_TITLE}"
-                               />
-
-                       <p:outputLabel value="#{project.ADMIN_ENTER_PRODUCT_PRICE}" />
-                       <product:inputProductPricePanelGrid targetController="#{adminProductController}" />
-
-                       <p:outputLabel for="productCurrencyCode" value="#{project.ADMIN_ENTER_PRODUCT_CURRENCY_CODE}" />
-                       <p:inputText
-                               id="productCurrencyCode"
-                               value="#{adminProductController.productCurrencyCode}"
-                               size="3"
-                               maxlength="3"
-                               title="#{project.ADMIN_ENTER_PRODUCT_CURRENCY_CODE_TITLE}"
-                               />
-
-                       <p:outputLabel for="productUnitAmount" value="#{project.ADMIN_ENTER_PRODUCT_UNIT_AMOUNT}" />
-                       <p:inputNumber
-                               id="productUnitAmount"
-                               value="#{adminProductController.productUnitAmount}"
-                               decimalSeparator=","
-                               thousandSeparator="."
-                               title="#{project.ADMIN_ENTER_PRODUCT_UNIT_AMOUNT_TITLE}"
-                               />
-
-                       <p:outputLabel for="productUnitType" value="#{project.ADMIN_ENTER_PRODUCT_UNIT_TYPE}" />
-                       <p:inputText
-                               id="productUnitType"
-                               value="#{adminProductController.productUnitType}"
-                               size="10"
-                               maxlength="255"
-                               title="#{project.ADMIN_ENTER_PRODUCT_UNIT_TYPE_TITLE}"
-                               />
-               </p:panelGrid>
-       </p:fieldset>
-</ui:composition>
diff --git a/web/WEB-INF/templates/admin/product_category/admin_form_category_data.tpl b/web/WEB-INF/templates/admin/product_category/admin_form_category_data.tpl
new file mode 100644 (file)
index 0000000..c4d265c
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+@TODO: title="#{project.ADMIN_PRODUCT_CATEGORY_DATA_LEGEND_TITLE}"
+-->
+<ui:composition
+       xmlns="http://www.w3.org/1999/xhtml"
+       xmlns:f="http://xmlns.jcp.org/jsf/core"
+       xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+       xmlns:p="http://primefaces.org/ui">
+
+       <p:fieldset legend="#{project.ADMIN_PRODUCT_CATEGORY_DATA_LEGEND}">
+               <p:panelGrid layout="grid" columns="2" columnClasses="ui-grid-col-4,ui-grid-col-8" styleClass="table table-full ui-noborder">
+                       <p:outputLabel for="parentCategory" value="#{project.ADMIN_ASSIGN_PARENT_CATEGORY}" />
+                       <p:selectOneMenu
+                               id="parentCategory"
+                               value="#{adminCategoryController.parentCategory}"
+                               filter="true"
+                               filterMatchMode="contains"
+                               title="#{project.ADMIN_ASSIGN_PARENT_CATEGORY_TITLE}"
+                               >
+                               <f:converter converterId="ProductCategoryConverter" />
+                               <f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
+                               <f:selectItems value="#{categoryController.allCategories()}" var="category" itemValue="#{category}" itemLabel="#{beanHelper.renderProductCategory(category)}" />
+                       </p:selectOneMenu>
+
+                       <p:outputLabel for="categoryI18nKey" value="#{project.ADMIN_ENTER_CATEGORY_I18N_KEY}" />
+                       <p:inputText
+                               id="categoryI18nKey"
+                               value="#{adminCategoryController.categoryI18nKey}"
+                               size="10"
+                               maxlength="255"
+                               required="true"
+                               requiredMessage="#{project.ADMIN_CATEGORY_I18N_KEY_REQUIRED}"
+                               title="#{project.ADMIN_ENTER_CATEGORY_I18N_KEY_TITLE}"
+                               />
+
+                       <p:outputLabel for="categoryShownInStatistics" value="#{project.ADMIN_ENABLE_CATEGORY_IN_STATISTICS}" />
+                       <p:selectBooleanCheckbox
+                               id="categoryShownInStatistics"
+                               value="#{adminCategoryController.categoryShownInStatistics}"
+                               required="true"
+                               requiredMessage="#{project.ADMIN_ENABLE_CATEGORY_IN_STATISTICS_REQUIRED}"
+                               title="#{project.ADMIN_ENABLE_CATEGORY_IN_STATISTICS_TITLE}"
+                               />
+               </p:panelGrid>
+       </p:fieldset>
+</ui:composition>
diff --git a/web/admin/category/admin_product_category_list.xhtml b/web/admin/category/admin_product_category_list.xhtml
deleted file mode 100644 (file)
index 1796183..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<ui:composition template="/WEB-INF/templates/admin/admin_base.tpl"
-                               xmlns="http://www.w3.org/1999/xhtml"
-                               xmlns:product-links="http://mxchange.org/jsf/jproduct/links"
-                               xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
-                               xmlns:h="http://xmlns.jcp.org/jsf/html"
-                               xmlns:f="http://xmlns.jcp.org/jsf/core"
-                               xmlns:p="http://primefaces.org/ui">
-
-       <ui:define name="document_admin_title">
-               <h:outputText value="#{project.PAGE_TITLE_ADMIN_LIST_PRODUCT_CATEGORY}" />
-       </ui:define>
-
-       <ui:define name="content_header">
-               <h:outputText value="#{project.CONTENT_TITLE_ADMIN_LIST_PRODUCT_CATEGORY}" />
-       </ui:define>
-
-       <ui:define name="content">
-               <h:form id="form-list-categories">
-                       <p:dataTable
-                               id="table-list-categories"
-                               var="category"
-                               value="#{categoryController.allCategories()}"
-                               tableStyleClass="table table-full"
-                               paginator="true"
-                               paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
-                               filteredValue="#{categoryController.filteredCategories}"
-                               rows="10"
-                               reflow="true"
-                               resizableColumns="true"
-                               rowsPerPageTemplate="5,10,20,50,100"
-                               sortMode="multiple"
-                               summary="#{project.TABLE_SUMMARY_ADMIN_LIST_PRODUCT_CATEGORIES}"
-                               emptyMessage="#{project.ADMIN_EMPTY_LIST_PRODUCT_CATEGORIES}"
-                               widgetVar="categoryList"
-                               >
-
-                               <f:facet name="header">
-                                       <p:panelGrid columns="2" columnClasses="ui-grid-col-10,ui-grid-col-2" layout="grid" styleClass="ui-noborder ui-transparent-widget">
-                                               <h:outputText value="#{project.ADMIN_LIST_PRODUCT_CATEGORIES_HEADER}" />
-
-                                               <h:panelGroup>
-                                                       <p:commandButton id="toggler" type="button" value="#{msg.SELECT_SHOWN_COLUMNS}" styleClass="column-selector" />
-                                                       <p:columnToggler datasource="table-list-categories" trigger="toggler" />
-                                               </h:panelGroup>
-                                       </p:panelGrid>
-                               </f:facet>
-
-                               <p:column headerText="#{msg.ADMIN_HEADER_ID_NUMBER}" sortBy="#{category.categoryId}" filterable="false">
-                                       <p:link outcome="admin_show_product_category" title="#{project.ADMIN_LINK_SHOW_PRODUCT_CATEGORY_TITLE}" value="#{category.categoryId}">
-                                               <f:param name="categoryId" value="#{category.categoryId}" />
-                                       </p:link>
-                               </p:column>
-
-                               <p:column headerText="#{msg.ADMIN_HEADER_I18N_KEY}" sortBy="#{category.categoryI18nKey}" filterBy="#{category.categoryI18nKey}" filterMatchMode="contains">
-                                       <h:outputText value="#{local[category.categoryI18nKey]}" />
-                               </p:column>
-
-                               <p:column headerText="#{project.ADMIN_HEADER_ASSIGNED_PARENT_CATEGORY}" sortBy="#{category.parentCategory.categoryI18nKey}" filterBy="#{category.parentCategory}" filterMatchMode="in">
-                                       <f:facet name="filter">
-                                               <p:selectCheckboxMenu
-                                                       filter="true"
-                                                       filterMatchMode="contains"
-                                                       label="#{project.LABEL_PRODUCT_CATEGORIES}"
-                                                       onchange="PF('categoryList').filter()"
-                                                       updateLabel="true"
-                                                       title="#{project.FILTER_BY_MULTIPLE_PRODUCT_CATEGORIES_TITLE}"
-                                                       >
-                                                       <f:converter converterId="ProductCategoryConverter" />
-                                                       <f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
-                                                       <f:selectItems value="#{categoryController.allCategories()}" var="category" itemValue="#{category}" itemLabel="#{beanHelper.renderProductCategory(category)}" />
-                                               </p:selectCheckboxMenu>
-                                       </f:facet>
-
-                                       <p:link outcome="admin_show_product_category" title="#{project.ADMIN_LINK_SHOW_PRODUCT_CATEGORY_TITLE}" value="#{category.parentCategory.categoryId}" rendered="#{not empty category.parentCategory}">
-                                               <f:param name="categoryId" value="#{category.parentCategory.categoryId}" />
-                                       </p:link>
-
-                                       <p:link outcome="admin_assign_parent_category" title="#{project.ADMIN_LINK_ASSIGN_PARENT_CATEGORY_TITLE}" value="#{msg.ADMIN_NOT_ASSIGNED}" rendered="#{empty category.parentCategory}">
-                                               <f:param name="categoryId" value="#{category.categoryId}" />
-                                       </p:link>
-                               </p:column>
-
-                               <p:column headerText="#{msg.ADMIN_HEADER_ENTRY_CREATED}" sortBy="#{category.categoryCreated}" filterable="false">
-                                       <h:outputText id="categoryCreated" value="#{category.categoryCreated.time}">
-                                               <f:convertDateTime for="categoryCreated" type="both" timeStyle="short" dateStyle="short" />
-                                       </h:outputText>
-                               </p:column>
-
-                               <p:column headerText="#{msg.ADMIN_HEADER_ACTION_LINKS}" sortable="false" filterable="false">
-                                       <product-links:outputProductCategoryAdminMiniLinks category="#{category}" />
-                               </p:column>
-                       </p:dataTable>
-               </h:form>
-
-               <h:form>
-                       <p:panelGrid columns="1" styleClass="table table-full" layout="grid">
-                               <f:facet name="header">
-                                       <h:outputText value="#{project.ADMIN_ADD_PRODUCT_CATEGORY_TITLE}" />
-                               </f:facet>
-
-                               <h:panelGroup styleClass="para" layout="block">
-                                       <h:outputText value="#{project.ADMIN_ADD_PRODUCT_CATEGORY_MINIMUM_DATA}" />
-                               </h:panelGroup>
-
-                               <ui:include src="/WEB-INF/templates/admin/category/admin_form_category_data.tpl" />
-
-                               <f:facet name="footer">
-                                       <p:panelGrid columns="2" layout="grid">
-                                               <p:commandButton
-                                                       styleClass="reset"
-                                                       type="reset"
-                                                       value="#{msg.BUTTON_RESET_FORM}"
-                                                       />
-
-                                               <p:commandButton
-                                                       styleClass="submit"
-                                                       type="submit"
-                                                       value="#{project.BUTTON_ADMIN_ADD_PRODUCT_CATEGORY}"
-                                                       action="#{adminCategoryController.addCategory()}"
-                                                       update=":master:form-list-categories:table-list-categories"
-                                                       />
-                                       </p:panelGrid>
-                               </f:facet>
-                       </p:panelGrid>
-               </h:form>
-       </ui:define>
-</ui:composition>
diff --git a/web/admin/generic_product/admin_generic_product_list.xhtml b/web/admin/generic_product/admin_generic_product_list.xhtml
new file mode 100644 (file)
index 0000000..9b47ab6
--- /dev/null
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<ui:composition template="/WEB-INF/templates/admin/admin_base.tpl"
+                               xmlns="http://www.w3.org/1999/xhtml"
+                               xmlns:product-links="http://mxchange.org/jsf/jproduct/links"
+                               xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+                               xmlns:h="http://xmlns.jcp.org/jsf/html"
+                               xmlns:f="http://xmlns.jcp.org/jsf/core"
+                               xmlns:p="http://primefaces.org/ui">
+
+       <ui:define name="document_admin_title">
+               <h:outputText value="#{project.PAGE_TITLE_ADMIN_LIST_GENERIC_PRODUCT}" />
+       </ui:define>
+
+       <ui:define name="content_header">
+               <h:outputText value="#{project.CONTENT_TITLE_ADMIN_LIST_GENERIC_PRODUCT}" />
+       </ui:define>
+
+       <ui:define name="content">
+               <h:form id="form-list-products">
+                       <p:dataTable
+                               id="table-list-products"
+                               var="product"
+                               value="#{productController.allProducts()}"
+                               tableStyleClass="table table-full"
+                               paginator="true"
+                               paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
+                               filteredValue="#{productController.filteredProducts}"
+                               rows="10"
+                               reflow="true"
+                               resizableColumns="true"
+                               rowsPerPageTemplate="5,10,20,50,100"
+                               sortMode="multiple"
+                               summary="#{project.TABLE_SUMMARY_ADMIN_LIST_GENERIC_PRODUCTS}"
+                               emptyMessage="#{project.ADMIN_EMPTY_LIST_GENERIC_PRODUCTS}"
+                               widgetVar="productList"
+                               >
+
+                               <f:facet name="header">
+                                       <p:panelGrid columns="2" columnClasses="ui-grid-col-10,ui-grid-col-2" layout="grid" styleClass="ui-noborder ui-transparent-widget">
+                                               <h:outputText value="#{project.ADMIN_LIST_GENERIC_PRODUCTS_HEADER}" />
+
+                                               <h:panelGroup>
+                                                       <p:commandButton id="toggler" type="button" value="#{msg.SELECT_SHOWN_COLUMNS}" styleClass="column-selector" />
+                                                       <p:columnToggler datasource="table-list-products" trigger="toggler" />
+                                               </h:panelGroup>
+                                       </p:panelGrid>
+                               </f:facet>
+
+                               <p:column headerText="#{msg.ADMIN_HEADER_ID_NUMBER}" sortBy="#{product.productId}" filterable="false">
+                                       <p:link outcome="admin_show_generic_product" title="#{project.ADMIN_LINK_SHOW_GENERIC_PRODUCT_TITLE}" value="#{product.productId}">
+                                               <f:param name="productId" value="#{product.productId}" />
+                                       </p:link>
+                               </p:column>
+
+                               <p:column headerText="#{project.ADMIN_HEADER_I18N_KEY}" sortBy="#{product.productI18nKey}" filterBy="#{product.productI18nKey}" filterMatchMode="contains">
+                                       <h:outputText value="#{product.productI18nKey}" />
+                               </p:column>
+
+                               <p:column headerText="#{project.ADMIN_HEADER_ASSIGNED_PRODUCT_CATEGORY}" sortBy="#{product.productCategory.categoryI18nKey}" filterBy="#{product.productCategory}" filterMatchMode="in">
+                                       <f:facet name="filter">
+                                               <p:selectCheckboxMenu
+                                                       filter="true"
+                                                       filterMatchMode="contains"
+                                                       label="#{project.LABEL_PRODUCT_CATEGORIES}"
+                                                       onchange="PF('productList').filter()"
+                                                       updateLabel="true"
+                                                       title="#{project.FILTER_BY_MULTIPLE_PRODUCT_CATEGORIES_TITLE}"
+                                                       >
+                                                       <f:converter converterId="ProductCategoryConverter" />
+                                                       <f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
+                                                       <f:selectItems value="#{categoryController.allCategories()}" var="category" itemValue="#{category}" itemLabel="#{beanHelper.renderProductCategory(category)}" />
+                                               </p:selectCheckboxMenu>
+                                       </f:facet>
+
+                                       <p:link outcome="admin_show_product_category" title="#{project.ADMIN_LINK_SHOW_GENERIC_PRODUCT_CATEGORY_TITLE}" value="#{product.productCategory.categoryId}">
+                                               <f:param name="categoryId" value="#{product.productCategory.categoryId}" />
+                                       </p:link>
+                               </p:column>
+
+                               <p:column headerText="#{project.ADMIN_HEADER_PRODUCT_GROSS_PRICE}" sortBy="#{product.productAvailability}" filterBy="#{product.productGrossPrice}" filterMatchMode="choose">
+                                       <h:outputText value="#{product.productGrossPrice}">
+                                               <!-- @TODO Hard-coded EUR again -->
+                                               <f:convertNumber type="currency" currencyCode="EUR" />
+                                       </h:outputText>
+                               </p:column>
+
+                               <p:column headerText="#{project.ADMIN_HEADER_PRODUCT_AVAILABILITY}" sortBy="#{product.productAvailability}" filterBy="#{product.productAvailability}" filterMatchMode="">
+                                       <h:outputText value="#{product.productAvailability ? msg.CHOICE_YES : msg.CHOICE_NO}" />
+                               </p:column>
+
+                               <p:column headerText="#{msg.ADMIN_HEADER_ENTRY_CREATED}" sortBy="#{product.productCreated}" filterable="false">
+                                       <h:outputText id="productCreated" value="#{product.productCreated.time}">
+                                               <f:convertDateTime for="productCreated" type="both" timeStyle="short" dateStyle="short" />
+                                       </h:outputText>
+                               </p:column>
+
+                               <p:column headerText="#{msg.ADMIN_HEADER_ACTION_LINKS}" sortable="false" filterable="false">
+                                       <product-links:outputGenericProductAdminMiniLinks product="#{product}" />
+                               </p:column>
+                       </p:dataTable>
+               </h:form>
+
+               <h:form>
+                       <p:panelGrid columns="1" styleClass="table table-full" layout="grid">
+                               <f:facet name="header">
+                                       <h:outputText value="#{project.ADMIN_ADD_GENERIC_PRODUCT_TITLE}" />
+                               </f:facet>
+
+                               <h:panelGroup styleClass="para" layout="block">
+                                       <h:outputText value="#{project.ADMIN_ADD_GENERIC_PRODUCT_MINIMUM_DATA}" />
+                               </h:panelGroup>
+
+                               <ui:include src="/WEB-INF/templates/admin/generic_product/admin_form_product_data.tpl" />
+
+                               <f:facet name="footer">
+                                       <p:panelGrid columns="2" layout="grid">
+                                               <p:commandButton
+                                                       styleClass="reset"
+                                                       type="reset"
+                                                       value="#{msg.BUTTON_RESET_FORM}"
+                                                       />
+
+                                               <p:commandButton
+                                                       styleClass="submit"
+                                                       type="submit"
+                                                       value="#{project.BUTTON_ADMIN_ADD_GENERIC_PRODUCT}"
+                                                       action="#{adminProductController.addProduct()}"
+                                                       update=":master:form-list-products:table-list-products"
+                                                       />
+                                       </p:panelGrid>
+                               </f:facet>
+                       </p:panelGrid>
+               </h:form>
+       </ui:define>
+</ui:composition>
diff --git a/web/admin/product/admin_generic_product_list.xhtml b/web/admin/product/admin_generic_product_list.xhtml
deleted file mode 100644 (file)
index bcaa819..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<ui:composition template="/WEB-INF/templates/admin/admin_base.tpl"
-                               xmlns="http://www.w3.org/1999/xhtml"
-                               xmlns:product-links="http://mxchange.org/jsf/jproduct/links"
-                               xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
-                               xmlns:h="http://xmlns.jcp.org/jsf/html"
-                               xmlns:f="http://xmlns.jcp.org/jsf/core"
-                               xmlns:p="http://primefaces.org/ui">
-
-       <ui:define name="document_admin_title">
-               <h:outputText value="#{project.PAGE_TITLE_ADMIN_LIST_GENERIC_PRODUCT}" />
-       </ui:define>
-
-       <ui:define name="content_header">
-               <h:outputText value="#{project.CONTENT_TITLE_ADMIN_LIST_GENERIC_PRODUCT}" />
-       </ui:define>
-
-       <ui:define name="content">
-               <h:form id="form-list-products">
-                       <p:dataTable
-                               id="table-list-products"
-                               var="product"
-                               value="#{productController.allProducts()}"
-                               tableStyleClass="table table-full"
-                               paginator="true"
-                               paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
-                               filteredValue="#{productController.filteredProducts}"
-                               rows="10"
-                               reflow="true"
-                               resizableColumns="true"
-                               rowsPerPageTemplate="5,10,20,50,100"
-                               sortMode="multiple"
-                               summary="#{project.TABLE_SUMMARY_ADMIN_LIST_GENERIC_PRODUCTS}"
-                               emptyMessage="#{project.ADMIN_EMPTY_LIST_GENERIC_PRODUCTS}"
-                               widgetVar="productList"
-                               >
-
-                               <f:facet name="header">
-                                       <p:panelGrid columns="2" columnClasses="ui-grid-col-10,ui-grid-col-2" layout="grid" styleClass="ui-noborder ui-transparent-widget">
-                                               <h:outputText value="#{project.ADMIN_LIST_GENERIC_PRODUCTS_HEADER}" />
-
-                                               <h:panelGroup>
-                                                       <p:commandButton id="toggler" type="button" value="#{msg.SELECT_SHOWN_COLUMNS}" styleClass="column-selector" />
-                                                       <p:columnToggler datasource="table-list-products" trigger="toggler" />
-                                               </h:panelGroup>
-                                       </p:panelGrid>
-                               </f:facet>
-
-                               <p:column headerText="#{msg.ADMIN_HEADER_ID_NUMBER}" sortBy="#{product.productId}" filterable="false">
-                                       <p:link outcome="admin_show_generic_product" title="#{project.ADMIN_LINK_SHOW_GENERIC_PRODUCT_TITLE}" value="#{product.productId}">
-                                               <f:param name="productId" value="#{product.productId}" />
-                                       </p:link>
-                               </p:column>
-
-                               <p:column headerText="#{project.ADMIN_HEADER_I18N_KEY}" sortBy="#{product.productI18nKey}" filterBy="#{product.productI18nKey}" filterMatchMode="contains">
-                                       <h:outputText value="#{product.productI18nKey}" />
-                               </p:column>
-
-                               <p:column headerText="#{project.ADMIN_HEADER_ASSIGNED_PRODUCT_CATEGORY}" sortBy="#{product.productCategory.categoryI18nKey}" filterBy="#{product.productCategory}" filterMatchMode="in">
-                                       <f:facet name="filter">
-                                               <p:selectCheckboxMenu
-                                                       filter="true"
-                                                       filterMatchMode="contains"
-                                                       label="#{project.LABEL_PRODUCT_CATEGORIES}"
-                                                       onchange="PF('productList').filter()"
-                                                       updateLabel="true"
-                                                       title="#{project.FILTER_BY_MULTIPLE_PRODUCT_CATEGORIES_TITLE}"
-                                                       >
-                                                       <f:converter converterId="ProductCategoryConverter" />
-                                                       <f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
-                                                       <f:selectItems value="#{categoryController.allCategories()}" var="category" itemValue="#{category}" itemLabel="#{beanHelper.renderProductCategory(category)}" />
-                                               </p:selectCheckboxMenu>
-                                       </f:facet>
-
-                                       <p:link outcome="admin_show_product_category" title="#{project.ADMIN_LINK_SHOW_GENERIC_PRODUCT_CATEGORY_TITLE}" value="#{product.productCategory.categoryId}">
-                                               <f:param name="categoryId" value="#{product.productCategory.categoryId}" />
-                                       </p:link>
-                               </p:column>
-
-                               <p:column headerText="#{project.ADMIN_HEADER_PRODUCT_GROSS_PRICE}" sortBy="#{product.productAvailability}" filterBy="#{product.productGrossPrice}" filterMatchMode="choose">
-                                       <h:outputText value="#{product.productGrossPrice}">
-                                               <!-- @TODO Hard-coded EUR again -->
-                                               <f:convertNumber type="currency" currencyCode="EUR" />
-                                       </h:outputText>
-                               </p:column>
-
-                               <p:column headerText="#{project.ADMIN_HEADER_PRODUCT_AVAILABILITY}" sortBy="#{product.productAvailability}" filterBy="#{product.productAvailability}" filterMatchMode="">
-                                       <h:outputText value="#{product.productAvailability ? msg.CHOICE_YES : msg.CHOICE_NO}" />
-                               </p:column>
-
-                               <p:column headerText="#{msg.ADMIN_HEADER_ENTRY_CREATED}" sortBy="#{product.productCreated}" filterable="false">
-                                       <h:outputText id="productCreated" value="#{product.productCreated.time}">
-                                               <f:convertDateTime for="productCreated" type="both" timeStyle="short" dateStyle="short" />
-                                       </h:outputText>
-                               </p:column>
-
-                               <p:column headerText="#{msg.ADMIN_HEADER_ACTION_LINKS}" sortable="false" filterable="false">
-                                       <product-links:outputGenericProductAdminMiniLinks product="#{product}" />
-                               </p:column>
-                       </p:dataTable>
-               </h:form>
-
-               <h:form>
-                       <p:panelGrid columns="1" styleClass="table table-full" layout="grid">
-                               <f:facet name="header">
-                                       <h:outputText value="#{project.ADMIN_ADD_GENERIC_PRODUCT_TITLE}" />
-                               </f:facet>
-
-                               <h:panelGroup styleClass="para" layout="block">
-                                       <h:outputText value="#{project.ADMIN_ADD_GENERIC_PRODUCT_MINIMUM_DATA}" />
-                               </h:panelGroup>
-
-                               <ui:include src="/WEB-INF/templates/admin/product/admin_form_product_data.tpl" />
-
-                               <f:facet name="footer">
-                                       <p:panelGrid columns="2" layout="grid">
-                                               <p:commandButton
-                                                       styleClass="reset"
-                                                       type="reset"
-                                                       value="#{msg.BUTTON_RESET_FORM}"
-                                                       />
-
-                                               <p:commandButton
-                                                       styleClass="submit"
-                                                       type="submit"
-                                                       value="#{project.BUTTON_ADMIN_ADD_GENERIC_PRODUCT}"
-                                                       action="#{adminProductController.addProduct()}"
-                                                       update=":master:form-list-products:table-list-products"
-                                                       />
-                                       </p:panelGrid>
-                               </f:facet>
-                       </p:panelGrid>
-               </h:form>
-       </ui:define>
-</ui:composition>
diff --git a/web/admin/product_category/admin_product_category_list.xhtml b/web/admin/product_category/admin_product_category_list.xhtml
new file mode 100644 (file)
index 0000000..884fe1f
--- /dev/null
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<ui:composition template="/WEB-INF/templates/admin/admin_base.tpl"
+                               xmlns="http://www.w3.org/1999/xhtml"
+                               xmlns:product-links="http://mxchange.org/jsf/jproduct/links"
+                               xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+                               xmlns:h="http://xmlns.jcp.org/jsf/html"
+                               xmlns:f="http://xmlns.jcp.org/jsf/core"
+                               xmlns:p="http://primefaces.org/ui">
+
+       <ui:define name="document_admin_title">
+               <h:outputText value="#{project.PAGE_TITLE_ADMIN_LIST_PRODUCT_CATEGORY}" />
+       </ui:define>
+
+       <ui:define name="content_header">
+               <h:outputText value="#{project.CONTENT_TITLE_ADMIN_LIST_PRODUCT_CATEGORY}" />
+       </ui:define>
+
+       <ui:define name="content">
+               <h:form id="form-list-categories">
+                       <p:dataTable
+                               id="table-list-categories"
+                               var="category"
+                               value="#{categoryController.allCategories()}"
+                               tableStyleClass="table table-full"
+                               paginator="true"
+                               paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
+                               filteredValue="#{categoryController.filteredCategories}"
+                               rows="10"
+                               reflow="true"
+                               resizableColumns="true"
+                               rowsPerPageTemplate="5,10,20,50,100"
+                               sortMode="multiple"
+                               summary="#{project.TABLE_SUMMARY_ADMIN_LIST_PRODUCT_CATEGORIES}"
+                               emptyMessage="#{project.ADMIN_EMPTY_LIST_PRODUCT_CATEGORIES}"
+                               widgetVar="categoryList"
+                               >
+
+                               <f:facet name="header">
+                                       <p:panelGrid columns="2" columnClasses="ui-grid-col-10,ui-grid-col-2" layout="grid" styleClass="ui-noborder ui-transparent-widget">
+                                               <h:outputText value="#{project.ADMIN_LIST_PRODUCT_CATEGORIES_HEADER}" />
+
+                                               <h:panelGroup>
+                                                       <p:commandButton id="toggler" type="button" value="#{msg.SELECT_SHOWN_COLUMNS}" styleClass="column-selector" />
+                                                       <p:columnToggler datasource="table-list-categories" trigger="toggler" />
+                                               </h:panelGroup>
+                                       </p:panelGrid>
+                               </f:facet>
+
+                               <p:column headerText="#{msg.ADMIN_HEADER_ID_NUMBER}" sortBy="#{category.categoryId}" filterable="false">
+                                       <p:link outcome="admin_show_product_category" title="#{project.ADMIN_LINK_SHOW_PRODUCT_CATEGORY_TITLE}" value="#{category.categoryId}">
+                                               <f:param name="categoryId" value="#{category.categoryId}" />
+                                       </p:link>
+                               </p:column>
+
+                               <p:column headerText="#{msg.ADMIN_HEADER_I18N_KEY}" sortBy="#{category.categoryI18nKey}" filterBy="#{category.categoryI18nKey}" filterMatchMode="contains">
+                                       <h:outputText value="#{local[category.categoryI18nKey]}" />
+                               </p:column>
+
+                               <p:column headerText="#{project.ADMIN_HEADER_ASSIGNED_PARENT_CATEGORY}" sortBy="#{category.parentCategory.categoryI18nKey}" filterBy="#{category.parentCategory}" filterMatchMode="in">
+                                       <f:facet name="filter">
+                                               <p:selectCheckboxMenu
+                                                       filter="true"
+                                                       filterMatchMode="contains"
+                                                       label="#{project.LABEL_PRODUCT_CATEGORIES}"
+                                                       onchange="PF('categoryList').filter()"
+                                                       updateLabel="true"
+                                                       title="#{project.FILTER_BY_MULTIPLE_PRODUCT_CATEGORIES_TITLE}"
+                                                       >
+                                                       <f:converter converterId="ProductCategoryConverter" />
+                                                       <f:selectItem itemValue="#{null}" itemLabel="#{msg.NONE_SELECTED}" />
+                                                       <f:selectItems value="#{categoryController.allCategories()}" var="category" itemValue="#{category}" itemLabel="#{beanHelper.renderProductCategory(category)}" />
+                                               </p:selectCheckboxMenu>
+                                       </f:facet>
+
+                                       <p:link outcome="admin_show_product_category" title="#{project.ADMIN_LINK_SHOW_PRODUCT_CATEGORY_TITLE}" value="#{category.parentCategory.categoryId}" rendered="#{not empty category.parentCategory}">
+                                               <f:param name="categoryId" value="#{category.parentCategory.categoryId}" />
+                                       </p:link>
+
+                                       <p:link outcome="admin_assign_parent_category" title="#{project.ADMIN_LINK_ASSIGN_PARENT_CATEGORY_TITLE}" value="#{msg.ADMIN_NOT_ASSIGNED}" rendered="#{empty category.parentCategory}">
+                                               <f:param name="categoryId" value="#{category.categoryId}" />
+                                       </p:link>
+                               </p:column>
+
+                               <p:column headerText="#{msg.ADMIN_HEADER_ENTRY_CREATED}" sortBy="#{category.categoryCreated}" filterable="false">
+                                       <h:outputText id="categoryCreated" value="#{category.categoryCreated.time}">
+                                               <f:convertDateTime for="categoryCreated" type="both" timeStyle="short" dateStyle="short" />
+                                       </h:outputText>
+                               </p:column>
+
+                               <p:column headerText="#{msg.ADMIN_HEADER_ACTION_LINKS}" sortable="false" filterable="false">
+                                       <product-links:outputProductCategoryAdminMiniLinks category="#{category}" />
+                               </p:column>
+                       </p:dataTable>
+               </h:form>
+
+               <h:form>
+                       <p:panelGrid columns="1" styleClass="table table-full" layout="grid">
+                               <f:facet name="header">
+                                       <h:outputText value="#{project.ADMIN_ADD_PRODUCT_CATEGORY_TITLE}" />
+                               </f:facet>
+
+                               <h:panelGroup styleClass="para" layout="block">
+                                       <h:outputText value="#{project.ADMIN_ADD_PRODUCT_CATEGORY_MINIMUM_DATA}" />
+                               </h:panelGroup>
+
+                               <ui:include src="/WEB-INF/templates/admin/product_category/admin_form_category_data.tpl" />
+
+                               <f:facet name="footer">
+                                       <p:panelGrid columns="2" layout="grid">
+                                               <p:commandButton
+                                                       styleClass="reset"
+                                                       type="reset"
+                                                       value="#{msg.BUTTON_RESET_FORM}"
+                                                       />
+
+                                               <p:commandButton
+                                                       styleClass="submit"
+                                                       type="submit"
+                                                       value="#{project.BUTTON_ADMIN_ADD_PRODUCT_CATEGORY}"
+                                                       action="#{adminCategoryController.addCategory()}"
+                                                       update=":master:form-list-categories:table-list-categories"
+                                                       />
+                                       </p:panelGrid>
+                               </f:facet>
+                       </p:panelGrid>
+               </h:form>
+       </ui:define>
+</ui:composition>