/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * 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. * * Copyright (c) 2006 - 2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.modules.output.fast.template; import org.pentaho.reporting.engine.classic.core.AttributeNames; import org.pentaho.reporting.engine.classic.core.Band; import org.pentaho.reporting.engine.classic.core.ReportElement; import org.pentaho.reporting.engine.classic.core.Section; import org.pentaho.reporting.engine.classic.core.function.ExpressionRuntime; import org.pentaho.reporting.engine.classic.core.layout.style.SimpleStyleSheet; import org.pentaho.reporting.engine.classic.core.style.StyleKey; import org.pentaho.reporting.engine.classic.core.util.AbstractStructureVisitor; import org.pentaho.reporting.engine.classic.core.util.InstanceID; import org.pentaho.reporting.libraries.base.util.ArgumentNullException; import org.pentaho.reporting.libraries.base.util.ObjectUtilities; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; public class DynamicStyleKey { private static class StyleInfoCollection { private static class StyleInfo { private int styleKeyIndex; private Object styleValue; private StyleInfo( final int styleKeyIndex, final Object styleValue ) { this.styleKeyIndex = styleKeyIndex; this.styleValue = styleValue; } public boolean equals( final Object o ) { if ( this == o ) { return true; } if ( o == null || getClass() != o.getClass() ) { return false; } final StyleInfo styleInfo = (StyleInfo) o; if ( styleKeyIndex != styleInfo.styleKeyIndex ) { return false; } if ( styleValue != null ? !styleValue.equals( styleInfo.styleValue ) : styleInfo.styleValue != null ) { return false; } return true; } public int hashCode() { int result = styleKeyIndex; result = 31 * result + ( styleValue != null ? styleValue.hashCode() : 0 ); return result; } } private ArrayList<StyleInfo> styleInfo; private Integer hashCode; private long styleChangeTracker; private boolean nullValue; private StyleInfoCollection( int length, boolean nullValue ) { this.styleInfo = new ArrayList<StyleInfo>( length ); this.nullValue = nullValue; } public void add( StyleKey k, Object o ) { styleInfo.add( new StyleInfo( k.getIdentifier(), o ) ); } public long getStyleChangeTracker() { return styleChangeTracker; } private void setStyleChangeTracker( final long styleChangeTracker ) { this.styleChangeTracker = styleChangeTracker; } public boolean equals( final Object o ) { if ( this == o ) { return true; } if ( o == null || getClass() != o.getClass() ) { return false; } final StyleInfoCollection that = (StyleInfoCollection) o; if ( ObjectUtilities.equal( hashCode, that.hashCode ) == false ) { return false; } if ( !styleInfo.equals( that.styleInfo ) ) { return false; } if ( nullValue != that.nullValue ) { return false; } return true; } public int hashCode() { if ( hashCode == null ) { hashCode = styleInfo.hashCode() + 23 * ( nullValue ? 1 : 0 ); } return hashCode; } } private InstanceID rootBandId; private Map<InstanceID, StyleInfoCollection> dynamicStylePerElement; private Integer hashCode; private DynamicStyleKey( final InstanceID rootBandId, final Map<InstanceID, StyleInfoCollection> dynamicStylePerElement ) { this.rootBandId = rootBandId; this.dynamicStylePerElement = dynamicStylePerElement; } public boolean equals( final Object o ) { if ( this == o ) { return true; } if ( o == null || getClass() != o.getClass() ) { return false; } final DynamicStyleKey that = (DynamicStyleKey) o; if ( ObjectUtilities.equal( hashCode, that.hashCode ) == false ) { return false; } if ( !dynamicStylePerElement.equals( that.dynamicStylePerElement ) ) { return false; } if ( !rootBandId.equals( that.rootBandId ) ) { return false; } return true; } public int hashCode() { if ( hashCode == null ) { int result = rootBandId.hashCode(); result = 31 * result + dynamicStylePerElement.hashCode(); hashCode = result; } return hashCode; } public static DynamicStyleKey create( Band band, ExpressionRuntime runtime ) { Map<InstanceID, StyleInfoCollection> style = new DynamicStyleKeyProducer().collect( band, runtime ); return new DynamicStyleKey( band.getObjectID(), style ); } private static class DynamicStyleKeyProducer extends AbstractStructureVisitor { private HashMap<InstanceID, StyleKey[]> dynamicTemplateInfo; private HashMap<InstanceID, StyleInfoCollection> styleInfo; private ExpressionRuntime runtime; public Map<InstanceID, StyleInfoCollection> collect( Band band, ExpressionRuntime runtime ) { ArgumentNullException.validate( "band", band ); ArgumentNullException.validate( "runtime", runtime ); this.runtime = runtime; dynamicTemplateInfo = (HashMap<InstanceID, StyleKey[]>) band.getAttribute( AttributeNames.Internal.NAMESPACE, AttributeNames.Internal.FAST_EXPORT_DYNAMIC_STASH ); if ( dynamicTemplateInfo == null ) { return Collections.emptyMap(); } styleInfo = new HashMap<InstanceID, StyleInfoCollection>(); inspectElement( band ); traverseSection( band ); return styleInfo; } protected void traverseSection( final Section section ) { traverseSectionWithoutSubReports( section ); } protected void inspectElement( final ReportElement element ) { StyleKey[] styleIndex = dynamicTemplateInfo.get( element.getObjectID() ); if ( styleIndex == null || styleIndex.length == 0 ) { return; } Object value = element.getElementType().getValue( runtime, element ); boolean empty = isEmpty( value ); StyleInfoCollection lastCollection = (StyleInfoCollection) element.getAttribute( AttributeNames.Internal.NAMESPACE, AttributeNames.Internal.FAST_EXPORT_ELEMENT_STASH ); SimpleStyleSheet computedStyle = element.getComputedStyle(); if ( lastCollection != null && lastCollection.getStyleChangeTracker() == computedStyle.getChangeTrackerHash() && lastCollection.nullValue == empty ) { // no changes styleInfo.put( element.getObjectID(), lastCollection ); return; } StyleInfoCollection collection = new StyleInfoCollection( styleIndex.length, empty ); collection.setStyleChangeTracker( computedStyle.getChangeTrackerHash() ); for ( StyleKey styleKey : styleIndex ) { collection.add( styleKey, computedStyle.getStyleProperty( styleKey ) ); } styleInfo.put( element.getObjectID(), collection ); } private boolean isEmpty( Object o ) { if ( o == null ) { return true; } if ( "".equals( o ) ) { return true; } return false; } } }