Skip to content

Commit

Permalink
MONDRIAN: A new attribute "formatter" for a Level specifies a formatt…
Browse files Browse the repository at this point in the history
…er class (see mondrian.olap.MemberFormatter) to dynamically format a member caption beeing displayed.

A new attribute "formatter" for a Measure specifies a formatter class (see mondrian.olap.CellFormatter) to dynamically format a cell value beeing displayed.
A WHERE clause can be added to a schema table.

[git-p4: depot-paths = "//open/mondrian/": change = 2752]
  • Loading branch information
hhaas committed Oct 6, 2004
1 parent 7e946f3 commit 3e2e5bf
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 5 deletions.
57 changes: 57 additions & 0 deletions src/main/mondrian/olap/CellFormatter.java
@@ -0,0 +1,57 @@
/*
* ====================================================================
* Copyright (c) 2003 TONBELLER AG.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* TONBELLER AG (http://www.tonbeller.com)"
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE TON BELLER AG OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* $Id$
*/

package mondrian.olap;

/**
* this interface provides a user exit to format
* the cell value beeing beeing displayed.
*/
public interface CellFormatter {

/**
* user provided cell formatting function
* @param value
* @return the formatted value
*/
public String formatCell(Object value);

} // CellFormatter
4 changes: 4 additions & 0 deletions src/main/mondrian/olap/Level.java
Expand Up @@ -42,6 +42,10 @@ public interface Level extends OlapElement {
Property[] getProperties();
/** Returns properties defined against this level and parent levels. **/
Property[] getInheritedProperties();

/** @return the MemberFormatter
*/
MemberFormatter getMemberFormatter();
}

// End Level.java
7 changes: 7 additions & 0 deletions src/main/mondrian/olap/LevelBase.java
Expand Up @@ -29,6 +29,7 @@ public abstract class LevelBase
protected String description;
protected int depth;
protected LevelType levelType;
protected MemberFormatter memberFormatter = null;

// from Element
public String getQualifiedName() {
Expand Down Expand Up @@ -89,6 +90,12 @@ public void childrenAccept(Visitor visitor)
{
// we don't generally visit child members
}

/** @return the MemberFormatter
*/
public MemberFormatter getMemberFormatter(){
return memberFormatter;
}
}


Expand Down
7 changes: 7 additions & 0 deletions src/main/mondrian/olap/MemberBase.java
Expand Up @@ -44,6 +44,13 @@ public final String getUniqueName() {
return uniqueName;
}
public final String getCaption() {
// if there is a member formatter for the members level,
// we will call this interface to provide the display string
MemberFormatter mf = getLevel().getMemberFormatter();
if (mf != null) {
return mf.formatMember(this);
}

final String caption = (String) getPropertyValue(Property.PROPERTY_CAPTION);
if (caption != null) {
return caption;
Expand Down
49 changes: 49 additions & 0 deletions src/main/mondrian/olap/MemberFormatter.java
@@ -0,0 +1,49 @@
/*
* ====================================================================
* Copyright (c) 2003 TONBELLER AG.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* TONBELLER AG (http://www.tonbeller.com)"
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE TON BELLER AG OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* $Id$
*/
package mondrian.olap;

/**
* this interface provides a user exit to redefine
* the member caption beeing displayed.
*/
public interface MemberFormatter {
String formatMember(Member m);
} // MemberFormatter
27 changes: 26 additions & 1 deletion src/main/mondrian/olap/Mondrian.xml
Expand Up @@ -367,6 +367,12 @@ todo:
<Value>IfBlankName</Value>
<Value>IfParentsName</Value>
</Attribute>
<Attribute name="formatter" required="false">
<Doc>
Name of a formatter class for the member labels beeing displayed.
The class must implement the mondrian.olap.MemberFormatter interface.
</Doc>
</Attribute>
<Object name="keyExp" type="KeyExpression" required="false">
<Doc>
The SQL expression used to populate this level's key.
Expand Down Expand Up @@ -469,6 +475,12 @@ todo:
<Value>avg</Value>
<Value>distinct count</Value>
</Attribute>
<Attribute name="formatter" required="false">
<Doc>
Name of a formatter class for the appropriate cell beeing displayed.
The class must implement the mondrian.olap.CellFormatter interface.
</Doc>
</Attribute>
</Element>

<Element type="Parameter">
Expand Down Expand Up @@ -609,6 +621,12 @@ todo:
hierarchies, but it must have different aliases.)
</Doc>
</Attribute>
<Object name="filter" type="SQL" required="false">
<Doc>
The SQL WHERE clause expression to be appended to any select statement
</Doc>
</Object>

<Code><![CDATA[
/** Convenience contructor. **/
public Table(String schema, String name, String alias) {
Expand Down Expand Up @@ -649,7 +667,14 @@ todo:
}
public int hashCode() {
return toString().hashCode();
}]]>
}
public String getFilter() {
if (filter == null)
return null;
else
return filter.cdata;
}
]]>
</Code>
</Element>

