blob: 429b3cb2a28f260379af7018475ad3c54b104030 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.sun.star.report;
import com.sun.star.beans.PropertyVetoException;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.beans.XPropertySet;
import com.sun.star.container.NoSuchElementException;
import com.sun.star.container.XIndexAccess;
import com.sun.star.container.XNameAccess;
import com.sun.star.lang.IllegalArgumentException;
import com.sun.star.lang.IndexOutOfBoundsException;
import com.sun.star.lang.WrappedTargetException;
import com.sun.star.lang.XComponent;
import com.sun.star.sdb.CommandType;
import com.sun.star.sdb.XCompletedExecution;
import com.sun.star.sdb.XParametersSupplier;
import com.sun.star.sdb.XQueriesSupplier;
import com.sun.star.sdb.XSingleSelectQueryComposer;
import com.sun.star.sdb.tools.XConnectionTools;
import com.sun.star.sdbc.SQLException;
import com.sun.star.sdbc.XConnection;
import com.sun.star.sdbc.XParameters;
import com.sun.star.sdbc.XRowSet;
import com.sun.star.task.XInteractionHandler;
import com.sun.star.uno.Exception;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Very primitive implementation, just to show how this could be used ...
*
*/
public class SDBCReportDataFactory implements DataSourceFactory
{
private static final String ESCAPEPROCESSING = "EscapeProcessing";
private class RowSetProperties
{
final Boolean escapeProcessing;
final int commandType;
final Integer maxRows;
final String command;
final String filter;
public RowSetProperties(final Boolean escapeProcessing, final int commandType, final String command, final String filter, final Integer maxRows)
{
this.escapeProcessing = escapeProcessing;
this.commandType = commandType;
this.command = command;
this.filter = filter;
this.maxRows = maxRows;
}
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final RowSetProperties other = (RowSetProperties) obj;
if (this.escapeProcessing != other.escapeProcessing && (this.escapeProcessing == null || !this.escapeProcessing.equals(other.escapeProcessing)))
{
return false;
}
if (this.commandType != other.commandType)
{
return false;
}
if (this.maxRows != other.maxRows && (this.maxRows == null || !this.maxRows.equals(other.maxRows)))
{
return false;
}
if ((this.command == null) ? (other.command != null) : !this.command.equals(other.command))
{
return false;
}
if ((this.filter == null) ? (other.filter != null) : !this.filter.equals(other.filter))
{
return false;
}
return true;
}
public int hashCode()
{
int hash = 3;
hash = 59 * hash + (this.escapeProcessing != null ? this.escapeProcessing.hashCode() : 0);
hash = 59 * hash + this.commandType;
hash = 59 * hash + (this.maxRows != null ? this.maxRows.hashCode() : 0);
hash = 59 * hash + (this.command != null ? this.command.hashCode() : 0);
hash = 59 * hash + (this.filter != null ? this.filter.hashCode() : 0);
return hash;
}
}
class ParameterDefinition
{
int parameterCount = 0;
private ArrayList parameterIndex = new ArrayList();
}
private static final Log LOGGER = LogFactory.getLog(SDBCReportDataFactory.class);
public static final String COMMAND_TYPE = "command-type";
public static final String ESCAPE_PROCESSING = "escape-processing";
public static final String GROUP_EXPRESSIONS = "group-expressions";
public static final String MASTER_VALUES = "master-values";
public static final String MASTER_COLUMNS = "master-columns";
public static final String DETAIL_COLUMNS = "detail-columns";
public static final String UNO_FILTER = "Filter";
private static final String APPLY_FILTER = "ApplyFilter";
private static final String UNO_COMMAND = "Command";
private static final String UNO_ORDER = "Order";
private static final String UNO_APPLY_FILTER = "ApplyFilter";
private static final String UNO_COMMAND_TYPE = "CommandType";
private final XConnection connection;
private final XComponentContext m_cmpCtx;
private static final int FAILED = 0;
private static final int DONE = 1;
private static final int RETRIEVE_COLUMNS = 2;
private static final int RETRIEVE_OBJECT = 3;
private static final int HANDLE_QUERY = 4;
private static final int HANDLE_TABLE = 5;
private static final int HANDLE_SQL = 6;
private final Map rowSetProperties = new HashMap();
private final Map parameterMap = new HashMap();
private boolean rowSetCreated = false;
public SDBCReportDataFactory(final XComponentContext cmpCtx, final XConnection connection)
{
this.connection = connection;
m_cmpCtx = cmpCtx;
}
public DataSource queryData(final String command, final Map parameters) throws DataSourceException
{
try
{
if (command == null)
{
return new SDBCReportData(null);
}
int commandType = CommandType.COMMAND;
final String commandTypeValue = (String) parameters.get(COMMAND_TYPE);
if (commandTypeValue != null)
{
if ("query".equals(commandTypeValue))
{
commandType = CommandType.QUERY;
}
else if ("table".equals(commandTypeValue))
{
commandType = CommandType.TABLE;
}
else
{
commandType = CommandType.COMMAND;
}
}
final Boolean escapeProcessing = (Boolean) parameters.get(ESCAPE_PROCESSING);
final String filter = (String) parameters.get(UNO_FILTER);
final Integer maxRows = (Integer) parameters.get("MaxRows");
final RowSetProperties rowSetProps = new RowSetProperties(escapeProcessing, commandType, command, filter, maxRows);
final Object[] p = createRowSet(rowSetProps, parameters);
final XRowSet rowSet = (XRowSet) p[0];
if (command.length() != 0)
{
final ParameterDefinition paramDef = (ParameterDefinition) p[1];
fillParameter(parameters, rowSet, paramDef);
rowSetCreated = rowSetCreated && (maxRows == null || maxRows == 0);
final XCompletedExecution execute = (XCompletedExecution) UnoRuntime.queryInterface(XCompletedExecution.class, rowSet);
if (rowSetCreated && execute != null && paramDef.parameterCount > 0)
{
final XInteractionHandler handler = (XInteractionHandler) UnoRuntime.queryInterface(XInteractionHandler.class, m_cmpCtx.getServiceManager().createInstanceWithContext("com.sun.star.sdb.InteractionHandler", m_cmpCtx));
execute.executeWithCompletion(handler);
}
else
{
rowSet.execute();
}
}
rowSetCreated = false;
return new SDBCReportData(rowSet);
}
catch (Exception ex)
{
rowSetCreated = false;
throw new DataSourceException(ex.getMessage(), ex);
}
}
private String getOrderStatement(final int commandType, final String command, final List groupExpressions)
{
final StringBuffer order = new StringBuffer();
final int count = groupExpressions.size();
if (count != 0)
{
try
{
final String quote = connection.getMetaData().getIdentifierQuoteString();
final XComponent[] hold = new XComponent[1];
final XNameAccess columns = getFieldsByCommandDescriptor(commandType, command, hold);
if (columns != null)
{
for (int i = 0; i < count; i++)
{
final Object[] pair = (Object[]) groupExpressions.get(i);
String expression = (String) pair[0];
if (!expression.startsWith(quote) && columns.hasByName(expression))
{
XPropertySet column;
try
{
column = UnoRuntime.queryInterface(XPropertySet.class, columns.getByName(expression));
expression = quote + column.getPropertyValue("TableName") + quote + "." + quote + expression + quote;
}
catch (Exception ex)
{
Logger.getLogger(SDBCReportDataFactory.class.getName()).log(Level.SEVERE, null, ex);
expression = quote + expression + quote;
}
}
expression = expression.trim(); // Trim away white spaces
if (expression.length() > 0)
{
order.append(expression);
if (order.length() > 0)
{
order.append(' ');
}
final String sorting = (String) pair[1];
if (sorting == null || sorting.equals(OfficeToken.FALSE))
{
order.append("DESC");
}
if ((i + 1) < count)
{
order.append(", ");
}
}
}
}
}
catch (SQLException ex)
{
LOGGER.error("ReportProcessing failed", ex);
}
}
return order.toString();
}
private XNameAccess getFieldsByCommandDescriptor(final int commandType, final String command, final XComponent[] out) throws SQLException
{
final Class[] parameter = new Class[3];
parameter[0] = int.class;
parameter[1] = String.class;
parameter[2] = out.getClass();
final XConnectionTools tools = (XConnectionTools) UnoRuntime.queryInterface(XConnectionTools.class, connection);
try
{
tools.getClass().getMethod("getFieldsByCommandDescriptor", parameter);
return tools.getFieldsByCommandDescriptor(commandType, command, out);
}
catch (NoSuchMethodException ex)
{
}
throw new SQLException();
}
private XSingleSelectQueryComposer getComposer(final XConnectionTools tools,
final String command,
final int commandType)
{
final Class[] parameter = new Class[2];
parameter[0] = int.class;
parameter[1] = String.class;
try
{
final Object[] param = new Object[2];
param[0] = commandType;
param[1] = command;
final Method call = tools.getClass().getMethod("getComposer", parameter);
return (XSingleSelectQueryComposer) call.invoke(tools, param);
}
catch (NoSuchMethodException ex)
{
}
catch (IllegalAccessException ex)
{
// should not happen
// assert False
}
catch (java.lang.reflect.InvocationTargetException ex)
{
// should not happen
// assert False
}
return null;
}
private void fillParameter(final Map parameters,
final XRowSet rowSet, final ParameterDefinition paramDef)
throws SQLException,
UnknownPropertyException,
PropertyVetoException,
IllegalArgumentException,
WrappedTargetException
{
final ArrayList masterValues = (ArrayList) parameters.get(MASTER_VALUES);
if (masterValues != null && !masterValues.isEmpty())
{
final XParameters para = (XParameters) UnoRuntime.queryInterface(XParameters.class, rowSet);
for (int i = 0;
i < masterValues.size();
i++)
{
Object object = masterValues.get(i);
if (object instanceof BigDecimal)
{
object = ((BigDecimal) object).toString();
}
final Integer pos = (Integer) paramDef.parameterIndex.get(i);
para.setObject(pos + 1, object);
}
}
}
private final Object[] createRowSet(final RowSetProperties rowSetProps, final Map parameters)
throws Exception
{
final ArrayList detailColumns = (ArrayList) parameters.get(DETAIL_COLUMNS);
if (rowSetProperties.containsKey(rowSetProps) && detailColumns != null && !detailColumns.isEmpty())
{
return new Object[]
{
rowSetProperties.get(rowSetProps), parameterMap.get(rowSetProps)
};
}
rowSetCreated = true;
final XRowSet rowSet = (XRowSet) UnoRuntime.queryInterface(XRowSet.class, m_cmpCtx.getServiceManager().createInstanceWithContext("com.sun.star.sdb.RowSet", m_cmpCtx));
final XPropertySet rowSetProp = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, rowSet);
rowSetProp.setPropertyValue("ActiveConnection", connection);
rowSetProp.setPropertyValue(ESCAPEPROCESSING, rowSetProps.escapeProcessing);
rowSetProp.setPropertyValue(UNO_COMMAND_TYPE, Integer.valueOf(rowSetProps.commandType));
rowSetProp.setPropertyValue(UNO_COMMAND, rowSetProps.command);
if (rowSetProps.filter != null)
{
rowSetProp.setPropertyValue("Filter", rowSetProps.filter);
rowSetProp.setPropertyValue(APPLY_FILTER, Boolean.valueOf(rowSetProps.filter.length() != 0));
}
else
{
rowSetProp.setPropertyValue(APPLY_FILTER, Boolean.FALSE);
}
if (rowSetProps.maxRows != null)
{
rowSetProp.setPropertyValue("MaxRows", rowSetProps.maxRows);
}
final XConnectionTools tools = (XConnectionTools) UnoRuntime.queryInterface(XConnectionTools.class, connection);
fillOrderStatement(rowSetProps.command, rowSetProps.commandType, parameters, tools, rowSetProp);
final ParameterDefinition paramDef = createParameter(parameters, tools, rowSetProps, rowSet);
rowSetProperties.put(rowSetProps, rowSet);
parameterMap.put(rowSetProps, paramDef);
return new Object[]
{
rowSet, paramDef
};
}
private ParameterDefinition createParameter(final Map parameters,
final XConnectionTools tools,
RowSetProperties rowSetProps, final XRowSet rowSet)
throws SQLException,
UnknownPropertyException,
PropertyVetoException,
IllegalArgumentException,
WrappedTargetException
{
final ParameterDefinition paramDef = new ParameterDefinition();
final XSingleSelectQueryComposer composer = getComposer(tools, rowSetProps.command, rowSetProps.commandType);
if (composer != null)
{
final XPropertySet rowSetProp = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, rowSet);
if ((Boolean) rowSetProp.getPropertyValue(APPLY_FILTER))
{
composer.setFilter((String) rowSetProp.getPropertyValue("Filter"));
}
// get old parameter count
final ArrayList detailColumns = (ArrayList) parameters.get(DETAIL_COLUMNS);
final ArrayList handledColumns = new ArrayList();
final XParametersSupplier paraSup = (XParametersSupplier) UnoRuntime.queryInterface(XParametersSupplier.class, composer);
if (paraSup != null)
{
final XIndexAccess params = paraSup.getParameters();
if (params != null)
{
final int oldParameterCount = params.getCount();
paramDef.parameterCount = oldParameterCount;
if (detailColumns != null)
{
for (int i = 0; i < oldParameterCount; i++)
{
try
{
final XPropertySet parameter = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, params.getByIndex(i));
if (parameter != null)
{
final String name = (String) parameter.getPropertyValue("Name");
for (int j = 0; j < detailColumns.size(); j++)
{
if (name.equals(detailColumns.get(j)))
{
handledColumns.add(name);
paramDef.parameterIndex.add(i);
--paramDef.parameterCount;
break;
}
}
}
}
catch (IndexOutOfBoundsException ex)
{
Logger.getLogger(SDBCReportDataFactory.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
final ArrayList masterValues = (ArrayList) parameters.get(MASTER_VALUES);
if (masterValues != null && !masterValues.isEmpty() && paramDef.parameterIndex.size() != detailColumns.size())
{
// Vector masterColumns = (Vector) parameters.get("master-columns");
// create the new filter
final String quote = connection.getMetaData().getIdentifierQuoteString();
final StringBuffer oldFilter = new StringBuffer();
oldFilter.append(composer.getFilter());
if (oldFilter.length() != 0)
{
oldFilter.append(" AND ");
}
int newParamterCounter = 1;
for (final Iterator it = detailColumns.iterator(); it.hasNext();
++newParamterCounter)
{
final String detail = (String) it.next();
if (!handledColumns.contains(detail))
{
//String master = (String) masterIt.next();
oldFilter.append(quote);
oldFilter.append(detail);
oldFilter.append(quote);
oldFilter.append(" = :link_");
oldFilter.append(newParamterCounter);
if (it.hasNext())
{
oldFilter.append(" AND ");
}
paramDef.parameterIndex.add(newParamterCounter + paramDef.parameterCount - 1);
}
}
composer.setFilter(oldFilter.toString());
final String sQuery = composer.getQuery();
rowSetProp.setPropertyValue(UNO_COMMAND, sQuery);
rowSetProp.setPropertyValue(UNO_COMMAND_TYPE, Integer.valueOf(CommandType.COMMAND));
}
}
return paramDef;
}
void fillOrderStatement(final String command,
final int commandType, final Map parameters,
final XConnectionTools tools,
final XPropertySet rowSetProp)
throws SQLException,
UnknownPropertyException,
PropertyVetoException,
IllegalArgumentException,
WrappedTargetException,
NoSuchElementException
{
final StringBuffer order = new StringBuffer(getOrderStatement(commandType, command, (ArrayList) parameters.get(GROUP_EXPRESSIONS)));
if (order.length() > 0 && commandType != CommandType.TABLE)
{
String statement = command;
final XSingleSelectQueryComposer composer = getComposer(tools, command, commandType);
if (composer != null)
{
statement = composer.getQuery();
composer.setQuery(statement);
final String sOldOrder = composer.getOrder();
if (sOldOrder.length() > 0)
{
order.append(',');
order.append(sOldOrder);
composer.setOrder("");
statement = composer.getQuery();
}
}
else
{
if (commandType == CommandType.QUERY)
{
final XQueriesSupplier xSupplyQueries = (XQueriesSupplier) UnoRuntime.queryInterface(XQueriesSupplier.class, connection);
final XNameAccess queries = xSupplyQueries.getQueries();
if (queries.hasByName(command))
{
final XPropertySet prop = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, queries.getByName(command));
final Boolean escape = (Boolean) prop.getPropertyValue(ESCAPEPROCESSING);
rowSetProp.setPropertyValue(ESCAPEPROCESSING, escape);
final String queryCommand = (String) prop.getPropertyValue(UNO_COMMAND);
statement = "SELECT * FROM (" + queryCommand + ")";
}
}
else
{
statement = "SELECT * FROM (" + command + ")";
}
}
rowSetProp.setPropertyValue(UNO_COMMAND, statement);
rowSetProp.setPropertyValue(UNO_COMMAND_TYPE, Integer.valueOf(CommandType.COMMAND));
}
rowSetProp.setPropertyValue("Order", order.toString());
}
}