diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCell.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCell.java index d62423d..cc215c6 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCell.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCell.java @@ -2,7 +2,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2007-2008 Julian Hyde +// Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -10,6 +10,7 @@ import org.olap4j.*; import org.olap4j.impl.ArrayMap; +import org.olap4j.impl.UnmodifiableArrayMap; import org.olap4j.metadata.Property; import java.sql.ResultSet; @@ -42,12 +43,9 @@ class XmlaOlap4jCell implements Cell { this.value = value; this.formattedValue = formattedValue; - // Use emptyMap and ArrayMap for memory efficiency, because cells + // Use an ArrayMap for memory efficiency, because cells // typically have few properties, but there are a lot of cells - this.propertyValues = - propertyValues.isEmpty() - ? Collections.emptyMap() - : new ArrayMap(propertyValues); + this.propertyValues = UnmodifiableArrayMap.of(propertyValues); } public CellSet getCellSet() { diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCellProperty.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCellProperty.java index 6d6cd52..fc7b358 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCellProperty.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCellProperty.java @@ -2,7 +2,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2007-2008 Julian Hyde +// Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -40,7 +40,7 @@ public Datatype getDatatype() { } public Set getType() { - return TypeFlag.forMask(TypeFlag.CELL.xmlaOrdinal); + return TypeFlag.CELL_TYPE_FLAG; } public String getName() { diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMemberProperty.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMemberProperty.java index 5536265..c90c335 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMemberProperty.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCellSetMemberProperty.java @@ -2,7 +2,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2007-2008 Julian Hyde +// Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -43,7 +43,7 @@ public Datatype getDatatype() { } public Set getType() { - return TypeFlag.forMask(TypeFlag.MEMBER.xmlaOrdinal); + return TypeFlag.MEMBER_TYPE_FLAG; } public String getName() { diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java index 40643e4..05539d4 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java @@ -196,7 +196,7 @@ abstract class XmlaOlap4jConnection implements OlapConnection { * Returns the error-handler * @return Error-handler */ - private final XmlaHelper getHelper() { + private XmlaHelper getHelper() { return helper; } @@ -975,6 +975,7 @@ public void handle( static class DimensionHandler extends HandlerImpl { private final XmlaOlap4jCube cubeForCallback; + public DimensionHandler(XmlaOlap4jCube dimensionsByUname) { this.cubeForCallback = dimensionsByUname; } @@ -1016,7 +1017,7 @@ public void handle( final int dimensionType = integerElement(row, "DIMENSION_TYPE"); final Dimension.Type type = - Dimension.Type.forXmlaOrdinal(dimensionType); + Dimension.Type.getDictionary().forOrdinal(dimensionType); final String defaultHierarchyUniqueName = stringElement(row, "DEFAULT_HIERARCHY"); final Integer dimensionOrdinal = @@ -1117,6 +1118,7 @@ public void handle( static class LevelHandler extends HandlerImpl { public static final int MDLEVEL_TYPE_CALCULATED = 0x0002; private final XmlaOlap4jCube cubeForCallback; + public LevelHandler(XmlaOlap4jCube cubeForCallback) { this.cubeForCallback = cubeForCallback; } @@ -1161,7 +1163,7 @@ public void handle( integerElement(row, "LEVEL_NUMBER"); final Integer levelTypeCode = integerElement(row, "LEVEL_TYPE"); final Level.Type levelType = - Level.Type.forXmlaOrdinal(levelTypeCode); + Level.Type.getDictionary().forOrdinal(levelTypeCode); boolean calculated = (levelTypeCode & MDLEVEL_TYPE_CALCULATED) != 0; final int levelCardinality = integerElement(row, "LEVEL_CARDINALITY"); @@ -1178,6 +1180,7 @@ public void handle( static class MeasureHandler extends HandlerImpl { private final XmlaOlap4jDimension measuresDimension; + public MeasureHandler(XmlaOlap4jDimension measuresDimension) { this.measuresDimension = measuresDimension; } @@ -1213,10 +1216,11 @@ public void handle( final String description = stringElement(row, "DESCRIPTION"); final Measure.Aggregator measureAggregator = - Measure.Aggregator.forXmlaOrdinal( - integerElement(row, "MEASURE_AGGREGATOR")); + Measure.Aggregator.getDictionary().forOrdinal( + integerElement( + row, "MEASURE_AGGREGATOR")); final Datatype datatype = - Datatype.forXmlaOrdinal( + Datatype.getDictionary().forOrdinal( integerElement(row, "DATA_TYPE")); final boolean measureIsVisible = booleanElement(row, "MEASURE_IS_VISIBLE"); @@ -1533,6 +1537,7 @@ public void handle( } static class PropertyHandler extends HandlerImpl { + public void handle( Element row, Context context, List list) throws OlapException @@ -1561,17 +1566,18 @@ public void handle( String caption = stringElement(row, "PROPERTY_CAPTION"); String name = stringElement(row, "PROPERTY_NAME"); Datatype dataType = - Datatype.forXmlaOrdinal( + Datatype.getDictionary().forOrdinal( integerElement(row, "DATA_TYPE")); final Integer contentTypeOrdinal = integerElement(row, "PROPERTY_CONTENT_TYPE"); Property.ContentType contentType = contentTypeOrdinal == null ? null - : Property.ContentType.forXmlaOrdinal(contentTypeOrdinal); + : Property.ContentType.getDictionary().forOrdinal( + contentTypeOrdinal); int propertyType = integerElement(row, "PROPERTY_TYPE"); Set type = - Property.TypeFlag.forMask(propertyType); + Property.TypeFlag.getDictionary().forMask(propertyType); list.add( new XmlaOlap4jProperty( uniqueName, name, caption, description, dataType, type, diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java b/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java index 65194a5..ae26540 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java @@ -2,7 +2,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2007-2008 Julian Hyde +// Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -81,12 +81,7 @@ class XmlaOlap4jMember this.parentMemberUniqueName = parentMemberUniqueName; this.type = type; this.childMemberCount = childMemberCount; - if (propertyValueMap.isEmpty()) { - this.propertyValueMap = Collections.emptyMap(); - } else { - this.propertyValueMap = - new ArrayMap(propertyValueMap); - } + this.propertyValueMap = UnmodifiableArrayMap.of(propertyValueMap); } public int hashCode() { diff --git a/src/org/olap4j/impl/ArrayMap.java b/src/org/olap4j/impl/ArrayMap.java index 55b4986..ace6a17 100644 --- a/src/org/olap4j/impl/ArrayMap.java +++ b/src/org/olap4j/impl/ArrayMap.java @@ -2,7 +2,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2007-2009 Julian Hyde +// Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -53,6 +53,27 @@ public ArrayMap(Map map) { } } + /** + * Returns an array map with given contents. + * + * @param key First key + * @param value First value + * @param keyValues Second and sequent key/value pairs + * @param Key type + * @param Value type + * @return Map with given contents + */ + public static Map of( + K key, + V value, + Object... keyValues) + { + // Because ArrayMap is so bad at bulk inserts, it makes sense to build + // another map (HashMap) just so we can populate the ArrayMap in one + // shot. + return new ArrayMap(Olap4jUtil.mapOf(key, value, keyValues)); + } + public boolean equals(Object o) { if (o == this) { return true; @@ -65,9 +86,7 @@ public boolean equals(Object o) { return false; } try { - Iterator> i = entrySet().iterator(); - while (i.hasNext()) { - Entry e = i.next(); + for (Entry e : entrySet()) { K key = e.getKey(); V value = e.getValue(); if (value == null) { @@ -210,6 +229,27 @@ public Set> entrySet() { return new EntrySet(); } + public String toString() { + Iterator> i = entrySet().iterator(); + if (! i.hasNext()) { + return "{}"; + } + StringBuilder sb = new StringBuilder(); + sb.append('{'); + for (;;) { + Entry e = i.next(); + K key = e.getKey(); + V value = e.getValue(); + sb.append(key == this ? "(this Map)" : key); + sb.append('='); + sb.append(value == this ? "(this Map)" : value); + if (! i.hasNext()) { + return sb.append('}').toString(); + } + sb.append(", "); + } + } + private class KeySet extends AbstractSet { public Iterator iterator() { return new Iterator() { diff --git a/src/org/olap4j/impl/Olap4jUtil.java b/src/org/olap4j/impl/Olap4jUtil.java index b8abb8d..67791f4 100644 --- a/src/org/olap4j/impl/Olap4jUtil.java +++ b/src/org/olap4j/impl/Olap4jUtil.java @@ -2,7 +2,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2007-2008 Julian Hyde +// Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -143,6 +143,38 @@ public static NamedList cast(NamedList list) { return (NamedList) list; } + /** + * Returns a hashmap with given contents. + * + *

Use this method in initializers. Type parameters are inferred from + * context, and the contents are initialized declaratively. For example, + * + *