Expand Down
24 changes: 23 additions & 1 deletion src/main/mondrian/rolap/RolapCube.java
Expand Up @@ -14,6 +14,7 @@
import mondrian.olap.*;
import mondrian.rolap.agg.AggregationManager;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
Expand Down Expand Up @@ -66,13 +67,26 @@ class RolapCube extends CubeBase
MondrianDef.Dimension xmlDimension = xmlCubeDimension.getDimension(xmlSchema);
dimensions[i + 1] = new RolapDimension(schema, this, xmlDimension, xmlCubeDimension);
}
RolapMeasure measures[] = new RolapMeasure[
RolapStoredMeasure measures[] = new RolapStoredMeasure[
xmlCube.measures.length];
for (int i = 0; i < xmlCube.measures.length; i++) {
MondrianDef.Measure xmlMeasure = xmlCube.measures[i];
measures[i] = new RolapStoredMeasure(
this, null, measuresLevel, xmlMeasure.name, xmlMeasure.formatString,
xmlMeasure.column, xmlMeasure.aggregator);

if (xmlMeasure.formatter != null) {
// there is a special cell formatter class
try {
Class clazz = Class.forName(xmlMeasure.formatter);
Constructor ctor = clazz.getConstructor(new Class[0]);
CellFormatter cellFormatter = (CellFormatter) ctor.newInstance(new Object[0]);
measures[i].setFormatter(cellFormatter);
} catch (Exception e) {
e.printStackTrace();
}
}

}
this.measuresHierarchy.memberReader = new CacheMemberReader(
new MeasureMemberSource(measuresHierarchy, measures));
Expand Down Expand Up @@ -338,6 +352,14 @@ public OlapElement lookupChild(OlapElement parent, String s) {
// use OlapElement's virtual lookup
return parent.lookupChild(getSchemaReader(), s);
}

/**
* get the measures hierarchy
*/
public Hierarchy getMeasuresHierarchy(){
return measuresHierarchy;
}

}

// End RolapCube.java
11 changes: 11 additions & 0 deletions src/main/mondrian/rolap/RolapLevel.java
Expand Up @@ -13,6 +13,7 @@
package mondrian.rolap;
import mondrian.olap.*;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;

Expand Down Expand Up @@ -169,6 +170,16 @@ private Property lookupProperty(ArrayList list, String propertyName) {
(xmlLevel.uniqueMembers.booleanValue() ? UNIQUE : 0),
HideMemberCondition.lookup(xmlLevel.hideMemberIf),
LevelType.lookup(xmlLevel.levelType));
if (xmlLevel.formatter != null) {
// there is a special member formatter class
try {
Class clazz = Class.forName(xmlLevel.formatter);
Constructor ctor = clazz.getConstructor(new Class[0]);
memberFormatter = (MemberFormatter) ctor.newInstance(new Object[0]);
} catch (Exception e) {
e.printStackTrace();
}
}
}

// helper for constructor
Expand Down
12 changes: 12 additions & 0 deletions src/main/mondrian/rolap/RolapResult.java
Expand Up @@ -21,6 +21,7 @@

import mondrian.olap.Axis;
import mondrian.olap.Cell;
import mondrian.olap.CellFormatter;
import mondrian.olap.Dimension;
import mondrian.olap.Evaluator;
import mondrian.olap.Exp;
Expand Down Expand Up @@ -54,6 +55,7 @@ class RolapResult extends ResultBase
FastBatchingCellReader batchingReader;
private int[] modulos;
private static final int MAX_AGGREGATION_PASS_COUNT = 5;
private Dimension measuresDim = null;

