/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.visualvm.core.datasource.descriptor;
import com.sun.tools.visualvm.core.datasource.DataSource;
import com.sun.tools.visualvm.core.datasource.Storage;
import com.sun.tools.visualvm.core.datasupport.Positionable;
import com.sun.tools.visualvm.core.model.Model;
import java.awt.Image;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Comparator;
/**
* DataSourceDescriptor defines runtime appearance of the DataSource in Applications window.
*
* @author Jiri Sedlacek
* @author Tomas Hurka
*/
public abstract class DataSourceDescriptor<X extends DataSource> extends Model implements Positionable {
/**
* Named property for DataSource icon.
*/
public static final String PROPERTY_ICON = "prop_icon"; // NOI18N
/**
* Named property for DataSource name.
*/
public static final String PROPERTY_NAME = "prop_name"; // NOI18N
/**
* Named property for DataSource description.
*/
public static final String PROPERTY_DESCRIPTION = "prop_description"; // NOI18N
/**
* Named property for DataSource position within its owner.
*/
public static final String PROPERTY_PREFERRED_POSITION = "prop_preferred_position"; // NOI18N
/**
* Named property for comparator used to sort nested DataSources.
*/
public static final String PROPERTY_CHILDREN_COMPARATOR = "prop_children_comparator"; // NOI18N
/**
* Named property for DataSource expansion policy.
*/
public static final String PROPERTY_EXPANSION_POLICY = "prop_expansion_policy"; // NOI18N
/**
* Expansion policy - DataSource will never expand automatically.
*/
public static final int EXPAND_NEVER = 0;
/**
* Expansion policy - DataSource will be automatically expanded when first child is added, not more than once.
*/
public static final int EXPAND_ON_FIRST_CHILD = 1;
/**
* Expansion policy - DataSource will be automatically expanded whenever first child is added, for each first child.
*/
public static final int EXPAND_ON_EACH_FIRST_CHILD = 2;
/**
* Expansion policy - DataSource will be automatically expanded whenever new child is added.
*/
public static final int EXPAND_ON_EACH_NEW_CHILD = 3;
/**
* Expansion policy - DataSource will be automatically expanded whenever a child is added or removed.
*/
public static final int EXPAND_ON_EACH_CHILD_CHANGE = 4;
private X dataSource;
private Image icon;
private String name;
private String description;
private int preferredPosition;
private Comparator<DataSource> childrenComparator;
private int autoExpansionPolicy;
private final PropertyChangeSupport changeSupport;
/**
* Creates new instance of DataSourceDescriptor.
*
* @param dataSource DataSource described by the descriptor, cannot be null.
*/
public DataSourceDescriptor(X dataSource) {
this(dataSource, dataSource != null ? dataSource.toString() : null, null, null, POSITION_AT_THE_END, EXPAND_ON_FIRST_CHILD);
}
/**
* Creates new instance of DataSourceDescriptor.
*
* @param ds DataSource described by the descriptor, cannot be null.
* @param n DataSource name.
* @param desc DataSource description.
* @param ic DataSource icon.
* @param pos DataSource position.
* @param aep DataSource expansion policy.
*
* @throws NullPointerException if the provided DataSource is null.
*/
public DataSourceDescriptor(X ds, String n, String desc, Image ic, int pos, int aep) {
if (ds == null) throw new NullPointerException("DataSource cannot be null");
dataSource = ds;
changeSupport = new PropertyChangeSupport(dataSource);
name = n;
description = desc;
icon = ic;
preferredPosition = pos;
autoExpansionPolicy = aep;
}
/**
* Returns icon of the DataSource.
*
* @return icon of the DataSource.
*/
public Image getIcon() {
return icon;
}
/**
* Returns true if the DataSource can be renamed using the Rename action, false otherwise.
*
* @return true if the DataSource can be renamed using the Rename action, false otherwise.
*/
public boolean supportsRename() {
return false;
}
/**
* Sets DataSource name.
*
* @param newName DataSource name.
*/
public void setName(String newName) {
if (!supportsRename()) throw new UnsupportedOperationException("Rename not supported for this descriptor"); // NOI18N
if (newName == null) throw new IllegalArgumentException("Name cannot be null"); // NOI18N
String oldName = name;
name = newName;
getDataSource().getStorage().setCustomProperties(new String[] { PROPERTY_NAME }, new String[] { newName });
getChangeSupport().firePropertyChange(PROPERTY_NAME, oldName, newName);
}
/**
* Returns name of the DataSource.
*
* @return name of the DataSource.
*/
public String getName() {
return name;
}
/**
* Returns description of the DataSource.
*
* @return description of the DataSource.
*/
public String getDescription() {
return description;
}
/**
* Returns preferred position of the DataSource.
*
* @return preferred position of the DataSource.
*/
public int getPreferredPosition() {
return preferredPosition;
}
/**
* Returns comparator used to sort nested DataSources. If defined, it overrides
* the default sorting which uses DataSourceDescriptor.getPreferredPosition().
* Default implementation returns null.
*
* @return comparator used to sort nested DataSources or null
*
* @since VisualVM 1.3
*/
public Comparator<DataSource> getChildrenComparator() {
return childrenComparator;
}
/**
* Returns expansion policy of the DataSource.
*
* @return expansion policy of the DataSource.
*/
public int getAutoExpansionPolicy() {
return autoExpansionPolicy;
}
/**
* Returns true if the General properties section should be available for
* the DataSource, false otherwise.
*
* @return true if the General properties section should be available for
* the DataSource, false otherwise
*
* @since VisualVM 1.2
*/
public boolean providesProperties() {
return false;
}
/**
* Add a PropertyChangeListener to the listener list.
* The listener is registered for all properties.
* The same listener object may be added more than once, and will be called
* as many times as it is added.
* If <code>listener</code> is null, no exception is thrown and no action
* is taken.
*
* @param listener The PropertyChangeListener to be added
*/
public final void addPropertyChangeListener(PropertyChangeListener listener) {
getChangeSupport().addPropertyChangeListener(listener);
}
/**
* Add a PropertyChangeListener for a specific property. The listener
* will be invoked only when a call on firePropertyChange names that
* specific property.
* The same listener object may be added more than once. For each
* property, the listener will be invoked the number of times it was added
* for that property.
* If <code>propertyName</code> or <code>listener</code> is null, no
* exception is thrown and no action is taken.
*
* @param propertyName The name of the property to listen on.
* @param listener The PropertyChangeListener to be added
*/
public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
getChangeSupport().addPropertyChangeListener(propertyName, listener);
}
/**
* Remove a PropertyChangeListener from the listener list.
* This removes a PropertyChangeListener that was registered
* for all properties.
* If <code>listener</code> was added more than once to the same event
* source, it will be notified one less time after being removed.
* If <code>listener</code> is null, or was never added, no exception is
* thrown and no action is taken.
*
* @param listener The PropertyChangeListener to be removed
*/
public final void removePropertyChangeListener(PropertyChangeListener listener) {
getChangeSupport().removePropertyChangeListener(listener);
}
/**
* Remove a PropertyChangeListener for a specific property.
* If <code>listener</code> was added more than once to the same event
* source for the specified property, it will be notified one less time
* after being removed.
* If <code>propertyName</code> is null, no exception is thrown and no
* action is taken.
* If <code>listener</code> is null, or was never added for the specified
* property, no exception is thrown and no action is taken.
*
* @param propertyName The name of the property that was listened on.
* @param listener The PropertyChangeListener to be removed
*/
public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
getChangeSupport().removePropertyChangeListener(propertyName, listener);
}
protected final X getDataSource() {
return dataSource;
}
protected void setDescription(String newDescription) {
if (description == null && newDescription == null) return;
String oldDescription = description;
description = newDescription;
getChangeSupport().firePropertyChange(PROPERTY_DESCRIPTION, oldDescription, newDescription);
}
protected void setIcon(Image newIcon) {
if (icon == null && newIcon == null) return;
Image oldIcon = icon;
icon = newIcon;
getChangeSupport().firePropertyChange(PROPERTY_ICON, oldIcon, newIcon);
}
protected void setPreferredPosition(int newPosition) {
int oldPosition = preferredPosition;
preferredPosition = newPosition;
getChangeSupport().firePropertyChange(PROPERTY_PREFERRED_POSITION, oldPosition, newPosition);
}
/**
* Sets a custom comparator for sorting DataSources within a DataSource.
* Use setChildrenComparator(null) to restore the default sorting.
*
* @param newComparator comparator for sorting DataSources within a DataSource
*
* @since VisualVM 1.3
*/
protected void setChildrenComparator(Comparator<DataSource> newComparator) {
Comparator<DataSource> oldComparator = childrenComparator;
childrenComparator = newComparator;
getChangeSupport().firePropertyChange(PROPERTY_CHILDREN_COMPARATOR, oldComparator, newComparator);
}
protected void getAutoExpansionPolicy(int newPolicy) {
int oldPolicy = autoExpansionPolicy;
autoExpansionPolicy = newPolicy;
getChangeSupport().firePropertyChange(PROPERTY_EXPANSION_POLICY, oldPolicy, newPolicy);
}
protected final PropertyChangeSupport getChangeSupport() {
return changeSupport;
}
/**
* Returns persisted DataSource name if available in DataSource Storage as
* PROPERTY_NAME. Otherwise returns the provided name.
*
* @param dataSource DataSource for which to resolve the name
* @param name name to be used if not available in DataSource Storage
* @return persisted DataSource name if available or the provided name
*
* @since VisualVM 1.3
*/
protected static String resolveName(DataSource dataSource, String name) {
String persistedName = dataSource.getStorage().getCustomProperty(PROPERTY_NAME);
if (persistedName != null) return persistedName;
else return name;
}
/**
* Returns persisted DataSource position if available in DataSource Storage
* as PROPERTY_PREFERRED_POSITION. Otherwise uses the provided position.
* Optionally saves the position to DataSource storage which also ensures that
* relative positions POSITION_AT_THE_END and POSITION_LAST will be correctly
* persisted.
*
* @param dataSource DataSource for which to resolve the position
* @param position position to be used if not available in DataSource Storage
* @param savePosition true when the position should be saved to DataSource's Storage
* @return persisted DataSource position if available or the provided position
*
* @since VisualVM 1.3
*/
protected static int resolvePosition(DataSource dataSource, int position,
boolean savePosition) {
Storage storage = dataSource.getStorage();
String positionS = storage.getCustomProperty(PROPERTY_PREFERRED_POSITION);
if (positionS != null) try {
position = Integer.parseInt(positionS);
} catch (NumberFormatException e) {
if (savePosition) storage.setCustomProperty(PROPERTY_PREFERRED_POSITION,
Integer.toString(position));
} else {
if (savePosition) storage.setCustomProperty(PROPERTY_PREFERRED_POSITION,
Integer.toString(position));
}
return position;
}
}