/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.translator.odata4; import java.io.InputStream; import java.util.Arrays; import java.util.List; import java.util.Map; import org.apache.olingo.client.api.serialization.ODataDeserializerException; import org.apache.olingo.client.core.serialization.JsonDeserializer; import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.teiid.language.Argument; import org.teiid.language.Argument.Direction; import org.teiid.language.Call; import org.teiid.language.SQLConstants.Tokens; import org.teiid.metadata.Procedure; import org.teiid.metadata.ProcedureParameter; import org.teiid.metadata.RuntimeMetadata; import org.teiid.olingo.common.ODataTypeManager; import org.teiid.translator.DataNotAvailableException; import org.teiid.translator.ExecutionContext; import org.teiid.translator.ProcedureExecution; import org.teiid.translator.TranslatorException; import org.teiid.translator.WSConnection; import org.teiid.translator.document.DocumentNode; import org.teiid.translator.odata4.ODataMetadataProcessor.ODataType; public class ODataProcedureExecution extends BaseQueryExecution implements ProcedureExecution { private Object returnValue; private ODataResponse response; private Class<?>[] expectedColumnTypes; private Call command; public ODataProcedureExecution(Call command, ODataExecutionFactory translator, ExecutionContext executionContext, RuntimeMetadata metadata, WSConnection connection) throws TranslatorException { super(translator, executionContext, metadata, connection); this.command = command; this.expectedColumnTypes = command.getResultSetColumnTypes(); } private boolean isFunction(Procedure proc) { ODataType type = ODataType.valueOf(proc.getProperty(ODataMetadataProcessor.ODATA_TYPE, false)); return type == ODataType.FUNCTION; } private ProcedureParameter getReturnParameter() { for (ProcedureParameter pp : this.command.getMetadataObject().getParameters()) { if (pp.getType() == ProcedureParameter.Type.ReturnValue) { return pp; } } return null; } private String getQueryParameters(Call obj) throws EdmPrimitiveTypeException { StringBuilder sb = new StringBuilder(); final List<Argument> params = obj.getArguments(); if (params != null && params.size() != 0) { Argument param = null; for (int i = 0; i < params.size(); i++) { param = params.get(i); if (param.getDirection() == Direction.IN || param.getDirection() == Direction.INOUT) { if (i != 0) { sb.append("&"); //$NON-NLS-1$ } sb.append(WSConnection.Util.httpURLEncode(param.getMetadataObject().getName())); sb.append(Tokens.EQ); sb.append(WSConnection.Util.httpURLEncode(ODataTypeManager.convertToODataURIValue(param.getArgumentValue().getValue(), ODataTypeManager.odataType(param.getType()).getFullQualifiedName() .getFullQualifiedNameAsString()))); } } } return sb.toString(); } private String buildFunctionURL(Call obj, String parameters) { StringBuilder sb = new StringBuilder(); sb.append(obj.getProcedureName()); if (parameters != null && !parameters.isEmpty()) { sb.append("?"); sb.append(parameters); } return sb.toString(); } @Override public void execute() throws TranslatorException { try { String parameters = getQueryParameters(this.command); InputStream response = null; Procedure procedure = this.command.getMetadataObject(); if (isFunction(procedure)) { String URI = buildFunctionURL(this.command, parameters); response = executeQuery("GET", URI, null, null, new HttpStatusCode[] { HttpStatusCode.OK }); handleResponse(procedure, URI, response); } else { String URI = this.command.getProcedureName(); response = executeQuery("POST", URI, parameters, null, new HttpStatusCode[] { HttpStatusCode.OK }); handleResponse(procedure, URI, response); } } catch (ODataDeserializerException e) { throw new TranslatorException(e); } catch (EdmPrimitiveTypeException e) { throw new TranslatorException(e); } } private void handleResponse(final Procedure procedure, final String baseUri, final InputStream payload) throws TranslatorException, ODataDeserializerException { if (procedure.getResultSet() != null) { ODataType type = ODataType.valueOf(procedure.getResultSet().getProperty( ODataMetadataProcessor.ODATA_TYPE, false)); this.response = new ODataResponse(payload, type, new DocumentNode()) { @Override public InputStream nextBatch(java.net.URI uri) throws TranslatorException { return executeSkipToken(uri, baseUri, new HttpStatusCode[] { HttpStatusCode.OK }); } }; } else if (getReturnParameter() != null) { // this is scalar result JsonDeserializer parser = new JsonDeserializer(false); Property property = parser.toProperty(payload).getPayload(); if (property.isCollection()) { this.returnValue = property.asCollection(); } else { this.returnValue = property.asPrimitive(); } } } @Override public List<?> next() throws TranslatorException, DataNotAvailableException { Procedure procedure = this.command.getMetadataObject(); if (this.response != null) { Map<String, Object> row = this.response.getNext(); if (row != null) { return buildRow(procedure.getResultSet(), procedure.getResultSet().getColumns(), this.expectedColumnTypes, row); } } return null; } @Override public List<?> getOutputParameterValues() throws TranslatorException { return Arrays.asList(this.returnValue); } @Override public void close() { } @Override public void cancel() throws TranslatorException { } }