/** * Copyright (c) 2010 Kenn Hussey and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * Kenn Hussey - Initial API and implementation */ package org.eclipse.emf.oda.ecore.impl; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; import org.eclipse.datatools.connectivity.oda.IParameterMetaData; import org.eclipse.datatools.connectivity.oda.IQuery; import org.eclipse.datatools.connectivity.oda.IResultSet; import org.eclipse.datatools.connectivity.oda.IResultSetMetaData; import org.eclipse.datatools.connectivity.oda.OdaException; import org.eclipse.datatools.connectivity.oda.SortSpec; import org.eclipse.datatools.connectivity.oda.spec.QuerySpecification; import org.eclipse.datatools.connectivity.oda.spec.QuerySpecification.ParameterIdentifier; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.common.util.UniqueEList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.QueryDelegate; import org.eclipse.emf.oda.ecore.util.StringUtil; /** * Implementation of IQuery for EMF ODA runtime driver. */ public class Query implements IQuery { public static final String DELEGATE_PROPERTY_NAME = "delegate"; //$NON-NLS-1$ public static final String CONTEXT_PROPERTY_NAME = "context"; //$NON-NLS-1$ public static final String VARIABLES_PROPERTY_NAME = "variables"; //$NON-NLS-1$ public static final String TYPE_PROPERTY_NAME = "type"; //$NON-NLS-1$ protected final Connection connection; protected QuerySpecification specification = null; protected QueryDelegate.Factory factory = null; protected QueryDelegate delegate = null; protected EClassifier context = null; protected Map<String, EClassifier> variables = null; protected EClassifier type = null; protected String queryText = null; protected int maxRows = 0; protected Query(Connection connection) { super(); this.connection = connection; } /** * Asserts that a specification has been provided for this query. * @throws OdaException if a specification has not been provided */ protected void assertSpecified() throws OdaException { if (specification == null) { throw new OdaException(new IllegalStateException()); } } /** * Asserts that this query has been prepared. * @throws OdaException if the query has not been prepared */ protected void assertPrepared() throws OdaException { if (delegate == null || context == null || type == null) { throw new OdaException(new IllegalStateException()); } } /** * Returns the expression variables specified for this query. * @return a map of variable names to types * @throws OdaException if a specification has not been provided */ protected Map<String, EClassifier> getVariables() throws OdaException { assertSpecified(); if (variables == null) { variables = new HashMap<String, EClassifier>(); String string = (String)specification.getProperty(VARIABLES_PROPERTY_NAME); if (!StringUtil.isEmpty(string)) { ResourceSet resourceSet = connection.getResourceSet(); String[] strings = string.split(Pattern.quote(" ")); //$NON-NLS-1$ for (int i = 0; i < strings.length; i += 2) { variables.put(strings[i], (EClassifier)resourceSet.getEObject(URI.createURI((strings[i + 1])), true)); } } } return variables; } public void prepare(String queryText) throws OdaException { assertSpecified(); if (StringUtil.isEmpty(queryText)) { throw new OdaException(new IllegalArgumentException(queryText)); } this.queryText = queryText; try { factory = (QueryDelegate.Factory)QueryDelegate.Factory.Registry.INSTANCE.get(specification.getProperty(DELEGATE_PROPERTY_NAME)); ResourceSet resourceSet = connection.getResourceSet(); context = (EClassifier)resourceSet.getEObject(URI.createURI(((String)specification.getProperty(CONTEXT_PROPERTY_NAME))), true); Map<String, EClassifier> variables = getVariables(); delegate = factory.createQueryDelegate(context, variables.isEmpty() ? null : variables, queryText); type = (EClassifier)resourceSet.getEObject(URI.createURI(((String)specification.getProperty(TYPE_PROPERTY_NAME))), true); delegate.prepare(); } catch (Exception e) { throw new OdaException(e); } } public void setAppContext(Object context) throws OdaException { // do nothing; no support for pass-through context } public void close() throws OdaException { delegate = null; context = null; type = null; } public IResultSetMetaData getMetaData() throws OdaException { assertPrepared(); return ResultSetMetaData.create(type); } protected EList<Object> getAllObjectsByType(EList<Object> objects, EClassifier type) { for (TreeIterator<Object> allContents = EcoreUtil.getAllContents(connection.getResourceSet(), true); allContents.hasNext();) { Object next = allContents.next(); if (type.isInstance(next)) { objects.add(next); } } return objects; } protected EList<Object> getResults( EList<Object> results, QueryDelegate delegate, EList<Object> targets, Map<String, Object> arguments, EClassifier type) throws InvocationTargetException { for (Object target : targets) { Object result = delegate.execute(target, arguments); if (result instanceof Collection< ? >) { results.addAll(EcoreUtil.getObjectsByType((Collection< ? >)result, type)); } else if (type.isInstance(result)) { results.add(result); } } return results; } public IResultSet executeQuery() throws OdaException { assertPrepared(); EList<Object> targets = new UniqueEList.FastCompare<Object>(); Map<String, Object> arguments = new HashMap<String, Object>(); Map<ParameterIdentifier, ? > parameterValues = specification.getParameterValues(); if (!parameterValues.isEmpty()) { Object targetArgument = null; Map<String, EClassifier> dataTypeParameters = new HashMap<String, EClassifier>(); Map<String, Object> dataTypeArguments = new HashMap<String, Object>(); Map<String, Object> classArguments = new HashMap<String, Object>(); for (Map.Entry<ParameterIdentifier, ? > entry : parameterValues.entrySet()) { String name = entry.getKey().getParameterName(); if (!StringUtil.isEmpty(name)) { Object value = entry.getValue(); if (value instanceof ResultSet.JavaObject) { value = ((ResultSet.JavaObject)value).getObject(); } if (value != null) { if (ParameterMetaData.TARGET_PARAMETER_NAME.equals(name)) { targetArgument = value; } else { EClassifier type = variables.get(name); if (type instanceof EClass) { classArguments.put(name, value); } else { dataTypeParameters.put(name, type); dataTypeArguments.put(name, value); } } } } } if (targetArgument == null || ParameterMetaData.DEFAULT_PARAMETER_VALUE.equals(targetArgument)) { getAllObjectsByType(targets, context); } else if (targetArgument instanceof String) { try { QueryDelegate delegate = factory.createQueryDelegate(context, dataTypeParameters, (String)targetArgument); getResults(targets, delegate, getAllObjectsByType(new UniqueEList.FastCompare<Object>(), context), dataTypeArguments, context); } catch (Exception e) { Throwable cause = e.getCause(); throw new OdaException(ParameterMetaData.TARGET_PARAMETER_NAME + ": " + (cause == null ? e.getLocalizedMessage() : cause.getLocalizedMessage())); //$NON-NLS-1$ } } else if (targetArgument instanceof Collection< ? >) { targets.addAll((Collection< ? >)targetArgument); } else { targets.add(targetArgument); } arguments.putAll(dataTypeArguments); for (Map.Entry<String, Object> entry : classArguments.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); if (value instanceof String) { EClassifier type = variables.get(name); EList<Object> values = getAllObjectsByType(new UniqueEList.FastCompare<Object>(), type); if (!ParameterMetaData.DEFAULT_PARAMETER_VALUE.equals(value)) { try { QueryDelegate delegate = factory.createQueryDelegate(type, dataTypeParameters, (String)value); values = getResults(new UniqueEList.FastCompare<Object>(), delegate, values, dataTypeArguments, type); } catch (Exception e) { Throwable cause = e.getCause(); throw new OdaException(name + ": " + (cause == null ? e.getLocalizedMessage() : cause.getLocalizedMessage())); //$NON-NLS-1$ } } value = values.isEmpty() ? null : values.iterator().next(); } arguments.put(name, value); } } try { IResultSet resultSet = ResultSet.create(type, getResults(new UniqueEList<Object>(), delegate, targets, arguments, type)); resultSet.setMaxRows(getMaxRows()); return resultSet; } catch (Exception e) { Throwable cause = e.getCause(); throw new OdaException(cause == null ? e.getLocalizedMessage() : cause.getLocalizedMessage()); } } public void setProperty(String name, String value) throws OdaException { assertSpecified(); specification.setProperty(name, value); } public void setMaxRows(int max) throws OdaException { maxRows = max; } public int getMaxRows() throws OdaException { return maxRows; } public void clearInParameters() throws OdaException { throw new OdaException(new UnsupportedOperationException()); } public void setInt(String parameterName, int value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setInt(int parameterId, int value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setDouble(String parameterName, double value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setDouble(int parameterId, double value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setBigDecimal(String parameterName, BigDecimal value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setBigDecimal(int parameterId, BigDecimal value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setString(String parameterName, String value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setString(int parameterId, String value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setDate(String parameterName, Date value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setDate(int parameterId, Date value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setTime(String parameterName, Time value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setTime(int parameterId, Time value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setTimestamp(String parameterName, Timestamp value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setTimestamp(int parameterId, Timestamp value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setBoolean(String parameterName, boolean value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setBoolean(int parameterId, boolean value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setObject(String parameterName, Object value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, value); } public void setObject(int parameterId, Object value) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, value); } public void setNull(String parameterName) throws OdaException { assertSpecified(); specification.setParameterValue(parameterName, null); } public void setNull(int parameterId) throws OdaException { assertSpecified(); specification.setParameterValue(parameterId, null); } public int findInParameter(String parameterName) throws OdaException { assertSpecified(); for (Map.Entry<ParameterIdentifier, ? > entry : specification.getParameterValues().entrySet()) { ParameterIdentifier identifier = entry.getKey(); if (identifier.hasName() && identifier.getParameterName().equals(parameterName)) { return identifier.getParameterId(); } } throw new OdaException(new IllegalArgumentException(parameterName)); } public IParameterMetaData getParameterMetaData() throws OdaException { assertSpecified(); return new ParameterMetaData(this); } public void setSortSpec(SortSpec sortBy) throws OdaException { // sorting not supported throw new OdaException(new UnsupportedOperationException()); } public SortSpec getSortSpec() throws OdaException { // only applies to sorting return null; } public void setSpecification(QuerySpecification querySpec) throws OdaException, UnsupportedOperationException { specification = querySpec; } public QuerySpecification getSpecification() { return specification; } public String getEffectiveQueryText() { return queryText; } public void cancel() throws OdaException, UnsupportedOperationException { // unable to cancel while executing a query throw new UnsupportedOperationException(); } }