com.netspective.axiom.value.source.QueryResultsValueSource.java Source code

Java tutorial

Introduction

Here is the source code for com.netspective.axiom.value.source.QueryResultsValueSource.java

Source

/*
 * Copyright (c) 2000-2004 Netspective Communications LLC. All rights reserved.
 *
 * Netspective Communications LLC ("Netspective") permits redistribution, modification and use of this file in source
 * and binary form ("The Software") under the Netspective Source License ("NSL" or "The License"). The following
 * conditions are provided as a summary of the NSL but the NSL remains the canonical license and must be accepted
 * before using The Software. Any use of The Software indicates agreement with the NSL.
 *
 * 1. Each copy or derived work of The Software must preserve the copyright notice and this notice unmodified.
 *
 * 2. Redistribution of The Software is allowed in object code form only (as Java .class files or a .jar file
 *    containing the .class files) and only as part of an application that uses The Software as part of its primary
 *    functionality. No distribution of the package is allowed as part of a software development kit, other library,
 *    or development tool without written consent of Netspective. Any modified form of The Software is bound by these
 *    same restrictions.
 *
 * 3. Redistributions of The Software in any form must include an unmodified copy of The License, normally in a plain
 *    ASCII text file unless otherwise agreed to, in writing, by Netspective.
 *
 * 4. The names "Netspective", "Axiom", "Commons", "Junxion", and "Sparx" are trademarks of Netspective and may not be
 *    used to endorse or appear in products derived from The Software without written consent of Netspective.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT,
 * ARE HEREBY DISCLAIMED.
 *
 * NETSPECTIVE AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A
 * RESULT OF USING OR DISTRIBUTING THE SOFTWARE. IN NO EVENT WILL NETSPECTIVE OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN
 * IF IT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 */
package com.netspective.axiom.value.source;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.lang.exception.NestableRuntimeException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.netspective.axiom.SqlManager;
import com.netspective.axiom.SqlManagerComponent;
import com.netspective.axiom.sql.Query;
import com.netspective.axiom.sql.QueryResultSet;
import com.netspective.axiom.value.DatabaseConnValueContext;
import com.netspective.commons.io.Resource;
import com.netspective.commons.value.CachedValue;
import com.netspective.commons.value.GenericValue;
import com.netspective.commons.value.PresentationValue;
import com.netspective.commons.value.Value;
import com.netspective.commons.value.ValueContext;
import com.netspective.commons.value.ValueSource;
import com.netspective.commons.value.ValueSourceDocumentation;
import com.netspective.commons.value.ValueSourceSpecification;
import com.netspective.commons.value.ValueSources;
import com.netspective.commons.value.exception.ValueSourceInitializeException;
import com.netspective.commons.value.source.AbstractValueSource;
import com.netspective.commons.xdm.XdmComponentFactory;
import com.netspective.commons.xdm.exception.DataModelException;

public class QueryResultsValueSource extends AbstractValueSource {
    private static final Log log = LogFactory.getLog(QueryResultsValueSource.class);
    static private String[] RESULT_STYLE_NAMES = new String[] { "single-column", "row-map", "multi-row-map",
            "single-row-array", "multi-row-matrix", "result-set", "presentation" };

    public static final String[] IDENTIFIERS = new String[] { "query" };
    public static final ValueSourceDocumentation DOCUMENTATION = new ValueSourceDocumentation(
            "Executes a static query and returns the results.",
            new ValueSourceDocumentation.Parameter[] { new ValueSourceDocumentation.Parameter("query-source", true,
                    "The format is 'query-source/query-id@data-source-id'. Where the only required "
                            + "item is the query-id. Query-source may be either a static value or a value source and may resolve to either a "
                            + "resource id or a file name. If a resource id is required, use 'r resourceId' (prefix 'r ' in front of the value "
                            + "to indicate it's a resource). The Query id is always a static text item and data-source-id may be a value source, "
                            + "null, or a static text string."),
                    new ValueSourceDocumentation.Parameter("style", false, RESULT_STYLE_NAMES, "multi-row-matrix",
                            "The style of result requested."),
                    new ValueSourceDocumentation.Parameter("cache-timeout", false, "0",
                            "Number of milliseconds to cache the query results."),
                    new ValueSourceDocumentation.Parameter("params", false, "Bind parameters.") });

