001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap4j/MondrianOlap4jConnection.java#9 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2007-2007 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.olap4j; 011 012 import mondrian.mdx.*; 013 import mondrian.olap.*; 014 import mondrian.rolap.RolapMeasure; 015 import org.olap4j.Axis; 016 import org.olap4j.Cell; 017 import org.olap4j.*; 018 import org.olap4j.impl.Olap4jUtil; 019 import org.olap4j.mdx.*; 020 import org.olap4j.mdx.parser.*; 021 import org.olap4j.mdx.parser.impl.DefaultMdxParserImpl; 022 import org.olap4j.metadata.*; 023 import org.olap4j.metadata.Schema; 024 import org.olap4j.type.*; 025 import org.olap4j.type.DimensionType; 026 027 import java.io.PrintWriter; 028 import java.io.StringWriter; 029 import java.sql.*; 030 import java.util.*; 031 032 /** 033 * Implementation of {@link org.olap4j.OlapConnection} 034 * for the Mondrian OLAP engine. 035 * 036 * <p>This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; 037 * it is instantiated using {@link Factory#newConnection}.</p> 038 * 039 * @author jhyde 040 * @version $Id: //open/mondrian/src/main/mondrian/olap4j/MondrianOlap4jConnection.java#9 $ 041 * @since May 23, 2007 042 */ 043 abstract class MondrianOlap4jConnection implements OlapConnection { 044 /** 045 * Handler for errors. 046 */ 047 final Helper helper = new Helper(); 048 049 /** 050 * Underlying mondrian connection. Set on creation, cleared on close. 051 */ 052 mondrian.olap.Connection connection; 053 054 /** 055 * Current schema. 056 */ 057 MondrianOlap4jSchema olap4jSchema; 058 059 /** 060 * Map from mondrian schema objects to olap4j schemas. 061 */ 062 final Map<mondrian.olap.Schema,MondrianOlap4jSchema> schemaMap = 063 new HashMap<mondrian.olap.Schema, MondrianOlap4jSchema>(); 064 065 private final MondrianOlap4jDatabaseMetaData olap4jDatabaseMetaData; 066 067 /** 068 * The name of the sole catalog. 069 */ 070 static final String LOCALDB_CATALOG_NAME = "LOCALDB"; 071 private static final String CONNECT_STRING_PREFIX = "jdbc:mondrian:"; 072 073 final Factory factory; 074 private Locale locale; 075 private String roleName; 076 private boolean autoCommit; 077 private boolean readOnly; 078 079 /** 080 * Creates an Olap4j connection to Mondrian. 081 * 082 * <p>This method is intentionally package-protected. The public API 083 * uses the traditional JDBC {@link java.sql.DriverManager}. 084 * See {@link mondrian.olap4j.MondrianOlap4jDriver} for more details. 085 * 086 * @pre acceptsURL(url) 087 * 088 * @param factory Factory 089 * @param url Connect-string URL 090 * @param info Additional properties 091 * @throws SQLException if there is an error 092 */ 093 MondrianOlap4jConnection( 094 Factory factory, 095 String url, 096 Properties info) 097 throws SQLException 098 { 099 this.factory = factory; 100 if (!acceptsURL(url)) { 101 // This is not a URL we can handle. 102 // DriverManager should not have invoked us. 103 throw new AssertionError( 104 "does not start with '" + CONNECT_STRING_PREFIX + "'"); 105 } 106 String x = url.substring(CONNECT_STRING_PREFIX.length()); 107 Util.PropertyList list = Util.parseConnectString(x); 108 for (Map.Entry<String,String> entry : toMap(info).entrySet()) { 109 list.put(entry.getKey(), entry.getValue()); 110 } 111 this.connection = 112 mondrian.olap.DriverManager.getConnection(list, null); 113 this.olap4jDatabaseMetaData = 114 factory.newDatabaseMetaData(this); 115 this.olap4jSchema = toOlap4j(connection.getSchema()); 116 } 117 118 static boolean acceptsURL(String url) { 119 return url.startsWith(CONNECT_STRING_PREFIX); 120 } 121 122 public OlapStatement createStatement() { 123 return new MondrianOlap4jStatement(this); 124 } 125 126 public PreparedStatement prepareStatement(String sql) throws SQLException { 127 throw new UnsupportedOperationException(); 128 } 129 130 public CallableStatement prepareCall(String sql) throws SQLException { 131 throw new UnsupportedOperationException(); 132 } 133 134 public String nativeSQL(String sql) throws SQLException { 135 throw new UnsupportedOperationException(); 136 } 137 138 public void setAutoCommit(boolean autoCommit) throws SQLException { 139 this.autoCommit = autoCommit; 140 } 141 142 public boolean getAutoCommit() throws SQLException { 143 return autoCommit; 144 } 145 146 public void commit() throws SQLException { 147 throw new UnsupportedOperationException(); 148 } 149 150 public void rollback() throws SQLException { 151 throw new UnsupportedOperationException(); 152 } 153 154 public void close() throws SQLException { 155 if (connection != null) { 156 mondrian.olap.Connection c = connection; 157 connection = null; 158 c.close(); 159 } 160 } 161 162 public boolean isClosed() throws SQLException { 163 return connection == null; 164 } 165 166 public OlapDatabaseMetaData getMetaData() { 167 return olap4jDatabaseMetaData; 168 } 169 170 public NamedList<Catalog> getCatalogs() { 171 return olap4jDatabaseMetaData.getCatalogObjects(); 172 } 173 174 public void setReadOnly(boolean readOnly) throws SQLException { 175 this.readOnly = readOnly; 176 } 177 178 public boolean isReadOnly() throws SQLException { 179 return readOnly; 180 } 181 182 public void setCatalog(String catalog) throws SQLException { 183 if (!catalog.equals(LOCALDB_CATALOG_NAME)) { 184 throw new UnsupportedOperationException(); 185 } 186 } 187 188 public String getCatalog() throws SQLException { 189 return LOCALDB_CATALOG_NAME; 190 } 191 192 public void setTransactionIsolation(int level) throws SQLException { 193 throw new UnsupportedOperationException(); 194 } 195 196 public int getTransactionIsolation() throws SQLException { 197 throw new UnsupportedOperationException(); 198 } 199 200 public SQLWarning getWarnings() throws SQLException { 201 throw new UnsupportedOperationException(); 202 } 203 204 public void clearWarnings() throws SQLException { 205 } 206 207 public Statement createStatement( 208 int resultSetType, int resultSetConcurrency) throws SQLException { 209 throw new UnsupportedOperationException(); 210 } 211 212 public PreparedStatement prepareStatement( 213 String sql, 214 int resultSetType, 215 int resultSetConcurrency) throws SQLException { 216 throw new UnsupportedOperationException(); 217 } 218 219 public CallableStatement prepareCall( 220 String sql, 221 int resultSetType, 222 int resultSetConcurrency) throws SQLException { 223 throw new UnsupportedOperationException(); 224 } 225 226 public Map<String, Class<?>> getTypeMap() throws SQLException { 227 throw new UnsupportedOperationException(); 228 } 229 230 public void setTypeMap(Map<String, Class<?>> map) throws SQLException { 231 throw new UnsupportedOperationException(); 232 } 233 234 public void setHoldability(int holdability) throws SQLException { 235 throw new UnsupportedOperationException(); 236 } 237 238 public int getHoldability() throws SQLException { 239 throw new UnsupportedOperationException(); 240 } 241 242 public Savepoint setSavepoint() throws SQLException { 243 throw new UnsupportedOperationException(); 244 } 245 246 public Savepoint setSavepoint(String name) throws SQLException { 247 throw new UnsupportedOperationException(); 248 } 249 250 public void rollback(Savepoint savepoint) throws SQLException { 251 throw new UnsupportedOperationException(); 252 } 253 254 public void releaseSavepoint(Savepoint savepoint) throws SQLException { 255 throw new UnsupportedOperationException(); 256 } 257 258 public Statement createStatement( 259 int resultSetType, 260 int resultSetConcurrency, 261 int resultSetHoldability) throws SQLException { 262 throw new UnsupportedOperationException(); 263 } 264 265 public PreparedStatement prepareStatement( 266 String sql, 267 int resultSetType, 268 int resultSetConcurrency, 269 int resultSetHoldability) throws SQLException { 270 throw new UnsupportedOperationException(); 271 } 272 273 public CallableStatement prepareCall( 274 String sql, 275 int resultSetType, 276 int resultSetConcurrency, 277 int resultSetHoldability) throws SQLException { 278 throw new UnsupportedOperationException(); 279 } 280 281 public PreparedStatement prepareStatement( 282 String sql, int autoGeneratedKeys) throws SQLException { 283 throw new UnsupportedOperationException(); 284 } 285 286 public PreparedStatement prepareStatement( 287 String sql, int columnIndexes[]) throws SQLException { 288 throw new UnsupportedOperationException(); 289 } 290 291 public PreparedStatement prepareStatement( 292 String sql, String columnNames[]) throws SQLException { 293 throw new UnsupportedOperationException(); 294 } 295 296 // implement Wrapper 297 298 public <T> T unwrap(Class<T> iface) throws SQLException { 299 if (iface.isInstance(this)) { 300 return iface.cast(this); 301 } else if (iface.isInstance(connection)) { 302 return iface.cast(connection); 303 } 304 throw helper.createException("does not implement '" + iface + "'"); 305 } 306 307 public boolean isWrapperFor(Class<?> iface) throws SQLException { 308 return iface.isInstance(this) || 309 iface.isInstance(connection); 310 } 311 312 // implement OlapConnection 313 314 public PreparedOlapStatement prepareOlapStatement( 315 String mdx) 316 throws OlapException 317 { 318 return factory.newPreparedStatement(mdx, this); 319 } 320 321 public MdxParserFactory getParserFactory() { 322 return new MdxParserFactory() { 323 public MdxParser createMdxParser(OlapConnection connection) { 324 return new DefaultMdxParserImpl(connection); 325 } 326 327 public MdxValidator createMdxValidator(OlapConnection connection) { 328 return new MondrianOlap4jMdxValidator(connection); 329 } 330 }; 331 } 332 333 public Schema getSchema() throws OlapException { 334 return olap4jSchema; 335 } 336 337 MondrianOlap4jCube toOlap4j(mondrian.olap.Cube cube) { 338 MondrianOlap4jSchema schema = toOlap4j(cube.getSchema()); 339 return new MondrianOlap4jCube(cube, schema); 340 } 341 342 MondrianOlap4jDimension toOlap4j(mondrian.olap.Dimension dimension) { 343 return new MondrianOlap4jDimension( 344 toOlap4j(dimension.getSchema()), 345 dimension); 346 } 347 348 synchronized MondrianOlap4jSchema toOlap4j(mondrian.olap.Schema schema) { 349 MondrianOlap4jSchema olap4jSchema = schemaMap.get(schema); 350 if (olap4jSchema == null) { 351 final MondrianOlap4jCatalog olap4jCatalog = 352 (MondrianOlap4jCatalog) getCatalogs().get(LOCALDB_CATALOG_NAME); 353 olap4jSchema = 354 new MondrianOlap4jSchema( 355 olap4jCatalog, 356 schema.getSchemaReader(), 357 schema); 358 schemaMap.put(schema, olap4jSchema); 359 } 360 return olap4jSchema; 361 } 362 363 Type toOlap4j(mondrian.olap.type.Type type) { 364 if (type instanceof mondrian.olap.type.BooleanType) { 365 return new BooleanType(); 366 } else if (type instanceof mondrian.olap.type.CubeType) { 367 final mondrian.olap.Cube mondrianCube = 368 ((mondrian.olap.type.CubeType) type).getCube(); 369 return new CubeType(toOlap4j(mondrianCube)); 370 } else if (type instanceof mondrian.olap.type.DecimalType) { 371 mondrian.olap.type.DecimalType decimalType = 372 (mondrian.olap.type.DecimalType) type; 373 return new DecimalType( 374 decimalType.getPrecision(), 375 decimalType.getScale()); 376 } else if (type instanceof mondrian.olap.type.DimensionType) { 377 mondrian.olap.type.DimensionType dimensionType = 378 (mondrian.olap.type.DimensionType) type; 379 return new DimensionType( 380 toOlap4j(dimensionType.getDimension())); 381 } else if (type instanceof mondrian.olap.type.HierarchyType) { 382 return new BooleanType(); 383 } else if (type instanceof mondrian.olap.type.LevelType) { 384 return new BooleanType(); 385 } else if (type instanceof mondrian.olap.type.MemberType) { 386 final mondrian.olap.type.MemberType memberType = 387 (mondrian.olap.type.MemberType) type; 388 return new MemberType( 389 toOlap4j(memberType.getDimension()), 390 toOlap4j(memberType.getHierarchy()), 391 toOlap4j(memberType.getLevel()), 392 toOlap4j(memberType.getMember())); 393 } else if (type instanceof mondrian.olap.type.NullType) { 394 return new NullType(); 395 } else if (type instanceof mondrian.olap.type.NumericType) { 396 return new NumericType(); 397 } else if (type instanceof mondrian.olap.type.SetType) { 398 final mondrian.olap.type.SetType setType = 399 (mondrian.olap.type.SetType) type; 400 return new SetType(toOlap4j(setType.getElementType())); 401 } else if (type instanceof mondrian.olap.type.StringType) { 402 return new StringType(); 403 } else if (type instanceof mondrian.olap.type.TupleType) { 404 mondrian.olap.type.TupleType tupleType = 405 (mondrian.olap.type.TupleType) type; 406 final Type[] types = toOlap4j(tupleType.elementTypes); 407 return new TupleType(types); 408 } else if (type instanceof mondrian.olap.type.SymbolType) { 409 return new SymbolType(); 410 } else { 411 throw new UnsupportedOperationException(); 412 } 413 } 414 415 MondrianOlap4jMember toOlap4j(mondrian.olap.Member member) { 416 if (member == null) { 417 return null; 418 } 419 if (member instanceof RolapMeasure) { 420 RolapMeasure measure = (RolapMeasure) member; 421 return new MondrianOlap4jMeasure( 422 toOlap4j(member.getDimension().getSchema()), 423 measure); 424 } 425 return new MondrianOlap4jMember( 426 toOlap4j(member.getDimension().getSchema()), 427 member); 428 } 429 430 MondrianOlap4jLevel toOlap4j(mondrian.olap.Level level) { 431 if (level == null) { 432 return null; 433 } 434 return new MondrianOlap4jLevel( 435 toOlap4j(level.getDimension().getSchema()), 436 level); 437 } 438 439 MondrianOlap4jHierarchy toOlap4j(mondrian.olap.Hierarchy hierarchy) { 440 if (hierarchy == null) { 441 return null; 442 } 443 return new MondrianOlap4jHierarchy( 444 toOlap4j(hierarchy.getDimension().getSchema()), 445 hierarchy); 446 } 447 448 Type[] toOlap4j(mondrian.olap.type.Type[] mondrianTypes) { 449 final Type[] types = new Type[mondrianTypes.length]; 450 for (int i = 0; i < types.length; i++) { 451 types[i] = toOlap4j(mondrianTypes[i]); 452 } 453 return types; 454 } 455 456 /** 457 * Converts a Properties object to a Map with String keys and values. 458 * 459 * @param properties Properties 460 * @return Map backed by the given Properties object 461 */ 462 public static Map<String, String> toMap(final Properties properties) { 463 return new AbstractMap<String, String>() { 464 public Set<Entry<String, String>> entrySet() { 465 return Olap4jUtil.cast(properties.entrySet()); 466 } 467 }; 468 } 469 470 MondrianOlap4jNamedSet toOlap4j( 471 mondrian.olap.Cube cube, 472 mondrian.olap.NamedSet namedSet) 473 { 474 if (namedSet == null) { 475 return null; 476 } 477 return new MondrianOlap4jNamedSet( 478 toOlap4j(cube), 479 namedSet); 480 } 481 482 ParseTreeNode toOlap4j(Exp exp) { 483 return new MondrianToOlap4jNodeConverter(this).toOlap4j(exp); 484 } 485 486 SelectNode toOlap4j(Query query) { 487 return new MondrianToOlap4jNodeConverter(this).toOlap4j(query); 488 } 489 490 public void setLocale(Locale locale) { 491 if (locale == null) { 492 throw new IllegalArgumentException("locale must not be null"); 493 } 494 this.locale = locale; 495 } 496 497 public Locale getLocale() { 498 if (locale == null) { 499 return Locale.getDefault(); 500 } 501 return locale; 502 } 503 504 public void setRoleName(String roleName) throws OlapException { 505 final Role role; 506 if (roleName == null) { 507 role = null; 508 } else { 509 role = this.connection.getSchema().lookupRole(roleName); 510 if (role == null) { 511 throw helper.createException("Unknown role '" + roleName + "'"); 512 } 513 } 514 // Remember the name of the role, because mondrian roles don't know 515 // their own name. 516 this.roleName = roleName; 517 this.connection.setRole(role); 518 } 519 520 public String getRoleName() { 521 return roleName; 522 } 523 524 // inner classes 525 526 /** 527 * Package-private helper class which encapsulates policies which are 528 * common throughout the driver. These policies include exception handling 529 * and factory methods. 530 */ 531 static class Helper { 532 OlapException createException(String msg) { 533 return new OlapException(msg); 534 } 535 536 /** 537 * Creates an exception in the context of a particular Cell. 538 * 539 * @param context Cell context for exception 540 * @param msg Message 541 * @return New exception 542 */ 543 OlapException createException(Cell context, String msg) { 544 OlapException exception = new OlapException(msg); 545 exception.setContext(context); 546 return exception; 547 } 548 549 /** 550 * Creates an exception in the context of a particular Cell and with 551 * a given cause. 552 * 553 * @param context Cell context for exception 554 * @param msg Message 555 * @param cause Causing exception 556 * @return New exception 557 */ 558 OlapException createException( 559 Cell context, String msg, Throwable cause) 560 { 561 OlapException exception = new OlapException(msg, cause); 562 exception.setContext(context); 563 return exception; 564 } 565 566 /** 567 * Creates an exception with a given cause. 568 * 569 * @param msg Message 570 * @param cause Causing exception 571 * @return New exception 572 */ 573 OlapException createException( 574 String msg, Throwable cause) 575 { 576 return new OlapException(msg, cause); 577 } 578 579 /** 580 * Converts a SQLException to an OlapException. Casts the exception 581 * if it is already an OlapException, wraps otherwise. 582 * 583 * <p>This method is typically used as an adapter for SQLException 584 * instances coming from a base class, where derived interface declares 585 * that it throws the more specific OlapException. 586 * 587 * @param e Exception 588 * @return Exception as an OlapException 589 */ 590 public OlapException toOlapException(SQLException e) { 591 if (e instanceof OlapException) { 592 return (OlapException) e; 593 } else { 594 return new OlapException(null, e); 595 } 596 } 597 } 598 599 private static class MondrianOlap4jMdxValidator implements MdxValidator { 600 private final MondrianOlap4jConnection connection; 601 602 public MondrianOlap4jMdxValidator(OlapConnection connection) { 603 this.connection = (MondrianOlap4jConnection) connection; 604 } 605 606 public SelectNode validateSelect(SelectNode selectNode) 607 throws OlapException 608 { 609 try { 610 // A lot of mondrian's validation happens during parsing. 611 // Therefore to do effective validation, we need to go back to 612 // the MDX string. Someday we will reshape mondrian's 613 // parse/validation process to fit the olap4j model better. 614 StringWriter sw = new StringWriter(); 615 selectNode.unparse(new ParseTreeWriter(new PrintWriter(sw))); 616 String mdx = sw.toString(); 617 Query query = 618 connection.connection 619 .parseQuery(mdx); 620 query.resolve(); 621 return connection.toOlap4j(query); 622 } catch (MondrianException e) { 623 throw connection.helper.createException("Validation error", e); 624 } 625 } 626 } 627 628 static Axis toOlap4j(String axisName) { 629 if (axisName.equals("SLICER")) { 630 axisName = "FILTER"; 631 } 632 return Axis.valueOf(axisName); 633 } 634 635 private static class MondrianToOlap4jNodeConverter { 636 private final MondrianOlap4jConnection olap4jConnection; 637 638 MondrianToOlap4jNodeConverter( 639 MondrianOlap4jConnection olap4jConnection) 640 { 641 this.olap4jConnection = olap4jConnection; 642 } 643 644 public SelectNode toOlap4j(Query query) { 645 List<IdentifierNode> list = Collections.emptyList(); 646 return new SelectNode( 647 null, 648 toOlap4j(query.getFormulas()), 649 toOlap4j(query.getAxes()), 650 new CubeNode( 651 null, 652 olap4jConnection.toOlap4j(query.getCube())), 653 query.getSlicerAxis() == null 654 ? null 655 : toOlap4j(query.getSlicerAxis()), 656 list); 657 } 658 659 private AxisNode toOlap4j(QueryAxis axis) { 660 return new AxisNode( 661 null, 662 axis.isNonEmpty(), 663 MondrianOlap4jConnection.toOlap4j(axis.getAxisName()), 664 toOlap4j(axis.getDimensionProperties()), 665 toOlap4j(axis.getSet())); 666 } 667 668 private List<IdentifierNode> toOlap4j(Id[] dimensionProperties) { 669 final List<IdentifierNode> list = new ArrayList<IdentifierNode>(); 670 for (Id property : dimensionProperties) { 671 list.add(toOlap4j(property)); 672 } 673 return list; 674 } 675 676 private ParseTreeNode toOlap4j(Exp exp) { 677 if (exp instanceof Id) { 678 Id id = (Id) exp; 679 return toOlap4j(id); 680 } 681 if (exp instanceof ResolvedFunCall) { 682 ResolvedFunCall call = (ResolvedFunCall) exp; 683 return toOlap4j(call); 684 } 685 if (exp instanceof DimensionExpr) { 686 DimensionExpr dimensionExpr = (DimensionExpr) exp; 687 return new DimensionNode( 688 null, 689 olap4jConnection.toOlap4j(dimensionExpr.getDimension())); 690 } 691 if (exp instanceof HierarchyExpr) { 692 HierarchyExpr hierarchyExpr = (HierarchyExpr) exp; 693 return new HierarchyNode( 694 null, 695 olap4jConnection.toOlap4j(hierarchyExpr.getHierarchy())); 696 } 697 if (exp instanceof LevelExpr) { 698 LevelExpr levelExpr = (LevelExpr) exp; 699 return new LevelNode( 700 null, 701 olap4jConnection.toOlap4j(levelExpr.getLevel())); 702 } 703 if (exp instanceof MemberExpr) { 704 MemberExpr memberExpr = (MemberExpr) exp; 705 return new MemberNode( 706 null, 707 olap4jConnection.toOlap4j(memberExpr.getMember())); 708 } 709 if (exp instanceof Literal) { 710 Literal literal = (Literal) exp; 711 final Object value = literal.getValue(); 712 if (literal.getCategory() == Category.Symbol) { 713 return LiteralNode.createSymbol( 714 null, (String) literal.getValue()); 715 } else if (value instanceof Double) { 716 return LiteralNode.create(null, (Double) value); 717 } else if (value instanceof Integer) { 718 return LiteralNode.create(null, (Integer) value); 719 } else if (value instanceof String) { 720 return LiteralNode.createString(null, (String) value); 721 } else if (value == null) { 722 return LiteralNode.createNull(null); 723 } else { 724 throw new RuntimeException("unknown literal " + literal); 725 } 726 } 727 throw Util.needToImplement(exp.getClass()); 728 } 729 730 private ParseTreeNode toOlap4j(ResolvedFunCall call) { 731 final CallNode callNode = new CallNode( 732 null, 733 call.getFunName(), 734 toOlap4j(call.getSyntax()), 735 toOlap4j(Arrays.asList(call.getArgs()))); 736 if (call.getType() != null) { 737 callNode.setType(olap4jConnection.toOlap4j(call.getType())); 738 } 739 return callNode; 740 } 741 742 private List<ParseTreeNode> toOlap4j(List<Exp> exprList) { 743 final List<ParseTreeNode> result = new ArrayList<ParseTreeNode>(); 744 for (Exp expr : exprList) { 745 result.add(toOlap4j(expr)); 746 } 747 return result; 748 } 749 750 private org.olap4j.mdx.Syntax toOlap4j(mondrian.olap.Syntax syntax) { 751 return org.olap4j.mdx.Syntax.valueOf(syntax.name()); 752 } 753 754 private List<AxisNode> toOlap4j(QueryAxis[] axes) { 755 final ArrayList<AxisNode> axisList = new ArrayList<AxisNode>(); 756 for (QueryAxis axis : axes) { 757 axisList.add(toOlap4j(axis)); 758 } 759 return axisList; 760 } 761 762 private List<ParseTreeNode> toOlap4j(Formula[] formulas) { 763 final List<ParseTreeNode> list = new ArrayList<ParseTreeNode>(); 764 for (Formula formula : formulas) { 765 if (formula.isMember()) { 766 List<PropertyValueNode> memberPropertyList = 767 new ArrayList<PropertyValueNode>(); 768 for (Object child : formula.getChildren()) { 769 if (child instanceof MemberProperty) { 770 MemberProperty memberProperty = 771 (MemberProperty) child; 772 memberPropertyList.add( 773 new PropertyValueNode( 774 null, 775 memberProperty.getName(), 776 toOlap4j(memberProperty.getExp()))); 777 } 778 } 779 list.add( 780 new WithMemberNode( 781 null, 782 toOlap4j(formula.getIdentifier()), 783 toOlap4j(formula.getExpression()), 784 memberPropertyList)); 785 } 786 } 787 return list; 788 } 789 790 private IdentifierNode toOlap4j(Id id) { 791 List<IdentifierNode.Segment> list = 792 new ArrayList<IdentifierNode.Segment>(); 793 for (Id.Segment segment : id.getSegments()) { 794 list.add( 795 new IdentifierNode.Segment( 796 null, 797 segment.name, 798 toOlap4j(segment.quoting))); 799 } 800 return new IdentifierNode( 801 list.toArray( 802 new IdentifierNode.Segment[list.size()])); 803 } 804 805 private IdentifierNode.Quoting toOlap4j(Id.Quoting quoting) { 806 return IdentifierNode.Quoting.valueOf(quoting.name()); 807 } 808 } 809 } 810 811 // End MondrianOlap4jConnection.java