InvokeConfig.java
/*
** Module : InvokeConfig.java
** Abstract : Defines a builder configuration with the details required to execute a RUN statement.
**
** Copyright (c) 2018-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
** 001 CA 20181029 Created initial version.
** 002 CA 20190628 Refactored to allow OO invocations and to be used for appserver calls. Moved invoke() API
** to ControlFlowOps.
** 003 CA 20200427 Added support for Agent's SESSION:CURRENT-REQUEST-INFO, as sent by the remote
** SERVER:REQUEST-INFO.
** CA 20200514 Added getter and setter for requestID.
** 004 IAS 20200908 Rework (de)serialization.
** 005 CA 20220405 Added authentication and authorization for web requests. When this is enabled, the target
** API call will be executed under the authenticated FWD context, and not the agent's context.
** CA 20220930 Refactored the callback invocation to be performed via a call-site and InvokeConfig, to
** allow caching of the resolved target.
** CA 20221010 runSuper() and execute() calls always mark the configuration as FUNCTION.
** OM 20221017 Implemented toString() method for debugging usage.
** 006 CA 20220428 Fixed (de)serialization.
** 007 HC 20230116 Replaced some handle usages with the actual wrapped resources for
** performance.
** 008 CA 20230215 Use PayloadSerializer for serialization.
** 009 CA 20231020 Fixed (de)serialization for inHandle referencing a ProxyProcedureWrapper.
** 010 GBB 20250403 restoreRequest made public to be accessed by CoreAppserver.
*/
/*
** 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.util;
import static com.goldencode.util.NativeTypeSerializer.*;
import java.io.*;
import java.util.*;
import com.goldencode.p2j.oo.lang.*;
import com.goldencode.util.*;
/**
* Defines a configuration which can be used by a RUN or dynamic function call. All the
* information required to perform a call can be setup using a builder approach, as all setters
* return this instance.
* <p>
* The final call can be delegated to {@link ControlFlowOps#invoke(InvokeConfig)}.
*/
public class InvokeConfig
implements Externalizable
{
/** Constant to identify field {@link #inHandle} during serialization. */
private static final int FIELD_IN_HANDLE = 0;
/** Constant to identify field {@link #function} during serialization. */
private static final int FIELD_FUNCTION = FIELD_IN_HANDLE + 1;
/** Constant to identify field {@link #persistent} during serialization. */
private static final int FIELD_PERSISTENT = FIELD_FUNCTION + 1;
/** Constant to identify field {@link #singleRun} during serialization. */
private static final int FIELD_SINGLE_RUN = FIELD_PERSISTENT + 1;
/** Constant to identify field {@link #singleton} during serialization. */
private static final int FIELD_SINGLETON = FIELD_SINGLE_RUN + 1;
/** Constant to identify field {@link #procedureHandle} during serialization. */
private static final int FIELD_PROC_HANDLE = FIELD_SINGLETON + 1;
/** Constant to identify field {@link #serverHandle} during serialization. */
private static final int FIELD_SERVER_HANDLE = FIELD_PROC_HANDLE + 1;
/** Constant to identify field {@link #transactionDistinct} during serialization. */
private static final int FIELD_TX_DISTINCT = FIELD_SERVER_HANDLE + 1;
/** Constant to identify field {@link #asynchronous} during serialization. */
private static final int FIELD_ASYNC = FIELD_TX_DISTINCT + 1;
/** Constant to identify field {@link #asyncHandle} during serialization. */
private static final int FIELD_ASYNC_HANDLE = FIELD_ASYNC + 1;
/** Constant to identify field {@link #eventProcedure} during serialization. */
private static final int FIELD_EVT_PROC = FIELD_ASYNC_HANDLE + 1;
/** Constant to identify field {@link #eventProcedureContext} during serialization. */
private static final int FIELD_EVT_PROC_CONTEXT = FIELD_EVT_PROC + 1;
/** Constant to identify field {@link #arguments} during serialization. */
private static final int FIELD_ARGS = FIELD_EVT_PROC_CONTEXT + 1;
/** Constant to identify field {@link #modes} during serialization. */
private static final int FIELD_MODES = FIELD_ARGS + 1;
/** Constant to identify field {@link #portHandle} during serialization. */
private static final int FIELD_PORT_HANDLE = FIELD_MODES + 1;
/** Constant to identify field {@link #dynamicFunction} during serialization. */
private static final int FIELD_DYN_FUNC = FIELD_PORT_HANDLE + 1;
/** Constant to identify field {@link #superCall} during serialization. */
private static final int FIELD_SUPER_CALL = FIELD_DYN_FUNC + 1;
/** Constant to identify field {@link #isClass} during serialization. */
private static final int FIELD_IS_CLASS = FIELD_SUPER_CALL + 1;
/** Constant to identify field {@link #returnValue} during serialization. */
private static final int FIELD_RETURN_VALUE = FIELD_IS_CLASS + 1;
/** Constant to identify field {@link #clientContextId} during serialization. */
private static final int FIELD_CLIENTCONTEXTID = FIELD_RETURN_VALUE + 1;
/** Constant to identify field {@link #requestId} during serialization. */
private static final int FIELD_REQUESTID = FIELD_CLIENTCONTEXTID + 1;
/** Constant to identify field {@link #clientPrincipal} during serialization. */
private static final int FIELD_CLIENTPRINCIPAL = FIELD_REQUESTID + 1;
/** Constant to identify field {@link #versionInfo} during serialization. */
private static final int FIELD_VERSIONINFO = FIELD_CLIENTPRINCIPAL + 1;
/** Constant to identify field {@link #clientType} during serialization. */
private static final int FIELD_CLIENTTYPE = FIELD_VERSIONINFO + 1;
/** Constant to identify field {@link #webServiceToken} during serialization. */
private static final int FIELD_WEB_SERVICE_TOKEN = FIELD_CLIENTTYPE + 1;
/** Constant to identify field {@link #asThread} during serialization. */
private static final int FIELD_AS_THREAD = FIELD_WEB_SERVICE_TOKEN + 1;
/** This call's target (a function, internal procedure or program name). */
private String target = null;
/** Flag indicating that this is a legacy OO class. */
private boolean isClass = false;
/**
* When specified, it will mean the target will be a function or internal procedure, using
* the given procedure handle as a start.
*/
private handle inHandle = null;
/** Flag indicating if this is a function or procedure call. */
private boolean function = false;
/** When set, this call will be an external program call, ran persistent. */
private boolean persistent = false;
/** When set, this call will be an external program call, ran in SINGLE-RUN mode. */
private boolean singleRun = false;
/** When set, this call will be an external program call, ran in SINGLETON mode. */
private boolean singleton = false;
/** The handle where to pass back the reference to the newly persistent-run external program. */
private handle procedureHandle = null;
/** The handle where to pass back the reference in case of a web service invocation. */
private handle portHandle = null;
/** The remote server handle where to run this request. */
private handle serverHandle = null;
/** Flag indicating if TRANSACTION-DISTINCT option is present. */
private boolean transactionDistinct = false;
/** Flag indicating if ASYNCHRONOUS option is present. */
private boolean asynchronous = false;
/** Flag indicating if AS-THREAD FWD-extension option is present. */
private boolean asThread = false;
/** The handle where to pass back the reference to the {@link AsyncRequest async resource}. */
private handle asyncHandle = null;
/**
* This represents the name of the internal procedure for the EVENT-PROCEDURE clause, null if
* this clause is not specified.
*/
private character eventProcedure = null;
/**
* The handle to a procedure in which context the specified EVENT-PROCEDURE internal procedure
* is found, null if EVENT-PROCEDURE clause is not specified.
*/
private handle eventProcedureContext = null;
/** The arguments for this call. */
private Object[] arguments = new Object[0];
/** A string representation of the modes of each parameter. */
private String modes = null;
/** Flag indicating if this is a DYNAMIC-FUNCTION call. */
private boolean dynamicFunction = false;
/** Flag indicating if this is a RUN SUPER or SUPER(). call. */
private boolean superCall = false;
/** Flag indicating if the OO method call is function-like (return value is needed). */
private boolean returnValue = false;
/** The value of the <code>OERequestInfo:</code> field. */
private String clientContextId = null;
/** The value of the <code>OERequestInfo:requestId</code> field. */
private String requestId = null;
/** The value of the <code>OERequestInfo:clientPrincipal</code> field. */
private byte[] clientPrincipal = null;
/** The value of the <code>OERequestInfo:versionInfo</code> field. */
private String[] versionInfo = null;
/** The value of the <code>OERequestInfo:clientType</code> field. */
private String clientType = null;
/** A token sent via a web service request, to execute the target service in the specified FWD context. */
private String webServiceToken = null;
/** The callsite instance (at the converted code) for this call. */
private InvokeConfig callSite = null;
/**
* Default constructor.
*/
public InvokeConfig()
{
// no-op
}
/**
* Copy constructor. This also saves the call-site reference, to be able to cache the target.
*/
public InvokeConfig(InvokeConfig callSite)
{
this.callSite = callSite;
target = callSite.target;
isClass = callSite.isClass;
inHandle = callSite.inHandle == null ? null : new handle(callSite.inHandle);
function = callSite.function;
persistent = callSite.persistent;
singleRun = callSite.singleRun;
singleton = callSite.singleton;
procedureHandle = callSite.procedureHandle == null ? null : new handle(callSite.procedureHandle);
portHandle = callSite.portHandle == null ? null : new handle(callSite.portHandle);
serverHandle = callSite.serverHandle == null ? null : new handle(callSite.serverHandle);
transactionDistinct = callSite.transactionDistinct;
asynchronous = callSite.asynchronous;
asThread = callSite.asThread;
asyncHandle = callSite.asyncHandle == null ? null : new handle(callSite.asyncHandle);
eventProcedure = callSite.eventProcedure == null ? null : new character(callSite.eventProcedure);
eventProcedureContext = callSite.eventProcedureContext == null
? null
: new handle(callSite.eventProcedureContext);
if (callSite.arguments != null && callSite.arguments.length > 0)
{
arguments = Arrays.copyOf(callSite.arguments, callSite.arguments.length);
}
modes = callSite.modes;
dynamicFunction = callSite.dynamicFunction;
superCall = callSite.superCall;
returnValue = callSite.returnValue;
clientContextId = callSite.clientContextId;
requestId = callSite.requestId;
if (callSite.clientPrincipal != null)
{
clientPrincipal = Arrays.copyOf(callSite.clientPrincipal, callSite.clientPrincipal.length);
}
if (callSite.versionInfo != null)
{
versionInfo = Arrays.copyOf(callSite.versionInfo, callSite.versionInfo.length);
}
clientType = callSite.clientType;
webServiceToken = callSite.webServiceToken;
}
/**
* Create a new invocation for the given target.
*
* @param target
* The target to be invoked.
*/
public InvokeConfig(character target)
{
this.target = target.getValue();
}
/**
* Create a new invocation for the given target.
*
* @param target
* The target to be invoked.
*/
public InvokeConfig(String target)
{
this.target = target;
}
/**
* Clone this instance.
*
* @return A copy of this instance.
*/
@Override
public InvokeConfig clone()
{
return new InvokeConfig(this);
}
/**
* Execute this config for a callback procedure associated with a resource event.
*
* @param resource
* The resource associated with the {@link #callSite call-site}.
*
* @return The result of the invocation, if this is a function call.
*/
public BaseDataType executeForResource(WrappedResource resource)
{
return ControlFlowOps.invoke(null, resource, this);
}
/**
* Execute this config as a <code>RUN SUPER</code> statement with the provided arguments.
*
* @param args
* The arguments.
*/
public void runSuper(Object... args)
{
setArguments(args);
setSuperCall(true);
ControlFlowOps.invoke(null, null, this);
}
/**
* Execute this config as a <code>SUPER()</code> function, with the provided arguments and return type.
*
* @param type
* The return type.
* @param args
* The arguments.
*
* @return The function's return value.
*/
public <T extends BaseDataType> T runSuper(Class<T> type, Object... args)
{
setArguments(args);
setSuperCall(true);
setFunction(true);
BaseDataType superVal = ControlFlowOps.invoke(type, null, this);
T ret = null;
if (type.isAssignableFrom(superVal.getClass()))
{
ret = (T) superVal;
}
else
{
ret = (T) BaseDataType.generateUnknown(type);
ret.assign(superVal);
}
return ret;
}
/**
* Execute this config for a RUN call.
*/
public void run(Object... args)
{
setArguments(args);
ControlFlowOps.invoke(null, null, this);
}
/**
* Execute this config for a function typed call.
*
* @return The function's returned value.
*/
public <T extends BaseDataType> T execute(Class<T> cls, Object... args)
{
setArguments(args);
setFunction(true);
return (T) ControlFlowOps.invoke(cls, null, this);
}
/**
* Execute this config for a function call.
*
* @return The function's returned value.
*/
public BaseDataType execute(Object... args)
{
setArguments(args);
setFunction(true);
return ControlFlowOps.invoke(null, null, this);
}
/**
* Get the {@link #callSite}.
*
* @return See above.
*/
public InvokeConfig getCallSite()
{
return callSite;
}
/**
* Set this invocation's {@link #target}.
*
* @param target
* The target to be invoked.
*
* @return This instance.
*/
public InvokeConfig setTarget(character target)
{
this.target = target.getValue();
return this;
}
/**
* Set this invocation's {@link #target}.
*
* @param target
* The target to be invoked.
*
* @return This instance.
*/
public InvokeConfig setTarget(String target)
{
this.target = target;
return this;
}
/**
* Mark this configuration as a OO invocation.
*
* @return This instance.
*/
public InvokeConfig setClass()
{
this.isClass = true;
return this;
}
/**
* Set this invocation's {@link #returnValue} flag.
*
* @param returnValue
* The new value of this flag.
*
* @return This instance.
*/
public InvokeConfig setReturnValue(boolean returnValue)
{
this.returnValue = returnValue;
return this;
}
/**
* Set this invocation's {@link #function} flag.
*
* @param function
* The new value of this flag.
*
* @return This instance.
*/
public InvokeConfig setFunction(boolean function)
{
this.function = function;
return this;
}
/**
* Set this invocation's {@link #function} flag to <code>true</code>.
*
* @return This instance.
*/
public InvokeConfig function()
{
this.function = true;
return this;
}
/**
* Set this invocation's {@link #persistent} flag.
*
* @param persistent
* The new value of this flag.
*
* @return This instance.
*/
public InvokeConfig setPersistent(boolean persistent)
{
this.persistent = persistent;
return this;
}
/**
* Set this invocation's {@link #persistent} flag to <code>true</code>.
*
* @return This instance.
*/
public InvokeConfig persistent()
{
this.persistent = true;
return this;
}
/**
* Set this invocation's {@link #singleRun} flag.
*
* @param singleRun
* The new value of this flag.
*
* @return This instance.
*/
public InvokeConfig setSingleRun(boolean singleRun)
{
this.singleRun = singleRun;
return this;
}
/**
* Set this invocation's {@link #singleRun} flag to <code>true</code>.
*
* @return This instance.
*/
public InvokeConfig singleRun()
{
this.singleRun = true;
return this;
}
/**
* Set this invocation's {@link #singleton} flag.
*
* @param singleton
* The new value of this flag.
*
* @return This instance.
*/
public InvokeConfig setSingleton(boolean singleton)
{
this.singleton = singleton;
return this;
}
/**
* Set this invocation's {@link #singleton} flag to <code>true</code>.
*
* @return This instance.
*/
public InvokeConfig singleton()
{
this.singleton = true;
return this;
}
/**
* Set this invocation's {@link #procedureHandle} handle where to save the persistent program.
*
* @param procedureHandle
* A handle variable or field reference.
*
* @return This instance.
*/
public InvokeConfig setProcedureHandle(handle procedureHandle)
{
// the reference is saved
this.procedureHandle = procedureHandle;
return this;
}
/**
* Set this invocation's {@link #portHandle} handle where to save the web service.
*
* @param portHandle
* A handle variable or field reference.
*
* @return This instance.
*/
public InvokeConfig setPortHandle(handle portHandle)
{
// the reference is saved
this.portHandle = portHandle;
return this;
}
/**
* Set this invocation's {@link #serverHandle} remote handle where to perform the call.
*
* @param serverHandle
* A handle to a remote appserver.
*
* @return This instance.
*/
public InvokeConfig setServerHandle(handle serverHandle)
{
this.serverHandle = serverHandle == null ? null : new handle(serverHandle);
return this;
}
/**
* Set this invocation's {@link #transactionDistinct} flag.
*
* @param transactionDistinct
* The new value of this flag.
*
* @return This instance.
*/
public InvokeConfig setTransactionDistinct(boolean transactionDistinct)
{
this.transactionDistinct = transactionDistinct;
return this;
}
/**
* Set this invocation's {@link #transactionDistinct} flag to <code>true</code>.
*
* @return This instance.
*/
public InvokeConfig transactionDistinct()
{
this.transactionDistinct = true;
return this;
}
/**
* Set this invocation's {@link #asynchronous} flag.
*
* @param asynchronous
* The new value of this flag.
*
* @return This instance.
*/
public InvokeConfig setAsynchronous(boolean asynchronous)
{
this.asynchronous = asynchronous;
return this;
}
/**
* Set this invocation's {@link #asThread} flag to <code>true</code>.
*
* @return This instance.
*/
public InvokeConfig asThread()
{
this.asThread = true;
return this;
}
/**
* Set this invocation's {@link #asThread} flag.
*
* @param asThread
* The new value of this flag.
*
* @return This instance.
*/
public InvokeConfig setAsThread(boolean asThread)
{
this.asThread = asThread;
return this;
}
/**
* Set this invocation's {@link #asynchronous} flag to <code>true</code>.
*
* @return This instance.
*/
public InvokeConfig asynchronous()
{
this.asynchronous = true;
return this;
}
/**
* Set this invocation's {@link #asyncHandle} handle where to save the async resource.
*
* @param asyncHandle
* A handle variable or field reference.
*
* @return This instance.
*/
public InvokeConfig setAsyncHandle(handle asyncHandle)
{
// the reference is saved
this.asyncHandle = asyncHandle;
return this;
}
/**
* Set this invocation's {@link #eventProcedure EVENT-PROCEDURE} option.
*
* @param eventProcedure
* The event procedure name.
*
* @return This instance.
*/
public InvokeConfig setEventProcedure(character eventProcedure)
{
this.eventProcedure = new character(eventProcedure);
return this;
}
/**
* Set this invocation's {@link #eventProcedure EVENT-PROCEDURE} option.
*
* @param eventProcedure
* The event procedure name.
*
* @return This instance.
*/
public InvokeConfig setEventProcedure(String eventProcedure)
{
this.eventProcedure = new character(eventProcedure);
return this;
}
/**
* Set this invocation's {@link #eventProcedureContext EVENT-PROCEDURE-CONTEXT} option.
*
* @param eventProcedureContext
* The event procedure context.
*
* @return This instance.
*/
public InvokeConfig setEventProcedureContext(handle eventProcedureContext)
{
this.eventProcedureContext = new handle(eventProcedureContext);
return this;
}
/**
* Set this invocation's {@link #inHandle IN handle} option.
*
* @param inHandle
* A program handle where to perform the call.
*
* @return This instance.
*/
public InvokeConfig setInHandle(handle inHandle)
{
this.inHandle = inHandle == null ? null : new handle(inHandle);
return this;
}
/**
* Set this invocation's {@link #arguments}.
*
* @param arguments
* A invocation's arguments.
*
* @return This instance.
*/
public InvokeConfig setArguments(Object... arguments)
{
this.arguments = arguments;
return this;
}
/**
* Set this invocation's {@link #modes argument modes}.
*
* @param modes
* A invocation's argument modes.
*
* @return This instance.
*/
public InvokeConfig setModes(String modes)
{
this.modes = modes;
return this;
}
/**
* Set this invocation's {@link #superCall} flag.
*
* @param superCall
* Flag indicating that this is a super-call.
*
* @return This instance.
*/
public InvokeConfig setSuperCall(boolean superCall)
{
this.superCall = superCall;
return this;
}
/**
* Set this invocation's {@link #dynamicFunction} flag.
*
* @param dynamicFunction
* Flag indicating that this is a dynamic-function call.
*
* @return This instance.
*/
public InvokeConfig setDynamicFunction(boolean dynamicFunction)
{
this.dynamicFunction = dynamicFunction;
return this;
}
/**
* Set this invocation's {@link #dynamicFunction} and {@link #function} flags to <code>true</code>.
*
* @return This instance.
*/
public InvokeConfig dynamicFunction()
{
this.function = true;
this.dynamicFunction = true;
return this;
}
/**
* Set the {@link #requestId}.
*
* @param requestId
* The request ID.
*
* @return This instance.
*/
public InvokeConfig setRequestId(String requestId)
{
this.requestId = requestId;
return this;
}
/**
* Set the {@link #webServiceToken}.
*
* @param webServiceToken
* The web service token.
*
* @return This instance.
*/
public InvokeConfig setWebServiceToken(String webServiceToken)
{
this.webServiceToken = webServiceToken;
return this;
}
/**
* Get the {@link #isClass} flag.
*
* @return See above.
*/
public boolean isClass()
{
return isClass;
}
/**
* Get the {@link #returnValue} flag.
*
* @return See above.
*/
public boolean isReturnValue()
{
return returnValue;
}
/**
* Get the {@link #function} flag.
*
* @return See above.
*/
public boolean isFunction()
{
return function;
}
/**
* Get the {@link #persistent} flag.
*
* @return See above.
*/
public boolean isPersistent()
{
return persistent;
}
/**
* Get the {@link #singleRun} flag.
*
* @return See above.
*/
public boolean isSingleRun()
{
return singleRun;
}
/**
* Get the {@link #singleton} flag.
*
* @return See above.
*/
public boolean isSingleton()
{
return singleton;
}
/**
* Get the {@link #transactionDistinct} flag.
*
* @return See above.
*/
public boolean isTransactionDistinct()
{
return transactionDistinct;
}
/**
* Get the {@link #asynchronous} flag.
*
* @return See above.
*/
public boolean isAsynchronous()
{
return asynchronous;
}
/**
* Get the {@link #asThread} flag.
*
* @return See above.
*/
public boolean isAsThread()
{
return asThread;
}
/**
* Get the caller's target.
*
* @return the {@link #target}.
*/
public String getTarget()
{
return target;
}
/**
* Get the target handle for internal entry call.
*
* @return the {@link #inHandle}
*/
public handle getInHandle()
{
return inHandle;
}
/**
* Get the {@link #procedureHandle}.
*
* @return the {@link #procedureHandle}
*/
public handle getProcedureHandle()
{
return procedureHandle;
}
/**
* Get the {@link #portHandle}.
*
* @return the {@link #portHandle}
*/
public handle getPortHandle()
{
return portHandle;
}
/**
* Get the {@link #serverHandle}.
*
* @return the {@link #serverHandle}
*/
public handle getServerHandle()
{
return serverHandle;
}
/**
* Get the caller's {@link #asyncHandle}.
*
* @return the {@link #asyncHandle}.
*/
public handle getAsyncHandle()
{
return asyncHandle;
}
/**
* Get the caller's {@link #eventProcedure}.
*
* @return the {@link #eventProcedure}
*/
public character getEventProcedure()
{
return eventProcedure;
}
/**
* Get the caller's {@link #eventProcedureContext}.
*
* @return the {@link #eventProcedureContext}
*/
public handle getEventProcedureContext()
{
return eventProcedureContext;
}
/**
* Get the caller's {@link #arguments}.
*
* @return the {@link #arguments}
*/
public Object[] getArguments()
{
return arguments;
}
/**
* Get the caller's {@link #modes}.
*
* @return the {@link #modes}
*/
public String getModes()
{
return modes;
}
/**
* Get the caller's {@link #superCall}.
*
* @return the {@link #superCall}
*/
public boolean isSuperCall()
{
return superCall;
}
/**
* Get the caller's {@link #dynamicFunction}.
*
* @return the {@link #dynamicFunction}
*/
public boolean isDynamicFunction()
{
return dynamicFunction;
}
/**
* Get the request ID.
*
* @return The {@link #requestId}.
*/
public String getRequestId()
{
return requestId;
}
/**
* Get the web service token.
*
* @return The {@link #webServiceToken}.
*/
public String getWebServiceToken()
{
return webServiceToken;
}
/**
* Serialize this invoke configuration. To reduce the size of the written data,
* {@link #computeWriting()} will be used to set a bit for each field in this class, which was
* changed from its default value. Only the fields which are no longer holding the default
* value will be serialized.
* <p>
* The {@link #target} field is always written.
*
* @param out
* The output stream.
*/
@Override
public void writeExternal(ObjectOutput out)
throws IOException
{
// compute what to write
long writing = computeWriting();
out.writeLong(writing);
out.writeUTF(target);
if (singleRun)
{
out.writeBoolean(singleRun);
}
if (singleton)
{
out.writeBoolean(singleton);
}
if (inHandle != null)
{
if (singleRun || singleton)
{
out.writeUTF(((DeferredProgram) inHandle.get()).getName());
}
else
{
WrappedResource res = inHandle.getResource();
boolean isProxy = res instanceof ProxyProcedureWrapper;
out.writeBoolean(isProxy);
if (isProxy)
{
ProxyProcedureWrapper proxy = (ProxyProcedureWrapper) res;
out.writeUTF(proxy.getFileName().getValue());
out.writeInt(proxy.getAgentId());
}
out.writeUTF((String) inHandle.get());
}
}
if (function)
{
out.writeBoolean(function);
}
if (persistent)
{
out.writeBoolean(persistent);
}
if (procedureHandle != null)
{
procedureHandle.writeExternal(out);
}
if (serverHandle != null)
{
serverHandle.writeExternal(out);
}
if (transactionDistinct)
{
out.writeBoolean(transactionDistinct);
}
if (asynchronous)
{
out.writeBoolean(asynchronous);
}
if (asyncHandle != null)
{
asyncHandle.writeExternal(out);
}
if (eventProcedure != null)
{
eventProcedure.writeExternal(out);
}
if (eventProcedureContext != null)
{
eventProcedureContext.writeExternal(out);
}
if (arguments != null && arguments.length > 0)
{
PayloadSerializer.writePayload(out, arguments);
}
if (modes != null && !modes.isEmpty())
{
out.writeUTF(modes);
}
if (portHandle != null)
{
portHandle.writeExternal(out);
}
if (dynamicFunction)
{
out.writeBoolean(dynamicFunction);
}
if (superCall)
{
out.writeBoolean(superCall);
}
if (isClass)
{
out.writeBoolean(isClass);
}
if (returnValue)
{
out.writeBoolean(returnValue);
}
if (clientContextId != null)
{
out.writeUTF(clientContextId);
}
if (requestId != null)
{
out.writeUTF(requestId);
}
if (clientPrincipal != null)
{
writeByteArray(out, clientPrincipal);
}
if (versionInfo != null)
{
writeStringArray(out, versionInfo);
}
if (clientType != null)
{
out.writeUTF(clientType);
}
if (webServiceToken != null)
{
out.writeUTF(webServiceToken);
}
if (asThread)
{
out.writeBoolean(asThread);
}
}
/**
* Read this invoke configuration from a stream. Only the fields which are no longer holding
* the default value will be read (see {@link #computeWriting()}).
* <p>
* The {@link #target} field is always read.
*
* @param in
* The input stream.
*/
@Override
public void readExternal(ObjectInput in)
throws IOException,
ClassNotFoundException
{
long writing = in.readLong();
target = in.readUTF();
if ((writing & (1l << FIELD_SINGLE_RUN)) != 0)
{
singleRun = in.readBoolean();
}
if ((writing & (1l << FIELD_SINGLETON)) != 0)
{
singleton = in.readBoolean();
}
if ((writing & (1l << FIELD_IN_HANDLE)) != 0)
{
inHandle = new handle();
if (singleRun || singleton)
{
String code = in.readUTF();
inHandle.assign(new DeferredProgramWrapper(new DeferredProgram(code)));
}
else
{
boolean isProxy = in.readBoolean();
if (isProxy)
{
String filename = in.readUTF();
int agentId = in.readInt();
String referent = in.readUTF();
ProxyProcedureWrapper proxy = new ProxyProcedureWrapper(referent, new character(filename), agentId);
inHandle.assign(proxy);
}
else
{
String code = in.readUTF();
inHandle.assign(handle.fromString(code));
}
}
}
if ((writing & (1l << FIELD_FUNCTION)) != 0)
{
function = in.readBoolean();
}
if ((writing & (1l << FIELD_PERSISTENT)) != 0)
{
persistent = in.readBoolean();
}
if ((writing & (1l << FIELD_PROC_HANDLE)) != 0)
{
procedureHandle = new handle();
procedureHandle.readExternal(in);
}
if ((writing & (1l << FIELD_SERVER_HANDLE)) != 0)
{
serverHandle = new handle();
serverHandle.readExternal(in);
}
if ((writing & (1l << FIELD_TX_DISTINCT)) != 0)
{
transactionDistinct = in.readBoolean();
}
if ((writing & (1l << FIELD_ASYNC)) != 0)
{
asynchronous = in.readBoolean();
}
if ((writing & (1l << FIELD_ASYNC_HANDLE)) != 0)
{
asyncHandle = new handle();
asyncHandle.readExternal(in);
}
if ((writing & (1l << FIELD_EVT_PROC)) != 0)
{
eventProcedure = new character();
eventProcedure.readExternal(in);
}
if ((writing & (1l << FIELD_EVT_PROC_CONTEXT)) != 0)
{
eventProcedureContext = new handle();
eventProcedureContext.readExternal(in);
}
if ((writing & (1l << FIELD_ARGS)) != 0)
{
arguments = (Object[]) PayloadSerializer.readPayload(in);
}
else
{
arguments = new Object[0];
}
if ((writing & (1l << FIELD_MODES)) != 0)
{
modes = in.readUTF();
}
if ((writing & (1l << FIELD_PORT_HANDLE)) != 0)
{
portHandle = new handle();
portHandle.readExternal(in);
}
if ((writing & (1l << FIELD_DYN_FUNC)) != 0)
{
dynamicFunction = in.readBoolean();
}
if ((writing & (1l << FIELD_SUPER_CALL)) != 0)
{
superCall = in.readBoolean();
}
if ((writing & (1l << FIELD_IS_CLASS)) != 0)
{
isClass = in.readBoolean();
}
if ((writing & (1l << FIELD_RETURN_VALUE)) != 0)
{
returnValue = in.readBoolean();
}
if ((writing & (1l << FIELD_CLIENTCONTEXTID)) != 0)
{
clientContextId = in.readUTF();
}
if ((writing & (1l << FIELD_REQUESTID)) != 0)
{
requestId = in.readUTF();
}
if ((writing & (1l << FIELD_CLIENTPRINCIPAL)) != 0)
{
clientPrincipal = readByteArray(in);
}
if ((writing & (1l << FIELD_VERSIONINFO)) != 0)
{
versionInfo = readStringArray(in);
}
if ((writing & (1l << FIELD_CLIENTTYPE)) != 0)
{
clientType = in.readUTF();
}
if ((writing & (1l << FIELD_WEB_SERVICE_TOKEN)) != 0)
{
webServiceToken = in.readUTF();
}
if ((writing & (1l << FIELD_AS_THREAD)) != 0)
{
asThread = in.readBoolean();
}
}
/**
* Store the passed request info object, to be sent to a remote side.
*
* @param requestInfo
* The {@link OerequestInfo} instance.
*
* @return This instance.
*/
InvokeConfig storeRequest(object<? extends OerequestInfo> requestInfo)
{
if (!requestInfo._isValid())
{
return this;
}
OerequestInfo req = requestInfo.ref();
this.clientContextId = req.getClientContextId().getValue();
this.requestId = AppServerManager.nextContextId(false);
req.setRequestId(requestId);
this.requestId = req.getRequestId().getValue();
ClientPrincipal cp = req.getClientPrincipalNative();
if (cp != null && cp.valid())
{
raw r = cp.exportPrincipal();
this.clientPrincipal = r.getByteArray();
}
object<? extends OeversionInfo> oever = req.getVersionInfo();
if (oever._isValid())
{
OeversionInfo ver = oever.ref();
versionInfo = new String[]
{
ver.getOemajorVersion().getValue(),
ver.getOeminorVersion().getValue(),
ver.getOemaintVersion().getValue()
};
clientType = ver.getOeclientType().getValue();
}
return this;
}
/**
* Restore the {@link OerequestInfo} from this call details, as received from a remote call.
*
* @param req
* The request info for the Agent's SESSION.
* @param agentId
* The agent ID, as computed by the Agent.
* @param sessionId
* The sessionID, as computed by the Agent.
* @param threadId
* The threadID, as computed by the Agent.
*/
public void restoreRequest(OerequestInfo req, Integer agentId, Integer sessionId, Integer threadId)
{
if (AppServerManager.isMultiSession())
{
// TODO: adapter type based on the request type...
// REST
// WEB
// SOAP
// req.setAdapterType()
}
req.initialize(target,
clientContextId,
requestId,
versionInfo,
clientType,
agentId,
sessionId,
threadId,
clientPrincipal);
}
/**
* For each field, it sets a bit if the field's value is no longer the default value.
* <p>
* For {@link Boolean} fields, this means the field is set to <code>true</code>.
* <p>
* For {@link Object} fields, this means the field is now not-null.
*
* @return A 64-bit value with bits set only for changed fields.
*/
private long computeWriting()
{
long writing = 0;
if (inHandle != null)
{
writing |= (1 << FIELD_IN_HANDLE);
}
if (function)
{
writing |= (1 << FIELD_FUNCTION);
}
if (persistent)
{
writing |= (1 << FIELD_PERSISTENT);
}
if (singleRun)
{
writing |= (1 << FIELD_SINGLE_RUN);
}
if (singleton)
{
writing |= (1 << FIELD_SINGLETON);
}
if (procedureHandle != null)
{
writing |= (1 << FIELD_PROC_HANDLE);
}
if (serverHandle != null)
{
writing |= (1 << FIELD_SERVER_HANDLE);
}
if (transactionDistinct)
{
writing |= (1 << FIELD_TX_DISTINCT);
}
if (asynchronous)
{
writing |= (1 << FIELD_ASYNC);
}
if (asyncHandle != null)
{
writing |= (1 << FIELD_ASYNC_HANDLE);
}
if (eventProcedure != null)
{
writing |= (1 << FIELD_EVT_PROC);
}
if (eventProcedureContext != null)
{
writing |= (1 << FIELD_EVT_PROC_CONTEXT);
}
if (arguments != null && arguments.length > 0)
{
writing |= (1 << FIELD_ARGS);
}
if (modes != null && !modes.isEmpty())
{
writing |= (1 << FIELD_MODES);
}
if (portHandle != null)
{
writing |= (1 << FIELD_PORT_HANDLE);
}
if (dynamicFunction)
{
writing |= (1 << FIELD_DYN_FUNC);
}
if (superCall)
{
writing |= (1 << FIELD_SUPER_CALL);
}
if (isClass)
{
writing |= (1 << FIELD_IS_CLASS);
}
if (returnValue)
{
writing |= (1 << FIELD_RETURN_VALUE);
}
if (clientContextId != null)
{
writing |= (1 << FIELD_CLIENTCONTEXTID);
}
if (requestId != null)
{
writing |= (1 << FIELD_REQUESTID);
}
if (clientPrincipal != null)
{
writing |= (1 << FIELD_CLIENTPRINCIPAL);
}
if (versionInfo != null)
{
writing |= (1 << FIELD_VERSIONINFO);
}
if (clientType != null)
{
writing |= (1 << FIELD_CLIENTTYPE);
}
if (webServiceToken != null)
{
writing |= (1 << FIELD_WEB_SERVICE_TOKEN);
}
if (asThread)
{
writing |= (1 << FIELD_AS_THREAD);
}
return writing;
}
/**
* Construct and return a short representation of this object to be used mainly for debugging. In this
* case, the returned string is composed of name and parameter types of the target routine.
*
* @return name and parameter types (in, out) of the target routine.
*/
@Override
public String toString()
{
return target + "(" + modes + ")";
}
}