    static public final int RESULTSTYLE_SINGLECOLUMN_OBJECT = 0;
    static public final int RESULTSTYLE_FIRST_ROW_MAP_OBJECT = 1;
    static public final int RESULTSTYLE_ALL_ROWS_MAP_LIST = 2;
    static public final int RESULTSTYLE_FIRST_ROW_LIST = 3;
    static public final int RESULTSTYLE_ALL_ROWS_LIST = 4;
    static public final int RESULTSTYLE_RESULTSET = 5;
    static public final int RESULTSTYLE_PRESENTATION = 6;

    static private Map cachedValues = new HashMap();
    static private Map cachedPresentationValues = new HashMap();

    private int resultStyle = RESULTSTYLE_ALL_ROWS_LIST;
    private ValueSource sourceId;
    private String queryId;
    private long cacheTimeoutMillis;
    private ValueSource dataSourceId;
    private ValueSource[] params;

    public static String[] getIdentifiers() {
        return IDENTIFIERS;
    }

    public static ValueSourceDocumentation getDocumentation() {
        return DOCUMENTATION;
    }

    public QueryResultsValueSource() {
    }

    public void setDataSourceId(ValueSource value) {
        dataSourceId = value;
    }

    /**
     * Assigns the source of the query. The format is 'query-source/query-id@data-source-id'. Where the only required
     * item is the query-id. Query-source may be either a static value or a value source and may resolve to either a
     * resource id or a file name. If a resource id is required, use 'r resourceId' (prefix 'r ' in front of the value
     * to indicate it's a resource). The Query id is always a static text item and data-source-id may be a value source,
     * null, or a static text string.
     */
    public void setSource(String params) {
        int dataSrcIdDelim = params.indexOf('@');
        if (dataSrcIdDelim != -1) {
            String srcParams = params.substring(0, dataSrcIdDelim);
            int querySrcIdDelim = srcParams.lastIndexOf('/');
            if (querySrcIdDelim != -1) {
                sourceId = ValueSources.getInstance()
                        .getValueSourceOrStatic(srcParams.substring(0, querySrcIdDelim));
                queryId = srcParams.substring(querySrcIdDelim + 1);
            } else
                queryId = srcParams;

            setDataSourceId(
                    ValueSources.getInstance().getValueSourceOrStatic(params.substring(dataSrcIdDelim + 1)));
        } else {
            int querySrcIdDelim = params.lastIndexOf('/');
            if (querySrcIdDelim != -1) {
                sourceId = ValueSources.getInstance().getValueSourceOrStatic(params.substring(0, querySrcIdDelim));
                queryId = params.substring(querySrcIdDelim + 1);
            } else {
                queryId = params;
            }
            dataSourceId = null;
        }
    }

    public void initialize(ValueSourceSpecification spec) throws ValueSourceInitializeException {
        super.initialize(spec);

        StringTokenizer st = new StringTokenizer(spec.getParams(), ",");
        if (st.hasMoreTokens())
            setSource(st.nextToken().trim());

        if (st.hasMoreTokens()) {
            String styleText = st.nextToken().trim();
            if (styleText.equals("-"))
                resultStyle = RESULTSTYLE_ALL_ROWS_LIST;
            else {
                for (int i = 0; i < RESULT_STYLE_NAMES.length; i++) {
                    resultStyle = -1;
                    if (styleText.equalsIgnoreCase(RESULT_STYLE_NAMES[i])) {
                        resultStyle = i;
                        break;
                    }
                }
                if (resultStyle == -1)
                    throw new ValueSourceInitializeException("Invalid style '" + styleText + "' specified", this,
                            spec);
            }
        }

        if (st.hasMoreTokens()) {
            String cacheAmount = st.nextToken().trim();
            if (cacheAmount.equals("-"))
                cacheTimeoutMillis = 0;
            else
                cacheTimeoutMillis = Long.parseLong(cacheAmount);
        }

        if (st.hasMoreTokens()) {
            List queryParams = new ArrayList();
            while (st.hasMoreTokens())
                queryParams.add(ValueSources.getInstance().getValueSourceOrStatic(st.nextToken().trim()));
            params = (ValueSource[]) queryParams.toArray(new ValueSource[queryParams.size()]);
        }
    }

