/*
* RHQ Management Platform
* Copyright (C) 2005-2008 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.configuration.definition;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import org.jetbrains.annotations.NotNull;
/**
* The definition of properties in a map. The map may be null allowing for the requirement of the map's existence but no
* constraints on its contents. (i.e. an arbitrary map)
*
* @author Greg Hinkle
*/
@DiscriminatorValue("map")
@Entity(name = "PropertyDefinitionMap")
@XmlRootElement(name = "PropertyDefinitionMap")
@XmlSeeAlso({ PropertyDefinitionSimple.class, PropertyDefinitionList.class, PropertyDefinitionMap.class })
@XmlAccessorType(XmlAccessType.FIELD)
public class PropertyDefinitionMap extends PropertyDefinition {
private static final long serialVersionUID = 1L;
// use the propDef name as the map key
@MapKey(name = "name")
@OneToMany(mappedBy = "parentPropertyMapDefinition", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Map<String, PropertyDefinition> map;
public PropertyDefinitionMap(@NotNull String name, String description, boolean required,
PropertyDefinition... properties) {
super(name, description, required);
if (properties != null) {
for (PropertyDefinition property : properties) {
put(property);
}
}
}
protected PropertyDefinitionMap() {
}
/**
* @return The <name,propDef> Map. This guarantees no ordering.
*/
@NotNull
public Map<String, PropertyDefinition> getMap() {
if (this.map == null) {
this.map = new HashMap<String, PropertyDefinition>();
}
return map;
}
public void setMap(@NotNull Map<String, PropertyDefinition> map) {
this.map = map;
}
/**
* For public API compatibility.
* @deprecated use {@link #setMap(Map)}
*/
public void setPropertyDefinitions(@NotNull Map<String, PropertyDefinition> propertyDefinitions) {
setMap(propertyDefinitions);
}
/**
* This returned {@link Map} is backed by a {@link SortedMap} sorted on PropertyDefinition.order. This means that
* result.keySet() and result.values() will be sorted by PropertyDefinition.order, ascending. Min(order) is 0.
* <p>
* For an unsorted Map use {@link #getMap()}.</p>
*
* @return The map's property definitions sorted by PropertyDefinition.order, ascending. Min(order) is 0.
*/
@NotNull
public Map<String, PropertyDefinition> getPropertyDefinitions() {
Map<String, PropertyDefinition> map = getMap();
// if there is nothing to sort just return it.
if (map.size() <= 1) {
return map;
}
// a funky comparator that compares index order given prop def names (i.e. keys)
Comparator<String> orderComparator = new Comparator<String>() {
public int compare(String o1, String o2) {
return Integer.valueOf(get(o1).getOrder()).compareTo(get(o2).getOrder());
}
};
final Map<String, PropertyDefinition> result = new TreeMap<String, PropertyDefinition>(orderComparator);
for (String key : map.keySet()) {
result.put(key, map.get(key));
}
return result;
}
/**
* Convenience routine to get the ordered property definitions from the Map.
*
* @return The map's property definitions sorted by PropertyDefinition.order, ascending. Min(order) is 0.
*/
@NotNull
public Collection<PropertyDefinition> getOrderedPropertyDefinitions() {
return getPropertyDefinitions().values();
}
/**
* Convenience routine to get only the summary property definitions.
*
* @return the summary property definitions. If no property definitions were defined
* as summary properties in the plugin descriptor, all property definitions will be returned.
* The property definitions will be sorted by PropertyDefinition.order, ascending. Min(order) is 0.
*/
@NotNull
public List<PropertyDefinition> getSummaryPropertyDefinitions() {
List<PropertyDefinition> result = new ArrayList<PropertyDefinition>();
Collection<PropertyDefinition> propDefs = getOrderedPropertyDefinitions();
for (PropertyDefinition pd : propDefs) {
if (pd.isSummary()) {
result.add(pd);
}
}
if (result.isEmpty()) {
result.addAll(propDefs);
}
return result;
}
public PropertyDefinitionSimple getPropertyDefinitionSimple(String name) {
return (PropertyDefinitionSimple) this.get(name);
}
public PropertyDefinitionList getPropertyDefinitionList(String name) {
return (PropertyDefinitionList) this.get(name);
}
public PropertyDefinitionMap getPropertyDefinitionMap(String name) {
return (PropertyDefinitionMap) this.get(name);
}
public PropertyDefinition get(String name) {
return getMap().get(name);
}
/**
* If propertyDefinition.order is <= 0 or > Map.size() it will be set to the current number of propDefs for
* the map (placing it at the end). Otherwise, it will be inserted, incrementing the order of existing
* Map entries.
*
* @param propertyDefinition
*/
public void put(PropertyDefinition propertyDefinition) {
Map<String, PropertyDefinition> map = getMap();
if (map.isEmpty()) {
propertyDefinition.setOrder(0);
} else {
int order = propertyDefinition.getOrder();
int size = map.size();
if ((order <= 0) || (order >= size)) {
propertyDefinition.setOrder(size);
} else {
// insert into existing ordering by bumping up existing entries
for (PropertyDefinition p : map.values()) {
if (p.getOrder() >= order) {
p.setOrder(p.getOrder() + 1);
}
}
}
}
map.put(propertyDefinition.getName(), propertyDefinition);
propertyDefinition.setParentPropertyMapDefinition(this);
}
}