/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.extensions.datasources.cda;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.swing.table.TableModel;
import org.pentaho.reporting.engine.classic.core.DataFactoryContext;
import org.pentaho.reporting.engine.classic.core.DataRow;
import org.pentaho.reporting.engine.classic.core.ParameterMapping;
import org.pentaho.reporting.engine.classic.core.ReportDataFactoryException;
import org.pentaho.reporting.engine.classic.core.ResourceBundleFactory;
import org.pentaho.reporting.engine.classic.core.util.TypedTableModel;
import org.pentaho.reporting.libraries.base.config.Configuration;
import org.pentaho.reporting.libraries.base.util.CSVQuoter;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.base.util.URLEncoder;
/**
* Abstract Class that will be extended by each implementation of CDA invocation LOCAL or HTTP
*
* @author dduque
*/
public abstract class CdaQueryBackend implements Cloneable
{
public static final String METHOD_LIST_PARAMETERS = "listParameters";
public static final String DATA_ACCESS_ID = "dataAccessId";
public static final String METHOD_DO_QUERY = "doQuery";
public static final String PARAM_NAME = "name";
public static final String PARAM_TYPE = "type";
public static final String PARAM_DEFAULT_VALUE = "defaultValue";
public static final String PARAM_PATTERN = "pattern";
public static final String TYPE_DATE = "Date";
public static final String TYPE_INTEGER = "Integer";
public static final String TYPE_NUMERIC = "Numeric";
public static final String TYPE_STRING = "String";
public static final String TYPE_ARRAY_SUFFIX = "Array";
private String username;
private String password;
private String solution;
private String path;
private String file;
private boolean sugarMode;
private transient String baseUrl;
private DataFactoryContext context;
public CdaQueryBackend()
{
}
public void initialize(final DataFactoryContext context)
{
this.context = context;
}
protected DataFactoryContext getContext()
{
return context;
}
protected String parameterToString(final String name,
final String type,
final String pattern,
final Object raw) throws ReportDataFactoryException
{
if (raw == null)
{
return "";
}
if (TYPE_DATE.equals(type))
{
if (raw instanceof Date == false && raw instanceof Number == false)
{
throw new ReportDataFactoryException("For parameter " + name + " Expected date, but got " + raw.getClass());
}
final ResourceBundleFactory resourceBundleFactory = context.getResourceBundleFactory();
final SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, resourceBundleFactory.getLocale());
dateFormat.setTimeZone(resourceBundleFactory.getTimeZone());
return dateFormat.format(raw);
}
if (TYPE_INTEGER.equals(type) || TYPE_NUMERIC.equals(type))
{
if (raw instanceof Number == false)
{
throw new ReportDataFactoryException("For parameter " + name + " Expected number, but got " + raw.getClass());
}
return String.valueOf(raw);
}
if (TYPE_STRING.equals(type))
{
return String.valueOf(raw);
}
if (type.endsWith(TYPE_ARRAY_SUFFIX))
{
if (raw.getClass().isArray() == false)
{
if (raw instanceof String)
{
return raw.toString();
}
else
{
throw new ReportDataFactoryException("For parameter " + name + " Expected array, but got " + raw.getClass());
}
}
final CSVQuoter quoter = new CSVQuoter(';');
final String arrayType = type.substring(0, type.length() - 5);
final StringBuilder b = new StringBuilder();
final int length = Array.getLength(raw);
for (int i = 0; i < length; i++)
{
final Object o = Array.get(raw, i);
if (i > 0)
{
b.append(";");
}
final String str = parameterToString(name + "[" + i + "]", arrayType, pattern, o);
b.append(quoter.doQuoting(str));
}
return b.toString();
}
throw new ReportDataFactoryException("Unknown type " + type + " for parameter " + name);
}
private String getURLEncoding()
{
final Configuration configuration = context.getConfiguration();
return configuration.getConfigProperty("org.pentaho.reporting.engine.classic.core.URLEncoding");
}
protected String encodeParameter(final String value)
{
if (StringUtils.isEmpty(value))
{
return "";
}
try
{
return URLEncoder.encode(value, getURLEncoding());
}
catch (UnsupportedEncodingException e)
{
throw new IllegalStateException(e);
}
}
public String createURL(final String method,
final Map<String, String> extraParameter)
{
final String baseURL = getBaseUrl();
final String basePath = isSugarMode() ? "/plugin/cda/api/" : "/content/cda/";
final StringBuilder url = new StringBuilder();
url.append(baseURL);
url.append(basePath);
url.append(method);
url.append("?");
url.append("outputType=xml");
url.append("&path=");
url.append(encodeParameter(getPath()));
if (!isSugarMode()) {
url.append("&solution=");
url.append(encodeParameter(getSolution()));
url.append("&file=");
url.append(encodeParameter(getFile()));
}
for (final Map.Entry<String, String> entry : extraParameter.entrySet())
{
final String key = encodeParameter(entry.getKey());
if (StringUtils.isEmpty(key))
{
continue;
}
url.append("&");
url.append(key);
url.append("=");
url.append(encodeParameter(entry.getValue()));
}
return url.toString();
}
protected TypedTableModel fetchParameter(final DataRow dataRow, final CdaQueryEntry realQuery)
throws ReportDataFactoryException
{
final HashMap<String, String> extras = new HashMap<String, String>();
extras.put(DATA_ACCESS_ID, realQuery.getId());
return fetchData(dataRow, METHOD_LIST_PARAMETERS, extras);
}
public synchronized TableModel queryData(final CdaQueryEntry realQuery,
final DataRow parameters)
throws ReportDataFactoryException
{
if (realQuery == null)
{
throw new NullPointerException("Query is null."); //$NON-NLS-1$
}
final TypedTableModel parameterModel = fetchParameter(parameters, realQuery);
// name = 0
// type = 1
// defaultValue = 2
// pattern = 3
final HashMap<String, String> extraParams = new HashMap<String, String>();
extraParams.put(DATA_ACCESS_ID, realQuery.getId());
final int nameIdx = parameterModel.findColumn(PARAM_NAME);
final int typeIdx = parameterModel.findColumn(PARAM_TYPE);
final int defaultValueIdx = parameterModel.findColumn(PARAM_DEFAULT_VALUE);
final int patternIdx = parameterModel.findColumn(PARAM_PATTERN);
for (int p = 0; p < parameterModel.getRowCount(); p++)
{
final String name = (String) parameterModel.getValueAt(p, nameIdx);
final String type = (String) parameterModel.getValueAt(p, typeIdx);
final String pattern = (String) parameterModel.getValueAt(p, patternIdx);
final String aliasName = findParameterAlias(realQuery, name);
final Object rawValue = parameters.get(aliasName);
final String param;
if (rawValue == null)
{
param = (String) parameterModel.getValueAt(p, defaultValueIdx);
}
else
{
param = parameterToString(name, type, pattern, rawValue);
}
extraParams.put("param" + name, param);
}
return fetchData(parameters, METHOD_DO_QUERY, extraParams);
}
private String findParameterAlias(final CdaQueryEntry query, final String name)
{
final ParameterMapping[] parameterMapping = query.getParameters();
for (int i = 0; i < parameterMapping.length; i++)
{
final ParameterMapping mapping = parameterMapping[i];
if (name.equals(mapping.getAlias()))
{
return mapping.getName();
}
}
return name;
}
/**
* Fetch the data, has to be implemented in each sub class
*
* @param dataRow
* @param method
* @param extraParameter
* @return
* @throws ReportDataFactoryException
*/
public abstract TypedTableModel fetchData(final DataRow dataRow,
final String method,
final Map<String, String> extraParameter) throws ReportDataFactoryException;
public Object clone()
{
try
{
return super.clone();
}
catch (CloneNotSupportedException cne)
{
throw new IllegalStateException(cne);
}
}
public String getUsername()
{
return username;
}
public void setUsername(final String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(final String password)
{
this.password = password;
}
public String getSolution()
{
return solution;
}
public void setSolution(final String solution)
{
this.solution = solution;
}
public String getPath()
{
return path;
}
public void setPath(final String path)
{
this.path = path;
}
public String getFile()
{
return file;
}
public void setFile(final String file)
{
this.file = file;
}
public String getBaseUrl()
{
return baseUrl;
}
public void setBaseUrl(final String baseUrl)
{
this.baseUrl = baseUrl;
}
public boolean isSugarMode() {
return sugarMode;
}
public void setSugarMode(boolean sugarMode) {
this.sugarMode = sugarMode;
}
public void cancelRunningQuery()
{
}
}