/**
* Serial number
*/
- private static final long serialVersionUID = 542_145_347_916L;
+ private static final long serialVersionUID = 542_145_351_001L;
/**
* Academic academicTitle
/**
* Serial number
*/
- private static final long serialVersionUID = 542_145_347_916L;
+ private static final long serialVersionUID = 542_145_352_001L;
/**
* Academic academicTitle
/**
* Serial number
*/
- private static final long serialVersionUID = 542_145_347_916L;
+ private static final long serialVersionUID = 542_145_353_001L;
/**
* An instance of a contact-list controller
/**
* Serial number
*/
- private static final long serialVersionUID = 542_145_347_916L;
+ private static final long serialVersionUID = 542_145_354_001L;
/**
* Administrative EJB for phone number
/**
* Serial number
*/
- private static final long serialVersionUID = 542_145_347_916L;
+ private static final long serialVersionUID = 542_145_355_001L;
/**
* An instance of a contact-list controller
--- /dev/null
+/*
+ * Copyright (C) 2017 - 2022 Free Software Foundation
+ *
+ * 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.jjobs.beans.jobs.skill.list;
+
+import fish.payara.cdi.jsr107.impl.NamedCache;
+import java.text.MessageFormat;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.cache.Cache;
+import javax.ejb.EJB;
+import javax.enterprise.event.Observes;
+import javax.faces.view.ViewScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.mxchange.jjobs.beans.BaseJobsBean;
+import org.mxchange.jjobs.events.skill.add.ObservableAdminAddedSkillEvent;
+import org.mxchange.jjobs.model.exceptions.SkillNotFoundException;
+import org.mxchange.jjobs.model.skill.SkillSessionBeanRemote;
+import org.mxchange.jjobs.model.skill.Skillable;
+
+/**
+ * A view-scoped bean for product lists
+ * <p>
+ * @author Roland Haeder<roland@mxchange.org>
+ */
+@Named ("skillListController")
+@ViewScoped
+public class JobsSkillListWebViewBean extends BaseJobsBean implements JobsSkillListWebViewController {
+
+ /**
+ * Serial number
+ */
+ private static final long serialVersionUID = 34_869_872_672_645L;
+
+ /**
+ * List of all basic company data
+ */
+ private final List<Skillable> allSkills;
+
+ /**
+ * List of filtered basic company data
+ */
+ private List<Skillable> filteredSkills;
+
+ /**
+ * Selected basic data
+ */
+ private Skillable selectedSkill;
+
+ /**
+ * EJB for general basic business data purposes
+ */
+ @EJB (lookup = "java:global/jjobs-ejb/skill!org.mxchange.jjobs.model.skill.SkillSessionBeanRemote", description = "A stateless session bean for skills")
+ private SkillSessionBeanRemote skillBean;
+
+ /**
+ * A list of all registered companies (globally)
+ */
+ @Inject
+ @NamedCache (cacheName = "skillCache")
+ private transient Cache<Long, Skillable> skillCache;
+
+ /**
+ * Default constructor
+ */
+ public JobsSkillListWebViewBean () {
+ // Call super constructor
+ super();
+
+ // Init list
+ this.allSkills = new LinkedList<>();
+ }
+
+ /**
+ * Observers events being fired when an administrator has added company
+ * basic data.
+ * <p>
+ * @param event Event being fired
+ */
+ public void afterAdminAddedBasicCompanyDataEvent (@Observes final ObservableAdminAddedSkillEvent event) {
+ // Is the parameter valid?
+ if (null == event) {
+ // Throw NPE
+ throw new NullPointerException("event is null"); //NOI18N
+ } else if (event.getSkillable() == null) {
+ // Throw NPE again
+ throw new NullPointerException("event.skillableis null"); //NOI18N
+ } else if (event.getSkillable().getSkillId() == null) {
+ // Throw NPE again
+ throw new NullPointerException("event.skillable.skillId is null"); //NOI18N
+ } else if (event.getSkillable().getSkillId() < 1) {
+ // Throw IAE
+ throw new IllegalArgumentException(MessageFormat.format("event.skillable.skillId={0} is invalid", event.getSkillable().getSkillId())); //NOI18N
+ } else if (event.getSkillable().getSkillName() == null) {
+ // Throw NPE again
+ throw new NullPointerException("event.skillable.skillName is null"); //NOI18N
+ } else if (event.getSkillable().getSkillName().isEmpty()) {
+ // Throw IAE again
+ throw new IllegalArgumentException("event.skillable.skillName is empty"); //NOI18N
+ }
+
+ // Add it to list
+ this.skillCache.put(event.getSkillable().getSkillId(), event.getSkillable());
+ this.getAllSkills().add(event.getSkillable());
+ }
+
+ @Override
+ public Skillable findSkillById (final Long skillId) throws SkillNotFoundException {
+ // Validate parameter
+ if (null == skillId) {
+ // Throw NPE
+ throw new NullPointerException("skillId is null"); //NOI18N
+ } else if (skillId < 1) {
+ // Throw IAE
+ throw new IllegalArgumentException(MessageFormat.format("skillId={0} is invalid", skillId)); //NOI18N
+ } else if (!this.skillCache.containsKey(skillId)) {
+ // Not found
+ throw new SkillNotFoundException(skillId);
+ }
+
+ // Get it from cache
+ final Skillable skill = this.skillCache.get(skillId);
+
+ // Return it
+ return skill;
+ }
+
+ /**
+ * Getter for a list of all business contacts
+ * <p>
+ * @return A list of all business contacts
+ */
+ @SuppressWarnings ("ReturnOfCollectionOrArrayField")
+ public List<Skillable> getAllSkills () {
+ return this.allSkills;
+ }
+
+ /**
+ * Getter for filtered basic company data
+ * <p>
+ * @return Filtered basic company data
+ */
+ @SuppressWarnings ("ReturnOfCollectionOrArrayField")
+ public List<Skillable> getFilteredSkills () {
+ return this.filteredSkills;
+ }
+
+ /**
+ * Setter for filtered basic company data
+ * <p>
+ * @param filteredSkills Filtered basic company data
+ */
+ @SuppressWarnings ("AssignmentToCollectionOrArrayFieldFromParameter")
+ public void setFilteredSkills (final List<Skillable> filteredSkills) {
+ this.filteredSkills = filteredSkills;
+ }
+
+ /**
+ * Getter for selected basic data
+ * <p>
+ * @return Selected basic data
+ */
+ public Skillable getSelectedSkill () {
+ return this.selectedSkill;
+ }
+
+ /**
+ * Setter for selected basic data
+ * <p>
+ * @param selectedSkill Selected basic data
+ */
+ public void setSelectedSkill (final Skillable selectedSkill) {
+ this.selectedSkill = selectedSkill;
+ }
+
+ /**
+ * Initializer method
+ */
+ @PostConstruct
+ public void initializeList () {
+ // Is cache there?
+ if (!this.skillCache.iterator().hasNext()) {
+ // Add all
+ for (final Skillable skill : this.skillBean.fetchAllSkills()) {
+ // Add it to cache
+ this.skillCache.put(skill.getSkillId(), skill);
+ }
+ }
+
+ // Is cache there and list is not full?
+ if ((this.getAllSkills().isEmpty()) && (this.skillCache.iterator().hasNext())) {
+ // Build up list
+ for (final Cache.Entry<Long, Skillable> currentEntry : this.skillCache) {
+ // Add to list
+ this.getAllSkills().add(currentEntry.getValue());
+ }
+
+ // Sort list
+ this.getAllSkills().sort(new Comparator<Skillable>() {
+ @Override
+ public int compare (final Skillable skill1, final Skillable skill2) {
+ return skill1.getSkillId() > skill2.getSkillId() ? 1 : skill1.getSkillId() < skill2.getSkillId() ? -1 : 0;
+ }
+ });
+
+ // Set full list
+ this.setFilteredSkills(this.getAllSkills());
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2022 Free Software Foundation
+ *
+ * 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.jjobs.beans.jobs.skill.list;
+
+import java.io.Serializable;
+import org.mxchange.jjobs.model.exceptions.SkillNotFoundException;
+import org.mxchange.jjobs.model.skill.Skillable;
+
+/**
+ * An interface of basic data list backing beans
+ * <p>
+ * @author Roland Häder<roland@mxchange.org>
+ */
+public interface JobsSkillListWebViewController extends Serializable {
+
+ /**
+ * Retrieves a single skill entity for given id number or throws a proper
+ * exception if not found.
+ * <p>
+ * @param skillId Company basic data id to lookup
+ * <p>
+ * @return Skillinstance
+ * <p>
+ * @throws SkillNotFoundException If the id number could not be looked up
+ * and solved into an entity
+ */
+ Skillable findSkillById (final Long skillId) throws SkillNotFoundException;
+
+}
/**
* Serial number
*/
- private static final long serialVersionUID = 542_145_347_916L;
+ private static final long serialVersionUID = 542_145_356_001L;
/**
* An event fired when the administrator has added a new user
/**
* Serial number
*/
- private static final long serialVersionUID = 542_145_347_916L;
+ private static final long serialVersionUID = 542_145_357_001L;
/**
* Default constructor
<from-outcome>admin_list_contact_mobile</from-outcome>
<to-view-id>/admin/mobile/admin_contact_mobile_list.xhtml</to-view-id>
</navigation-case>
+ <navigation-case>
+ <from-outcome>admin_list_skills</from-outcome>
+ <to-view-id>/admin/jobs/skill/admin_skill_list.xhtml</to-view-id>
+ </navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/user/login_index.xhtml</from-view-id>
<?xml version="1.0" encoding="UTF-8" ?>
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
- xmlns:f="http://xmlns.jcp.org/jsf/core"
- xmlns:h="http://xmlns.jcp.org/jsf/html"
- xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
+ xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+ xmlns:p="http://primefaces.org/ui"
+ >
- <!-- Put your stuff here //-->
+ <p:submenu label="#{project.ADMIN_MENU_SKILLS_TITLE}" expanded="false">
+ <p:menuitem title="#{project.ADMIN_LINK_LIST_SKILLS_TITLE}" outcome="admin_list_skills" value="#{project.ADMIN_LINK_LIST_SKILLS}" />
+ </p:submenu>
</ui:composition>
--- /dev/null
+<?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: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"
+ xmlns:core="http://mxchange.org/jsf/core/widgets"
+ xmlns:validator="http://mxchange.org/jsf/core/validators"
+ >
+
+ <ui:define name="document_admin_title">
+ <h:outputText value="#{msg.PAGE_TITLE_ADMIN_LIST_SKILLS}" />
+ </ui:define>
+
+ <ui:define name="content_header">
+ <h:outputText value="#{msg.CONTENT_TITLE_ADMIN_LIST_SKILLS}" />
+ </ui:define>
+
+ <ui:define name="content">
+ <h:form id="form-list-skill">
+ <p:dataTable
+ id="skillList"
+ var="skill"
+ value="#{skillListController.allSkills}"
+ paginator="true"
+ paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
+ filteredValue="#{skillListController.filteredSkills}"
+ rows="10"
+ rowKey="#{skill.skillId}"
+ reflow="true"
+ resizableColumns="true"
+ rowsPerPageTemplate="5,10,20,50,100"
+ sortMode="multiple"
+ summary="#{msg.TABLE_SUMMARY_ADMIN_LIST_SKILLS}"
+ emptyMessage="#{msg.ADMIN_EMPTY_LIST_SKILLS}"
+ widgetVar="skillList"
+ selectionMode="single"
+ selection="#{skillListController.selectedSkill}"
+ skipChildren="true"
+ >
+
+ <f:facet name="header">
+ <p:panelGrid
+ columns="3"
+ layout="grid"
+ columnClasses="ui-grid-col-4,ui-grid-col-6,ui-grid-col-2"
+ >
+ <p:spacer />
+
+ <p:panelGrid
+ columns="2"
+ columnClasses="ui-grid-4,ui-grid-8"
+ layout="grid"
+ styleClass="ui-noborder"
+ >
+ <p:outputLabel
+ for="globalFilter"
+ value="#{msg.SEARCH_ALL_FIELDS}"
+ style="float: right"
+ />
+
+ <p:inputText
+ id="globalFilter"
+ onkeyup="PF('skillList').filter()"
+ placeholder="#{msg.ENTER_KEYWORD}"
+ />
+ </p:panelGrid>
+
+ <p:outputPanel>
+ <p:spacer height="4" />
+
+ <p:commandButton
+ id="toggler"
+ type="button"
+ value="#{msg.SELECT_SHOWN_COLUMNS}"
+ styleClass="column-selector"
+ />
+
+ <p:columnToggler datasource="skillList" trigger="toggler" />
+ </p:outputPanel>
+ </p:panelGrid>
+ </f:facet>
+
+ <p:ajax
+ event="rowSelect"
+ update="form-list-skill:skill-details"
+ oncomplete="PF('skillDialog').show()"
+ />
+
+ <p:column
+ headerText="#{msg.ID_HEADER}"
+ sortBy="#{skill.skillId}"
+ filterable="false"
+ >
+ <p:link
+ outcome="admin_show_basic_data"
+ value="#{skill.skillId}"
+ title="#{msg.ADMIN_LINK_SHOW_SKILL_TITLE}"
+ >
+ <f:param name="skillId" value="#{skill.skillId}" />
+ </p:link>
+ </p:column>
+
+ <p:column
+ headerText="#{msg.ADMIN_SKILL_NAME_HEADER}"
+ sortBy="#{skill.skillName}"
+ filterBy="#{skill.skillName}"
+ filterMatchMode="contains"
+ >
+ <h:outputText value="#{skill.skillName}"/>
+ </p:column>
+
+ <p:column
+ headerText="#{msg.ADMIN_SKILL_STATUS_HEADER}"
+ sortBy="#{skill.skillStatus}"
+ filterBy="#{skill.skillStatus}"
+ filterMatchMode="in"
+ >
+ <h:outputText value="#{project[skill.skillStatus.messageKey]}"/>
+ </p:column>
+
+ <p:column
+ headerText="#{msg.ADMIN_SKILL_LAST_LOCKED_HEADER}"
+ sortBy="#{skill.skillLastLocked}"
+ filterBy="#{skill.skillLastLocked}"
+ filterMatchMode="contains"
+ >
+ <h:outputText value="#{skill.skillLastLocked}">
+ <f:convertDateTime type="both" timeStyle="short" dateStyle="short" />
+ </h:outputText>
+ </p:column>
+
+ <p:column
+ headerText="#{msg.ENTRY_CREATED_HEADER}"
+ sortBy="#{skill.skillEntryCreated}"
+ filterBy="#{skill.skillEntryCreated}"
+ filterMatchMode="contains"
+ >
+ <h:outputText value="#{skill.skillEntryCreated}">
+ <f:convertDateTime type="both" timeStyle="short" dateStyle="short" />
+ </h:outputText>
+ </p:column>
+
+ <p:column
+ headerText="#{msg.ENTRY_UPDATED_HEADER}"
+ sortBy="#{skill.skillEntryUpdated}"
+ filterBy="#{skill.skillEntryUpdated}"
+ filterMatchMode="contains"
+ >
+ <h:outputText value="#{skill.skillEntryUpdated}">
+ <f:convertDateTime type="both" timeStyle="short" dateStyle="short" />
+ </h:outputText>
+ </p:column>
+
+ <p:column
+ headerText="#{msg.ADMIN_ACTION_LINKS_HEADER}"
+ sortable="false"
+ filterable="false"
+ >
+ <p:menuButton value="#{msg.OPTIONS}">
+ <p:menuitem
+ outcome="admin_show_basic_data"
+ value="#{msg.ADMIN_LINK_SHOW_SHORT}"
+ title="#{msg.ADMIN_LINK_SHOW_SKILL_TITLE}"
+ >
+ <f:param name="skillId" value="#{skill.skillId}" />
+ </p:menuitem>
+
+ <p:menuitem
+ outcome="admin_edit_basic_data"
+ value="#{msg.ADMIN_LINK_EDIT_SHORT}"
+ title="#{msg.ADMIN_LINK_EDIT_SKILL_TITLE}"
+ >
+ <f:param name="skillId" value="#{skill.skillId}" />
+ </p:menuitem>
+
+ <p:menuitem outcome="admin_delete_basic_data">
+ <h:outputText
+ styleClass="link-danger"
+ value="#{msg.ADMIN_LINK_DELETE_SHORT}"
+ title="#{msg.ADMIN_LINK_DELETE_SKILL_TITLE}"
+ />
+ <f:param name="skillId" value="#{skill.skillId}" />
+ </p:menuitem>
+ </p:menuButton>
+ </p:column>
+ </p:dataTable>
+
+ <p:dialog
+ dynamic="true"
+ modal="true"
+ resizable="false"
+ header="#{msg.ADMIN_SINGLE_SKILL_DETAILS_HEADER}"
+ hideEffect="fade"
+ showEffect="fade"
+ widgetVar="skillDialog"
+ position="top"
+ responsive="true"
+ closeOnEscape="true"
+ >
+ <p:outputPanel id="skill-details">
+ <p:panelGrid columns="2" rendered="#{not empty skillListController.selectedSkill}">
+ <f:facet name="header">
+ <h:outputFormat value="#{msg.ADMIN_SKILL_DETAILS_HEADER}">
+ <f:param value="#{skillListController.selectedSkill.skillName}" />
+ <f:param value="#{skillListController.selectedSkill.skillId}" />
+ </h:outputFormat>
+ </f:facet>
+
+ <p:outputLabel value="#{msg.ID_HEADER}" title="#{msg.SKILL_ID_NUMBER_TITLE}" />
+ <h:outputText value="#{skillListController.selectedSkill.skillId}" />
+ </p:panelGrid>
+ </p:outputPanel>
+ </p:dialog>
+ </h:form>
+
+ <h:form>
+ <p:panelGrid
+ columns="1"
+ layout="grid"
+ >
+ <f:facet name="header">
+ <h:outputText value="#{msg.ADMIN_ADD_SKILL_TITLE}" />
+ </f:facet>
+
+ <h:panelGroup styleClass="para" layout="block">
+ <h:outputText value="#{msg.ADMIN_ADD_SKILL_MINIMUM_DATA}" />
+ </h:panelGroup>
+
+ <h:panelGroup styleClass="para" layout="block">
+ <p:fieldset legend="#{msg.ADMIN_SKILL_LEGEND}">
+ <p:panelGrid
+ columns="2"
+ columnClasses="ui-grid-col-4,ui-grid-col-8"
+ styleClass="ui-noborder"
+ >
+ <p:outputLabel for="skillName" value="#{msg.ADMIN_SKILL_NAME}" />
+ <p:inputText
+ id="skillName"
+ value="#{adminSkillController.skillName}"
+ size="20"
+ maxlength="100"
+ required="true"
+ requiredMessage="#{msg.ADMIN_SKILL_NAME_REQUIRED}"
+ >
+ </p:inputText>
+ </p:panelGrid>
+ </p:fieldset>
+ </h:panelGroup>
+
+ <f:facet name="footer">
+ <p:panelGrid columns="2" layout="grid">
+ <p:commandButton
+ type="reset"
+ value="#{msg.BUTTON_RESET_FORM}"
+ />
+
+ <p:commandButton
+ type="submit"
+ value="#{msg.BUTTON_ADMIN_ADD_SKILL}"
+ action="#{adminSkillController.addSkill()}"
+ update="form-list-skill:skillList"
+ />
+ </p:panelGrid>
+ </f:facet>
+ </p:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>