AppServerInvocationResult.java
/*
** Module : AppServerInvocationResult.java
** Abstract : Container for the result of a remote appserver procedure call.
**
** Copyright (c) 2013-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------Description----------------------------------
** 001 CA 20130529 Created initial version.
** 002 CA 20130829 Return the resolved parameter modes to the caller too.
** 003 CA 20131220 Extracted data common with async web service calls to RemoteInvocationResult.
** 004 CA 20200427 Added support for OERequestInfo legacy class, in response and request.
** 005 IAS 20200908 Rework (de)serialization.
** 006 IAS 20200922 Fix typo in deserialization.
** CA 20201027 The remote side can delete the IN HANDLE used by the requester at the RUN statement.
** 007 CA 20230215 Use PayloadSerializer for serialization.
** 008 GBB 20250403 Adding childConnectionID and appServerConnectionModel to support MSA appservers.
*/
/*
** 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.main;
import static com.goldencode.util.NativeTypeSerializer.*;
import java.io.*;
import com.goldencode.p2j.oo.lang.*;
import com.goldencode.p2j.util.*;
import com.goldencode.util.*;
/**
* This class acts as a container for the various data which is returned by or updated during
* remote appserver calls. This includes the function/procedure return value, updated
* OUTPUT/INPUT-OUTPUT parameters or the persistent procedure handle for a RUN ... PERSISTENT
* call.
*/
public class AppServerInvocationResult
extends RemoteInvocationResult
implements Externalizable
{
/** The remote procedure handle, used to build a {@link ProxyProcedureWrapper} instance. */
private String procedureId;
/** The connection ID, returned during the connect request. */
private String connectionID;
/** The child connection ID, returned during the connect request. */
private String childConnectionID;
/** The session model used by the connection running this request. */
private AppServerSessionModel appServerConnectionModel;
/** The response for the <code>OERequestInfo:clientContextId</code> value. */
private String clientContextId;
/** The response for the <code>OERequestInfo:requestId</code> value. */
private String requestId;
/** The response for the <code>OERequestInfo:versionInfo</code> value. */
private String[] versionInfo; // major, minor, maint
/** The response for the <code>OERequestInfo:versionInfo</code> value. */
private String clientType;
/** The response for the <code>OERequestInfo:agentId</code> value. */
private Integer agentId;
/** The response for the <code>OERequestInfo:sessionId</code> value. */
private Integer sessionId;
/** The response for the <code>OERequestInfo:threadId</code> value. */
private Integer threadId;
/** The response for the <code>OERequestInfo:clientPrincipal</code> value. */
private byte[] clientPrincipal;
/** Flag indicating that the requester's IN HANDLE has been deleted by the remote side. */
private boolean invalidInHandle;
/**
* Serialize this object, to be picked up by the other side.
*
* @param out
* The output destination to which the data will be sent.
*
* @throws IOException
* In case of I/O errors.
*/
public void writeExternal(ObjectOutput out)
throws IOException
{
PayloadSerializer.writePayload(out, arguments);
PayloadSerializer.writePayload(out, result);
writeString(out, procedureId);
PayloadSerializer.writePayload(out, error);
writeString(out, connectionID);
writeString(out, childConnectionID);
writeString(out, appServerConnectionModel == null ? null : appServerConnectionModel.toString());
writeString(out, modes);
// write the data to build the server:RESPONSE-INFO on the caller's side
writeString(out, clientContextId);
writeString(out, requestId);
writeStringArray(out, versionInfo);
writeString(out, clientType);
writeInteger(out, agentId);
writeInteger(out, sessionId);
writeInteger(out, threadId);
writeByteArray(out, clientPrincipal);
out.writeBoolean(invalidInHandle);
}
/**
* Used the specified input source and initialize this instance.
*
* @param in
* The input source from which the data will be restored.
*
* @throws IOException
* In case of I/O errors.
* @throws ClassNotFoundException
* If payload can't be instantiated.
*/
public void readExternal(ObjectInput in)
throws IOException,
ClassNotFoundException
{
arguments = (Object[]) PayloadSerializer.readPayload(in);
result = PayloadSerializer.readPayload(in);
procedureId = readString(in);
error = (Throwable) PayloadSerializer.readPayload(in);
connectionID = readString(in);
childConnectionID = readString(in);
appServerConnectionModel = AppServerSessionModel.fromString(readString(in));
modes = readString(in);
// read the data to build the server:RESPONSE-INFO
clientContextId = readString(in);
requestId = readString(in);
versionInfo = readStringArray(in);
clientType = readString(in);
agentId = readInteger(in);
sessionId = readInteger(in);
threadId = readInteger(in);
clientPrincipal = readByteArray(in);
invalidInHandle = in.readBoolean();
}
/**
* Get the state of the {@link #invalidInHandle} flag.
*
* @return See above.
*/
public boolean isInvalidInHandle()
{
return invalidInHandle;
}
/**
* Set the state of the {@link #invalidInHandle} flag.
*
* @param invalidInHandle
* The new flag value.
*/
public void setInvalidInHandle(boolean invalidInHandle)
{
this.invalidInHandle = invalidInHandle;
}
/**
* Get the handle code for the remote persistent procedure.
*
* @return The {@link #procedureId} field.
*/
public String getProcedureId()
{
return procedureId;
}
/**
* Save the remote persistent procedure handle's code.
*
* @param procedureId
* The code for the remote persistent procedure handle.
*/
public void setProcedureId(String procedureId)
{
this.procedureId = procedureId;
}
/**
* Get the established connection ID, for a connect request.
*
* @return See above.
*/
public String getConnectionID()
{
return connectionID;
}
/**
* Set the new connection ID, after a connect request.
*
* @param connectionID
* The connection ID, which will be unknown if there are any {@link #error errors}.
*/
public void setConnectionID(String connectionID)
{
this.connectionID = connectionID;
}
/**
* Get the ID of the child connection handling the request.
*
* @return See above.
*/
public String getChildConnectionID()
{
return childConnectionID;
}
/**
* Set the ID of the child connection handling the request.
*
* @param childConnectionID
* The ID of the child connection handling the request.
*/
public void setChildConnectionID(String childConnectionID)
{
this.childConnectionID = childConnectionID;
}
/**
* Get the session model used by the connection running this request.
*
* @return See above.
*/
public AppServerSessionModel getConnectionModel()
{
return appServerConnectionModel;
}
/**
* Set the ID of the child connection handling the request.
*
* @param appServerConnectionModel
* The session model used by the connection running this request.
*/
public void setConnectionModel(AppServerSessionModel appServerConnectionModel)
{
this.appServerConnectionModel = appServerConnectionModel;
}
/**
* Check if the RETURN-VALUE will be set.
*
* @return In case of appserver results, it returns <code>true</code>.
*/
public boolean setReturnValue()
{
return true;
}
/**
* Get the {@link #clientContextId}.
*
* @return See above.
*/
public String getClientContextId()
{
return clientContextId;
}
/**
* Set the {@link #clientContextId}.
*
* @param clientContextId
* The clientContextId to set
*/
public void setClientContextId(String clientContextId)
{
this.clientContextId = clientContextId;
}
/**
* Get the {@link #requestId}.
*
* @return See above.
*/
public String getRequestId()
{
return requestId;
}
/**
* Set the {@link #requestId}.
*
* @param requestId
* The requestId to set
*/
public void setRequestId(String requestId)
{
this.requestId = requestId;
}
/**
* Get the {@link #versionInfo}.
*
* @return See above.
*/
public String[] getVersionInfo()
{
return versionInfo;
}
/**
* Set the {@link #versionInfo}.
*
* @param versionInfo
* The versionInfo to set
*/
public void setVersionInfo(String[] versionInfo)
{
this.versionInfo = versionInfo;
}
/**
* Get the {@link #clientType}.
*
* @return See above.
*/
public String getClientType()
{
return clientType;
}
/**
* Set the {@link #clientType}.
*
* @param clientType
* The clientType to set
*/
public void setClientType(String clientType)
{
this.clientType = clientType;
}
/**
* Get the {@link #agentId}.
*
* @return See above.
*/
public Integer getAgentId()
{
return agentId;
}
/**
* Set the {@link #agentId}.
*
* @param agentId
* The agentId to set
*/
public void setAgentId(Integer agentId)
{
this.agentId = agentId;
}
/**
* Get the {@link #sessionId}.
*
* @return See above.
*/
public Integer getSessionId()
{
return sessionId;
}
/**
* Set the {@link #sessionId}.
*
* @param sessionId
* The sessionId to set
*/
public void setSessionId(Integer sessionId)
{
this.sessionId = sessionId;
}
/**
* Get the {@link #threadId}.
*
* @return See above.
*/
public Integer getThreadId()
{
return threadId;
}
/**
* Set the {@link #threadId}.
*
* @param threadId
* The threadId to set
*/
public void setThreadId(Integer threadId)
{
this.threadId = threadId;
}
/**
* Get the {@link #clientPrincipal}.
*
* @return See above.
*/
public byte[] getClientPrincipal()
{
return clientPrincipal;
}
/**
* Set the {@link #clientPrincipal}.
*
* @param clientPrincipal
* The clientPrincipal to set
*/
public void setClientPrincipal(byte[] clientPrincipal)
{
this.clientPrincipal = clientPrincipal;
}
/**
* Store a {@link OerequestInfo} response from the appserver agent, to be sent to the caller.
*
* @param currentResponseInfo
* The <code>SESSION:CURRENT-RESPONSE-INFO</code> instance.
*/
public void storeResponse(object<? extends OerequestInfo> currentResponseInfo)
{
if (currentResponseInfo.isUnknown() || !currentResponseInfo._isValid())
{
return;
}
OerequestInfo response = currentResponseInfo.ref();
this.clientContextId = response.getClientContextId().getValue();
this.requestId = response.getRequestId().getValue();
if (response.getVersionInfo()._isValid())
{
OeversionInfo oever = response.getVersionInfo().ref();
this.versionInfo = new String[3];
this.versionInfo[0] = oever.getOemajorVersion().getValue();
this.versionInfo[1] = oever.getOeminorVersion().getValue();
this.versionInfo[2] = oever.getOemaintVersion().getValue();
this.clientType = oever.getOeclientType().getValue();
}
this.agentId = response.getAgentId().toJavaIntegerType();
this.sessionId = response.getSessionId().toJavaIntegerType();
this.threadId = response.getThreadId().toJavaIntegerType();
handle cp = response.getClientPrincipal();
if (cp._isValid())
{
raw r = cp.unwrapClientPrincipal().exportPrincipal();
this.clientPrincipal = r.getByteArray();
}
else
{
this.clientPrincipal = null;
}
}
}