    public SqlManager getSqlManager(DatabaseConnValueContext dbcvc)
            throws DataModelException, InvocationTargetException, InstantiationException, IllegalAccessException,
            IOException, NoSuchMethodException {
        SqlManager result = null;
        if (sourceId != null) {
            SqlManagerComponent component = null;

            String sourceIdText = sourceId.getTextValue(dbcvc);
            if (sourceIdText == null)
                throw new RuntimeException("sourceId returned null text value in " + this);

            if (sourceIdText.startsWith("r ")) {
                String resourceId = sourceIdText.substring(2);
                component = (SqlManagerComponent) XdmComponentFactory.get(SqlManagerComponent.class,
                        new Resource(QueryResultsValueSource.class, resourceId),
                        XdmComponentFactory.XDMCOMPFLAGS_DEFAULT);
            } else
                component = (SqlManagerComponent) XdmComponentFactory.get(SqlManagerComponent.class,
                        new File(sourceIdText), XdmComponentFactory.XDMCOMPFLAGS_DEFAULT);
            result = component.getManager();
        } else
            result = dbcvc.getSqlManager();

        return result;
    }

    public String getCachedValueKey(ValueContext vc) {
        StringBuffer sb = new StringBuffer();
        if (sourceId != null)
            sb.append(sourceId.getTextValue(vc));
        sb.append(" ");
        sb.append(queryId);

        if (params != null) {
            sb.append(" ");

            Object[] parameters = new Object[params.length];
            for (int p = 0; p < params.length; p++)
                sb.append(parameters[p] = params[p].getValue(vc).getValueForSqlBindParam());
        }

        return sb.toString();
    }

    public Value getQueryResults(ValueContext vc, int style) {
        ValueSources.getInstance().assertValueContextInstance(DatabaseConnValueContext.class, vc, this);
        DatabaseConnValueContext dcvc = (DatabaseConnValueContext) vc;

        SqlManager sqlManager = null;
        try {
            sqlManager = getSqlManager(dcvc);
            if (sqlManager == null)
                throw new RuntimeException("Unable to locate SQL Manager for " + this);
        } catch (Exception e) {
            log.error("Error retrieving SQL Manager", e);
            throw new NestableRuntimeException(e);
        }

        Query query = sqlManager.getQuery(queryId);
        if (query == null) {
            log.error("Unable to locate Query '" + queryId + "' in SQL Manager '" + sqlManager + "' in " + this
                    + ". Available: " + sqlManager.getQueries().getNames());
            if (style == RESULTSTYLE_PRESENTATION) {
                PresentationValue pValue = new PresentationValue();
                PresentationValue.Items items = pValue.createItems();
                items.addItem("Unable to find query " + queryId);
                return pValue;
            } else
                return new GenericValue("Unable to find query " + queryId);
        }

        String dataSourceIdText = dataSourceId != null ? dataSourceId.getTextValue(vc) : null;
        QueryResultSet qrs = null;

        try {
            if (params == null)
                qrs = query.execute(dcvc, dataSourceIdText, null);
            else {
                Object[] parameters = new Object[params.length];
                for (int p = 0; p < params.length; p++)
                    parameters[p] = params[p].getValue(vc).getValueForSqlBindParam();
                qrs = query.execute(dcvc, dataSourceIdText, parameters);
            }
        } catch (Exception e) {
            log.error("Error executing query", e);
            throw new NestableRuntimeException(e);
        }

        Value value = null;
        try {
            ResultSet rs = qrs.getResultSet();
            switch (style) {
            case RESULTSTYLE_SINGLECOLUMN_OBJECT:
                if (rs.next())
                    value = new GenericValue(rs.getObject(1));
                else
                    value = null;
                break;

            case RESULTSTYLE_FIRST_ROW_MAP_OBJECT:
                if (rs.next()) {
                    Map rowMap = new HashMap();
                    ResultSetMetaData rsmd = rs.getMetaData();
                    for (int i = 1; i <= rsmd.getColumnCount(); i++)
                        rowMap.put(rsmd.getColumnName(i), rs.getObject(i));
                    value = new GenericValue(rowMap);
                } else
                    value = null;
                break;

            case RESULTSTYLE_ALL_ROWS_MAP_LIST:
                List rows = new ArrayList();
                ResultSetMetaData rsmd = rs.getMetaData();
                while (rs.next()) {
                    Map rowMap = new HashMap();
                    for (int i = 1; i <= rsmd.getColumnCount(); i++)
                        rowMap.put(rsmd.getColumnName(i), rs.getObject(i));
                    rows.add(rowMap);
                }
                value = new GenericValue(rows);
                break;

            case RESULTSTYLE_FIRST_ROW_LIST:
                rsmd = rs.getMetaData();
                if (rs.next()) {
                    List row = new ArrayList();
                    for (int i = 1; i <= rsmd.getColumnCount(); i++)
                        row.add(rs.getObject(i));
                    value = new GenericValue(row);
                } else
                    value = null;
                break;

            case RESULTSTYLE_ALL_ROWS_LIST:
                rsmd = rs.getMetaData();
                rows = new ArrayList();
                while (rs.next()) {
                    List row = new ArrayList();
                    for (int i = 1; i <= rsmd.getColumnCount(); i++)
                        row.add(rs.getObject(i));
                    rows.add(row);
                }
                value = new GenericValue(rows);
                break;

            case RESULTSTYLE_RESULTSET:
                value = new GenericValue(qrs);
                break;

            case RESULTSTYLE_PRESENTATION:
                PresentationValue pValue = new PresentationValue();
                PresentationValue.Items items = pValue.createItems();
                rsmd = rs.getMetaData();
                rows = new ArrayList();
                switch (rsmd.getColumnCount()) {
                case 1:
                    while (rs.next())
                        items.addItem(rs.getString(1));
                    break;

                default:
                    while (rs.next())
                        items.addItem(rs.getString(1), rs.getString(2));
                    break;
                }
                value = pValue;
                break;

            default:
                throw new RuntimeException("Invalid style " + resultStyle + " in " + this);
            }
        } catch (Exception e) {
            log.error("Error retrieving results", e);
            throw new NestableRuntimeException(e);
        } finally {
            if (resultStyle != RESULTSTYLE_RESULTSET) {
                try {
                    if (qrs != null)
                        qrs.close(true);
                } catch (SQLException e) {
                    log.error("Error closing result set", e);
                    throw new NestableRuntimeException(e);
                }
            }
        }
        return value;
    }

