/*
* Embedded Jopr Project
* Copyright (C) 2006-2009 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.jboss.on.embedded.ui;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import org.jetbrains.annotations.NotNull;
import org.rhq.core.domain.measurement.Availability;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.DisplayType;
import org.rhq.core.domain.measurement.MeasurementData;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.on.embedded.bean.MeasurementDisplay;
import org.jboss.on.embedded.bean.MeasurementUtils;
import org.jboss.on.embedded.bean.ResourceListItem;
import org.jboss.on.embedded.manager.ResourceManager;
import org.jboss.on.embedded.manager.ResourceManagerFactory;
import org.jboss.on.embedded.ui.nav.BaseTreeNode;
import org.jboss.on.embedded.ui.nav.JONTreeNode;
import org.jboss.on.embedded.ui.nav.NonSingletonResourceTypeTreeNode;
import org.jboss.on.embedded.ui.nav.SubCategoryTreeNode;
/**
* The Seam component that backs all three Summary tab pages:
* <ul>
* <li>/secure/resourceInstanceSummary.xhtml
* <li>/secure/resourceTypeSummary.xhtml
* <li>/secure/categorySummary.xhtml
* </ul>
*
* @author Jessica Sant
*/
@Name("summaryAction")
@Scope(ScopeType.EVENT)
public class SummaryAction
{
@In
private transient FacesMessages facesMessages;
/**
* the subCategory that was selected based on the path request parameter
*/
@Out(required = false, scope = ScopeType.PAGE)
private SubCategoryTreeNode subCategory;
/**
* the resourceType that was selected based on the path request parameter
*/
@Out(required = false, scope = ScopeType.PAGE)
private ResourceType resourceType;
/**
* the resource that was selected based on the path request parameter
*/
@Out(required = false)
private ResourceListItem resource;
/**
* all measurement data for this resource marked with the "summary" displayType
*/
@Out(required = false)
private List<MeasurementDisplay> summaryMeasurementDisplayList;
@Out(required = false)
Map<String, MeasurementDefinition> summaryMeasurementDefinitionMap;
/**
* list of all traits for this resource
*/
@Out(required = false)
private List<MeasurementDisplay> summaryTraitDisplayList;
// TODO why dont we have a summaryTraitDefinitionMap?
/**
* the list of resources that belong to this category or resourceType
*/
@Out(required = false, scope = ScopeType.PAGE)
private List<ResourceListItem> resources;
@In(value = "#{navigationAction}")
private NavigationAction navigationAction;
private String resourceTypeFilter;
/**
* determines which summary page should be displayed, based on the current navigation node
*
* @return an outcome indicating which summary page to display.
*/
public String view()
{
// TODO could consider renaming this getCurrentNavigationNode()
JONTreeNode selectedNode = navigationAction.getSelectedNode();
return selectedNode.getSummaryActionOutcome(this).getOutcome();
}
public interface SummaryActionOutcome
{
public String getOutcome();
}
public class ResourceOutcome implements SummaryActionOutcome
{
private Resource resource;
public ResourceOutcome(Resource resource)
{
this.resource = resource;
}
public String getOutcome()
{
ResourceManager resourceManager = ResourceManagerFactory.resourceManager();
if (resourceManager.getResource(this.resource.getId()) == null)
{
SummaryAction.this.facesMessages.add(FacesMessage.SEVERITY_WARN,
"#0 '#1' no longer exists.", this.resource.getResourceType().getName(),
this.resource.getName());
// Reset the current node to the stale Resource node's parent node.
JONTreeNode parentNode = SummaryAction.this.navigationAction.getSelectedNode().getParent();
SummaryAction.this.navigationAction.setCurrentPath(parentNode.getPath());
// And refresh the parent node's children to remove the stale Resource node.
parentNode.reInitializeChildrenMap();
return FacesOutcomes.ERROR;
}
setResourceAndSummaryInfo(this.resource);
return FacesOutcomes.RESOURCE_INSTANCE;
}
}
public class NonSingletonResourceTypeOutcome implements SummaryActionOutcome
{
private ResourceType resourceType;
private Resource parentResource;
public NonSingletonResourceTypeOutcome(ResourceType resType, Resource parentResource)
{
this.resourceType = resType;
this.parentResource = parentResource;
}
public String getOutcome()
{
SummaryAction.this.resourceType = this.resourceType;
SummaryAction.this.resources = getResourceListByType(this.resourceType, parentResource);
return FacesOutcomes.RESOURCE_TYPE_SUMMARY;
// ResourceTreeNode uses resource id as its 'path' variable
// so the xhtml can use that as well when rendering the link for a single item, i.e.
// <f:param name="path"
// value="#{navigationAction.getResourcePath(resourceItem.resource.id)}"/>
}
}
public class SubCategoryOutcome implements SummaryActionOutcome
{
private SubCategoryTreeNode selectedNode;
public SubCategoryOutcome(SubCategoryTreeNode node)
{
this.selectedNode = node;
}
public String getOutcome()
{
String outcome = FacesOutcomes.REPEAT_NAV;
if (!this.selectedNode.isLeaf())
{
outcome = FacesOutcomes.SUB_CATEGORY;
outcome = addResourcesToList(outcome, this.selectedNode);
}
// Whatever happens, make sure we set the subCategory field.
SummaryAction.this.subCategory = this.selectedNode;
return outcome;
}
}
private String addResourcesToList(String outcome, SubCategoryTreeNode selectedNode)
{
resources = new ArrayList<ResourceListItem>();
for (JONTreeNode childNode : selectedNode.getChildNodes())
{
if (childNode instanceof NonSingletonResourceTypeTreeNode)
{
NonSingletonResourceTypeTreeNode nonSingletonNode = (NonSingletonResourceTypeTreeNode)childNode;
ResourceType resourceType = nonSingletonNode.getResourceType();
if (resourceTypeFilter == null || resourceTypeFilter.equals("All Types") || resourceTypeFilter.equals(resourceType.getName()))
{
resources.addAll(getResourceListByType(resourceType, selectedNode.getClosestResource()));
}
}
else
{
// if we ever find a child which is not a NonSingletonResourceTypeTreeNode
// then we should just repeat the nav
outcome = FacesOutcomes.REPEAT_NAV;
resources.clear();
break;
}
}
return outcome;
}
// called from xhtml
// TODO move this to navigationAction, cf. getResourcePath
// TODO i dont think this is going to work when we have the same resource types
// appearing under multiple resources, see JBMANCON-365
public String getResourceTypePath(String resourceTypeName)
{
// TODO double check if this is still a problem
//need to put breakpoint here to work out why categorySummary paging is not working properly
//i.e. it renders the first page and the second page but not the third page
JONTreeNode treeNode = ((BaseTreeNode)navigationAction.getRootNode()).findNodeByTypeName(resourceTypeName);
return treeNode.getPath();
}
@NotNull
public void setResourceAndSummaryInfo(Resource selectedResource)
{
Availability availability = ResourceManagerFactory.resourceManager().getAvailability(selectedResource);
resource = new ResourceListItem(selectedResource, availability);
resourceType = selectedResource.getResourceType();
summaryMeasurementDisplayList = new ArrayList<MeasurementDisplay>();
MeasurementUtils measurementUtils = new MeasurementUtils(resource);
summaryMeasurementDefinitionMap = measurementUtils.getMeasurementDefinitionMap();
List<MeasurementData> measurementDataList = measurementUtils.loadMeasurementData(DisplayType.SUMMARY, DataType.MEASUREMENT);
if (measurementDataList != null)
{
for (MeasurementData measurementData : measurementDataList)
{
MeasurementDefinition measurementDefinition = summaryMeasurementDefinitionMap.get(measurementData.getName());
summaryMeasurementDisplayList.add(measurementUtils.createMeasurementDisplay(measurementData, measurementDefinition));
}
}
List<MeasurementData> traitDataList = measurementUtils.loadMeasurementData(DisplayType.SUMMARY, DataType.TRAIT);
if (traitDataList != null)
{
summaryTraitDisplayList = new ArrayList<MeasurementDisplay>();
for (MeasurementData traitData : traitDataList)
{
summaryTraitDisplayList.add(measurementUtils.createMeasurementDisplay(traitData, summaryMeasurementDefinitionMap.get(traitData.getName())));
}
}
}
/**
* gets all the resources associated with this ResourceType
*
* @param resourceType
* @return
*/
private List<ResourceListItem> getResourceListByType(ResourceType resourceType, Resource parentResource)
{
ResourceManager manager = ResourceManagerFactory.resourceManager();
Set<Resource> resources = manager.getResources(resourceType, parentResource);
List<ResourceListItem> items = new ArrayList<ResourceListItem>();
for (Resource r : resources)
{
Availability availability = manager.getAvailability(r);
ResourceListItem item = new ResourceListItem(r, availability);
items.add(item);
}
return items;
}
public SubCategoryTreeNode getSubCategoryNode()
{
return subCategory;
}
public NavigationAction getNavigationAction()
{
return navigationAction;
}
public void setNavigationAction(NavigationAction navigationAction)
{
this.navigationAction = navigationAction;
}
public void resourceTypeSelected(ValueChangeEvent event)
{
Object newValue = event.getNewValue();
if (newValue instanceof String)
{
resourceTypeFilter = (String)newValue;
resourceTypeFilter =
resourceTypeFilter.substring(resourceTypeFilter.lastIndexOf("/") + 1,
resourceTypeFilter.length());
JONTreeNode selectedNode = navigationAction.getSelectedNode();
if (selectedNode instanceof SubCategoryTreeNode)
{
SubCategoryTreeNode subCatTreeNode = (SubCategoryTreeNode)selectedNode;
addResourcesToList("", subCatTreeNode);
this.subCategory = subCatTreeNode;
}
}
FacesContext.getCurrentInstance().renderResponse();
}
}