/* Ara - capture species and specimen data
*
* Copyright (C) 2009 INBio (Instituto Naciona de Biodiversidad)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.inbio.ara.taxonomy;
import com.sun.rave.web.ui.appbase.AbstractPageBean;
import com.sun.webui.jsf.component.Tree;
import com.sun.webui.jsf.component.TreeNode;
import com.sun.webui.jsf.model.Option;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.faces.FacesException;
import javax.faces.context.FacesContext;
import org.inbio.ara.AraSessionBean;
import org.inbio.ara.dto.agent.CollectionDTO;
import org.inbio.ara.dto.inventory.TaxonDTO;
import org.inbio.ara.persistence.taxonomy.TaxonomicalRangeEntity;
import org.inbio.ara.util.MessageBean;
/**
* <p>Page bean that corresponds to EditTaxonomy.jsp. This
* class contains component definitions (and initialization code) for
* all components defined on this page, as well as
* lifecycle methods and event handlers</p>
*
* @version Created on 17/11/2009, 09:53:45 AM
* @author asanabria
*/
public class EditTaxonomy extends AbstractPageBean {
// <editor-fold defaultstate="collapsed" desc="Managed Component Definition">
/**
* <p>Automatically managed component initialization. <strong>WARNING:</strong>
* This method is automatically generated, so any user-specified code inserted
* here is subject to being replaced.</p>
*/
private void _init() throws Exception {
}
// </editor-fold>
private Tree displayTree = new Tree();
// Default Constructor
public EditTaxonomy() {
}
/**
* <p>Callback method that is called whenever a page is navigated to,
* either directly via a URL, or indirectly via page navigation.</p>
*/
@Override
public void init() {
// Perform initializations inherited from our superclass
super.init();
// Perform application initialization that must complete
// *before* managed components are initialized
// TODO - add your own initialiation code here
// <editor-fold defaultstate="collapsed" desc="Managed Component Initialization">
// Initialize automatically managed components
// *Note* - this logic should NOT be modified
try {
_init();
} catch (Exception e) {
log("EditTaxonomy Initialization Failure", e);
throw e instanceof FacesException ? (FacesException) e: new FacesException(e);
}
// </editor-fold>
// Perform application initialization that must complete
// *after* managed components are initialized
// TODO - add your own initialization code here
}
/**
* <p>Callback method that is called after the component tree has been
* restored, but before any event processing takes place.</p>
*/
@Override
public void preprocess() {
}
/**
* <p>Callback method that is called just before rendering takes place.</p>
*/
@Override
public void prerender() {
this.loadCollections();
this.loadTree();
}
/**
* <p>Callback method that is called just after rendering takes place.</p>
*/
@Override
public void destroy() {
}
/**
* update the selected taxon.
* @return null
*/
public String btnUpdateAction(){
TaxonomySessionBean tST = null;
TaxonDTO currentTaxon = null;
String clickedNodeId = null;
String taxonRangeName = null;
tST = this.getTaxonomySessionBean();
// Gets the current selected Tree node item
clickedNodeId = this.displayTree.getSelected();
//If there isn't a selected node
if(clickedNodeId==null){
MessageBean.setErrorMessageFromBundle("not_selected_node",
this.getMyLocale());
return null;
}
// Gets the current taxonDTO
if(tST.getTaxonId() != null){
currentTaxon = tST.getTaxon(tST.getTaxonId());
TreeNode node = this.displayTree.getChildNode(clickedNodeId);
TreeNode parent = Tree.getParentTreeNode(node);
this.updateTaxon(currentTaxon, parent.getText());
//Refresh the Tree
taxonRangeName = tST.getTaxonRangeName(Long.valueOf(currentTaxon.getTaxonomicalRangeId()));
node.setText(currentTaxon.getCurrentName() + " ("+taxonRangeName+")");
this.treeItemClickHandler();
}
return null;
}
/**
* Add a taxon under the currently selected taxon.
* @return null
*/
public String btnAddAction(){
TaxonomySessionBean tST = null;
TaxonDTO currentTaxon = null;
TaxonDTO newTaxon = null;
String clickedNodeId = null;
tST = this.getTaxonomySessionBean();
// Gets the current selected Tree node item
clickedNodeId = this.displayTree.getSelected();
//If there isn't a selected node
if(clickedNodeId==null){
MessageBean.setErrorMessageFromBundle("not_selected_node",
this.getMyLocale());
return null;
}
// Gets the current taxonDTO
if(tST.getTaxonId() != null){
currentTaxon = tST.getTaxon(tST.getTaxonId());
//Validate if the node is an species
if (currentTaxon.getTaxonomicalRangeId().equals
(TaxonomicalRangeEntity.SPECIES.getId())) {
MessageBean.setErrorMessageFromBundle("cant_add_taxon_under_this_level",
this.getMyLocale());
return null;
}
newTaxon = this.saveNewTaxon(currentTaxon);
if(newTaxon == null)
return null;
addTreeItems(clickedNodeId);
this.treeItemClickHandler();
}
return null;
}
/**
* complete the data necesary to create a new Taxon
* @param newTaxon
* @return a TaxonDTO
*/
private TaxonDTO updateTaxon(TaxonDTO updatedTaxon, String parentNodeName){
TaxonomySessionBean tST = null;
String taxonName = null;
String cleanParentName = null;
tST = this.getTaxonomySessionBean();
// create the taxonDTO to create the new TreeNode
updatedTaxon.setAncestorId(updatedTaxon.getAncestorId());
updatedTaxon.setTaxonKey(updatedTaxon.getTaxonKey());
updatedTaxon.setUserName(this.getAraSessionBean().getGlobalUserName());
updatedTaxon.setCollectionId(tST.getSelectedCollection());
updatedTaxon.setCurrentPredecessorTimestamp(updatedTaxon.getCurrentNameTimestamp());
updatedTaxon.setCurrentNameTimestamp(GregorianCalendar.getInstance());
if(updatedTaxon.getTaxonomicalRangeId() == 18){ // specie
cleanParentName = parentNodeName.substring(0, parentNodeName.indexOf(' '));
taxonName = cleanParentName+" "+tST.getTaxonName();
}else{
taxonName = tST.getTaxonName();
}
updatedTaxon.setDefaultName(taxonName);
updatedTaxon.setCurrentName(tST.getTaxonName());
if(updatedTaxon == null){
MessageBean.setErrorMessageFromBundle("cant_add_taxon_under_this_level", this.getMyLocale());
return null;
}
// save the new taxon into the database.
tST.updateTaxon(updatedTaxon);
return updatedTaxon;
}
/**
* complete the data necesary to create a new Taxon
* @param newTaxon
* @return a TaxonDTO
*/
private TaxonDTO saveNewTaxon(TaxonDTO newTaxon){
TaxonomySessionBean tST = null;
String taxonName = null;
tST = this.getTaxonomySessionBean();
// create the taxonDTO to create the new TreeNode
newTaxon.setAncestorId(newTaxon.getTaxonKey());
newTaxon.setTaxonKey(null);
newTaxon.setUserName(this.getAraSessionBean().getGlobalUserName());
newTaxon.setCollectionId(tST.getSelectedCollection());
newTaxon.setCurrentPredecessorTimestamp(newTaxon.getCurrentNameTimestamp());
newTaxon.setCurrentNameTimestamp(GregorianCalendar.getInstance());
newTaxon = this.setFullTaxonomicalAttributes(newTaxon);
if(newTaxon.getTaxonomicalRangeId() == 18){ // specie
taxonName = newTaxon.getCurrentName()+" "+tST.getTaxonName();
}else{
taxonName = tST.getTaxonName();
}
newTaxon.setDefaultName(taxonName);
newTaxon.setCurrentName(tST.getTaxonName());
if(newTaxon == null){
MessageBean.setErrorMessageFromBundle("cant_add_taxon_under_this_level", this.getMyLocale());
return null;
}
// save the new taxon into the database.
tST.saveTaxon(newTaxon);
return newTaxon;
}
/**
* Set the apropiate attribute acordind to the taxonomical range
* @param taxon
* @return the taxon with the atribute set.
*/
private TaxonDTO setFullTaxonomicalAttributes(TaxonDTO taxon){
TaxonomySessionBean tST = null;
Long taxonomicalRangeId = taxon.getTaxonomicalRangeId();
Long ancestorId = taxon.getAncestorId();
//Only Mandatory Levels
switch(taxonomicalRangeId.intValue()){
case 23: // Dominium
taxon.setDominiumTaxonId(ancestorId);
break;
case 18: // Specie
taxon.setSpeciesTaxonId(ancestorId);
break;
case 13: // Genus
taxon.setGenusTaxonId(ancestorId);
break;
case 9: // Family
taxon.setFamilyTaxonId(ancestorId);
break;
case 6: // Order
taxon.setOrderTaxonId(ancestorId);
break;
case 4: // Class
taxon.setClassTaxonId(ancestorId);
break;
case 2: //Phylum or Division
taxon.setPhylumDivisionTaxonId(ancestorId);
break;
case 1: // Kingdom
taxon.setKingdomTaxonId(ancestorId);
break;
}
tST = this.getTaxonomySessionBean();
taxonomicalRangeId =
tST.getNextMandatoryTaxonomicalLevel(
taxon.getTaxonomicalRangeId());
if(taxonomicalRangeId != null)
taxon.setTaxonomicalRangeId(taxonomicalRangeId);
else
taxon = null;
return taxon;
}
/**
* Delete the selected taxon in the tree component
* @return null
*/
public String btnDeleteAction(){
TaxonomySessionBean tST = null;
String clickedNodeId = null;
Long taxonId = null;
tST = this.getTaxonomySessionBean();
clickedNodeId = displayTree.getSelected();
taxonId = tST.getTaxonId();
//If there isn't a selected node
if(clickedNodeId==null){
MessageBean.setErrorMessageFromBundle("not_selected_node",
this.getMyLocale());
return null;
}
//The root element canot be deleted
if (tST.getTaxon(taxonId).getTaxonomicalRangeId().equals
(TaxonomicalRangeEntity.ROOT.getId())) {
MessageBean.setErrorMessageFromBundle("cant_delete_root_element",
this.getMyLocale());
return null;
}
// Verify that TreeNode doesn't have children
if (tST.getTaxonChildrenCount(taxonId) <= 0) {
// Check if taxon has associated nomencalturalgroups
if(tST.getAssociatedNumenclaturalG(taxonId) > 0L){
MessageBean.setErrorMessageFromBundle("has_associated_nomenclatural",
this.getMyLocale());
return null;
}
// Verify if the taxon doesn't has related specimens
if (tST.getAssociatedSpecimenCount(taxonId) <= 0) {
//Proceed to delete the node
try {
tST.removeTaxon(taxonId);
} catch (Exception e) {
MessageBean.setErrorMessageFromBundle("imposible_to_delete",
this.getMyLocale());
return null;
}
//Refresh the Tree
TreeNode node = this.displayTree.getChildNode(clickedNodeId);
TreeNode parent = TreeNode.getParentTreeNode(node);
parent.getChildren().clear();
this.displayTree.setSelected(parent.getId());
this.addTreeItems(parent.getId());
this.treeItemClickHandler();
} else { //The node has associated specimens
MessageBean.setErrorMessageFromBundle("has_associated_specimen",
this.getMyLocale());
}
} else { //The node has children
MessageBean.setErrorMessageFromBundle("has_children",
this.getMyLocale());
}
return null;
}
/**
* Load all the available collections in the dropdown of the jsp page.
*/
private void loadCollections(){
// convert the list from List<CollectionDTO> to Option[]
TaxonomySessionBean tST = this.getTaxonomySessionBean();
List<CollectionDTO> collections = tST.getAllCollections();
List<Option> temp = new ArrayList<Option>();
Option anOption = null;
for( CollectionDTO aCDTO : collections){
anOption = new Option();
anOption.setValue(aCDTO.getCollectionId());
anOption.setLabel(aCDTO.getCollectionName());
temp.add(anOption);
}
// set the available collections
tST.setAvailableCollections(temp.toArray(new Option[temp.size()]));
}
/**
* Load taxonomical hierarchy data to the taxonomical tree in the jsp page
*/
private void loadTree(){
TreeNode newNode = null;
TaxonomySessionBean tST = null;
List<TaxonDTO> taxonDTOList = null;
String treeNodeId = null;
if(this.displayTree.getChildCount() <= 0){
tST = this.getTaxonomySessionBean();
// look for the dominium level taxon
taxonDTOList = tST.getAllTaxonByRange(0L);
for(TaxonDTO taxonDTO : taxonDTOList){
treeNodeId = "i-"+taxonDTO.getTaxonomicalRangeId()
+"-"
+taxonDTO.getTaxonKey();
newNode = createNode(treeNodeId, taxonDTO.getCurrentName());
displayTree.getChildren().add(newNode);
}
}
}
/**
* Create a TreeNode Class with the information privided as parameters.
* @param id : taxon id.
* @param name : taxon name
* @return TreeNode
*/
private TreeNode createNode(String id, String name){
ELContext elContext = null;
ExpressionFactory expressionFactory = null;
MethodExpression actionMethod = null;
TreeNode aNode = null;
// create the action method to every node in the tree.
elContext = FacesContext.getCurrentInstance().getELContext();
expressionFactory = this.getApplication().getExpressionFactory();
actionMethod =
expressionFactory.createMethodExpression(
elContext
, "#{taxonomy$EditTaxonomy.treeItemClickHandler}"
, String.class
, new Class[] {});
// Create the note to add
aNode = new TreeNode();
aNode.setId(id);
aNode.setText(name);
aNode.setActionExpression(actionMethod);
aNode.setVisible(true);
return aNode;
}
/**
* Click event handler for the Tree items
* @return null
*/
public String treeItemClickHandler(){
String clickedNodeId = null;
clickedNodeId = this.displayTree.getSelected();
if(clickedNodeId != null && !clickedNodeId.isEmpty()){
// expand the tree item to show the new added nodes
addTreeItems(clickedNodeId);
/* sets the data from the selected treeNode to the form display
* form
*/
setDisplayData(clickedNodeId);
}
return null;
}
/**
* takes the data from the taxon and set it to the from.
* @param clickedNodeId
*/
private void setDisplayData(String clickedNodeId){
TaxonomySessionBean tST = null;
String[] clickedNodeInfo = null;
String taxonomicalRangeName = null;
TaxonDTO taxonDTO = null;
/**
* results spected in this order:
* [1] hierarchy level
* [2] taxon id
*/
clickedNodeInfo = clickedNodeId.split("-");
// load the SessionBean to comunicate with the facade
tST = this.getTaxonomySessionBean();
// Gets the information
taxonDTO = tST.getTaxon(Long.valueOf(clickedNodeInfo[2]));
taxonomicalRangeName = tST.getTaxonRangeName(taxonDTO.getTaxonomicalRangeId());
// Sets the information
tST.setTaxonId(taxonDTO.getTaxonKey());
tST.setTaxonName(taxonDTO.getCurrentName());
tST.setTaxonomicalLevel(taxonomicalRangeName);
tST.setSelectedCollection(taxonDTO.getCollectionId());
}
/**
* Expand a TreeItem according to the taxonId
* @param taxonId
*/
private void addTreeItems(String clickedNodeId) {
TaxonomySessionBean tST = null;
String[] clickedNodeInfo = null;
List<TaxonDTO> taxonChildren = null;
TreeNode currentNode = null;
/**
* results spected in this order:
* [1] hierarchy level
* [2] taxon id
*/
clickedNodeInfo = clickedNodeId.split("-");
// load the SessionBean to comunicate with the facade
tST = this.getTaxonomySessionBean();
// converts the taxon children into TreeNode and append it to the tree
currentNode = this.displayTree.getChildNode(clickedNodeId);
/*look for the taxa under the current taxon according to the
* taxonomical hierarchy
*/
taxonChildren = tST.getTaxonChildren(Long.valueOf(clickedNodeInfo[2]));
// add the provided nodes to the current node
addNewChildList(currentNode, taxonChildren);
}
/**
* Convert a taxon list into TreeNodes and add it at the end of the
* currentNode children list.
* @param currentNode
* @param taxonList
*/
private void addNewChildList(TreeNode currentNode, List<TaxonDTO> taxonList){
TaxonomySessionBean tST = null;
TreeNode newNode = null;
String treeNodeKey = null;
String taxonRangeId = null;
String taxonRangeName = null;
String treeNodeDisplayName = null;
// load the SessionBean to comunicate with the facade
tST = this.getTaxonomySessionBean();
/*
* 1. Iterates over the retrieved taxa
* 2. convert every taxon into a TreeNode Object
* 3. add the new TreeNode to the displayTree
*/
for(TaxonDTO currentTaxon : taxonList ){
newNode = new TreeNode();
taxonRangeId = currentTaxon.getTaxonomicalRangeId().toString();
taxonRangeName = tST.getTaxonRangeName(Long.valueOf(taxonRangeId));
treeNodeDisplayName =
currentTaxon.getCurrentName() + " ("+taxonRangeName+") ";
treeNodeKey = "i-"+taxonRangeId
+"-"
+currentTaxon.getTaxonKey();
/* look if the treeNodeKey already exist in the tree
* if not, creates the newNode an add it to the Tree.
*/
if(this.displayTree.getChildNode(treeNodeKey) == null){
newNode = this.createNode(treeNodeKey, treeNodeDisplayName);
currentNode.getChildren().add(newNode);
}
}
}
/**
* Return the Session bean corresponding to this module;
* @return TaxonomySessionBean
*/
protected TaxonomySessionBean getTaxonomySessionBean() {
return (TaxonomySessionBean) getBean("taxonomy$TaxonomySessionBean");
}
/*
* Return the Application bean corresponding to the ara software
* @return reference to the Ara application bean
*/
protected AraSessionBean getAraSessionBean() {
return (AraSessionBean) getBean("AraSessionBean");
}
/**
* @return the myLocale
*/
public Locale getMyLocale() {
return this.getAraSessionBean().getCurrentLocale();
}
/** Getters and Setters */
public Tree getDisplayTree() {
return displayTree;
}
public void setDisplayTree(Tree displayTree) {
this.displayTree = displayTree;
}
}