    public Value getValue(ValueContext vc) {
        if (cacheTimeoutMillis > 0) {
            String cacheKey = getCachedValueKey(vc);
            CachedValue cv = (CachedValue) cachedValues.get(cacheKey);
            if (cv != null) {
                if (cv.isValid())
                    return cv.getValue();
                else
                    cachedValues.remove(cacheKey);
            }

            Value value = getQueryResults(vc, resultStyle);
            cachedValues.put(cacheKey, new CachedValue(value, cacheTimeoutMillis));
            return value;
        } else
            return getQueryResults(vc, resultStyle);
    }

    public PresentationValue getPresentationValue(ValueContext vc) {
        if (cacheTimeoutMillis > 0) {
            String cacheKey = getCachedValueKey(vc);
            CachedValue cv = (CachedValue) cachedPresentationValues.get(cacheKey);
            if (cv != null) {
                if (cv.isValid())
                    return (PresentationValue) cv.getValue();
                else
                    cachedPresentationValues.remove(cacheKey);
            }

            PresentationValue value = (PresentationValue) getQueryResults(vc, RESULTSTYLE_PRESENTATION);
            cachedPresentationValues.put(cacheKey, new CachedValue(value, cacheTimeoutMillis));
            return value;
        } else
            return (PresentationValue) getQueryResults(vc, RESULTSTYLE_PRESENTATION);
    }

    public boolean hasValue(ValueContext vc) {
        return false;
    }

    public String toString() {
        StringBuffer result = new StringBuffer(super.toString());
        result.append(", source-id: " + sourceId);
        result.append(", query-id: " + queryId);
        result.append(", result-style: " + resultStyle + " (" + RESULT_STYLE_NAMES[resultStyle] + ")");
        result.append(", cache-timeout: " + cacheTimeoutMillis);
        result.append(", params: " + (params != null ? Integer.toString(params.length) : "null"));
        return result.toString();
    }
}