001 /*
002 // $Id: //open/mondrian-release/3.0/src/main/mondrian/olap4j/MondrianOlap4jConnection.java#2 $
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-release/3.0/src/main/mondrian/olap4j/MondrianOlap4jConnection.java#2 $
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 OlapConnection connection;
601
602 public MondrianOlap4jMdxValidator(OlapConnection connection) {
603 this.connection = connection;
604 }
605
606 public SelectNode validateSelect(SelectNode selectNode) throws OlapException {
607 StringWriter sw = new StringWriter();
608 selectNode.unparse(new ParseTreeWriter(new PrintWriter(sw)));
609 String mdx = sw.toString();
610 final MondrianOlap4jConnection olap4jConnection =
611 (MondrianOlap4jConnection) connection;
612 Query query =
613 olap4jConnection.connection
614 .parseQuery(mdx);
615 query.resolve();
616 return olap4jConnection.toOlap4j(query);
617 }
618 }
619
620 static Axis toOlap4j(String axisName) {
621 if (axisName.equals("SLICER")) {
622 axisName = "FILTER";
623 }
624 return Axis.valueOf(axisName);
625 }
626
627 private static class MondrianToOlap4jNodeConverter {
628 private final MondrianOlap4jConnection olap4jConnection;
629
630 MondrianToOlap4jNodeConverter(
631 MondrianOlap4jConnection olap4jConnection)
632 {
633 this.olap4jConnection = olap4jConnection;
634 }
635
636 public SelectNode toOlap4j(Query query) {
637 List<IdentifierNode> list = Collections.emptyList();
638 return new SelectNode(
639 null,
640 toOlap4j(query.getFormulas()),
641 toOlap4j(query.getAxes()),
642 new CubeNode(
643 null,
644 olap4jConnection.toOlap4j(query.getCube())),
645 query.getSlicerAxis() == null
646 ? null
647 : toOlap4j(query.getSlicerAxis()),
648 list);
649 }
650
651 private AxisNode toOlap4j(QueryAxis axis) {
652 return new AxisNode(
653 null,
654 axis.isNonEmpty(),
655 MondrianOlap4jConnection.toOlap4j(axis.getAxisName()),
656 toOlap4j(axis.getDimensionProperties()),
657 toOlap4j(axis.getSet()));
658 }
659
660 private List<IdentifierNode> toOlap4j(Id[] dimensionProperties) {
661 final List<IdentifierNode> list = new ArrayList<IdentifierNode>();
662 for (Id property : dimensionProperties) {
663 list.add(toOlap4j(property));
664 }
665 return list;
666 }
667
668 private ParseTreeNode toOlap4j(Exp exp) {
669 if (exp instanceof Id) {
670 Id id = (Id) exp;
671 return toOlap4j(id);
672 }
673 if (exp instanceof ResolvedFunCall) {
674 ResolvedFunCall call = (ResolvedFunCall) exp;
675 return toOlap4j(call);
676 }
677 if (exp instanceof DimensionExpr) {
678 DimensionExpr dimensionExpr = (DimensionExpr) exp;
679 return new DimensionNode(
680 null,
681 olap4jConnection.toOlap4j(dimensionExpr.getDimension()));
682 }
683 if (exp instanceof HierarchyExpr) {
684 HierarchyExpr hierarchyExpr = (HierarchyExpr) exp;
685 return new HierarchyNode(
686 null,
687 olap4jConnection.toOlap4j(hierarchyExpr.getHierarchy()));
688 }
689 if (exp instanceof LevelExpr) {
690 LevelExpr levelExpr = (LevelExpr) exp;
691 return new LevelNode(
692 null,
693 olap4jConnection.toOlap4j(levelExpr.getLevel()));
694 }
695 if (exp instanceof MemberExpr) {
696 MemberExpr memberExpr = (MemberExpr) exp;
697 return new MemberNode(
698 null,
699 olap4jConnection.toOlap4j(memberExpr.getMember()));
700 }
701 if (exp instanceof Literal) {
702 Literal literal = (Literal) exp;
703 final Object value = literal.getValue();
704 if (literal.getCategory() == Category.Symbol) {
705 return LiteralNode.createSymbol(
706 null, (String) literal.getValue());
707 } else if (value instanceof Double) {
708 return LiteralNode.create(null, (Double) value);
709 } else if (value instanceof Integer) {
710 return LiteralNode.create(null, (Integer) value);
711 } else if (value instanceof String) {
712 return LiteralNode.createString(null, (String) value);
713 } else if (value == null) {
714 return LiteralNode.createNull(null);
715 } else {
716 throw new RuntimeException("unknown literal " + literal);
717 }
718 }
719 throw Util.needToImplement(exp.getClass());
720 }
721
722 private ParseTreeNode toOlap4j(ResolvedFunCall call) {
723 final CallNode callNode = new CallNode(
724 null,
725 call.getFunName(),
726 toOlap4j(call.getSyntax()),
727 toOlap4j(Arrays.asList(call.getArgs())));
728 if (call.getType() != null) {
729 callNode.setType(olap4jConnection.toOlap4j(call.getType()));
730 }
731 return callNode;
732 }
733
734 private List<ParseTreeNode> toOlap4j(List<Exp> exprList) {
735 final List<ParseTreeNode> result = new ArrayList<ParseTreeNode>();
736 for (Exp expr : exprList) {
737 result.add(toOlap4j(expr));
738 }
739 return result;
740 }
741
742 private org.olap4j.mdx.Syntax toOlap4j(mondrian.olap.Syntax syntax) {
743 return org.olap4j.mdx.Syntax.valueOf(syntax.name());
744 }
745
746 private List<AxisNode> toOlap4j(QueryAxis[] axes) {
747 final ArrayList<AxisNode> axisList = new ArrayList<AxisNode>();
748 for (QueryAxis axis : axes) {
749 axisList.add(toOlap4j(axis));
750 }
751 return axisList;
752 }
753
754 private List<ParseTreeNode> toOlap4j(Formula[] formulas) {
755 final List<ParseTreeNode> list = new ArrayList<ParseTreeNode>();
756 for (Formula formula : formulas) {
757 if (formula.isMember()) {
758 List<PropertyValueNode> memberPropertyList =
759 new ArrayList<PropertyValueNode>();
760 for (Object child : formula.getChildren()) {
761 if (child instanceof MemberProperty) {
762 MemberProperty memberProperty =
763 (MemberProperty) child;
764 memberPropertyList.add(
765 new PropertyValueNode(
766 null,
767 memberProperty.getName(),
768 toOlap4j(memberProperty.getExp())));
769 }
770 }
771 list.add(
772 new WithMemberNode(
773 null,
774 toOlap4j(formula.getIdentifier()),
775 toOlap4j(formula.getExpression()),
776 memberPropertyList));
777 }
778 }
779 return list;
780 }
781
782 private IdentifierNode toOlap4j(Id id) {
783 List<IdentifierNode.Segment> list =
784 new ArrayList<IdentifierNode.Segment>();
785 for (Id.Segment segment : id.getSegments()) {
786 list.add(
787 new IdentifierNode.Segment(
788 null,
789 segment.name,
790 toOlap4j(segment.quoting)));
791 }
792 return new IdentifierNode(
793 list.toArray(
794 new IdentifierNode.Segment[list.size()]));
795 }
796
797 private IdentifierNode.Quoting toOlap4j(Id.Quoting quoting) {
798 return IdentifierNode.Quoting.valueOf(quoting.name());
799 }
800 }
801 }
802
803 // End MondrianOlap4jConnection.java