Map<String, Integer> population =
+ *   Olap4jUtil.mapOf(
+ *     "UK", 65000000,
+ *     "USA", 300000000);
+ * + * @see org.olap4j.impl.UnmodifiableArrayMap#of(Object, Object, Object...) + * @see org.olap4j.impl.ArrayMap#of(Object, Object, Object...) + * + * @param key First key + * @param value First value + * @param keyValues Second and sequent key/value pairs + * @param Key type + * @param Value type + * @return Map with given contents + */ + public static Map mapOf(K key, V value, Object... keyValues) + { + final Map map = new LinkedHashMap(1 + keyValues.length); + map.put(key, value); + for (int i = 0; i < keyValues.length;) { + //noinspection unchecked + map.put((K) keyValues[i++], (V) keyValues[i++]); + } + return map; + } + /** * Returns an exception indicating that we didn't expect to find this value * here. diff --git a/src/org/olap4j/impl/UnmodifiableArrayMap.java b/src/org/olap4j/impl/UnmodifiableArrayMap.java new file mode 100644 index 0000000..642ce4e --- /dev/null +++ b/src/org/olap4j/impl/UnmodifiableArrayMap.java @@ -0,0 +1,115 @@ +/* +// $Id: AbstractNamedList.java 229 2009-05-08 19:11:29Z jhyde $ +// This software is subject to the terms of the Eclipse Public License v1.0 +// Agreement, available at the following URL: +// http://www.eclipse.org/legal/epl-v10.html. +// Copyright (C) 2010-2010 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.impl; + +import java.util.*; + +/** + * Unmodifiable map backed by an array. + * + *

Has the same benefits and limitations as {@link ArrayMap}. It is extremely + * space-efficient but has poor performance for insert and lookup. + * + *

