From 97812f205e98456187eb1245a567ff5b9baeb28e Mon Sep 17 00:00:00 2001 From: Julian Hyde Date: Mon, 22 Feb 2010 07:23:28 +0000 Subject: [PATCH] Fix JDK1.4 compatability. Upgrade version of mondrian (previous version did not implement latest API). git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@302 c6a108a4-781c-0410-a6c6-c2d559e19af0 --- ivy.xml | 2 +- .../olap4j/driver/xmla/XmlaOlap4jCube.java | 6 ++- .../olap4j/driver/xmla/XmlaOlap4jMember.java | 2 +- src/org/olap4j/impl/Olap4jUtil.java | 47 ++++++++++++++++++- src/org/olap4j/impl/Olap4jUtilCompatible.java | 28 ++++++++++- .../impl/Olap4jUtilCompatibleJdk14.java | 22 ++++++++- .../impl/Olap4jUtilCompatibleJdk15.java | 19 +++++++- src/org/olap4j/metadata/DictionaryImpl.java | 33 +++++++++++-- src/org/olap4j/metadata/Property.java | 8 +++- testsrc/org/olap4j/ConnectionTest.java | 23 +++++---- testsrc/org/olap4j/MetadataTest.java | 6 ++- 11 files changed, 170 insertions(+), 26 deletions(-) diff --git a/ivy.xml b/ivy.xml index 7957b07..8a8ed96 100644 --- a/ivy.xml +++ b/ivy.xml @@ -76,7 +76,7 @@ - list = new NamedListImpl(); lookupMemberRelatives( - EnumSet.of(Member.TreeOp.SELF), memberUniqueName, list); + Olap4jUtil.enumSetOf(Member.TreeOp.SELF), + memberUniqueName, + list); switch (list.size()) { case 0: return null; diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java b/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java index ae26540..ec6fd69 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jMember.java @@ -99,7 +99,7 @@ public NamedList getChildMembers() throws OlapException { getCube() .getMetadataReader() .lookupMemberRelatives( - EnumSet.of(TreeOp.CHILDREN), + Olap4jUtil.enumSetOf(TreeOp.CHILDREN), uniqueName, list); return list; diff --git a/src/org/olap4j/impl/Olap4jUtil.java b/src/org/olap4j/impl/Olap4jUtil.java index 67791f4..f870271 100644 --- a/src/org/olap4j/impl/Olap4jUtil.java +++ b/src/org/olap4j/impl/Olap4jUtil.java @@ -386,7 +386,7 @@ public static RuntimeException needToImplement(Object o) { /** * Parses a unique name. * - *

For example, {@code uniqueNameToStringArray("[foo].[bar]")} returns + *

For example, uniqueNameToStringArray("[foo].[bar]") returns * {@code ["foo", "bar"]}. * * @see org.olap4j.mdx.IdentifierNode#parseIdentifier(String) @@ -410,6 +410,9 @@ public static List parseUniqueName(String uniqueName) { /** * Converts the contents of an array of strings to * a proper String representation. + * + * @param array Array of strings + * @return string representation of the array */ public static String stringArrayToString(String[] array) { StringBuilder sb = new StringBuilder("["); @@ -428,6 +431,48 @@ public static NamedList emptyNamedList() { return (NamedList) EMPTY_NAMED_LIST; } + /** + * Equivalent to {@link java.util.EnumSet#of(Enum, Enum[])} on JDK 1.5 or + * later. Otherwise, returns an ordinary set. + * + * @param first an element that the set is to contain initially + * @param rest the remaining elements the set is to contain initially + * @throws NullPointerException if any of the specified elements are null, + * or if rest is null + * @return an enum set initially containing the specified elements + */ + public static > Set enumSetOf(E first, E... rest) { + return compatible.enumSetOf(first, rest); + } + + /** + * Equivalent to {@link java.util.EnumSet#noneOf(Class)} on JDK 1.5 or + * later. Otherwise, returns an ordinary set. + * + * @param elementType the class object of the element type for this enum + * set + * @return an empty enum set + */ + public static > Set enumSetNoneOf( + Class elementType) + { + return compatible.enumSetNoneOf(elementType); + } + + /** + * Equivalent to {@link java.util.EnumSet#allOf(Class)} on JDK 1.5 or later. + * Otherwise, returns an ordinary set. + + * @param elementType the class object of the element type for this enum + * set + * @return an enum set containing all elements of the given enum class + */ + public static > Set enumSetAllOf( + Class elementType) + { + return compatible.enumSetAllOf(elementType); + } + private enum DummyEnum { } diff --git a/src/org/olap4j/impl/Olap4jUtilCompatible.java b/src/org/olap4j/impl/Olap4jUtilCompatible.java index 3d7b5bb..628d7b6 100644 --- a/src/org/olap4j/impl/Olap4jUtilCompatible.java +++ b/src/org/olap4j/impl/Olap4jUtilCompatible.java @@ -3,12 +3,14 @@ // 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. */ package org.olap4j.impl; +import java.util.Set; + /** * Interface containing methods which are implemented differently in different * versions of the JDK. @@ -27,7 +29,31 @@ * @since Feb 5, 2007 */ public interface Olap4jUtilCompatible { + /** + * Returns a literal pattern String for the specified String. + * + *

Specification as for {@link java.util.regex.Pattern#quote(String)}, + * which was introduced in JDK 1.5. + * + * @param s The string to be literalized + * @return A literal string replacement + */ String quotePattern(String s); + + /** + * See {@link org.olap4j.impl.Olap4jUtil#enumSetOf(Enum, Enum[])}. + */ + > Set enumSetOf(E first, E... rest); + + /** + * See {@link org.olap4j.impl.Olap4jUtil#enumSetNoneOf(Class)}. + */ + > Set enumSetNoneOf(Class elementType); + + /** + * See {@link org.olap4j.impl.Olap4jUtil#enumSetAllOf(Class)}. + */ + > Set enumSetAllOf(Class elementType); } // End Olap4jUtilCompatible.java diff --git a/src/org/olap4j/impl/Olap4jUtilCompatibleJdk14.java b/src/org/olap4j/impl/Olap4jUtilCompatibleJdk14.java index e23094f..2ee912e 100644 --- a/src/org/olap4j/impl/Olap4jUtilCompatibleJdk14.java +++ b/src/org/olap4j/impl/Olap4jUtilCompatibleJdk14.java @@ -3,12 +3,14 @@ // 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. */ package org.olap4j.impl; +import java.util.*; + /** * Implementation of {@link Olap4jUtilCompatible} which runs in * JDK 1.4. @@ -18,7 +20,7 @@ * @since Feb 5, 2007 */ public class Olap4jUtilCompatibleJdk14 implements Olap4jUtilCompatible { - public String quotePattern(String s) { + public final String quotePattern(String s) { int slashEIndex = s.indexOf("\\E"); if (slashEIndex == -1) { return "\\Q" + s + "\\E"; @@ -35,6 +37,22 @@ public String quotePattern(String s) { sb.append("\\E"); return sb.toString(); } + + public final > Set enumSetOf(E first, E... rest) { + HashSet set = new HashSet(); + set.add(first); + set.addAll(Arrays.asList(rest)); + return set; + } + + public final > Set enumSetNoneOf(Class elementType) + { + return new HashSet(); + } + + public final > Set enumSetAllOf(Class elementType) { + return new HashSet(Arrays.asList(elementType.getEnumConstants())); + } } // End Olap4jUtilCompatibleJdk14.java diff --git a/src/org/olap4j/impl/Olap4jUtilCompatibleJdk15.java b/src/org/olap4j/impl/Olap4jUtilCompatibleJdk15.java index 9a64d17..5e67b2c 100644 --- a/src/org/olap4j/impl/Olap4jUtilCompatibleJdk15.java +++ b/src/org/olap4j/impl/Olap4jUtilCompatibleJdk15.java @@ -3,12 +3,14 @@ // 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. */ package org.olap4j.impl; +import java.util.EnumSet; +import java.util.Set; import java.util.regex.Pattern; /** @@ -24,9 +26,22 @@ * @since Feb 5, 2007 */ public class Olap4jUtilCompatibleJdk15 implements Olap4jUtilCompatible { - public String quotePattern(String s) { + public final String quotePattern(String s) { return Pattern.quote(s); } + + public final > Set enumSetOf(E first, E... rest) { + return EnumSet.of(first, rest); + } + + public final > Set enumSetNoneOf(Class elementType) + { + return EnumSet.noneOf(elementType); + } + + public final > Set enumSetAllOf(Class elementType) { + return EnumSet.allOf(elementType); + } } // End Olap4jUtilCompatibleJdk15.java diff --git a/src/org/olap4j/metadata/DictionaryImpl.java b/src/org/olap4j/metadata/DictionaryImpl.java index f28c7cc..bd3bcdc 100644 --- a/src/org/olap4j/metadata/DictionaryImpl.java +++ b/src/org/olap4j/metadata/DictionaryImpl.java @@ -9,6 +9,8 @@ */ package org.olap4j.metadata; +import org.olap4j.impl.Olap4jUtil; + import java.util.*; /** @@ -23,16 +25,35 @@ class DictionaryImpl & XmlaConstant> private final Class clazz; private final Map byName = new HashMap(); private final Map byOrdinal = new HashMap(); - private final List values; + private List values; private static final Map map = new HashMap(); public DictionaryImpl(Class clazz) { this.clazz = clazz; + init(); + } + + private void init() { + if (values != null) { + // Already initialized. + return; + } + // The following statement throws NullPointerException under JDK1.4 + // (that is, when retrowoven) if clazz has not finished loading. This + // happens when a static member of clazz is a Dictionary. If this + // happens, swallow the NullPointerException and return null. init will + // be called later. + final E[] constants; + try { + constants = clazz.getEnumConstants(); + } catch (NullPointerException e) { + return; + } this.values = Collections.unmodifiableList( - Arrays.asList(clazz.getEnumConstants())); + Arrays.asList(constants)); for (E e : values) { byName.put(e.xmlaName(), e); byOrdinal.put(e.xmlaOrdinal(), e); @@ -56,19 +77,22 @@ public static & XmlaConstant> DictionaryImpl forClass( public E forOrdinal(int xmlaOrdinal) { + init(); return byOrdinal.get(xmlaOrdinal); } public E forName(String xmlaName) { + init(); return byName.get(xmlaName); } public Set forMask( int xmlaOrdinalMask) { - Set set = EnumSet.noneOf(clazz); - for (E e : clazz.getEnumConstants()) { + init(); + Set set = Olap4jUtil.enumSetNoneOf(clazz); + for (E e : values) { if ((xmlaOrdinalMask & e.xmlaOrdinal()) != 0) { set.add(e); } @@ -86,6 +110,7 @@ public int toMask(Set set) } public List getValues() { + init(); return values; } diff --git a/src/org/olap4j/metadata/Property.java b/src/org/olap4j/metadata/Property.java index 0acec48..cafc94f 100644 --- a/src/org/olap4j/metadata/Property.java +++ b/src/org/olap4j/metadata/Property.java @@ -9,6 +9,8 @@ */ package org.olap4j.metadata; +import org.olap4j.impl.Olap4jUtil; + import java.util.*; /** @@ -79,9 +81,11 @@ enum TypeFlag implements XmlaConstant { private final int xmlaOrdinal; public static final Set CELL_TYPE_FLAG = - Collections.unmodifiableSet(EnumSet.of(TypeFlag.CELL)); + Collections.unmodifiableSet( + Olap4jUtil.enumSetOf(TypeFlag.CELL)); public static final Set MEMBER_TYPE_FLAG = - Collections.unmodifiableSet(EnumSet.of(TypeFlag.MEMBER)); + Collections.unmodifiableSet( + Olap4jUtil.enumSetOf(TypeFlag.MEMBER)); private static final DictionaryImpl DICTIONARY = DictionaryImpl.forClass(TypeFlag.class); diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java index 702de58..e3a4d07 100644 --- a/testsrc/org/olap4j/ConnectionTest.java +++ b/testsrc/org/olap4j/ConnectionTest.java @@ -1461,7 +1461,8 @@ public void testCubeLookupMembers() throws Exception { List memberList = cube.lookupMembers( - EnumSet.of(Member.TreeOp.ANCESTORS, Member.TreeOp.CHILDREN), + Olap4jUtil.enumSetOf( + Member.TreeOp.ANCESTORS, Member.TreeOp.CHILDREN), "Time", "1997", "Q2"); String expected; switch (tester.getFlavor()) { @@ -1488,14 +1489,16 @@ public void testCubeLookupMembers() throws Exception { // ask for non-existent member; list should be empty memberList = cube.lookupMembers( - EnumSet.of(Member.TreeOp.ANCESTORS, Member.TreeOp.CHILDREN), + Olap4jUtil.enumSetOf( + Member.TreeOp.ANCESTORS, Member.TreeOp.CHILDREN), "Time", "1997", "Q5"); assertTrue(memberList.isEmpty()); // ask for parent & ancestors; should not get duplicates memberList = cube.lookupMembers( - EnumSet.of(Member.TreeOp.ANCESTORS, Member.TreeOp.PARENT), + Olap4jUtil.enumSetOf( + Member.TreeOp.ANCESTORS, Member.TreeOp.PARENT), "Time", "1997", "Q2"); TestContext.assertEqualsVerbose( "[Time].[1997]\n", @@ -1504,7 +1507,8 @@ public void testCubeLookupMembers() throws Exception { // ask for parent of root member, should not get null member in list memberList = cube.lookupMembers( - EnumSet.of(Member.TreeOp.ANCESTORS, Member.TreeOp.PARENT), + Olap4jUtil.enumSetOf( + Member.TreeOp.ANCESTORS, Member.TreeOp.PARENT), "Product"); assertTrue(memberList.isEmpty()); @@ -1512,7 +1516,8 @@ public void testCubeLookupMembers() throws Exception { // hierarchically ordered (as always) memberList = cube.lookupMembers( - EnumSet.of(Member.TreeOp.SIBLINGS, Member.TreeOp.CHILDREN), + Olap4jUtil.enumSetOf( + Member.TreeOp.SIBLINGS, Member.TreeOp.CHILDREN), "Time", "1997", "Q2"); switch (tester.getFlavor()) { case XMLA: @@ -1543,7 +1548,7 @@ public void testCubeLookupMembers() throws Exception { // siblings of the root member - potentially tricky memberList = cube.lookupMembers( - EnumSet.of(Member.TreeOp.SIBLINGS), + Olap4jUtil.enumSetOf(Member.TreeOp.SIBLINGS), "Time", "1997"); TestContext.assertEqualsVerbose( "[Time].[1998]\n", @@ -1551,7 +1556,8 @@ public void testCubeLookupMembers() throws Exception { memberList = cube.lookupMembers( - EnumSet.of(Member.TreeOp.SIBLINGS, Member.TreeOp.SELF), + Olap4jUtil.enumSetOf( + Member.TreeOp.SIBLINGS, Member.TreeOp.SELF), "Customers", "USA", "OR"); TestContext.assertEqualsVerbose( "[Customers].[All Customers].[USA].[CA]\n" @@ -1773,7 +1779,8 @@ public void testMetadata() throws Exception { assertEquals("MEMBER_CAPTION", property.getName()); assertEquals("MEMBER_CAPTION", property.getUniqueName()); - assertEquals(EnumSet.of(Property.TypeFlag.MEMBER), property.getType()); + assertEquals( + Olap4jUtil.enumSetOf(Property.TypeFlag.MEMBER), property.getType()); assertEquals(Datatype.STRING, property.getDatatype()); // Measures diff --git a/testsrc/org/olap4j/MetadataTest.java b/testsrc/org/olap4j/MetadataTest.java index bc1cfb8..0e5e066 100644 --- a/testsrc/org/olap4j/MetadataTest.java +++ b/testsrc/org/olap4j/MetadataTest.java @@ -2,13 +2,14 @@ // 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. */ package org.olap4j; import junit.framework.TestCase; +import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.*; import org.olap4j.test.TestContext; @@ -594,7 +595,8 @@ public void testDatabaseMetaDataGetMembers() throws SQLException { olapDatabaseMetaData.getMembers( catalogName, "FoodMart", "Sales", null, null, null, "[Customers].[USA].[CA]", - EnumSet.of(Member.TreeOp.ANCESTORS, Member.TreeOp.SIBLINGS)), + Olap4jUtil.enumSetOf( + Member.TreeOp.ANCESTORS, Member.TreeOp.SIBLINGS)), MEMBERS_COLUMN_NAMES); switch (tester.getFlavor()) { case MONDRIAN: