/*
* RHQ Management Platform
* Copyright (C) 2005-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 General Public License, version 2, as
* published by the Free Software Foundation, and/or the GNU Lesser
* General Public License, version 2.1, also as published by the Free
* Software Foundation.
*
* 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 and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.rhq.core.domain.dashboard;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.Cascade;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.group.ResourceGroup;
/**
* @author Greg Hinkle
* @author Jay Shaughnessy
*/
@Entity
@SequenceGenerator(allocationSize = org.rhq.core.domain.util.Constants.ALLOCATION_SIZE, name = "RHQ_DASHBOARD_ID_SEQ", sequenceName = "RHQ_DASHBOARD_ID_SEQ")
@Table(name = "RHQ_DASHBOARD")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class Dashboard implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name = "ID", nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "RHQ_DASHBOARD_ID_SEQ")
@Id
private int id = 0;
@Column(name = "NAME", nullable = false)
private String name;
@Column(name = "CATEGORY", nullable = false)
@Enumerated(EnumType.STRING)
private DashboardCategory category;
// currently unused
@Column(name = "SHARED", nullable = false)
private boolean shared = false;
@JoinColumn(name = "CONFIGURATION_ID", referencedColumnName = "ID", nullable = true)
@OneToOne(cascade = { CascadeType.ALL }, optional = true)
private Configuration configuration = new Configuration();
@JoinColumn(name = "SUBJECT_ID", nullable = false)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private Subject owner;
@JoinColumn(name = "RESOURCE_ID", nullable = true)
@ManyToOne(fetch = FetchType.LAZY, optional = true)
private Resource resource;
@JoinColumn(name = "GROUP_ID", nullable = true)
@ManyToOne(fetch = FetchType.LAZY, optional = true)
private ResourceGroup group;
@OneToMany(mappedBy = "dashboard", fetch = FetchType.EAGER, orphanRemoval = true)
@Cascade({ org.hibernate.annotations.CascadeType.PERSIST, org.hibernate.annotations.CascadeType.MERGE })
private Set<DashboardPortlet> portlets = new HashSet<DashboardPortlet>();
public static final String CFG_COLUMNS = "columns";
public static final String CFG_WIDTHS = "widths";
public static final String CFG_BACKGROUND = "background";
public static final String CFG_REFRESH_RATE = "refresh";
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isShared() {
return shared;
}
public void setShared(boolean shared) {
this.shared = shared;
}
public Subject getOwner() {
return owner;
}
public void setOwner(Subject owner) {
this.owner = owner;
}
public DashboardCategory getCategory() {
return category;
}
public void setCategory(DashboardCategory category) {
this.category = category;
}
public Resource getResource() {
return resource;
}
public void setResource(Resource resource) {
this.resource = resource;
}
public ResourceGroup getGroup() {
return group;
}
public void setGroup(ResourceGroup group) {
this.group = group;
}
public int getColumns() {
return Integer.valueOf(configuration.getSimpleValue(CFG_COLUMNS, "1"));
}
public void setColumns(int columns) {
configuration.put(new PropertySimple(CFG_COLUMNS, columns));
}
public String[] getColumnWidths() {
return configuration.getSimpleValue(CFG_WIDTHS, "").split(",");
}
public void setColumnWidths(String... columnWidths) {
if (null == columnWidths || columnWidths.length == 0) {
return;
}
// note - this impl is a little verbose but it avoids a smartgwt javascript problem with
// varargs handling. Not sure how bad the problem is but it definitely occured with SmartGwt 2.4
// when a single String was pssed as the varArg list. Be wary of directly using varargs array
// element 0...
StringBuilder sb = new StringBuilder();
sb.append(columnWidths[0]);
for (int i = 1; i < columnWidths.length; ++i) {
sb.append(",");
sb.append(columnWidths[i]);
}
configuration.put(new PropertySimple(CFG_WIDTHS, sb));
}
public Configuration getConfiguration() {
return configuration;
}
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
public Set<DashboardPortlet> getPortlets() {
return portlets;
}
public List<DashboardPortlet> getPortlets(int column) {
ArrayList<DashboardPortlet> columnPortlets = new ArrayList<DashboardPortlet>();
for (DashboardPortlet p : this.portlets) {
if (p.getColumn() == column) {
columnPortlets.add(p);
}
}
Collections.sort(columnPortlets, new Comparator<DashboardPortlet>() {
public int compare(DashboardPortlet o1, DashboardPortlet o2) {
return (o1.getIndex() < o2.getIndex() ? -1 : (o1.getIndex() == o2.getIndex() ? 0 : 1));
}
});
return columnPortlets;
}
public boolean removePortlet(DashboardPortlet storedPortlet) {
if (!portlets.contains(storedPortlet)) {
return false;
}
// lower the index by 1 for portlets in the same column, below the one being removed
int col = storedPortlet.getColumn();
int index = storedPortlet.getIndex();
portlets.remove(storedPortlet);
for (Iterator<DashboardPortlet> i = portlets.iterator(); i.hasNext();) {
DashboardPortlet next = i.next();
if (col == next.getColumn() && index < next.getIndex()) {
next.setIndex(next.getIndex() - 1);
}
}
return true;
}
/**
* This can be used to safely add a portlet without knowing the current portlet positioning on the
* Dashboard. It adds the portlet to the bottom of column with the least portlets.
*
* @param storedPortlet MODIFIED with assigned column, index
*/
public void addPortlet(DashboardPortlet storedPortlet) {
int[] columnCounts = new int[getColumns()];
Arrays.fill(columnCounts, 0);
// set column counts
for (DashboardPortlet dashboardPortlet : portlets) {
++(columnCounts[dashboardPortlet.getColumn()]);
}
// get best column
int bestColumn = -1;
int minPortlets = Integer.MAX_VALUE;
for (int column = 0; (column < columnCounts.length); ++column) {
if (columnCounts[column] < minPortlets) {
bestColumn = column;
minPortlets = columnCounts[column];
}
}
// addPortlet to best Column
addPortlet(storedPortlet, bestColumn, minPortlets);
}
/**
* Call this only if you are sure the column and index are valid, not already used and not leaving gaps.
*
* @param storedPortlet MODIFIED with assigned column, index
* @param column
* @param index
*/
public void addPortlet(DashboardPortlet storedPortlet, int column, int index) {
storedPortlet.setColumn(column);
storedPortlet.setIndex(index);
storedPortlet.setDashboard(this);
portlets.add(storedPortlet);
}
public Dashboard deepCopy(boolean keepIds) {
Dashboard newDashboard = new Dashboard();
if (keepIds) {
newDashboard.id = this.id;
}
newDashboard.name = this.name;
newDashboard.owner = this.owner;
newDashboard.shared = this.shared;
newDashboard.configuration = this.configuration.deepCopy(keepIds);
for (DashboardPortlet portlet : portlets) {
DashboardPortlet newPortlet = portlet.deepCopy(keepIds);
newPortlet.setDashboard(this);
newDashboard.addPortlet(newPortlet, newPortlet.getColumn(), newPortlet.getIndex());
}
return newDashboard;
}
}