ResponseArguments.java
/*
** Module : ResponseArguments.java
** Abstract : APIs to manage the response arguments in the HTTP servlet response.
**
** Copyright (c) 2019-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
** 001 CA 20190614 First version.
** 002 CA 20190628 Added TABLE output support.
** 003 CA 20190812 Added a TODO related to DECIMAL serialization.
** 004 CA 20200420 Fixes for DATASET, TABLE and error serialization.
** CA 20200514 Refactoring to allow common code for SOAP services support.
** CA 20200528 Added APIs for REST extent arguments (not implemented yet).
** 005 CA 20210304 Fixed an issue with INPUT-OUTPUT DATASET arguments.
** 006 CA 20211112 Refactored to allow transfer of the DATASET or TABLE via XML, for SOAP.
** CA 20220329 Added support for REST services written directly in Java.
** 007 AL2 20250325 Created reset abstract method to let SOAP requests hook on this event.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** 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 Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.rest;
import java.io.*;
import java.math.*;
import javax.servlet.http.*;
import javax.xml.bind.*;
import com.goldencode.p2j.oo.lang.*;
import com.goldencode.p2j.persist.*;
import com.goldencode.p2j.util.*;
/**
* Helper class to serialize the return value and OUTPUT arguments for a REST or SOAP call.
*/
public abstract class ResponseArguments
{
/** The actual serializer to use for interpreting and writing the arguments. */
protected ThreadLocal<ArgumentsSerializer> serializer = new ThreadLocal<>();
/**
* Serialize the error, to be included in the response.
*
* @param err
* The error.
*
* @return The serialized version of the error.
*/
public abstract String writeError(LegacyError err);
/**
* Serialize this argument's value, considering the target format.
*
* @param stream
* The response stream.
* @param target
* The argument's encoded target.
* @param sval
* The argument's string-converted value.
* @param val
* The argument's value.
* @param response
* The HTTP response.
*/
protected abstract void writeArgumentInt(OutputStream stream,
String target,
String sval,
Object val,
HttpServletResponse response)
throws IOException;
/**
* Flush the arguments to the response stream (i.e. HTTP body).
*
* @param stream
* The stream to write the parameters.
* @param response
* The servlet response.
*/
protected abstract void flushArguments(OutputStream stream, HttpServletResponse response)
throws IOException;
/**
* Serialize the specified table.
*
* @param target
* The target OUTPUT parameter.
* @param val
* The table result set, as received from the remote side.
*
* @return The serialized version of this table.
*/
protected abstract Object writeTable(String target, TableWrapper val);
/**
* Serialize the specified dataset.
*
* @param target
* The target OUTPUT parameter.
* @param val
* The dataset, as received from the remote side.
*
* @return The serialized version of this dataset.
*/
protected abstract Object writeDataSet(String target, DataSetContainer val);
/**
* Determine if unknown values must be ignored.
*
* @return See above.
*/
protected abstract boolean ignoreUnknown();
/**
* Serialize the specified dataset.
*
* @param target
* The target OUTPUT parameter.
* @param val
* The dataset, as received from the remote side.
*
* @return The serialized version of this dataset.
*/
protected Object writeDataSet(String target, DatasetWrapper val)
{
return writeDataSet(target, val.getResource());
}
/**
* Serialize this argument's values, considering the target format.
*
* @param stream
* The response stream.
* @param target
* The argument's encoded target.
* @param val
* The argument's value.
* @param response
* The HTTP response.
*/
protected abstract void writeExtentArgument(OutputStream stream,
String target,
Object val,
HttpServletResponse response)
throws IOException;
/**
* Serialize this arguments, considering each target's format.
*
* @param retVal
* The return value.
* @param args
* The arguments.
* @param service
* The service handler.
* @param stream
* The HTTP response stream.
* @param response
* The HTTP response.
*/
public void writeArguments(Object retVal,
Object[] args,
RestService service,
OutputStream stream,
HttpServletResponse response)
throws IOException
{
writeArguments(retVal, args, service.ls.parameters(), service.getSerializer(this), stream, response);
}
/**
* Serialize this arguments, considering each target's format.
*
* @param retVal
* The return value.
* @param args
* The arguments.
* @param serviceParameters
* The legacy service parameters.
* @param stream
* The HTTP response stream.
* @param response
* The HTTP response.
*/
public void writeArguments(Object retVal,
Object[] args,
LegacyServiceParameter[] serviceParameters,
OutputStream stream,
HttpServletResponse response)
throws IOException
{
writeArguments(retVal, args, serviceParameters, new LegacyArgumentsSerializer(this), stream, response);
}
/**
* Serialize this arguments, considering each target's format.
*
* @param retVal
* The return value.
* @param args
* The arguments.
* @param serviceParameters
* The legacy service parameters.
* @param serializer
* The serializer to use for interpreting and writing the arguments.
* @param stream
* The HTTP response stream.
* @param response
* The HTTP response.
*/
public void writeArguments(Object retVal,
Object[] args,
LegacyServiceParameter[] serviceParameters,
ArgumentsSerializer serializer,
OutputStream stream,
HttpServletResponse response)
throws IOException
{
this.serializer.set(serializer);
for (int i = 0; i < serviceParameters.length; i++)
{
LegacyServiceParameter lsp = serviceParameters[i];
if (lsp.returnValue())
{
writeArgument(stream, lsp.target(), retVal, response);
}
else if (lsp.output())
{
writeArgument(stream, lsp.target(), args[lsp.ordinal() - 1], response);
}
}
flushArguments(stream, response);
}
/**
* Get the string representation of this instance.
*
* @param bdt
* The instance.
*
* @return The string representation, using {@link DatatypeConverter}.
*/
protected String toString(BaseDataType bdt)
{
switch (bdt.getClass().getSimpleName())
{
case "integer":
return DatatypeConverter.printInt(((integer) bdt).toJavaIntegerType());
case "int64":
return DatatypeConverter.printLong(((int64) bdt).toJavaLongType());
case "decimal":
BigDecimal bd = new BigDecimal(((decimal) bdt).toStringExport());
return DatatypeConverter.printDecimal(bd);
case "logical":
return DatatypeConverter.printBoolean(((logical) bdt).booleanValue());
case "date":
case "datetime":
case "datetimetz":
return date.isoDate((date) bdt).toStringMessage();
case "blob":
blob b = (blob) bdt;
return DatatypeConverter.printBase64Binary(b.asByteArray(0, b.lengthOf()));
case "clob":
clob c = (clob) bdt;
return new String(c.asByteArray(0, c.lengthOf()));
case "raw":
case "memptr":
return DatatypeConverter.printBase64Binary(((BinaryData) bdt).getByteArray());
default:
return bdt.toStringMessage();
}
}
/**
* Serialize this argument's value, considering the target format.
*
* @param stream
* The response stream.
* @param target
* The argument's encoded target.
* @param val
* The argument's value.
* @param response
* The HTTP response.
*/
protected final void writeArgument(OutputStream stream,
String target,
Object val,
HttpServletResponse response)
throws IOException
{
serializer.get().writeArgument(stream, target, val, response);
}
/**
* Reset the state of the response arguments.
*/
protected abstract void reset();
}