/** * The contents of this file are subject to the OpenMRS Public License * Version 1.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://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.eclipse.datatools.connectivity.oda.openmrs.ui.impl; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.datatools.connectivity.oda.IConnection; import org.eclipse.datatools.connectivity.oda.IParameterMetaData; import org.eclipse.datatools.connectivity.oda.IQuery; import org.eclipse.datatools.connectivity.oda.IResultSetMetaData; import org.eclipse.datatools.connectivity.oda.OdaException; import org.eclipse.datatools.connectivity.oda.design.DataSetDesign; import org.eclipse.datatools.connectivity.oda.design.DesignFactory; import org.eclipse.datatools.connectivity.oda.design.ResultSetColumns; import org.eclipse.datatools.connectivity.oda.design.ResultSetDefinition; import org.eclipse.datatools.connectivity.oda.design.ui.designsession.DesignSessionUtil; import org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage; import org.eclipse.datatools.connectivity.oda.design.util.DesignUtil; import org.eclipse.datatools.connectivity.oda.openmrs.impl.QueryBuilder; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; /** * This page is where the user specifies how they want to "split" their tokens. * In addition to getting the token, value the user may be interested in * choosing other associated values with the token like Observation Date, * Observation Location, Encounter Date, and Encounter Type. This is * accomplished in this interface by table of check boxes where the columns are * the different "splitters" and the rows are the selected tokens. */ public class SplitterPage extends DataSetWizardPage { private static final String DATESTYLE = "DATESTYLE"; private static final String TOKENTAG = "TOKENTAG"; private static final String DATASTYLE = "DATASTYLE"; private static final String FILTER = "FILTER"; private static final String TOKENS = "TOKENS"; private Logger log = Logger.getLogger(SplitterPage.class.getName()); private static String SPLIT_MESSAGE = "Choose How Each Token will be \"Split\" into Additional Fields"; private Composite composite, split_composite = null; private Label[] split_labels; private Label[] token_labels; private String[] splits = { "Observation Date", "Observation Location", "Encounter Date", "Encounter Type" }; private String[] splitNames = { "OBSERVATIONDATE", "OBSERVATIONLOCATION", "ENCOUNTERDATE", "ENCOUNTERTYPE" }; private Map translateSplits; private List tokens; private Map checkBoxes; /** * Constructor. * * @param pageName the page name */ public SplitterPage(String pageName) { super(pageName); setTitle(pageName); setMessage(SPLIT_MESSAGE); setPageComplete(true); } /** * Constructor. * * @param pageName the page name * @param title the title * @param titleImage the title image */ public SplitterPage(String pageName, String title, ImageDescriptor titleImage) { super(pageName, title, titleImage); setMessage(SPLIT_MESSAGE); setPageComplete(true); } /** * @see org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage#createPageCustomControl(org.eclipse.swt.widgets.Composite) */ @Override public void createPageCustomControl(Composite parent) { log.setLevel(Level.INFO); setControl(createPageControl(parent)); initializeControl(); } /** * Creates custom control for user-defined query text. * * @param parent the parent * * @return the control */ private Control createPageControl(Composite parent) { composite = new Composite(parent, SWT.BORDER); composite.setSize(400, 600); composite.setLayout(new GridLayout(2, false)); GridData gridData = new GridData(SWT.FILL, SWT.FILL, false, false); gridData.heightHint = 400; gridData.widthHint = 600; composite.setLayoutData(gridData); /* * parent.setSize(405, 405); GridData parentData = new * GridData(SWT.FILL, SWT.FILL, false, false); parentData.heightHint = * 405; parentData.widthHint = 405; parent.setLayoutData(parentData); */ return composite; } /** * Sets the tokens that can be split based on the current TOKENS stored in * the InformationHolder. */ private void determineTokens() { tokens = QueryBuilder.getTokenNamesFromStorage(InformationHolder .getPropertyValue(TOKENS)); } /** * Initializes the page control with the last edited data set design. */ private void initializeControl() { /* * To optionally restore the designer state of the previous design * session, use getInitializationDesignerState(); */ log.info("Initializing splitter page"); // Restores the last saved data set design DataSetDesign dataSetDesign = getInitializationDesign(); if (InformationHolder.hasDestroyed()) InformationHolder.start(dataSetDesign); if (dataSetDesign == null) return; // nothing to initialize translateSplits = new HashMap(); for (int i = 0; i < splits.length; i++) { translateSplits.put(splits[i], splitNames[i]); } if (InformationHolder.getPropertyValue(TOKENS) != null) { determineTokens(); createSplit_composite(); loadCheckBoxes(); split_composite.layout(); composite.layout(); // composite.getParent().layout(); } } /** * Creates the SplitTokenCheckBoxes based on the current splitter settings * and selected tokens. */ private void loadCheckBoxes() { // cycle through the tokens and set their check boxes appropriately for (String token : tokens) { SplitTokenCheckBox[] splitTokenBoxes = checkBoxes.get(token); String splitsForThisToken = Utils .getSplitsForTokenFromTokenProperty(token, InformationHolder.getPropertyValue(TOKENS)); // add the splits for this token if there are any if (splitsForThisToken != null) { // go through each split that was found String[] tokenSplits = splitsForThisToken.split(":"); for (String tokenSplit : tokenSplits) { // now, find the check box for this split for (SplitTokenCheckBox splitTokenBox : splitTokenBoxes) { if (translateSplits.get(splitTokenBox.getSplit()) .equals(tokenSplit)) { splitTokenBox.getCheck().setSelection(true); } } } } } } /** * Architects the main composite that houses the grid of check boxes. */ private void createSplit_composite() { GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = splits.length + 1; // gridLayout.makeColumnsEqualWidth = true; GridData gridData = new GridData(SWT.FILL, SWT.FILL, false, true); gridData.widthHint = 400; split_composite = new Composite(composite, SWT.NONE); split_composite.setLayout(gridLayout); split_composite.setData(gridData); Label filler = new Label(split_composite, SWT.NONE); split_labels = new Label[splits.length]; for (int i = 0; i < split_labels.length; i++) { split_labels[i] = new Label(split_composite, SWT.NONE); split_labels[i].setText(splits[i]); } // setup the token rows token_labels = new Label[tokens.size()]; checkBoxes = new HashMap(); for (int i = 0; i < tokens.size(); i++) { token_labels[i] = new Label(split_composite, SWT.NONE); token_labels[i].setText(tokens.get(i)); final Button[] checks = new Button[split_labels.length]; SplitTokenCheckBox[] checkBoxRows = new SplitTokenCheckBox[split_labels.length]; for (int j = 0; j < checks.length; j++) { checks[j] = new Button(split_composite, SWT.CHECK); GridData checkData = new GridData(); checkData.horizontalAlignment = GridData.CENTER; checkData.verticalAlignment = GridData.CENTER; checks[j].setLayoutData(checkData); checkBoxRows[j] = new SplitTokenCheckBox(checks[j], splits[j], translateSplits.get(splits[j]), tokens.get(i)); } checkBoxes.put(tokens.get(i), checkBoxRows); } } /** * Obtains the user-defined query text of this data set from page control. * * @return query text */ private String getQueryText() { String queryText = QueryBuilder.getQuery(InformationHolder .getPropertyValue(TOKENS), InformationHolder .getPropertyValue(FILTER), InformationHolder .getPropertyValue(DATASTYLE)); log.info(queryText); return queryText; } /** * @see org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage#collectDataSetDesign(org.eclipse.datatools.connectivity.oda.design.DataSetDesign) */ @Override protected DataSetDesign collectDataSetDesign(DataSetDesign design) { savePage(design); return design; } /** * @see org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage#collectResponseState() */ @Override protected void collectResponseState() { super.collectResponseState(); /* * To optionally assign a custom response state, for inclusion in the * ODA design session response, use setResponseSessionStatus( * SessionStatus status ); setResponseDesignerState( DesignerState * customState ); */ } /** * @see org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage#canLeave() */ @Override protected boolean canLeave() { return isPageComplete(); } /** * Gets the blank page properties. * * @return the blank page properties */ private static java.util.Properties getBlankPageProperties() { java.util.Properties prop = new java.util.Properties(); prop.setProperty(FILTER, ""); prop.setProperty(TOKENTAG, ""); prop.setProperty(TOKENS, ""); prop.setProperty(DATESTYLE, ""); return prop; } /** * Saves the user-defined value in this page, and updates the specified * dataSetDesign with the latest design definition. * * @param dataSetDesign the data set design */ private void savePage(DataSetDesign dataSetDesign) { // save user-defined query text if (InformationHolder.hasDestroyed()) InformationHolder.start(dataSetDesign); String queryText = getQueryText(); dataSetDesign.setQueryText(queryText); log.info(queryText); if (dataSetDesign.getPublicProperties() == null) { try { dataSetDesign.setPublicProperties(DesignSessionUtil .createDataSetPublicProperties(dataSetDesign .getOdaExtensionDataSourceId(), dataSetDesign .getOdaExtensionDataSetId(), getBlankPageProperties())); } catch (OdaException e) { // TODO need some logging here e.printStackTrace(); } } if (dataSetDesign.getPublicProperties() != null) { if (dataSetDesign.getPublicProperties().findProperty(FILTER) != null) dataSetDesign.getPublicProperties().findProperty(FILTER) .setNameValue(FILTER, InformationHolder.getPropertyValue(FILTER)); if (dataSetDesign.getPublicProperties().findProperty(TOKENTAG) != null) dataSetDesign.getPublicProperties().findProperty(TOKENTAG) .setNameValue(TOKENTAG, InformationHolder.getPropertyValue(TOKENTAG)); if (dataSetDesign.getPublicProperties().findProperty(TOKENS) != null) dataSetDesign.getPublicProperties().findProperty(TOKENS) .setNameValue(TOKENS, InformationHolder.getPropertyValue(TOKENS)); if (dataSetDesign.getPublicProperties().findProperty(DATASTYLE) != null) dataSetDesign.getPublicProperties().findProperty(DATASTYLE) .setNameValue(DATASTYLE, InformationHolder.getPropertyValue(DATASTYLE)); } // obtain query's current runtime metadata, and maps it to the // dataSetDesign IConnection conn = null; try { // obtain and open a live connection conn = new org.eclipse.datatools.connectivity.oda.openmrs.impl.Driver() .getConnection(null); java.util.Properties connProps = DesignUtil .convertDataSourceProperties(getInitializationDesign() .getDataSourceDesign()); conn.open(connProps); // update the data set design with the query's current runtime // metadata updateDesign(dataSetDesign, conn, queryText); } catch (OdaException e) { // not able to get current metadata, reset previous derived metadata dataSetDesign.setResultSets(null); dataSetDesign.setParameters(null); e.printStackTrace(); } finally { closeConnection(conn); } log.info("Done saving filter page"); } /** * Updates the given dataSetDesign with the queryText and its derived * metadata obtained from the ODA runtime connection. * * @param dataSetDesign the data set design * @param conn the conn * @param queryText the query text * * @throws OdaException the oda exception */ private void updateDesign(DataSetDesign dataSetDesign, IConnection conn, String queryText) throws OdaException { IQuery query = conn.newQuery(null); query.prepare(queryText); try { IResultSetMetaData md = query.getMetaData(); updateResultSetDesign(md, dataSetDesign); } catch (OdaException e) { // no result set definition available, reset previous derived // metadata dataSetDesign.setResultSets(null); e.printStackTrace(); } // proceed to get parameter design definition try { IParameterMetaData paramMd = query.getParameterMetaData(); updateParameterDesign(paramMd, dataSetDesign); } catch (OdaException ex) { // no parameter definition available, reset previous derived // metadata dataSetDesign.setParameters(null); ex.printStackTrace(); } /* * See DesignSessionUtil for more convenience methods to define a data * set design instance. */ } /** * Updates the specified data set design's result set definition based on * the specified runtime metadata. * * @param md runtime result set metadata instance * @param dataSetDesign data set design instance to update * * @throws OdaException the oda exception */ private void updateResultSetDesign(IResultSetMetaData md, DataSetDesign dataSetDesign) throws OdaException { ResultSetColumns columns = DesignSessionUtil .toResultSetColumnsDesign(md); ResultSetDefinition resultSetDefn = DesignFactory.eINSTANCE .createResultSetDefinition(); // resultSetDefn.setName( value ); // result set name resultSetDefn.setResultSetColumns(columns); // no exception in conversion; go ahead and assign to specified // dataSetDesign dataSetDesign.setPrimaryResultSet(resultSetDefn); dataSetDesign.getResultSets().setDerivedMetaData(true); } /** * Updates the specified data set design's parameter definition based on the * specified runtime metadata. Unimplemented, as parameters are unsupported. * * @param paramMd the param md * @param dataSetDesign the data set design * * @throws OdaException the oda exception */ private void updateParameterDesign(IParameterMetaData paramMd, DataSetDesign dataSetDesign) throws OdaException { } /** * Attempts to close given ODA connection. * * @param conn the conn */ private void closeConnection(IConnection conn) { try { if (conn != null && conn.isOpen()) conn.close(); } catch (OdaException e) { // TODO need some logging here e.printStackTrace(); } } /** * @see org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage#refresh(org.eclipse.datatools.connectivity.oda.design.DataSetDesign) */ @Override protected void refresh(DataSetDesign dataSetDesign) { if (InformationHolder.hasDestroyed()) InformationHolder.start(dataSetDesign); refresh(); } /** * Refreshes the data page in the case that changes to the other page have * effected how this page is displayed like adding or removing tokens. */ protected void refresh() { translateSplits = new HashMap(); for (int i = 0; i < splits.length; i++) { translateSplits.put(splits[i], splitNames[i]); } if (InformationHolder.getPropertyValue(TOKENS) != null) { split_composite.dispose(); determineTokens(); createSplit_composite(); loadCheckBoxes(); split_composite.layout(); composite.layout(); // composite.getParent().layout(); } } /* * @see org.eclipse.datatools.connectivity.oda.design.ui.wizards.DataSetWizardPage#cleanup() */ @Override protected void cleanup() { InformationHolder.destroy(); } }