RolapResult(Query query) {
this.query = query;
Expand Down Expand Up @@ -140,6 +142,7 @@ class RolapResult extends ResultBase
} finally {
evaluator.clearExpResultCache();
}
query.getCube().getDimensions();
}

// implement Result
Expand Down Expand Up @@ -505,6 +508,15 @@ public Object getValue() {
public String getFormattedValue() {
final int[] pos = result.getCellPos(ordinal);
final Evaluator evaluator = result.getEvaluator(pos);
RolapCube c = (RolapCube) evaluator.getCube();
Dimension measuresDim = c.getMeasuresHierarchy().getDimension();
Member m = evaluator.getContext(measuresDim);
CellFormatter cf = null;
if (m instanceof RolapStoredMeasure)
cf = ((RolapStoredMeasure)m).getFormatter();
if (cf != null){
return cf.formatCell(value);
}
return evaluator.format(value);
}
public boolean isNull() {
Expand Down
5 changes: 4 additions & 1 deletion src/main/mondrian/rolap/RolapSchema.java
Expand Up @@ -262,7 +262,10 @@ synchronized RolapSchema get(
RolapSchema schema = (RolapSchema) mapUrlToSchema.get(key);
if (schema == null) {
schema = new RolapSchema(catalogName, connectInfo);
mapUrlToSchema.put(key, schema);
// do not chache the schema, if it dynamic
// .i.e created from an http URL.
if (!catalogName.toLowerCase().startsWith("http"))
mapUrlToSchema.put(key, schema);
// Must create RolapConnection after we add to map, otherwise
// we will loop.
// no, this is redundant - its set in the ctor of RolapSchema
Expand Down
9 changes: 9 additions & 0 deletions src/main/mondrian/rolap/RolapStoredMeasure.java
Expand Up @@ -11,6 +11,7 @@
*/

package mondrian.rolap;
import mondrian.olap.CellFormatter;
import mondrian.olap.MondrianDef;
import mondrian.olap.Property;
import mondrian.olap.Util;
Expand All @@ -30,6 +31,8 @@ class RolapStoredMeasure extends RolapMeasure
final RolapAggregator aggregator;
final RolapCube cube;

CellFormatter formatter = null;

RolapStoredMeasure(
RolapCube cube, RolapMember parentMember, RolapLevel level, String name,
String formatString, MondrianDef.Expression expression,
Expand Down Expand Up @@ -59,6 +62,12 @@ CellReader getCellReader() {
return cube.cellReader;
}

public CellFormatter getFormatter(){
return formatter;
}
void setFormatter(CellFormatter formatter){
this.formatter = formatter;
}
}

// End RolapStoredMeasure.java
9 changes: 7 additions & 2 deletions src/main/mondrian/rolap/sql/SqlQuery.java
Expand Up @@ -351,7 +351,7 @@ public boolean addFromQuery(
* @return true if table *was* added
*/
private boolean addFromTable(
String schema, String table, String alias, boolean failIfExists) {
String schema, String table, String alias, String filter, boolean failIfExists) {
if (fromAliases.contains(alias)) {
if (failIfExists) {
throw Util.newInternal(
Expand All @@ -376,6 +376,11 @@ private boolean addFromTable(
from.append(quoteIdentifier(alias));
fromAliases.add(alias);
}
if ( filter != null ) {
// append filter condition to where clause
String wclause = "(" + filter + ")";
addWhere(wclause);
}
return true;
}

Expand All @@ -399,7 +404,7 @@ public boolean addFrom(MondrianDef.Relation relation, boolean failIfExists) {
} else if (relation instanceof MondrianDef.Table) {
MondrianDef.Table table = (MondrianDef.Table) relation;
return addFromTable(
table.schema, table.name, table.getAlias(), failIfExists);
table.schema, table.name, table.getAlias(), table.getFilter(), failIfExists);
} else if (relation instanceof MondrianDef.Join) {
MondrianDef.Join join = (MondrianDef.Join) relation;
boolean added = false;
Expand Down

0 comments on commit 3e2e5bf

Please sign in to comment.