/*! * 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.ui.datasources.cda; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dialog; import java.awt.Frame; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.HashMap; import java.util.Map; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.border.EmptyBorder; import javax.swing.table.TableModel; import org.pentaho.reporting.engine.classic.core.DataFactory; import org.pentaho.reporting.engine.classic.core.ParameterMapping; import org.pentaho.reporting.engine.classic.core.ReportDataFactoryException; import org.pentaho.reporting.engine.classic.core.ReportProcessingException; import org.pentaho.reporting.engine.classic.core.designtime.DesignTimeContext; import org.pentaho.reporting.engine.classic.core.designtime.datafactory.DataFactoryEditorSupport; import org.pentaho.reporting.engine.classic.core.modules.gui.commonswing.ExceptionDialog; import org.pentaho.reporting.engine.classic.core.util.ReportParameterValues; import org.pentaho.reporting.engine.classic.extensions.datasources.cda.CdaDataFactory; import org.pentaho.reporting.engine.classic.extensions.datasources.cda.CdaQueryEntry; import org.pentaho.reporting.engine.classic.extensions.datasources.cda.HttpQueryBackend; import org.pentaho.reporting.libraries.base.util.StringUtils; import org.pentaho.reporting.libraries.designtime.swing.CommonDialog; import org.pentaho.reporting.libraries.designtime.swing.SmartComboBox; import org.pentaho.reporting.libraries.designtime.swing.VerticalLayout; import org.pentaho.reporting.libraries.designtime.swing.background.CancelEvent; import org.pentaho.reporting.libraries.designtime.swing.background.DataPreviewDialog; import org.pentaho.reporting.libraries.designtime.swing.background.PreviewWorker; public class CdaDataSourceEditor extends CommonDialog { private class FetchAction extends AbstractAction { private FetchAction() { putValue(Action.NAME, Messages.getString("CdaDataSourceEditor.FetchAction.Name")); } public void actionPerformed(final ActionEvent e) { try { final TableModel model = fetchData("listQueries", new HashMap<String, String>()); final QueriesTableModel clone = (QueriesTableModel) queriesTableModel.clone(); queriesTableModel.clear(); for (int i = 0; i < model.getRowCount(); i++) { final String query = (String) model.getValueAt(i, 0); final String name = (String) model.getValueAt(i, 1); final HashMap<String,String> extraParameter = new HashMap<String, String>(); extraParameter.put("dataAccessId", query); final TableModel param = fetchData("listParameters", extraParameter); final HashMap<String,String> oldParamMappings = new HashMap<String, String>(); final QueriesTableModel.QueryData queryById = clone.getQueryById(query); if (queryById != null) { final ParameterMapping[] parameters = queryById.getQueryEntry().getParameters(); for (final ParameterMapping parameter : parameters) { oldParamMappings.put(parameter.getAlias(), parameter.getName()); } } final ParameterMapping[] parameterMappings = new ParameterMapping[param.getRowCount()]; final String[] declaredParameters = new String[parameterMappings.length]; for (int j = 0; j < parameterMappings.length; j++) { final String paramNameOnServer = (String) param.getValueAt(j, 0); String mappedName = oldParamMappings.get(paramNameOnServer); if (mappedName == null) { mappedName = paramNameOnServer; } parameterMappings[j] = new ParameterMapping(mappedName, paramNameOnServer); declaredParameters[j] = paramNameOnServer; } final String queryName; if (StringUtils.isEmpty(name)) { queryName = "Anonymous Query #" + i; } else { queryName = name; } final CdaQueryEntry entry = new CdaQueryEntry(queryName, query); entry.setParameters(parameterMappings); queriesTableModel.add(new QueriesTableModel.QueryData(entry, declaredParameters)); extraParameter.clear(); } } catch (ReportProcessingException e1) { designTimeContext.error(e1); } } } private class PreviewAction extends AbstractAction { private PreviewAction() { putValue(Action.NAME, Messages.getString("CdaDataSourceEditor.Preview.Name")); } public void actionPerformed(final ActionEvent aEvt) { final int selectedRow = queriesTable.getSelectedRow(); if (selectedRow == -1) { return; } try { final CdaDataFactory dataFactory = produceDataFactory(); DataFactoryEditorSupport.configureDataFactoryForPreview(dataFactory, designTimeContext); final DataPreviewDialog previewDialog = new DataPreviewDialog(CdaDataSourceEditor.this); final CdaPreviewWorker worker = new CdaPreviewWorker(dataFactory, queriesTableModel.getName(selectedRow)); previewDialog.showData(worker); final ReportDataFactoryException factoryException = worker.getException(); if (factoryException != null) { ExceptionDialog.showExceptionDialog(CdaDataSourceEditor.this, Messages.getString("ErrorDialog.Title"), Messages.getString("ErrorDialog.PreviewError"), factoryException); } } catch (Exception e) { ExceptionDialog.showExceptionDialog(CdaDataSourceEditor.this, Messages.getString("ErrorDialog.Title"), Messages.getString("ErrorDialog.PreviewError"), e); } } } private static class CdaPreviewWorker implements PreviewWorker { private CdaDataFactory dataFactory; private TableModel resultTableModel; private ReportDataFactoryException exception; private String query; private CdaPreviewWorker(final CdaDataFactory dataFactory, final String query) { if (dataFactory == null) { throw new NullPointerException(); } this.query = query; this.dataFactory = dataFactory; } public ReportDataFactoryException getException() { return exception; } public TableModel getResultTableModel() { return resultTableModel; } public void close() { } /** * Requests that the thread stop processing as soon as possible. */ public void cancelProcessing(final CancelEvent event) { dataFactory.cancelRunningQuery(); } /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p/> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see Thread#run() */ public void run() { try { resultTableModel = dataFactory.queryData(query, new ReportParameterValues()); dataFactory.close(); } catch (ReportDataFactoryException e) { exception = e; } } } private JTextField baseUrl; private JComboBox baseUrlField; private JTextField solution; private JTextField path; private JTextField file; private JCheckBox sugarMode; private JTextField username; private JTextField password; private JCheckBox useLocalCall; private QueriesTableModel queriesTableModel; private DesignTimeContext designTimeContext; private JTable queriesTable; private Action editParameterAction; private Action previewAction; public CdaDataSourceEditor(final DesignTimeContext context) { init(context); } public CdaDataSourceEditor(final DesignTimeContext context, final Frame owner) throws HeadlessException { super(owner); init(context); } public CdaDataSourceEditor(final DesignTimeContext context, final Dialog owner) throws HeadlessException { super(owner); init(context); } private void init(final DesignTimeContext context) { this.designTimeContext = context; this.queriesTableModel = new QueriesTableModel(); queriesTable = new JTable(queriesTableModel); baseUrl = new JTextField(); baseUrl.addFocusListener(new FocusListener() { public void focusLost(FocusEvent e) { checkBaseUrl(); } public void focusGained(FocusEvent e) {} }); baseUrlField = new SmartComboBox(); baseUrlField.setEditable(true); final DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(context.getDataSchemaModel().getColumnNames()); comboBoxModel.insertElementAt(null, 0); comboBoxModel.setSelectedItem(null); baseUrlField.setModel(comboBoxModel); solution = new JTextField(); path = new JTextField(); file = new JTextField(); sugarMode = new JCheckBox(Messages.getString("CdaDataSourceEditor.SugarMode")); sugarMode.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { changeSugarMode(sugarMode.isSelected()); } }); username = new JTextField(); password = new JTextField(); useLocalCall = new JCheckBox(Messages.getString("CdaDataSourceEditor.AllowLocalAPICalls")); editParameterAction = new EditParameterAction(); previewAction = new PreviewAction(); super.init(); } protected String getDialogId() { return "CdaDataSourceEditor"; } protected Component createContentPane() { final JPanel fetchQueriesPanel = new JPanel(); fetchQueriesPanel.setLayout(new BorderLayout()); fetchQueriesPanel.add(new JLabel(Messages.getString("CdaDataSourceEditor.FetchQueryFromServer")), BorderLayout.CENTER); fetchQueriesPanel.add(new JButton(new FetchAction()), BorderLayout.EAST); final JPanel previewAndParameterPanel = new JPanel(new BorderLayout()); previewAndParameterPanel.add(new JButton(previewAction), BorderLayout.EAST); previewAndParameterPanel.add(new JButton(editParameterAction), BorderLayout.CENTER); final JPanel panel = new JPanel(); panel.setLayout(new VerticalLayout(5, VerticalLayout.BOTH)); panel.add(new JLabel(Messages.getString("CdaDataSourceEditor.ServerURL"))); panel.add(baseUrl); panel.add(new JLabel(Messages.getString("CdaDataSourceEditor.ServerURLField"))); panel.add(baseUrlField); panel.add(sugarMode); panel.add(new JLabel(Messages.getString("CdaDataSourceEditor.Username"))); panel.add(username); panel.add(new JLabel(Messages.getString("CdaDataSourceEditor.Password"))); panel.add(password); panel.add(new JLabel(Messages.getString("CdaDataSourceEditor.Solution"))); panel.add(solution); panel.add(new JLabel(Messages.getString("CdaDataSourceEditor.Path"))); panel.add(path); panel.add(new JLabel(Messages.getString("CdaDataSourceEditor.File"))); panel.add(file); panel.add(useLocalCall); panel.add(fetchQueriesPanel); final JPanel cpanel = new JPanel(); cpanel.setLayout(new BorderLayout()); cpanel.setBorder(new EmptyBorder(3,3,3,3)); cpanel.add(panel, BorderLayout.NORTH); cpanel.add(new JScrollPane(queriesTable), BorderLayout.CENTER); cpanel.add(previewAndParameterPanel, BorderLayout.SOUTH); return cpanel; } public DataFactory performConfiguration(final CdaDataFactory input, final String queryName) { if (input != null) { baseUrl.setText(input.getBaseUrl()); baseUrlField.setSelectedItem(input.getBaseUrlField()); password.setText(input.getPassword()); username.setText(input.getUsername()); file.setText(input.getFile()); solution.setText(input.getSolution()); path.setText(input.getPath()); useLocalCall.setSelected(input.isUseLocalCall()); sugarMode.setSelected(input.isSugarMode()); queriesTableModel.clear(); final String[] queryNames = input.getQueryNames(); for (int i = 0; i < queryNames.length; i++) { final String name = queryNames[i]; final CdaQueryEntry queryEntry = input.getQueryEntry(name); queriesTableModel.add(new QueriesTableModel.QueryData(queryEntry, new String[0])); } } else { useLocalCall.setSelected(true); } if (performEdit() == false) { return null; } return produceDataFactory(); } private CdaDataFactory produceDataFactory() { final CdaDataFactory dataFactory = new CdaDataFactory(); dataFactory.setBaseUrl(baseUrl.getText()); dataFactory.setBaseUrlField((String) baseUrlField.getSelectedItem()); dataFactory.setPassword(password.getText()); dataFactory.setUsername(username.getText()); dataFactory.setFile(file.getText()); dataFactory.setPath(path.getText()); dataFactory.setSolution(solution.getText()); dataFactory.setUseLocalCall(useLocalCall.isSelected()); dataFactory.setSugarMode(sugarMode.isSelected()); for (int i = 0; i < queriesTableModel.size(); i++) { final QueriesTableModel.QueryData queryData = queriesTableModel.get(i); dataFactory.setQueryEntry(queryData.getQueryEntry().getName(), queryData.getQueryEntry()); } return dataFactory; } private TableModel fetchData(final String method, final Map<String, String> extraParameter) throws ReportProcessingException { // ugly but might still beat constructing the whole query final CdaDataFactory dataFactory = produceDataFactory(); DataFactoryEditorSupport.configureDataFactoryForPreview(dataFactory, designTimeContext); HttpQueryBackend httpQuery = getHttpQuery(); httpQuery.initialize(dataFactory.getDataFactoryContext()); return httpQuery.fetchData(null, method, extraParameter); } private HttpQueryBackend getHttpQuery() { HttpQueryBackend query = new HttpQueryBackend(); query.setBaseUrl(baseUrl.getText()); query.setFile(file.getText()); query.setPath(path.getText()); query.setSolution(solution.getText()); query.setSugarMode(sugarMode.isSelected()); query.setUsername(username.getText()); query.setPassword(password.getText()); return query; } private void checkBaseUrl() { if (baseUrl.getText().endsWith("/")) { baseUrl.setText(baseUrl.getText().substring(0, baseUrl.getText().length() -1)); } } private void changeSugarMode(boolean sugarMode) { if (sugarMode) { // try a simple conversion if old path being used if (!StringUtils.isEmpty(solution.getText())) { String newPathPrefix = joinPathStrings("/public", solution.getText()); solution.setText(""); path.setText(joinPathStrings(newPathPrefix, path.getText())); } if (!StringUtils.isEmpty(file.getText())) { path.setText(joinPathStrings(path.getText(), file.getText())); file.setText(""); } } file.setEnabled(!sugarMode); solution.setEnabled(!sugarMode); } private String joinPathStrings(String first, String second) { final String separator = "/"; boolean inFirst = first.endsWith(separator); boolean inSecond = second.startsWith(separator); if (inFirst && inSecond) { return first + second.substring(1); } else if (!inFirst && !inSecond) { return first + separator + second; } return first + second; } private class EditParameterAction extends AbstractAction { /** * Defines an <code>Action</code> object with a default * description string and default icon. */ private EditParameterAction() { putValue(Action.NAME, Messages.getString("CdaDataSourceEditor.EditParameter.Name")); } /** * Invoked when an action occurs. */ public void actionPerformed(final ActionEvent e) { final int selectedRow = queriesTable.getSelectedRow(); if ((selectedRow == -1) || (queriesTable.getSelectedRowCount() > 1)) { return; /* TODO all error message */ } final QueriesTableModel.QueryData queryData = queriesTableModel.get(selectedRow); final CdaQueryEntry queryEntry = queryData.getQueryEntry(); try { final ParameterEditorDialog dialog = new ParameterEditorDialog(CdaDataSourceEditor.this); final String[] reportFields = designTimeContext.getDataSchemaModel().getColumnNames(); final ParameterEditorDialog.EditResult editResult = dialog.performEdit(queryEntry.getParameters(), reportFields, queryData.getDeclaredParameter()); if (editResult == null) { return; } queryEntry.setParameters(editResult.getParameterMappings()); } catch (Exception e1) { designTimeContext.error(e1); } catch (Throwable t1) { designTimeContext.error(new RuntimeException("Fatal error", t1)); } } } }