org.pivot4j.ui.AbstractPivotRenderer.java Source code

Java tutorial

Introduction

Here is the source code for org.pivot4j.ui.AbstractPivotRenderer.java

Source

/*
 * ====================================================================
 * This software is subject to the terms of the Common Public License
 * Agreement, available at the following URL:
 *   http://www.opensource.org/licenses/cpl.html .
 * You must accept the terms of that agreement to use this software.
 * ====================================================================
 */
package org.pivot4j.ui;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.logging.LogFactory;
import org.olap4j.Axis;
import org.pivot4j.sort.SortMode;
import org.pivot4j.ui.aggregator.AggregatorFactory;
import org.pivot4j.ui.aggregator.AggregatorPosition;
import org.pivot4j.ui.aggregator.DefaultAggregatorFactory;
import org.pivot4j.ui.collector.NonInternalPropertyCollector;
import org.pivot4j.ui.collector.PropertyCollector;
import org.pivot4j.ui.command.BasicDrillThroughCommand;
import org.pivot4j.ui.command.DrillCollapseMemberCommand;
import org.pivot4j.ui.command.DrillCollapsePositionCommand;
import org.pivot4j.ui.command.DrillDownCommand;
import org.pivot4j.ui.command.DrillDownReplaceCommand;
import org.pivot4j.ui.command.DrillExpandMemberCommand;
import org.pivot4j.ui.command.DrillExpandPositionCommand;
import org.pivot4j.ui.command.DrillUpReplaceCommand;
import org.pivot4j.ui.command.ToggleSortCommand;
import org.pivot4j.ui.command.UICommand;
import org.pivot4j.ui.condition.ConditionFactory;
import org.pivot4j.ui.condition.DefaultConditionFactory;
import org.pivot4j.ui.property.DefaultRenderPropertyList;
import org.pivot4j.ui.property.RenderPropertyList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractPivotRenderer<T1 extends RenderContext, T2 extends RenderCallback<T1>>
        implements PivotRenderer<T2> {

    private Map<String, UICommand<?>> commands = new HashMap<String, UICommand<?>>();

    private boolean enableSort = true;

    private SortMode sortMode = SortMode.BASIC;

    private boolean enableDrillDown = true;

    private String drillDownMode = DrillDownCommand.MODE_POSITION;

    private boolean enableDrillThrough = false;

    private boolean renderSlicer = false;

    private PropertyCollector propertyCollector;

    private ConditionFactory conditionFactory;

    private AggregatorFactory aggregatorFactory;

    private Map<AggregatorKey, List<String>> aggregatorNames;

    private Map<String, RenderPropertyList> renderProperties;

    public AbstractPivotRenderer() {
        this.conditionFactory = new DefaultConditionFactory();
        this.aggregatorFactory = new DefaultAggregatorFactory();
        this.aggregatorNames = new HashMap<AggregatorKey, List<String>>();
        this.renderProperties = new HashMap<String, RenderPropertyList>();

        registerCommands();
        initializeRenderProperties();
    }

    protected abstract String getLabel(T1 context);

    protected abstract Double getValue(T1 context);

    protected void registerCommands() {
        addCommand(new DrillExpandPositionCommand(this));
        addCommand(new DrillCollapsePositionCommand(this));
        addCommand(new DrillExpandMemberCommand(this));
        addCommand(new DrillCollapseMemberCommand(this));
        addCommand(new DrillDownReplaceCommand(this));
        addCommand(new DrillUpReplaceCommand(this));
        addCommand(new ToggleSortCommand(this));
        addCommand(new BasicDrillThroughCommand(this));
    }

    protected List<String> getRenderPropertyCategories() {
        return Collections.emptyList();
    }

    protected void initializeRenderProperties() {
        renderProperties.clear();

        if (conditionFactory != null) {
            for (String category : getRenderPropertyCategories()) {
                renderProperties.put(category, new DefaultRenderPropertyList(conditionFactory));
            }
        }
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#getCommand(java.lang.String)
     */
    @Override
    public UICommand<?> getCommand(String name) {
        return commands.get(name);
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#addCommand(org.pivot4j.ui.command.UICommand)
     */
    @Override
    public void addCommand(UICommand<?> command) {
        commands.put(command.getName(), command);
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#removeCommand(java.lang.String)
     */
    @Override
    public void removeCommand(String name) {
        commands.remove(name);
    }

    /**
     * @param context
     * @return
     */
    protected List<UICommand<?>> getCommands(T1 context) {
        List<UICommand<?>> availableCommands = new ArrayList<UICommand<?>>(commands.size());
        for (UICommand<?> command : commands.values()) {
            if (command.canExecute(context)) {
                availableCommands.add(command);
            }
        }

        return availableCommands;
    }

    /**
     * @return
     */
    @Override
    public SortMode getSortMode() {
        return sortMode;
    }

    /**
     * @param sortMode
     *            the sortMode to set
     * @see org.pivot4j.ui.PivotRenderer#setSortMode(org.pivot4j.sort.SortMode)
     */
    @Override
    public void setSortMode(SortMode sortMode) {
        this.sortMode = sortMode;
    }

    /**
     * @return the drillDownMode
     * @see org.pivot4j.ui.PivotRenderer#getDrillDownMode()
     */
    @Override
    public String getDrillDownMode() {
        return drillDownMode;
    }

    /**
     * @param drillDownMode
     *            the drillDownMode to set
     * @see org.pivot4j.ui.PivotRenderer#setDrillDownMode(java.lang.String)
     */
    @Override
    public void setDrillDownMode(String drillDownMode) {
        this.drillDownMode = drillDownMode;
    }

    /**
     * @return the enableDrillDown
     * @see org.pivot4j.ui.PivotRenderer#getEnableDrillDown()
     */
    @Override
    public boolean getEnableDrillDown() {
        return enableDrillDown;
    }

    /**
     * @param enableDrillDown
     *            the enableDrillDown to set
     * @see org.pivot4j.ui.PivotRenderer#setEnableDrillDown(boolean)
     */
    @Override
    public void setEnableDrillDown(boolean enableDrillDown) {
        this.enableDrillDown = enableDrillDown;
    }

    /**
     * @return the enableSort
     * @see org.pivot4j.ui.PivotRenderer#getEnableSort()
     */
    @Override
    public boolean getEnableSort() {
        return enableSort;
    }

    /**
     * @param enableSort
     *            the enableSort to set
     * @see org.pivot4j.ui.PivotRenderer#setEnableSort(boolean)
     */
    @Override
    public void setEnableSort(boolean enableSort) {
        this.enableSort = enableSort;
    }

    /**
     * @return the enableDrillThrough
     * @see org.pivot4j.ui.PivotRenderer#getEnableDrillThrough()
     */
    @Override
    public boolean getEnableDrillThrough() {
        return enableDrillThrough;
    }

    /**
     * @param enableDrillThrough
     *            the enableDrillThrough to set
     * @see org.pivot4j.ui.PivotRenderer#setEnableDrillThrough(boolean)
     */
    @Override
    public void setEnableDrillThrough(boolean enableDrillThrough) {
        this.enableDrillThrough = enableDrillThrough;
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#getRenderSlicer()
     */
    @Override
    public boolean getRenderSlicer() {
        return renderSlicer;
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#setRenderSlicer(boolean)
     */
    @Override
    public void setRenderSlicer(boolean renderSlicer) {
        this.renderSlicer = renderSlicer;
    }

    /**
     * @return the propertyCollector
     */
    @Override
    public PropertyCollector getPropertyCollector() {
        return propertyCollector;
    }

    /**
     * @param propertyCollector
     *            the propertyCollector to set
     */
    @Override
    public void setPropertyCollector(PropertyCollector propertyCollector) {
        this.propertyCollector = propertyCollector;
    }

    /**
     * @return the aggregatorFactory
     * @see org.pivot4j.ui.PivotRenderer#getAggregatorFactory()
     */
    @Override
    public AggregatorFactory getAggregatorFactory() {
        return aggregatorFactory;
    }

    /**
     * @param aggregatorFactory
     *            the aggregatorFactory to set
     */
    public void setAggregatorFactory(AggregatorFactory aggregatorFactory) {
        this.aggregatorFactory = aggregatorFactory;
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#getAggregators(org.olap4j.Axis,
     *      org.pivot4j.ui.aggregator.AggregatorPosition)
     */
    @Override
    public List<String> getAggregators(Axis axis, AggregatorPosition position) {
        if (axis == null) {
            throw new NullArgumentException("axis");
        }

        if (position == null) {
            throw new NullArgumentException("position");
        }

        List<String> names = aggregatorNames.get(new AggregatorKey(axis, position));

        if (names == null) {
            names = Collections.emptyList();
        }

        return names;
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#addAggregator(org.olap4j.Axis,
     *      org.pivot4j.ui.aggregator.AggregatorPosition, java.lang.String)
     */
    @Override
    public void addAggregator(Axis axis, AggregatorPosition position, String name) {
        if (axis == null) {
            throw new NullArgumentException("axis");
        }

        if (position == null) {
            throw new NullArgumentException("position");
        }

        if (name == null) {
            throw new NullArgumentException("name");
        }

        AggregatorKey key = new AggregatorKey(axis, position);

        List<String> names = aggregatorNames.get(key);

        if (names == null) {
            names = new ArrayList<String>();
            aggregatorNames.put(key, names);
        }

        if (!names.contains(name)) {
            names.add(name);
        }
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#removeAggregator(org.olap4j.Axis,
     *      org.pivot4j.ui.aggregator.AggregatorPosition, java.lang.String)
     */
    @Override
    public void removeAggregator(Axis axis, AggregatorPosition position, String name) {
        if (axis == null) {
            throw new NullArgumentException("axis");
        }

        if (position == null) {
            throw new NullArgumentException("position");
        }

        if (name == null) {
            throw new NullArgumentException("name");
        }

        AggregatorKey key = new AggregatorKey(axis, position);

        List<String> names = aggregatorNames.get(key);

        if (names != null) {
            names.remove(name);
        }
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#setAggregators(org.olap4j.Axis,
     *      org.pivot4j.ui.aggregator.AggregatorPosition, java.util.List)
     */
    @Override
    public void setAggregators(Axis axis, AggregatorPosition position, List<String> names) {
        if (axis == null) {
            throw new NullArgumentException("axis");
        }

        if (position == null) {
            throw new NullArgumentException("position");
        }

        AggregatorKey key = new AggregatorKey(axis, position);

        if (names == null || names.isEmpty()) {
            aggregatorNames.remove(key);
        } else {
            aggregatorNames.put(key, names);
        }
    }

    /**
     * @return the conditionFactory
     */
    public ConditionFactory getConditionFactory() {
        return conditionFactory;
    }

    /**
     * @param conditionFactory
     *            the conditionFactory to set
     */
    public void setConditionFactory(ConditionFactory conditionFactory) {
        this.conditionFactory = conditionFactory;
    }

    /**
     * @see org.pivot4j.ui.PivotRenderer#getRenderProperties()
     */
    @Override
    public Map<String, RenderPropertyList> getRenderProperties() {
        return renderProperties;
    }

    /**
     * @param context
     * @return
     */
    protected String getRenderPropertyCategory(T1 context) {
        return null;
    }

    /**
     * @see org.pivot4j.state.Bookmarkable#saveState()
     */
    @Override
    public Serializable saveState() {
        Serializable[] states = new Serializable[9];

        int index = 0;

        states[index++] = enableDrillDown;
        states[index++] = drillDownMode;
        states[index++] = enableSort;
        states[index++] = sortMode;
        states[index++] = enableDrillThrough;
        states[index++] = renderSlicer;
        states[index++] = (Serializable) aggregatorNames;

        HashMap<String, Serializable> propertyState = new HashMap<String, Serializable>(renderProperties.size());

        for (String category : getRenderPropertyCategories()) {
            RenderPropertyList properties = renderProperties.get(category);

            if (properties != null) {
                propertyState.put(category, properties.saveState());
            }
        }

        states[index++] = propertyState;

        if (propertyCollector instanceof Serializable) {
            states[index++] = (Serializable) propertyCollector;
        } else {
            states[index++] = null;
        }

        return states;
    }

    /**
     * @see org.pivot4j.ui.property.DefaultRenderPropertyList#restoreState(java.io.Serializable)
     */
    @SuppressWarnings("unchecked")
    @Override
    public void restoreState(Serializable state) {
        if (state == null) {
            throw new NullArgumentException("state");
        }

        Serializable[] states = (Serializable[]) state;

        int index = 0;

        this.enableDrillDown = (Boolean) states[index++];
        this.drillDownMode = (String) states[index++];
        this.enableSort = (Boolean) states[index++];
        this.sortMode = (SortMode) states[index++];
        this.enableDrillThrough = (Boolean) states[index++];
        this.renderSlicer = (Boolean) states[index++];
        this.aggregatorNames = (Map<AggregatorKey, List<String>>) states[index++];

        initializeRenderProperties();

        Map<String, Serializable> propertyStates = (Map<String, Serializable>) states[index++];

        for (String category : getRenderPropertyCategories()) {
            RenderPropertyList properties = renderProperties.get(category);
            Serializable propertyState = propertyStates.get(category);

            if (properties != null && propertyState != null) {
                properties.restoreState(propertyState);
            }
        }

        Serializable collectorState = states[index++];

        if (collectorState instanceof PropertyCollector) {
            this.propertyCollector = (PropertyCollector) collectorState;
        } else {
            this.propertyCollector = null;
        }
    }

    /**
     * @see org.pivot4j.ui.property.DefaultRenderPropertyList#saveSettings(org.apache.commons.configuration.HierarchicalConfiguration)
     */
    @Override
    public void saveSettings(HierarchicalConfiguration configuration) {
        if (configuration == null) {
            throw new NullArgumentException("configuration");
        }

        configuration.setDelimiterParsingDisabled(true);

        if (configuration.getLogger() == null) {
            configuration.setLogger(LogFactory.getLog(getClass()));
        }

        configuration.addProperty("drillDown[@mode]", drillDownMode);
        configuration.addProperty("drillDown[@enabled]", enableDrillDown);

        configuration.addProperty("sort[@enabled]", enableSort);

        if (sortMode != null) {
            configuration.addProperty("sort[@mode]", sortMode.getName());
        }

        configuration.addProperty("drillThrough[@enabled]", enableDrillThrough);

        if (!aggregatorNames.isEmpty()) {
            int index = 0;

            for (AggregatorKey key : aggregatorNames.keySet()) {
                Axis axis = key.getAxis();
                AggregatorPosition position = key.getPosition();

                List<String> names = aggregatorNames.get(key);

                for (String name : names) {
                    configuration.addProperty(String.format("aggregations.aggregation(%s)[@name]", index), name);
                    configuration.addProperty(String.format("aggregations.aggregation(%s)[@axis]", index),
                            axis.name());
                    configuration.addProperty(String.format("aggregations.aggregation(%s)[@position]", index),
                            position.name());

                    index++;
                }
            }
        }

        for (String category : renderProperties.keySet()) {
            RenderPropertyList properties = renderProperties.get(category);

            if (properties != null) {
                String propertyConfigName = "properties." + category;

                configuration.addProperty(propertyConfigName, "");

                properties.saveSettings(configuration.configurationAt(propertyConfigName));
            }
        }

        configuration.addProperty("filter[@visible]", renderSlicer);
    }

    /**
     * @see org.pivot4j.state.Configurable#restoreSettings(org.apache.commons.configuration.HierarchicalConfiguration)
     */
    @Override
    public void restoreSettings(HierarchicalConfiguration configuration) {
        if (configuration == null) {
            throw new NullArgumentException("configuration");
        }

        this.drillDownMode = configuration.getString("drillDown[@mode]", DrillDownCommand.MODE_POSITION);
        this.enableDrillDown = configuration.getBoolean("drillDown[@enabled]", true);
        this.enableSort = configuration.getBoolean("sort[@enabled]", true);

        // TODO Need to support a custom implementation.
        String sortModeName = configuration.getString("sort[@mode]", SortMode.BASIC.getName());

        this.sortMode = SortMode.fromName(sortModeName);

        if (sortMode == null) {
            Logger logger = LoggerFactory.getLogger(getClass());
            if (logger.isWarnEnabled()) {
                logger.warn("Ignoring unknown sort mode name : {}", sortModeName);
            }

            this.sortMode = SortMode.BASIC;
        }

        this.enableDrillThrough = configuration.getBoolean("drillThrough[@enabled]", false);

        List<HierarchicalConfiguration> aggregationSettings = configuration
                .configurationsAt("aggregations.aggregation");

        this.aggregatorNames.clear();

        for (HierarchicalConfiguration aggConfig : aggregationSettings) {
            String name = aggConfig.getString("[@name]");

            if (name != null) {
                Axis axis = Axis.Standard.valueOf(aggConfig.getString("[@axis]"));

                AggregatorPosition position = AggregatorPosition.valueOf(aggConfig.getString("[@position]"));

                AggregatorKey key = new AggregatorKey(axis, position);

                List<String> names = aggregatorNames.get(key);

                if (names == null) {
                    names = new LinkedList<String>();
                    aggregatorNames.put(key, names);
                }

                if (!names.contains(name)) {
                    names.add(name);
                }
            }
        }

        initializeRenderProperties();

        for (String category : getRenderPropertyCategories()) {
            RenderPropertyList properties = renderProperties.get(category);

            if (properties != null) {
                try {
                    properties.restoreSettings(configuration.configurationAt("properties." + category));
                } catch (IllegalArgumentException e) {
                }
            }
        }

        this.renderSlicer = configuration.getBoolean("filter[@visible]", false);

        String collectorType = configuration.getString("propertyCollector[@type]");

        // TODO At this time, we're not sure how to make property collector
        // configurable. So, let's just treat it as a read-only property.
        if ("non-internal".equalsIgnoreCase(collectorType)) {
            this.propertyCollector = new NonInternalPropertyCollector();
        } else {
            this.propertyCollector = null;
        }
    }

    static class AggregatorKey implements Serializable {

        private static final long serialVersionUID = 4244611391569825053L;

        private Axis axis;

        private AggregatorPosition position;

        AggregatorKey() {
        }

        /**
         * @param axis
         * @param position
         */
        AggregatorKey(Axis axis, AggregatorPosition position) {
            if (axis == null) {
                throw new NullArgumentException("axis");
            }

            if (position == null) {
                throw new NullArgumentException("position");
            }

            this.axis = axis;
            this.position = position;
        }

        /**
         * @return the axis
         */
        Axis getAxis() {
            return axis;
        }

        /**
         * @return the position
         */
        AggregatorPosition getPosition() {
            return position;
        }

        /**
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
            return new HashCodeBuilder().append(axis).append(position).toHashCode();
        }

        /**
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }

            if (getClass() != obj.getClass()) {
                return false;
            }

            AggregatorKey otherKey = (AggregatorKey) obj;

            return axis == otherKey.axis && position == otherKey.position;
        }
    }
}