Java tutorial
/* * Copyright 2012 OSBI Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.fer.hr.olap.query; import com.fer.hr.olap.dto.SaikuCube; import com.fer.hr.olap.dto.SaikuTag; import com.fer.hr.olap.dto.filter.SaikuFilter; import com.fer.hr.olap.query.QueryProperties.QueryProperty; import com.fer.hr.olap.query.QueryProperties.QueryPropertyFactory; import com.fer.hr.olap.util.QueryConverter; import com.fer.hr.olap.util.SaikuProperties; import com.fer.hr.olap.util.exception.SaikuIncompatibleException; import com.fer.hr.olap.util.exception.SaikuOlapException; import com.fer.hr.olap.util.formatter.ICellSetFormatter; import com.fer.hr.service.util.exception.SaikuServiceException; import org.apache.commons.lang.StringUtils; import org.olap4j.*; import org.olap4j.Axis.Standard; import org.olap4j.impl.IdentifierParser; import org.olap4j.mdx.ParseTreeWriter; import org.olap4j.mdx.SelectNode; import org.olap4j.metadata.Catalog; import org.olap4j.metadata.Cube; import org.olap4j.query.*; import org.olap4j.query.QueryDimension.HierarchizeMode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; import java.util.Properties; import mondrian.rolap.RolapConnection; public class OlapQuery implements IQuery { private static final Logger log = LoggerFactory.getLogger(OlapQuery.class); private static final String SCENARIO = "Scenario"; private final Query query; private final Properties properties = new Properties(); private final Map<String, String> totalsFunctions = new HashMap<>(); private final SaikuCube cube; private Scenario scenario; private SaikuTag tag = null; private SaikuFilter filter; private CellSet cellset = null; private OlapStatement statement = null; private final OlapConnection connection; private ICellSetFormatter formatter; public OlapQuery(Query query, OlapConnection connection, SaikuCube cube, boolean applyDefaultProperties) { this.query = query; this.cube = cube; this.connection = connection; if (applyDefaultProperties) { applyDefaultProperties(); } } public OlapQuery(Query query, OlapConnection connection, SaikuCube cube) { this(query, connection, cube, true); } public void swapAxes() { this.query.swapAxes(); QueryAxis rows = query.getAxis(Axis.ROWS); QueryAxis cols = query.getAxis(Axis.COLUMNS); SortOrder colSort = cols.getSortOrder(); String colSortIdentifier = cols.getSortIdentifierNodeName(); cols.clearSort(); if (rows.getSortOrder() != null) { cols.sort(rows.getSortOrder(), rows.getSortIdentifierNodeName()); } rows.clearSort(); if (colSort != null) { rows.sort(colSort, colSortIdentifier); } try { // 3-way swap String colFilter = cols.getFilterCondition(); LimitFunction colLimit = cols.getLimitFunction(); BigDecimal colN = cols.getLimitFunctionN(); String colLimitSort = cols.getLimitFunctionSortLiteral(); cols.clearFilter(); cols.clearLimitFunction(); // columns if (rows.getLimitFunction() != null) { cols.limit(rows.getLimitFunction(), rows.getLimitFunctionN(), rows.getLimitFunctionSortLiteral()); } if (StringUtils.isNotBlank(rows.getFilterCondition())) { cols.filter(rows.getFilterCondition()); } rows.clearFilter(); rows.clearLimitFunction(); // rows if (colLimit != null) { rows.limit(colLimit, colN, colLimitSort); } if (StringUtils.isNotBlank(colFilter)) { rows.filter(colFilter); } } catch (NoSuchMethodError e) { } } public Map<Axis, QueryAxis> getAxes() { return this.query.getAxes(); } public QueryAxis getAxis(Axis axis) { return this.query.getAxis(axis); } public QueryAxis getAxis(String name) throws SaikuOlapException { if ("UNUSED".equals(name)) { return getUnusedAxis(); } Standard standardAxis = Standard.valueOf(name); if (standardAxis == null) throw new SaikuOlapException("Axis (" + name + ") not found for query (" + query.getName() + ")"); Axis queryAxis = Axis.Factory.forOrdinal(standardAxis.axisOrdinal()); return query.getAxis(queryAxis); } public Cube getCube() { return this.query.getCube(); } public QueryAxis getUnusedAxis() { return this.query.getUnusedAxis(); } public void moveDimension(QueryDimension dimension, Axis axis) { moveDimension(dimension, axis, -1); } public void moveDimension(QueryDimension dimension, Axis axis, int position) { QueryAxis oldQueryAxis = findAxis(dimension); QueryAxis newQueryAxis = query.getAxis(axis); if (!Axis.FILTER.equals(axis)) { dimension.setHierarchyConsistent(true); dimension.setHierarchizeMode(HierarchizeMode.PRE); } else { dimension.setHierarchyConsistent(false); dimension.clearHierarchizeMode(); } if (oldQueryAxis != null && newQueryAxis != null && (oldQueryAxis.getLocation() != newQueryAxis.getLocation()) && oldQueryAxis.getLocation() != null) { for (QueryAxis qAxis : query.getAxes().values()) { if (qAxis.getSortOrder() != null && qAxis.getSortIdentifierNodeName() != null) { String sortLiteral = qAxis.getSortIdentifierNodeName(); if (sortLiteral.startsWith(dimension.getDimension().getUniqueName()) || sortLiteral.startsWith("[" + dimension.getName())) { qAxis.clearSort(); } } } } if (oldQueryAxis != null && newQueryAxis != null && (position > -1 || (oldQueryAxis.getLocation() != newQueryAxis.getLocation()))) { oldQueryAxis.removeDimension(dimension); if (position > -1) { newQueryAxis.addDimension(position, dimension); } else { newQueryAxis.addDimension(dimension); } } } public QueryDimension getDimension(String name) { return this.query.getDimension(name); } private QueryAxis findAxis(QueryDimension dimension) { if (query.getUnusedAxis().getDimensions().contains(dimension)) { return query.getUnusedAxis(); } else { Map<Axis, QueryAxis> axes = query.getAxes(); for (Axis axis : axes.keySet()) { if (axes.get(axis).getDimensions().contains(dimension)) { return axes.get(axis); } } } return null; } public String getMdx() { final Writer writer = new StringWriter(); if (SaikuProperties.olapConvertQuery) { try { SelectNode s = QueryConverter.convert(query); s.unparse(new ParseTreeWriter(new PrintWriter(writer))); } catch (SaikuIncompatibleException se) { log.debug("Cannot convert to new query model mdx, falling back to old version", se); this.query.getSelect().unparse(new ParseTreeWriter(new PrintWriter(writer))); } catch (Exception e) { throw new SaikuServiceException("Cannot convert to new query model", e); } } else { this.query.getSelect().unparse(new ParseTreeWriter(new PrintWriter(writer))); } return writer.toString(); } public SaikuCube getSaikuCube() { return cube; } public String getName() { return query.getName(); } public CellSet execute() throws Exception { try { if (statement != null) { statement.close(); statement = null; } if (scenario != null && query.getDimension(SCENARIO) != null) { QueryDimension dimension = query.getDimension(SCENARIO); moveDimension(dimension, Axis.FILTER); Selection sel = dimension.createSelection( IdentifierParser.parseIdentifier("[Scenario].[" + getScenario().getId() + "]")); if (!dimension.getInclusions().contains(sel)) { dimension.getInclusions().add(sel); } } String mdx = getMdx(); log.trace("Executing query (" + this.getName() + ") :\n" + mdx); final Catalog catalog = query.getCube().getSchema().getCatalog(); this.connection.setCatalog(catalog.getName()); OlapStatement stmt = connection.createStatement(); this.statement = stmt; CellSet cellSet = stmt.executeOlapQuery(mdx); if (scenario != null && query.getDimension(SCENARIO) != null) { QueryDimension dimension = query.getDimension(SCENARIO); dimension.getInclusions().clear(); moveDimension(dimension, null); } return cellSet; } finally { if (this.statement != null) { this.statement.close(); } } } private void applyDefaultProperties() { if (SaikuProperties.olapDefaultNonEmpty) { query.getAxis(Axis.ROWS).setNonEmpty(true); query.getAxis(Axis.COLUMNS).setNonEmpty(true); } } public void resetAxisSelections(QueryAxis axis) { for (QueryDimension dim : axis.getDimensions()) { dim.clearInclusions(); dim.clearExclusions(); dim.clearSort(); } try { axis.clearFilter(); axis.clearLimitFunction(); axis.clearSort(); } catch (NoSuchMethodError e) { } } public void clearAllQuerySelections() { resetAxisSelections(getUnusedAxis()); Map<Axis, QueryAxis> axes = getAxes(); for (Axis axis : axes.keySet()) { resetAxisSelections(axes.get(axis)); } } public void resetQuery() { clearAllQuerySelections(); Map<Axis, QueryAxis> axes = getAxes(); for (Axis axis : axes.keySet()) { QueryAxis qAxis = axes.get(axis); for (int i = 0; i < qAxis.getDimensions().size(); i++) { QueryDimension qDim = qAxis.getDimensions().get(0); moveDimension(qDim, null); } } } public void clearAxis(String axisName) throws SaikuOlapException { if (StringUtils.isNotBlank(axisName)) { QueryAxis qAxis = getAxis(axisName); resetAxisSelections(qAxis); for (int i = 0; i < qAxis.getDimensions().size(); i++) { QueryDimension qDim = qAxis.getDimensions().get(0); moveDimension(qDim, null); } } } public void setProperties(Properties props) { if (props != null) { this.properties.putAll(props); for (Object _key : props.keySet()) { String key = (String) _key; String value = props.getProperty((String) key); QueryProperty prop = QueryPropertyFactory.getProperty(key, value, this); prop.handle(); } } } public Properties getProperties() { this.properties.putAll(QueryPropertyFactory.forQuery(this)); try { connection.createScenario(); if (query.getDimension("Scenario") != null) { this.properties.put("org.saiku.connection.scenario", Boolean.toString(true)); } else { this.properties.put("org.saiku.connection.scenario", Boolean.toString(false)); } this.properties.put("org.saiku.query.explain", Boolean.toString(connection.isWrapperFor(RolapConnection.class))); } catch (Exception e) { this.properties.put("org.saiku.connection.scenario", Boolean.toString(false)); this.properties.put("org.saiku.query.explain", Boolean.toString(false)); } return this.properties; } public String toXml() { QuerySerializer qs = new QuerySerializer(this); return qs.createXML(); } public Boolean isDrillThroughEnabled() { return query.getCube().isDrillThroughEnabled(); } public QueryType getType() { return QueryType.QM; } public void setMdx(String mdx) { throw new UnsupportedOperationException(); } public void setScenario(Scenario scenario) { this.scenario = scenario; } public Scenario getScenario() { return scenario; } public void setTag(SaikuTag tag) { this.tag = tag; } public SaikuTag getTag() { return this.tag; } public void removeTag() { tag = null; } public void setFilter(SaikuFilter filter) { this.filter = filter; } public SaikuFilter getFilter() { return this.filter; } public void removeFilter() { this.filter = null; } public void storeCellset(CellSet cs) { this.cellset = cs; } public CellSet getCellset() { return cellset; } public void setStatement(OlapStatement os) { this.statement = os; } public OlapStatement getStatement() { return this.statement; } public void cancel() throws Exception { if (this.statement != null && !this.statement.isClosed()) { statement.cancel(); statement.close(); } this.statement = null; } public OlapConnection getConnection() { return this.connection; } public void storeFormatter(ICellSetFormatter formatter) { this.formatter = formatter; } public ICellSetFormatter getFormatter() { return formatter; } public void setTotalFunction(String uniqueLevelName, String value) { totalsFunctions.put(uniqueLevelName, value); } public String getTotalFunction(String uniqueLevelName) { return totalsFunctions.get(uniqueLevelName); } public Map<String, String> getTotalFunctions() { return totalsFunctions; } public Query getQuery() { return query; } }