This structure is ideal if you are creating many maps with few elements. + * The {@link #of(java.util.Map)} method will use + * {@link java.util.Collections#emptyMap} and + * {@link java.util.Collections#singletonMap(Object, Object)} if possible, and + * these are even more space-efficient for maps of size 0 and 1. + * + * @author jhyde + * @version $Id: AbstractNamedList.java 229 2009-05-08 19:11:29Z jhyde $ + * @since Jan 16, 2010 + */ +public class UnmodifiableArrayMap + extends ArrayMap +{ + /** + * Creates an UnmodifiableArrayMap. + * + * @param map Contents of map, copied on creation + */ + public UnmodifiableArrayMap(Map map) { + super(map); + } + + @Override + public V put(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + /** + * Returns an unmodifiable array map with given contents. + * + * @param key First key + * @param value First value + * @param keyValues Second and sequent key/value pairs + * @param Key type + * @param Value type + * @return Map with given contents + */ + public static Map of( + K key, + V value, + Object... keyValues) + { + if (keyValues.length == 0) { + return Collections.singletonMap(key, value); + } + // Because UnmodifiableArrayMap is so bad at bulk inserts, it makes + // sense to build another map just so we can populate the + // UnmodifiableArrayMap in one shot. We require that the other map + // preserves order; luckily mapOf uses LinkedHashMap. + return new UnmodifiableArrayMap( + Olap4jUtil.mapOf(key, value, keyValues)); + } + + /** + * Creates an unmodifable map as a shallow copy of a map. + * + *

Future changes to the map will not be reflected in the contents + * of the map. + * + * @param Key type + * @param Value type + * @return Unmodifiable map with same contents that the map had at + * call time + */ + public static Map of( + Map map) + { + switch (map.size()) { + case 0: + return Collections.emptyMap(); + case 1: + final Entry entry = map.entrySet().iterator().next(); + return Collections.singletonMap(entry.getKey(), entry.getValue()); + default: + //noinspection unchecked + return new UnmodifiableArrayMap(map); + } + } +} + +// End UnmodifiableArrayMap.java diff --git a/src/org/olap4j/metadata/Datatype.java b/src/org/olap4j/metadata/Datatype.java index a7423c4..ab3a07c 100644 --- a/src/org/olap4j/metadata/Datatype.java +++ b/src/org/olap4j/metadata/Datatype.java @@ -3,15 +3,12 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2006-2008 Julian Hyde +// Copyright (C) 2006-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ package org.olap4j.metadata; -import java.util.Map; -import java.util.HashMap; - /** * Enumeration of the allowable data types of a Property or Measure. * @@ -22,7 +19,7 @@ * @version $Id$ * @since Aug 23, 2006 */ -public enum Datatype { +public enum Datatype implements XmlaConstant { /* * The following values exactly match VARENUM * in Automation and may be used in VARIANT. @@ -88,15 +85,11 @@ public enum Datatype { + "integer."); private final int xmlaOrdinal; + private String dbTypeIndicator; + private String description; - private static final Map xmlaMap = - new HashMap(); - - static { - for (Datatype datatype : values()) { - xmlaMap.put(datatype.xmlaOrdinal, datatype); - } - } + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(Datatype.class); Datatype( int xmlaOrdinal, @@ -104,21 +97,31 @@ public enum Datatype { String description) { this.xmlaOrdinal = xmlaOrdinal; + this.dbTypeIndicator = dbTypeIndicator; + this.description = description; + } + + public String xmlaName() { + return dbTypeIndicator; + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; } /** - * Looks up a Datatype by its XMLA ordinal. + * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary + * of all values of this enumeration. * - * @param xmlaOrdinal Ordinal of a Datatype according to the XMLA - * specification. - * - * @return Datatype with the given ordinal, or null if there is no - * such Datatype + * @return Dictionary of all values */ - public static Datatype forXmlaOrdinal(int xmlaOrdinal) { - return xmlaMap.get(xmlaOrdinal); + public static Dictionary getDictionary() { + return DICTIONARY; } - } // End Datatype.java diff --git a/src/org/olap4j/metadata/DictionaryImpl.java b/src/org/olap4j/metadata/DictionaryImpl.java new file mode 100644 index 0000000..f28c7cc --- /dev/null +++ b/src/org/olap4j/metadata/DictionaryImpl.java @@ -0,0 +1,97 @@ +/* +// $Id: Datatype.java 253 2009-06-30 03:06:10Z jhyde $ +// This software is subject to the terms of the Eclipse Public License v1.0 +// Agreement, available at the following URL: +// http://www.eclipse.org/legal/epl-v10.html. +// Copyright (C) 2010-2010 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.metadata; + +import java.util.*; + +/** + * Implementation of {@link org.olap4j.metadata.XmlaConstant.Dictionary}. + * + * @author jhyde + * @version $Id: $ + */ +class DictionaryImpl & XmlaConstant> + implements XmlaConstant.Dictionary +{ + private final Class clazz; + private final Map byName = new HashMap(); + private final Map byOrdinal = new HashMap(); + private final List values; + + private static final Map map = + new HashMap(); + + public DictionaryImpl(Class clazz) { + this.clazz = clazz; + this.values = + Collections.unmodifiableList( + Arrays.asList(clazz.getEnumConstants())); + for (E e : values) { + byName.put(e.xmlaName(), e); + byOrdinal.put(e.xmlaOrdinal(), e); + } + } + + public static & XmlaConstant> DictionaryImpl forClass( + Class clazz) + { + assert clazz != null; + synchronized (map) { + @SuppressWarnings({"unchecked"}) + DictionaryImpl directory = map.get(clazz); + if (directory == null) { + directory = new DictionaryImpl(clazz); + map.put(clazz, directory); + } + return directory; + } + } + + public E forOrdinal(int xmlaOrdinal) + { + return byOrdinal.get(xmlaOrdinal); + } + + public E forName(String xmlaName) + { + return byName.get(xmlaName); + } + + public Set forMask( + int xmlaOrdinalMask) + { + Set set = EnumSet.noneOf(clazz); + for (E e : clazz.getEnumConstants()) { + if ((xmlaOrdinalMask & e.xmlaOrdinal()) != 0) { + set.add(e); + } + } + return set; + } + + public int toMask(Set set) + { + int mask = 0; + for (E e : set) { + mask |= e.xmlaOrdinal(); + } + return mask; + } + + public List getValues() { + return values; + } + + public Class getEnumClass() { + return clazz; + } +} + +// End DictionaryImpl.java diff --git a/src/org/olap4j/metadata/Dimension.java b/src/org/olap4j/metadata/Dimension.java index b11d6c4..b548024 100644 --- a/src/org/olap4j/metadata/Dimension.java +++ b/src/org/olap4j/metadata/Dimension.java @@ -3,7 +3,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2006-2009 Julian Hyde +// Copyright (C) 2006-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -11,9 +11,6 @@ import org.olap4j.OlapException; -import java.util.HashMap; -import java.util.Map; - /** * An organized hierarchy of categories, known as levels, that describes data * in a cube. @@ -73,7 +70,7 @@ public interface Dimension extends MetadataElement { * @see Member.Type * @see Dimension#getDimensionType */ - public enum Type { + public enum Type implements XmlaConstant { /** * Indicates that the dimension is not related to time. */ @@ -106,14 +103,17 @@ public enum Type { private final int xmlaOrdinal; - private static final Map xmlaOrdinalTypeMap; + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(Type.class); - static { - Map map = new HashMap(); - for (Type type : values()) { - map.put(type.xmlaOrdinal, type); - } - xmlaOrdinalTypeMap = map; + /** + * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; } /** @@ -125,26 +125,16 @@ private Type(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } - /** - * Returns the ordinal code as specified by XMLA. - * - *

For example, the XMLA specification says that the ordinal of - * {@link #PRODUCTS} is 8. - * - * @return ordinal code as specified by XMLA. - */ - public final int xmlaOrdinal() { - return xmlaOrdinal; + public String xmlaName() { + return "MD_DIMTYPE_" + name(); } - /** - * Returns the type whose XMLA ordinal code is as given. - * - * @param xmlaOrdinal Ordinal code as specified by XMLA - * @return Dimension type, or null - */ - public static Type forXmlaOrdinal(int xmlaOrdinal) { - return xmlaOrdinalTypeMap.get(xmlaOrdinal); + public String getDescription() { + return ""; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; } } } diff --git a/src/org/olap4j/metadata/Level.java b/src/org/olap4j/metadata/Level.java index a3c98b6..d8247b2 100644 --- a/src/org/olap4j/metadata/Level.java +++ b/src/org/olap4j/metadata/Level.java @@ -3,7 +3,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2006-2008 Julian Hyde +// Copyright (C) 2006-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -168,7 +168,7 @@ public interface Level extends MetadataElement { * @see Level#getLevelType * @see org.olap4j.OlapDatabaseMetaData#getLevels */ - public enum Type { + public enum Type implements XmlaConstant { /** * Indicates that the level is not related to time. @@ -285,13 +285,17 @@ public enum Type { private final int xmlaOrdinal; - private static final Map xmlaMap = - new HashMap(); + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(Type.class); - static { - for (Type type : values()) { - xmlaMap.put(type.xmlaOrdinal, type); - } + /** + * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; } /** @@ -304,29 +308,16 @@ private Type(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } - /** - * Returns the ordinal code as specified by XMLA. - * - *

For example, the XMLA specification says that the ordinal of - * {@link #CUSTOMER_HOUSEHOLD} is 0x1023. - * - * @return ordinal code as specified by XMLA. - */ - public int xmlaOrdinal() { - return xmlaOrdinal; + public String xmlaName() { + return "MDLEVEL_TYPE_" + name(); } - /** - * Looks up a Type by its XMLA ordinal. - * - * @param xmlaOrdinal Ordinal of a level Type according to XMLA - * specification. - * - * @return Type with the given ordinal, or null if there is no such - * Type - */ - public static Type forXmlaOrdinal(int xmlaOrdinal) { - return xmlaMap.get(xmlaOrdinal); + public String getDescription() { + return ""; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; } /** diff --git a/src/org/olap4j/metadata/Measure.java b/src/org/olap4j/metadata/Measure.java index c2e4aee..5eae0ac 100644 --- a/src/org/olap4j/metadata/Measure.java +++ b/src/org/olap4j/metadata/Measure.java @@ -3,14 +3,12 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2006-2008 Julian Hyde +// Copyright (C) 2006-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ package org.olap4j.metadata; -import java.util.*; - /** * Data value of primary interest to the user browsing the cube. * @@ -52,7 +50,7 @@ public interface Measure extends Member { * which corresponds to the value {@link #SUM}, * whose {@link #xmlaOrdinal} is 1. */ - enum Aggregator { + enum Aggregator implements XmlaConstant { /** * Identifies that the measure was derived using the * SUM aggregation function. @@ -101,15 +99,8 @@ enum Aggregator { UNKNOWN(0); private final int xmlaOrdinal; - - private static final Map xmlaMap = - new HashMap(); - - static { - for (Aggregator aggregator : values()) { - xmlaMap.put(aggregator.xmlaOrdinal, aggregator); - } - } + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(Aggregator.class); /** * Creates an Aggregator. @@ -121,29 +112,26 @@ private Aggregator(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } - /** - * Returns the ordinal code as specified by XMLA. - * - *

For example, the XMLA specification says that the ordinal of - * {@link #CALCULATED} is 127. - * - * @return ordinal code as specified by XMLA. - */ - public final int xmlaOrdinal() { + public String xmlaName() { + return "MDMEASURE_AGGR_" + name(); + } + + public String getDescription() { + return ""; + } + + public int xmlaOrdinal() { return xmlaOrdinal; } /** - * Looks up an Aggregator by its XMLA ordinal. - * - * @param xmlaOrdinal Ordinal of an Aggregator according to the XMLA - * specification. + * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary + * of all values of this enumeration. * - * @return Aggregator with the given ordinal, or null if there is no - * such Aggregator + * @return Dictionary of all values */ - public static Aggregator forXmlaOrdinal(int xmlaOrdinal) { - return xmlaMap.get(xmlaOrdinal); + public static Dictionary getDictionary() { + return DICTIONARY; } } } diff --git a/src/org/olap4j/metadata/Member.java b/src/org/olap4j/metadata/Member.java index 53a687d..0aba722 100644 --- a/src/org/olap4j/metadata/Member.java +++ b/src/org/olap4j/metadata/Member.java @@ -3,7 +3,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2006-2008 Julian Hyde +// Copyright (C) 2006-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -310,51 +310,79 @@ private Type(int ordinal) { * * @see org.olap4j.OlapDatabaseMetaData#getMembers */ - public enum TreeOp { + public enum TreeOp implements XmlaConstant { /** * Tree operation which returns only the immediate children. */ - CHILDREN(1), + CHILDREN( + 1, + "Tree operation which returns only the immediate children."), /** * Tree operation which returns members on the same level. */ - SIBLINGS(2), + SIBLINGS( + 2, + "Tree operation which returns members on the same level."), /** * Tree operation which returns only the immediate parent. */ - PARENT(4), + PARENT( + 4, + "Tree operation which returns only the immediate parent."), /** * Tree operation which returns itself in the list of returned rows. */ - SELF(8), + SELF( + 8, + "Tree operation which returns itself in the list of returned " + + "rows."), /** * Tree operation which returns all of the descendants. */ - DESCENDANTS(16), + DESCENDANTS( + 16, + "Tree operation which returns all of the descendants."), /** * Tree operation which returns all of the ancestors. */ - ANCESTORS(32); + ANCESTORS( + 32, + "Tree operation which returns all of the ancestors."); private final int xmlaOrdinal; + private String description; - private TreeOp(int userOrdinal) { - this.xmlaOrdinal = userOrdinal; - } + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(TreeOp.class); /** - * Returns the ordinal code as specified by XMLA. - * - *

For example, the XMLA specification says that the ordinal of - * {@link #ANCESTORS} is 32. + * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary + * of all values of this enumeration. * - * @return ordinal code as specified by XMLA. + * @return Dictionary of all values */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + private TreeOp(int xmlaOrdinal, String description) { + this.xmlaOrdinal = xmlaOrdinal; + this.description = description; + } + + public String xmlaName() { + return "MDTREEOP_" + name(); + } + + public String getDescription() { + return description; + } + public int xmlaOrdinal() { return xmlaOrdinal; } diff --git a/src/org/olap4j/metadata/Property.java b/src/org/olap4j/metadata/Property.java index f1333f5..0acec48 100644 --- a/src/org/olap4j/metadata/Property.java +++ b/src/org/olap4j/metadata/Property.java @@ -3,7 +3,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2006-2008 Julian Hyde +// Copyright (C) 2006-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -52,7 +52,7 @@ public interface Property extends MetadataElement { * In this case, {@link Property#getType} will return the {@link Set} * {{@link #MEMBER}, {@link #BLOB}}. */ - enum TypeFlag { + enum TypeFlag implements XmlaConstant { /** * Identifies a property of a member. This property can be used in the * DIMENSION PROPERTIES clause of the SELECT statement. @@ -76,64 +76,39 @@ enum TypeFlag { */ BLOB(8); - public final int xmlaOrdinal; - private static final Map xmlaMap = - new HashMap(); - - static { - for (TypeFlag typeFlag : values()) { - xmlaMap.put(typeFlag.xmlaOrdinal, typeFlag); - } - } + private final int xmlaOrdinal; - private static final Set CELL_TYPE_FLAG = + public static final Set CELL_TYPE_FLAG = Collections.unmodifiableSet(EnumSet.of(TypeFlag.CELL)); - private static final Set MEMBER_TYPE_FLAG = + public static final Set MEMBER_TYPE_FLAG = Collections.unmodifiableSet(EnumSet.of(TypeFlag.MEMBER)); + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(TypeFlag.class); private TypeFlag(int xmlaOrdinal) { this.xmlaOrdinal = xmlaOrdinal; } - /** - * Looks up a TypeFlag by its XMLA ordinal. - * - * @param xmlaOrdinal Ordinal of a TypeFlag according to the XMLA - * specification. - * - * @return TypeFlag with the given ordinal, or null if there is no - * such TypeFlag - */ - public static TypeFlag forXmlaOrdinal(int xmlaOrdinal) { - return xmlaMap.get(xmlaOrdinal); + public String xmlaName() { + return "MDPROP_" + name(); + } + + public String getDescription() { + return null; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; } /** - * Creates a set of TypeFlag values by parsing a mask. + * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary + * of all values of this enumeration. * - *

For example, forMask(9) returns the set - * {{@link #MEMBER}, {@link #BLOB}} because 9 = MEMBER (1) | BLOB (8). - * - * @param xmlaOrdinalMask Bit mask - * @return Set of TypeFlag values - */ - public static Set forMask(int xmlaOrdinalMask) { - switch (xmlaOrdinalMask) { - // Optimize common cases {MEMBER} and {CELL}. - case 1: - return MEMBER_TYPE_FLAG; - case 2: - return CELL_TYPE_FLAG; - default: - Set type = - EnumSet.noneOf(TypeFlag.class); - for (TypeFlag typeFlag : values()) { - if ((xmlaOrdinalMask & typeFlag.xmlaOrdinal) != 0) { - type.add(typeFlag); - } - } - return type; - } + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; } } @@ -171,7 +146,9 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 10, false, - "Optional. The name of the catalog to which this member belongs. NULL if the provider does not support catalogs."), + null, + "Optional. The name of the catalog to which this member belongs. " + + "NULL if the provider does not support catalogs."), /** * Definition of the property which @@ -181,7 +158,9 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 11, false, - "Optional. The name of the schema to which this member belongs. NULL if the provider does not support schemas."), + null, + "Optional. The name of the schema to which this member belongs. " + + "NULL if the provider does not support schemas."), /** * Definition of the property which @@ -191,7 +170,7 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 12, false, - "Required. Name of the cube to which this member belongs."), + null, "Required. Name of the cube to which this member belongs."), /** * Definition of the property which @@ -201,7 +180,10 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 13, false, - "Required. Unique name of the dimension to which this member belongs. For providers that generate unique names by qualification, each component of this name is delimited."), + null, + "Required. Unique name of the dimension to which this member " + + "belongs. For providers that generate unique names by " + + "qualification, each component of this name is delimited."), /** * Definition of the property which @@ -211,7 +193,11 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 14, false, - "Required. Unique name of the hierarchy. If the member belongs to more than one hierarchy, there is one row for each hierarchy to which it belongs. For providers that generate unique names by qualification, each component of this name is delimited."), + null, + "Required. Unique name of the hierarchy. If the member belongs to " + + "more than one hierarchy, there is one row for each hierarchy " + + "to which it belongs. For providers that generate unique names " + + "by qualification, each component of this name is delimited."), /** * Definition of the property which @@ -221,7 +207,10 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 15, false, - "Required. Unique name of the level to which the member belongs. For providers that generate unique names by qualification, each component of this name is delimited."), + null, + "Required. Unique name of the level to which the member belongs. " + + "For providers that generate unique names by qualification, " + + "each component of this name is delimited."), /** * Definition of the property which @@ -231,7 +220,9 @@ enum StandardMemberProperty implements Property { Datatype.UNSIGNED_INTEGER, 16, false, - "Required. The distance of the member from the root of the hierarchy. The root level is zero."), + null, + "Required. The distance of the member from the root of the " + + "hierarchy. The root level is zero."), /** * Definition of the property which @@ -241,7 +232,11 @@ enum StandardMemberProperty implements Property { Datatype.UNSIGNED_INTEGER, 17, false, - "Required. Ordinal number of the member. Sort rank of the member when members of this dimension are sorted in their natural sort order. If providers do not have the concept of natural ordering, this should be the rank when sorted by MEMBER_NAME."), + null, + "Required. Ordinal number of the member. Sort rank of the member " + + "when members of this dimension are sorted in their natural " + + "sort order. If providers do not have the concept of natural " + + "ordering, this should be the rank when sorted by MEMBER_NAME."), /** * Definition of the property which @@ -251,6 +246,7 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 18, false, + null, "Required. Name of the member."), /** @@ -261,7 +257,10 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 19, false, - "Required. Unique name of the member. For providers that generate unique names by qualification, each component of this name is delimited."), + null, + "Required. Unique name of the member. For providers that generate " + + "unique names by qualification, each component of this name is " + + "delimited."), /** * Definition of the property which @@ -271,7 +270,15 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 20, false, - "Required. Type of the member. Can be one of the following values: MDMEMBER_Datatype.TYPE_REGULAR, MDMEMBER_Datatype.TYPE_ALL, MDMEMBER_Datatype.TYPE_FORMULA, MDMEMBER_Datatype.TYPE_MEASURE, MDMEMBER_Datatype.TYPE_UNKNOWN. MDMEMBER_Datatype.TYPE_FORMULA takes precedence over MDMEMBER_Datatype.TYPE_MEASURE. Therefore, if there is a formula (calculated) member on the Measures dimension, it is listed as MDMEMBER_Datatype.TYPE_FORMULA."), + null, + "Required. Type of the member. Can be one of the following values: " + + "MDMEMBER_Datatype.TYPE_REGULAR, MDMEMBER_Datatype.TYPE_ALL, " + + "MDMEMBER_Datatype.TYPE_FORMULA, MDMEMBER_Datatype.TYPE_MEASURE, " + + "MDMEMBER_Datatype.TYPE_UNKNOWN. MDMEMBER_Datatype.TYPE_FORMULA " + + "takes precedence over MDMEMBER_Datatype.TYPE_MEASURE. " + + "Therefore, if there is a formula (calculated) member on the " + + "Measures dimension, it is listed as " + + "MDMEMBER_Datatype.TYPE_FORMULA."), /** * Definition of the property which @@ -281,6 +288,7 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 21, false, + null, "Optional. Member GUID. NULL if no GUID exists."), /** @@ -292,7 +300,10 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 22, false, - "Required. A label or caption associated with the member. Used primarily for display purposes. If a caption does not exist, MEMBER_NAME is returned."), + null, + "Required. A label or caption associated with the member. Used " + + "primarily for display purposes. If a caption does not exist, " + + "MEMBER_NAME is returned."), /** * Definition of the property which holds the @@ -302,7 +313,10 @@ enum StandardMemberProperty implements Property { Datatype.UNSIGNED_INTEGER, 23, false, - "Required. Number of children that the member has. This can be an estimate, so consumers should not rely on this to be the exact count. Providers should return the best estimate possible."), + null, + "Required. Number of children that the member has. This can be an " + + "estimate, so consumers should not rely on this to be the exact " + + "count. Providers should return the best estimate possible."), /** * Definition of the property which holds the @@ -312,7 +326,9 @@ enum StandardMemberProperty implements Property { Datatype.UNSIGNED_INTEGER, 24, false, - "Required. The distance of the member's parent from the root level of the hierarchy. The root level is zero."), + null, + "Required. The distance of the member's parent from the root level " + + "of the hierarchy. The root level is zero."), /** * Definition of the property which holds the @@ -322,7 +338,11 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 25, false, - "Required. Unique name of the member's parent. NULL is returned for any members at the root level. For providers that generate unique names by qualification, each component of this name is delimited."), + null, + "Required. Unique name of the member's parent. NULL is returned " + + "for any members at the root level. For providers that generate " + + "unique names by qualification, each component of this name is " + + "delimited."), /** * Definition of the property which holds the @@ -333,6 +353,7 @@ enum StandardMemberProperty implements Property { Datatype.UNSIGNED_INTEGER, 26, false, + null, "Required. Number of parents that this member has."), /** @@ -343,6 +364,7 @@ enum StandardMemberProperty implements Property { Datatype.STRING, 27, false, + null, "Optional. A human-readable description of the member."), /** @@ -355,6 +377,7 @@ enum StandardMemberProperty implements Property { Datatype.BOOLEAN, 28, true, + null, null), /** @@ -368,6 +391,7 @@ enum StandardMemberProperty implements Property { Datatype.VARIANT, 29, true, + null, "Optional. The value of the member key. Null for composite keys."), /** @@ -379,7 +403,9 @@ enum StandardMemberProperty implements Property { Datatype.BOOLEAN, 30, false, - "Required. Whether the member is a placeholder member for an empty position in a dimension hierarchy."), + null, + "Required. Whether the member is a placeholder member for an empty " + + "position in a dimension hierarchy."), /** * Definition of the property that indicates whether the member is a @@ -389,6 +415,7 @@ enum StandardMemberProperty implements Property { Datatype.BOOLEAN, 31, false, + null, "Required. whether the member is a data member"), /** @@ -403,6 +430,7 @@ enum StandardMemberProperty implements Property { Datatype.UNSIGNED_INTEGER, 43, true, + null, "The level depth of a member"), /** @@ -416,6 +444,7 @@ enum StandardMemberProperty implements Property { Datatype.UNSIGNED_INTEGER, 44, false, + null, "Display instruction of a member for XML/A"), /** @@ -427,6 +456,7 @@ enum StandardMemberProperty implements Property { Datatype.VARIANT, 41, false, + null, "The unformatted value of the cell."); private final Datatype type; @@ -437,6 +467,7 @@ private StandardMemberProperty( Datatype type, int ordinal, boolean internal, + Class enumClazz, String description) { // assert ordinal == ordinal(); @@ -466,7 +497,7 @@ public Datatype getDatatype() { } public Set getType() { - return TypeFlag.forMask(TypeFlag.MEMBER.xmlaOrdinal); + return TypeFlag.MEMBER_TYPE_FLAG; } public ContentType getContentType() { @@ -502,43 +533,64 @@ enum StandardCellProperty implements Property { Datatype.STRING, 30, false, - "The background color for displaying the VALUE or FORMATTED_VALUE property. For more information, see FORE_COLOR and BACK_COLOR Contents."), + null, + "The background color for displaying the VALUE or FORMATTED_VALUE " + + "property. For more information, see FORE_COLOR and BACK_COLOR " + + "Contents."), CELL_EVALUATION_LIST( Datatype.STRING, 31, false, - "The semicolon-delimited list of evaluated formulas applicable to the cell, in order from lowest to highest solve order. For more information about solve order, see Understanding Pass Order and Solve Order"), + null, + "The semicolon-delimited list of evaluated formulas applicable to " + + "the cell, in order from lowest to highest solve order. For more " + + "information about solve order, see Understanding Pass Order and " + + "Solve Order"), CELL_ORDINAL( Datatype.UNSIGNED_INTEGER, 32, false, + null, "The ordinal number of the cell in the dataset."), FORE_COLOR( Datatype.STRING, 33, false, - "The foreground color for displaying the VALUE or FORMATTED_VALUE property. For more information, see FORE_COLOR and BACK_COLOR Contents."), + null, + "The foreground color for displaying the VALUE or FORMATTED_VALUE " + + "property. For more information, see FORE_COLOR and BACK_COLOR " + + "Contents."), FONT_NAME( Datatype.STRING, 34, false, - "The font to be used to display the VALUE or FORMATTED_VALUE property."), + null, + "The font to be used to display the VALUE or FORMATTED_VALUE " + + "property."), FONT_SIZE( Datatype.STRING, 35, false, - "Font size to be used to display the VALUE or FORMATTED_VALUE property."), + null, + "Font size to be used to display the VALUE or FORMATTED_VALUE " + + "property."), FONT_FLAGS( Datatype.UNSIGNED_INTEGER, 36, false, - "The bitmask detailing effects on the font. The value is the result of a bitwise OR operation of one or more of the following constants: MDFF_BOLD = 1, MDFF_ITALIC = 2, MDFF_UNDERLINE = 4, MDFF_STRIKEOUT = 8. For example, the value 5 represents the combination of bold (MDFF_BOLD) and underline (MDFF_UNDERLINE) font effects."), + XmlaConstants.FontFlag.class, + "The bitmask detailing effects on the font. The value is the " + + "result of a bitwise OR operation of one or more of the " + + "following constants: MDFF_BOLD = 1, MDFF_ITALIC = 2, " + + "MDFF_UNDERLINE = 4, MDFF_STRIKEOUT = 8. For example, the value " + + "5 represents the combination of bold (MDFF_BOLD) and underline " + + "(MDFF_UNDERLINE) font effects."), /** * Definition of the property which @@ -548,7 +600,9 @@ enum StandardCellProperty implements Property { Datatype.STRING, 37, false, - "The character string that represents a formatted display of the VALUE property."), + null, + "The character string that represents a formatted display of the " + + "VALUE property."), /** * Definition of the property which @@ -558,13 +612,17 @@ enum StandardCellProperty implements Property { Datatype.STRING, 38, false, - "The format string used to create the FORMATTED_VALUE property value. For more information, see FORMAT_STRING Contents."), + null, + "The format string used to create the FORMATTED_VALUE property " + + "value. For more information, see FORMAT_STRING Contents."), NON_EMPTY_BEHAVIOR( Datatype.STRING, 39, false, - "The measure used to determine the behavior of calculated members when resolving empty cells."), + null, + "The measure used to determine the behavior of calculated members " + + "when resolving empty cells."), /** * Definition of the property which @@ -575,6 +633,7 @@ enum StandardCellProperty implements Property { Datatype.INTEGER, 40, false, + null, "The solve order of the cell."), /** @@ -586,6 +645,7 @@ enum StandardCellProperty implements Property { Datatype.VARIANT, 41, false, + null, "The unformatted value of the cell."), /** @@ -601,7 +661,31 @@ enum StandardCellProperty implements Property { Datatype.STRING, 42, false, - "The datatype of the cell."); + null, + "The datatype of the cell."), + + LANGUAGE( + Datatype.UNSIGNED_INTEGER, + 0, + false, + null, + "The locale where the FORMAT_STRING will be applied. LANGUAGE is " + + "usually used for currency conversion."), + + ACTION_TYPE( + Datatype.UNSIGNED_INTEGER, + 0, + false, + null, + "A bitmask that indicates which types of actions exist on the " + + "cell."), + + UPDATEABLE( + Datatype.UNSIGNED_INTEGER, + 0, + false, + XmlaConstants.Updateable.class, + "A value that indicates whether the cell can be updated."); /** * The datatype of the property. @@ -614,6 +698,7 @@ private StandardCellProperty( Datatype type, int ordinal, boolean internal, + Class enumClazz, String description) { this.type = type; @@ -626,7 +711,7 @@ public Datatype getDatatype() { } public Set getType() { - return TypeFlag.forMask(TypeFlag.CELL.xmlaOrdinal); + return TypeFlag.CELL_TYPE_FLAG; } public String getName() { @@ -662,7 +747,7 @@ public ContentType getContentType() { * which corresponds to the value {@link #CAPTION}, * whose {@link #xmlaOrdinal} is 0x21. */ - enum ContentType { + enum ContentType implements XmlaConstant { REGULAR(0x00), ID(0x01), RELATION_TO_PARENT(0x02), @@ -730,43 +815,33 @@ enum ContentType { VERSION(0xC1); private final int xmlaOrdinal; + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(ContentType.class); - private static final Map xmlaMap = - new HashMap(); + private ContentType(int xmlaOrdinal) { + this.xmlaOrdinal = xmlaOrdinal; + } - static { - for (ContentType contentType : values()) { - xmlaMap.put(contentType.xmlaOrdinal, contentType); - } + public String xmlaName() { + return "MD_PROPTYPE_" + name(); } - /** - * Returns the ordinal code as specified by XMLA. - * - *

For example, the XMLA specification says that the ordinal of - * {@link #FORMATTING_FONT_EFFECTS} is 0xA4. - * - * @return ordinal code as specified by XMLA. - */ - public int xmlaOrdinal() { - return xmlaOrdinal; + public String getDescription() { + return null; } - private ContentType(int xmlaOrdinal) { - this.xmlaOrdinal = xmlaOrdinal; + public int xmlaOrdinal() { + return xmlaOrdinal; } /** - * Looks up a ContentType by its XMLA ordinal. - * - * @param xmlaOrdinal Ordinal of a ContentType according to the XMLA - * specification. + * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary + * of all values of this enumeration. * - * @return ContentType with the given ordinal, or null if there is no - * such ContentType + * @return Dictionary of all values */ - public static ContentType forXmlaOrdinal(int xmlaOrdinal) { - return xmlaMap.get(xmlaOrdinal); + public static Dictionary getDictionary() { + return DICTIONARY; } } } diff --git a/src/org/olap4j/metadata/XmlaConstant.java b/src/org/olap4j/metadata/XmlaConstant.java new file mode 100644 index 0000000..118efbb --- /dev/null +++ b/src/org/olap4j/metadata/XmlaConstant.java @@ -0,0 +1,221 @@ +/* +// This software is subject to the terms of the Eclipse Public License v1.0 +// Agreement, available at the following URL: +// http://www.eclipse.org/legal/epl-v10.html. +// Copyright (C) 2010-2010 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.metadata; + +import java.util.*; + +/** + * Enumerated value that belongs to a set of constants in the XML for Analysis + * (XMLA) specification. + * + *

Every {@code enum} E that implements this interface also has a method to + * get the {@link org.olap4j.metadata.XmlaConstant.Dictionary} of all its values: + * + *

public static Dictionary<E> getDictionary();
+ * + *

Here is a collection of enum classes and the prefix used to generate + * their XMLA constant names. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
PrefixEnum class
DBTYPE_{@link Datatype}
MD_DIMTYPE_{@link org.olap4j.metadata.Dimension.Type}
MDLEVEL_TYPE_{@link org.olap4j.metadata.Level.Type}
MDMEASURE_AGG_{@link org.olap4j.metadata.Measure.Aggregator}
MDTREEOP_{@link org.olap4j.metadata.Member.TreeOp}
MD_PROPTYPE_{@link org.olap4j.metadata.Property.ContentType}
MDPROP_{@link org.olap4j.metadata.Property.TypeFlag}
none{@link org.olap4j.metadata.XmlaConstants.Access}
MDACTION_TYPE_{@link org.olap4j.metadata.XmlaConstants.ActionType}
none{@link org.olap4j.metadata.XmlaConstants.AuthenticationMode}
none{@link org.olap4j.metadata.XmlaConstants.AxisFormat}
DBTYPE_{@link org.olap4j.metadata.XmlaConstants.DBType}
MDFF_{@link org.olap4j.metadata.XmlaConstants.FontFlag}
none{@link org.olap4j.metadata.XmlaConstants.Format}
DBLITERAL_{@link org.olap4j.metadata.XmlaConstants.Literal}
none{@link org.olap4j.metadata.XmlaConstants.Method}
none{@link org.olap4j.metadata.XmlaConstants.ProviderType}
none{@link org.olap4j.metadata.XmlaConstants.Updateable}
DBPROPVAL_VISUAL_MODE_{@link org.olap4j.metadata.XmlaConstants.VisualMode}
+ * + * @author jhyde + * @version $Id: $ + */ +public interface XmlaConstant { + /** + * Returns the name of this constant as specified by XMLA. + * + *

Often the name is an enumeration-specific prefix plus the name of + * the Java enum constant. For example, + * {@link org.olap4j.metadata.Dimension.Type} has + * prefix "MD_DIMTYPE_", and therefore this method returns + * "MD_DIMTYPE_PRODUCTS" for the enum constant + * {@link org.olap4j.metadata.Dimension.Type#PRODUCTS}. + * + * @return ordinal code as specified by XMLA. + */ + String xmlaName(); + + /** + * Returns the description of this constant. + * + * @return Description of this constant. + */ + String getDescription(); + + /** + * Returns the code of this constant as specified by XMLA. + * + *

For example, the XMLA specification says that the ordinal of + * MD_DIMTYPE_PRODUCTS is 8, and therefore this method returns 8 + * for {@link org.olap4j.metadata.Dimension.Type#PRODUCTS}. + * + * @return ordinal code as specified by XMLA. + */ + int xmlaOrdinal(); + + interface Dictionary & XmlaConstant> { + + /** + * Returns the enumeration value with the given ordinal in the XMLA + * specification, or null if there is no such. + * + * @param xmlaOrdinal XMLA ordinal + * @return Enumeration value + */ + E forOrdinal(int xmlaOrdinal); + + /** + * Returns the enumeration value with the given name in the XMLA + * specification, or null if there is no such. + * + * @param xmlaName XMLA name + * @return Enumeration value + */ + E forName(String xmlaName); + + /** + * Creates a set of values by parsing a mask. + * + * @param xmlaOrdinalMask Bit mask + * @return Set of E values + */ + Set forMask(int xmlaOrdinalMask); + + /** + * Converts a set of enum values to an integer by logical OR-ing their + * codes. + * + * @param set Set of enum values + * @return Bitmap representing set of enum values + */ + int toMask(Set set); + + /** + * Returns all values of the enum. + * + *

This method may be more efficient than + * {@link Class#getEnumConstants()} because the latter is required to + * create a new array every call to prevent corruption. + * + * @return List of enum values + */ + List getValues(); + + /** + * Returns the class that the enum values belong to. + * + * @return enum class + */ + Class getEnumClass(); + } +} + +// End XmlaConstant.java diff --git a/src/org/olap4j/metadata/XmlaConstants.java b/src/org/olap4j/metadata/XmlaConstants.java new file mode 100644 index 0000000..e44a889 --- /dev/null +++ b/src/org/olap4j/metadata/XmlaConstants.java @@ -0,0 +1,779 @@ +/* +// $Id: Datatype.java 253 2009-06-30 03:06:10Z jhyde $ +// This software is subject to the terms of the Eclipse Public License v1.0 +// Agreement, available at the following URL: +// http://www.eclipse.org/legal/epl-v10.html. +// Copyright (C) 2010-2010 Julian Hyde +// All Rights Reserved. +// You must accept the terms of that agreement to use this software. +*/ +package org.olap4j.metadata; + +/** + * Collection of various enumerations and constants defined by the XML for + * Analysis (XMLA) and OLE DB for OLAP specifications. + * + * @author jhyde + * @version $Id: $ + */ +public class XmlaConstants +{ + // Suppresses default constructor, ensuring non-instantiability. + private XmlaConstants() { + } + + public enum VisualMode implements XmlaConstant { + DEFAULT( + 0, + "Provider-dependent. In Microsoft SQL Server 2000 Analysis " + + "Services, this is equivalent to " + + "DBPROPVAL_VISUAL_MODE_ORIGINAL."), + VISUAL( + 1, + "Visual totals are enabled."), + ORIGINAL( + 2, + "Visual totals are not enabled."); + + private final int xmlaOrdinal; + private final String description; + + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(VisualMode.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + VisualMode( + int xmlaOrdinal, String description) + { + this.xmlaOrdinal = xmlaOrdinal; + this.description = description; + } + + public String xmlaName() { + return "DBPROPVAL_VISUAL_MODE_"; + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; + } + } + + public static enum Method implements XmlaConstant { + DISCOVER, + EXECUTE, + DISCOVER_AND_EXECUTE; + + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(Method.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + public String xmlaName() { + return name(); + } + + public String getDescription() { + return null; + } + + public int xmlaOrdinal() { + return -1; + } + } + + public enum Access implements XmlaConstant { + Read(1), + Write(2), + ReadWrite(3); + + private final int xmlaOrdinal; + + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(Access.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + Access(int xmlaOrdinal) { + this.xmlaOrdinal = xmlaOrdinal; + } + + public String xmlaName() { + return name(); + } + + public String getDescription() { + return null; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; + } + } + + public static enum AuthenticationMode implements XmlaConstant { + Unauthenticated("no user ID or password needs to be sent."), + Authenticated( + "User ID and Password must be included in the information required " + + "for the connection."), + Integrated( + "the data source uses the underlying security to determine " + + "authorization, such as Integrated Security provided by " + + "Microsoft Internet Information Services (IIS)."); + + private final String description; + + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(AuthenticationMode.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + AuthenticationMode(String description) { + this.description = description; + } + + public String xmlaName() { + return name(); + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return -1; + } + } + + public static enum ProviderType implements XmlaConstant { + TDP("tabular data provider."), + MDP("multidimensional data provider."), + DMP( + "data mining provider. A DMP provider implements the OLE DB for " + + "Data Mining specification."); + + private final String description; + + private static final DictionaryImpl DICTIONARY = + DictionaryImpl.forClass(ProviderType.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + private ProviderType(String description) { + this.description = description; + } + + public String xmlaName() { + return name(); + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return -1; + } + } + + public static enum Updateable implements XmlaConstant { + MD_MASK_ENABLED( + 0x00000000, + "The cell can be updated."), + + MD_MASK_NOT_ENABLED( + 0x10000000, + "The cell cannot be updated."), + + CELL_UPDATE_ENABLED( + 0x00000001, + "Cell can be updated in the cellset."), + + CELL_UPDATE_ENABLED_WITH_UPDATE( + 0x00000002, + "The cell can be updated with an update statement. The update may " + + "fail if a leaf cell is updated that is not write-enabled."), + + CELL_UPDATE_NOT_ENABLED_FORMULA( + 0x10000001, + "The cell cannot be updated because the cell has a calculated " + + "member among its coordinates; the cell was retrieved with a set " + + "in the where clause. A cell can be updated even though a " + + "formula affects, or a calculated cell is on, the value of a " + + "cell (is somewhere along the aggregation path). In this " + + "scenario, the final value of the cell may not be the updated " + + "value, because the calculation will affect the result."), + + CELL_UPDATE_NOT_ENABLED_NONSUM_MEASURE( + 0x10000002, + "The cell cannot be updated because non-sum measures (count, min, " + + "max, distinct count, semi-additive) can not be updated."), + + CELL_UPDATE_NOT_ENABLED_NACELL_VIRTUALCUBE( + 0x10000003, + "The cell cannot be updated because the cell does not exist as it " + + "is at the intersection of a measure and a dimension member " + + "unrelated to the measure’s measure group."), + + CELL_UPDATE_NOT_ENABLED_SECURE( + 0x10000005, + "The cell cannot be updated because the cell is secured."), + + CELL_UPDATE_NOT_ENABLED_CALCLEVEL( + 0x10000006, + "Reserved for future use."), + + CELL_UPDATE_NOT_ENABLED_CANNOTUPDATE( + 0x10000007, + "The cell cannot be updated because of internal reasons."), + + CELL_UPDATE_NOT_ENABLED_INVALIDDIMENSIONTYPE( + 0x10000009, + "The cell cannot be updated because update is not supported in " + + "mining model, indirect, or data mining dimensions."); + + private final int xmlaOrdinal; + private final String description; + + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(Updateable.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + Updateable(int xmlaOrdinal, String description) { + this.xmlaOrdinal = xmlaOrdinal; + this.description = description; + } + + public String xmlaName() { + return name(); + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; + } + } + + public static enum FontFlag implements XmlaConstant { + BOLD(1), + ITALIC(2), + UNDERLINE(4), + STRIKEOUT(8); + + private final int xmlaOrdinal; + + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(FontFlag.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + FontFlag(int xmlaOrdinal) { + this.xmlaOrdinal = xmlaOrdinal; + } + + public String xmlaName() { + return "MDFF_" + name(); + } + + public String getDescription() { + return name(); + } + + public int xmlaOrdinal() { + return xmlaOrdinal; + } + } + + public static enum ActionType implements XmlaConstant { + URL(-1), + HTML(-1), + STATEMENT(-1), + DATASET(-1), + ROWSET(-1), + COMMANDLINE(-1), + PROPRIETARY(-1), + REPORT(-1), + DRILLTHROUGH(-1); + + private final int xmlaOrdinal; + + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(ActionType.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + ActionType(int xmlaOrdinal) { + this.xmlaOrdinal = xmlaOrdinal; + } + + public String xmlaName() { + return "MDACTION_TYPE_" + name(); + } + + public String getDescription() { + return name(); + } + + public int xmlaOrdinal() { + return xmlaOrdinal; + } + } + + /** + * The only OLE DB Types Indicators returned by SQL Server are thoses coded + * below. + */ + public enum DBType implements XmlaConstant { + /* + * The following values exactly match VARENUM + * in Automation and may be used in VARIANT. + */ + I4( + "INTEGER", 3, "DBTYPE_I4", "A four-byte, signed integer: INTEGER"), + + R8( + "DOUBLE", 5, "DBTYPE_R8", + "A double-precision floating-point value: Double"), + + CY( + "CURRENCY", 6, "DBTYPE_CY", + "A currency value: LARGE_INTEGER, Currency is a fixed-point number " + + "with four digits to the right of the decimal point. It is " + + "stored in an eight-byte signed integer, scaled by 10,000."), + + BOOL( + "BOOLEAN", 11, "DBTYPE_BOOL", + "A Boolean value stored in the same way as in Automation: " + + "VARIANT_BOOL; 0 means false and ~0 (bitwise, the value is not " + + "0; that is, all bits are set to 1) means true."), + + /** + * Used by SQL Server for value. + */ + VARIANT( + "VARIANT", 12, "DBTYPE_VARIANT", "An Automation VARIANT"), + + /** + * Used by SQL Server for font size. + */ + UI2("UNSIGNED_SHORT", 18, "DBTYPE_UI2", "A two-byte, unsigned integer"), + + /** + * Used by SQL Server for colors, font flags and cell ordinal. + */ + UI4( + "UNSIGNED_INTEGER", 19, "DBTYPE_UI4", + "A four-byte, unsigned integer"), + + /* + * The following values exactly match VARENUM + * in Automation but cannot be used in VARIANT. + */ + I8( + "LARGE_INTEGER", 20, "DBTYPE_I8", + "An eight-byte, signed integer: LARGE_INTEGER"), + + /* + * The following values are not in VARENUM in OLE. + */ + WSTR( + "STRING", 130, "DBTYPE_WSTR", + "A null-terminated Unicode character string: wchar_t[length]; If " + + "DBTYPE_WSTR is used by itself, the number of bytes allocated " + + "for the string, including the null-termination character, is " + + "specified by cbMaxLen in the DBBINDING structure. If " + + "DBTYPE_WSTR is combined with DBTYPE_BYREF, the number of bytes " + + "allocated for the string, including the null-termination " + + "character, is at least the length of the string plus two. In " + + "either case, the actual length of the string is determined from " + + "the bound length value. The maximum length of the string is the " + + "number of allocated bytes divided by sizeof(wchar_t) and " + + "truncated to the nearest integer."); + + + public final String userName; + + /** + * The length of a non-numeric column or parameter that refers to either + * the maximum or the length defined for this type by the provider. For + * character data, this is the maximum or defined length in characters. + * For DateTime data types, this is the length of the string + * representation (assuming the maximum allowed precision of the + * fractional seconds component). + * + * If the data type is numeric, this is the upper bound on the maximum + * precision of the data type. + int columnSize; + */ + + private final int xmlaOrdinal; + + /* + * A Boolean that indicates whether the data type is nullable. + * VARIANT_TRUE indicates that the data type is nullable. + * VARIANT_FALSE indicates that the data type is not nullable. + * NULL-- indicates that it is not known whether the data type is + * nullable. + boolean isNullable; + */ + + private String description; + + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(DBType.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + DBType( + String userName, + int xmlaOrdinal, + String dbTypeIndicator, + String description) + { + this.userName = userName; + this.xmlaOrdinal = xmlaOrdinal; + this.description = description; + assert xmlaName().equals(dbTypeIndicator); + } + + public String xmlaName() { + return "DBTYPE_" + name(); + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; + } + } + + public enum Format implements XmlaConstant { + Tabular( + "a flat or hierarchical rowset. Similar to the XML RAW format in " + + "SQL. The Format property should be set to Tabular for OLE DB " + + "for Data Mining commands."), + Multidimensional( + "Indicates that the result set will use the MDDataSet format " + + "(Execute method only)."), + Native( + "The client does not request a specific format, so the provider " + + "may return the format appropriate to the query. (The actual " + + "result type is identified by namespace of the result.)"); + + private final String description; + + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(Format.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + Format(String description) { + this.description = description; + } + + public String xmlaName() { + return name(); + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return -1; + } + } + + public enum AxisFormat implements XmlaConstant { + TupleFormat( + "The MDDataSet axis is made up of one or more CrossProduct " + + "elements."), + ClusterFormat( + "Analysis Services uses the TupleFormat format for this setting."), + CustomFormat( + "The MDDataSet axis contains one or more Tuple elements."); + + private final String description; + + private static final XmlaConstant.Dictionary DICTIONARY = + DictionaryImpl.forClass(AxisFormat.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static XmlaConstant.Dictionary getDictionary() { + return DICTIONARY; + } + + AxisFormat(String description) { + this.description = description; + } + + public String xmlaName() { + return name(); + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return -1; + } + } + + public enum Content { + None, + Schema, + Data, + SchemaData, + DataOmitDefaultSlicer, + DataIncludeDefaultSlicer; + + /** The content type default value - shared across more than one file */ + public static final Content DEFAULT = SchemaData; + } + + public enum MdxSupport { + Core + } + + public enum StateSupport { + None, + Sessions + } + + public enum Literal implements XmlaConstant { + CATALOG_NAME( + 2, null, 24, ".", "0123456789", + "A catalog name in a text command."), + CATALOG_SEPARATOR(3, ".", 0, null, null, null), + COLUMN_ALIAS(5, null, -1, "'\"[]", "0123456789", null), + COLUMN_NAME(6, null, -1, ".", "0123456789", null), + CORRELATION_NAME(7, null, -1, "'\"[]", "0123456789", null), + CUBE_NAME(21, null, -1, ".", "0123456789", null), + DIMENSION_NAME(22, null, -1, ".", "0123456789", null), + HIERARCHY_NAME(23, null, -1, ".", "0123456789", null), + LEVEL_NAME(24, null, -1, ".", "0123456789", null), + MEMBER_NAME(25, null, -1, ".", "0123456789", null), + PROCEDURE_NAME(14, null, -1, ".", "0123456789", null), + PROPERTY_NAME(26, null, -1, ".", "0123456789", null), + QUOTE( + 15, "[", -1, null, null, + "The character used in a text command as the opening quote for " + + "quoting identifiers that contain special characters."), + QUOTE_SUFFIX( + 28, "]", -1, null, null, + "The character used in a text command as the closing quote for " + + "quoting identifiers that contain special characters. 1.x " + + "providers that use the same character as the prefix and suffix " + + "may not return this literal value and can set the lt member of " + + "the DBLITERAL structure to DBLITERAL_INVALID if requested."), + TABLE_NAME(17, null, -1, ".", "0123456789", null), + TEXT_COMMAND( + 18, null, -1, null, null, + "A text command, such as an SQL statement."), + USER_NAME(19, null, 0, null, null, null); + + /* + // Enum DBLITERALENUM and DBLITERALENUM20, OLEDB.H. + public static final int DBLITERAL_INVALID = 0, + DBLITERAL_BINARY_LITERAL = 1, + DBLITERAL_CATALOG_NAME = 2, + DBLITERAL_CATALOG_SEPARATOR = 3, + DBLITERAL_CHAR_LITERAL = 4, + DBLITERAL_COLUMN_ALIAS = 5, + DBLITERAL_COLUMN_NAME = 6, + DBLITERAL_CORRELATION_NAME = 7, + DBLITERAL_CURSOR_NAME = 8, + DBLITERAL_ESCAPE_PERCENT = 9, + DBLITERAL_ESCAPE_UNDERSCORE = 10, + DBLITERAL_INDEX_NAME = 11, + DBLITERAL_LIKE_PERCENT = 12, + DBLITERAL_LIKE_UNDERSCORE = 13, + DBLITERAL_PROCEDURE_NAME = 14, + DBLITERAL_QUOTE = 15, + DBLITERAL_QUOTE_PREFIX = DBLITERAL_QUOTE, + DBLITERAL_SCHEMA_NAME = 16, + DBLITERAL_TABLE_NAME = 17, + DBLITERAL_TEXT_COMMAND = 18, + DBLITERAL_USER_NAME = 19, + DBLITERAL_VIEW_NAME = 20, + DBLITERAL_CUBE_NAME = 21, + DBLITERAL_DIMENSION_NAME = 22, + DBLITERAL_HIERARCHY_NAME = 23, + DBLITERAL_LEVEL_NAME = 24, + DBLITERAL_MEMBER_NAME = 25, + DBLITERAL_PROPERTY_NAME = 26, + DBLITERAL_SCHEMA_SEPARATOR = 27, + DBLITERAL_QUOTE_SUFFIX = 28; +*/ + + private int xmlaOrdinal; + private final String literalValue; + private final int literalMaxLength; + private final String literalInvalidChars; + private final String literalInvalidStartingChars; + private final String description; + + private static final Dictionary DICTIONARY = + DictionaryImpl.forClass(Literal.class); + + /** + * Per {@link XmlaConstant}, returns a dictionary + * of all values of this enumeration. + * + * @return Dictionary of all values + */ + public static Dictionary getDictionary() { + return DICTIONARY; + } + + Literal( + int xmlaOrdinal, + String literalValue, + int literalMaxLength, + String literalInvalidChars, + String literalInvalidStartingChars, + String description) + { + this.xmlaOrdinal = xmlaOrdinal; + this.literalValue = literalValue; + this.literalMaxLength = literalMaxLength; + this.literalInvalidChars = literalInvalidChars; + this.literalInvalidStartingChars = literalInvalidStartingChars; + this.description = description; + } + + public String getLiteralName() { + return xmlaName(); + } + + public String getLiteralValue() { + return literalValue; + } + + public String getLiteralInvalidChars() { + return literalInvalidChars; + } + + public String getLiteralInvalidStartingChars() { + return literalInvalidStartingChars; + } + + public int getLiteralMaxLength() { + return literalMaxLength; + } + + public String xmlaName() { + return "DBLITERAL_" + name(); + } + + public String getDescription() { + return description; + } + + public int xmlaOrdinal() { + return xmlaOrdinal; + } + } + + public interface EnumWithDesc { + String getDescription(); + } +} + +// XmlaConstants.java diff --git a/testsrc/org/olap4j/test/ArrayMapTest.java b/testsrc/org/olap4j/test/ArrayMapTest.java index ee9ad6f..514bf51 100644 --- a/testsrc/org/olap4j/test/ArrayMapTest.java +++ b/testsrc/org/olap4j/test/ArrayMapTest.java @@ -2,7 +2,7 @@ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. -// Copyright (C) 2007-2008 Julian Hyde +// Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ @@ -10,6 +10,7 @@ import junit.framework.TestCase; import org.olap4j.impl.ArrayMap; +import org.olap4j.impl.UnmodifiableArrayMap; import java.util.*; @@ -177,15 +178,191 @@ public void testArrayMap2() { // putAll to populate empty map (uses different code path than putAll // on non-empty map) - final ArrayMap map2 = + final Map map2 = new ArrayMap(); map2.putAll(hashMap); assertEquals(map2, hashMap); // copy constructor - final ArrayMap map3 = + final Map map3 = new ArrayMap(hashMap); assertEquals(map3, hashMap); + + // of + final Map map4 = + ArrayMap.of( + "foo", -5, + "bar", 1, + "baz", 0, + null, 75, + "zzzz", null); + assertEquals(map4, hashMap); + + // toString + assertEquals( + "{foo=-5, bar=1, baz=0, null=75, zzzz=null}", + map4.toString()); + assertEquals("{}", new ArrayMap().toString()); + } + + + /** + * Test for {@link org.olap4j.impl.UnmodifiableArrayMap}. + */ + public void testUnmodifiableArrayMap() { + Map map; + final Map hashMap = new HashMap(); + + map = new UnmodifiableArrayMap(hashMap); + assertEquals(0, map.size()); + assertEquals(map, hashMap); + assertEquals(map.hashCode(), hashMap.hashCode()); + + // put + try { + int x = map.put("foo", 0); + fail("expected fail, got " + x); + } catch (UnsupportedOperationException e) { + // ok + } + + hashMap.put("foo", 0); + map = new UnmodifiableArrayMap(hashMap); + assertEquals(1, map.size()); + assertEquals(1, map.keySet().size()); + assertEquals(1, map.values().size()); + + // equivalence to hashmap + assertEquals(map, hashMap); + assertEquals(hashMap, map); + assertEquals(map.hashCode(), hashMap.hashCode()); + + // containsKey, get + assertTrue(map.containsKey("foo")); + assertFalse(map.containsKey("bar")); + assertEquals(Integer.valueOf(0), map.get("foo")); + assertNull(map.get("baz")); + + // putall + final Map hashMap2 = new HashMap(); + hashMap2.put("bar", 1); + hashMap2.put("foo", 2); + hashMap2.put("baz", 0); + try { + map.putAll(hashMap2); + fail("expected fail"); + } catch (UnsupportedOperationException e) { + // ok + } + hashMap.putAll(hashMap2); + map = new UnmodifiableArrayMap(hashMap); + assertEquals(3, map.size()); + assertEquals(map, hashMap); + assertEquals(hashMap, map); + assertEquals(map.hashCode(), hashMap.hashCode()); + assertEquals(map.keySet(), hashMap.keySet()); + // values collections have same contents, not necessarily in same order + assertEquals( + new HashSet(map.values()), + new HashSet(hashMap.values())); + + // replace existing key + try { + int x = map.put("foo", -5); + fail("expected fail, got " + x); + } catch (UnsupportedOperationException e) { + // ok + } + hashMap.put("foo", -5); + map = new UnmodifiableArrayMap(hashMap); + assertEquals(3, map.size()); + assertEquals(Integer.valueOf(-5), map.get("foo")); + assertEquals(map, hashMap); + assertEquals(hashMap, map); + + // null key + assertFalse(map.containsKey(null)); + hashMap.put(null, 75); + map = new UnmodifiableArrayMap(hashMap); + assertEquals(Integer.valueOf(75), map.get(null)); + assertTrue(map.containsKey(null)); + + // null value + hashMap.put("zzzz", null); + map = new UnmodifiableArrayMap(hashMap); + assertTrue(map.containsKey("zzzz")); + assertNull(map.get("zzzz")); + + // compare to hashmap + assertEquals(map, hashMap); + assertEquals(hashMap, map); + + // isEmpty, clear + assertFalse(map.isEmpty()); + try { + map.clear(); + fail("expected fail"); + } catch (UnsupportedOperationException e) { + // ok + } + assertTrue( + new UnmodifiableArrayMap( + Collections.emptyMap()).isEmpty()); + + // copy constructor + final Map map3 = + new UnmodifiableArrayMap(hashMap); + assertEquals(map3, hashMap); + + // of + final Map map4 = + UnmodifiableArrayMap.of( + "foo", -5, + "bar", 1, + "baz", 0, + null, 75, + "zzzz", null); + assertEquals(map4, hashMap); + + // order is preserved + final List keyList = Arrays.asList( + "foo", "bar", "baz", null, "zzzz"); + assertEquals( + new ArrayList(map4.keySet()), keyList); + final List valueList = Arrays.asList(-5, 1, 0, 75, null); + assertEquals( + new ArrayList(map4.values()), valueList); + final Iterator valueIter = valueList.iterator(); + final Iterator keyIter = keyList.iterator(); + for (Map.Entry entry : map4.entrySet()) { + assertEquals(entry.getKey(), keyIter.next()); + assertEquals(entry.getValue(), valueIter.next()); + } + assertFalse(keyIter.hasNext()); + assertFalse(valueIter.hasNext()); + + // of(Map) - zero entries + hashMap.clear(); + final Map map5 = UnmodifiableArrayMap.of(hashMap); + assertTrue(map5 == Collections.emptyMap()); + + // of(Map) - one entry + hashMap.put("foo", -5); + final Map map6 = UnmodifiableArrayMap.of(hashMap); + assertTrue( + map6.getClass() == Collections.singletonMap("7", "y").getClass()); + + // of(Map) - 2 or more entries + hashMap.put("bar", 1); + hashMap.put("baz", 0); + final Map map7 = UnmodifiableArrayMap.of(hashMap); + assertEquals(map7, hashMap); + + // toString + assertEquals( + "{foo=-5, bar=1, baz=0, null=75, zzzz=null}", + map4.toString()); + assertEquals("{}", map5.toString()); } }