ComParameter.java
/*
** Module : ComParameter.java
** Abstract : Holds details for a COM parameter specified at a COM object method call.
**
** Copyright (c) 2017-2019, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------Description----------------------------------
** 001 CA 20171025 Created initial version.
** 002 CA 20171128 Added support for EXTENT parameters.
** 003 CA 20190530 Fixed unknown input value.
*/
/*
** 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.comauto;
import java.io.*;
import java.lang.reflect.*;
import java.util.function.*;
import com.goldencode.p2j.util.*;
/**
* Holds details for a COM parameter specified at a COM object method call.
*/
public class ComParameter
implements Externalizable
{
/** The data type for an AS clause. */
@SuppressWarnings("javadoc")
public static enum DataType
{
SHORT,
FLOAT,
CURRENCY,
UNSIGNED_BYTE,
ERROR_CODE,
IUNKNOWN;
};
/** The parameter's mode, 'I', 'O' or 'U'. */
private char mode;
/** The parameter's value. */
private Object value;
/** Flag matching {@code true} if {@code BY-POINTER} option is used. */
private boolean byPointer;
/** Flag matching {@code true} if {@code BY-VARIANT-POINTER} option is used. */
private boolean byVariantPointer;
/** Parameter's {@code AS data-type} option, or {@code null} if not used. */
private DataType dataType;
/** Used only by the native side, a string representation of this data type, in FWD terms. */
private String fwdDataType;
/** Flag identifying if the {@link #value} is an extent variable. */
private boolean extent;
/**
* In case of {@link #extent}, the current var's length (can be zero for uninitialized dynamic
* extent).
*/
private int length;
/**
* The reference replacement in case of output/input-output dynamic extent values.
*/
private final Consumer<BaseDataType[]> refReplacement;
/**
* Default c'tor.
*/
public ComParameter()
{
// no-op
refReplacement = null;
}
/**
* Create a copy of the specified parameter.
*
* @param aparam
* Parameter to copy.
*/
ComParameter(ComParameter aparam)
{
this.mode = aparam.mode;
this.value = aparam.value;
this.dataType = aparam.dataType;
this.byPointer = aparam.byPointer;
this.byVariantPointer = aparam.byVariantPointer;
this.fwdDataType = aparam.fwdDataType;
this.extent = aparam.extent;
this.length = aparam.length;
this.refReplacement = aparam.refReplacement;
}
/**
* Create a new instance with the specified details.
*
* @param mode
* The parameter's mode, 'I', 'O' or 'U'.
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param byPointer
* Flag matching {@code true} if {@code BY-POINTER} option is used.
* @param byVariantPointer
* Flag matching {@code true} if {@code BY-VARIANT-POINTER} option is used.
* @param ref
* The reference replacement for dynamic extent variables.
*/
private ComParameter(char mode,
Object value,
DataType dataType,
boolean byPointer,
boolean byVariantPointer,
Consumer<BaseDataType[]> ref)
{
this.mode = mode;
this.value = value;
this.byPointer = byPointer;
this.byVariantPointer = byVariantPointer;
this.dataType = dataType;
this.extent = value == null ? false : value.getClass().isArray();
this.length = extent ? Array.getLength(value) : 0;
this.refReplacement = ref;
}
/**
* Create an INPUT parameter with an unknown value.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input()
{
return new ComParameter('I', new unknown(), null, false, false, null);
}
/**
* Create an INPUT parameter with the specified value.
*
* @param value
* The parameter's value.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input(Object value)
{
return new ComParameter('I', value, null, false, false, null);
}
/**
* Create an OUTPUT parameter with the specified value.
*
* @param value
* The parameter's value.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter output(Object value)
{
return new ComParameter('O', value, null, false, false, null);
}
/**
* Create an INPUT-OUTPUT parameter with the specified value.
*
* @param value
* The parameter's value.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter inputOutput(Object value)
{
return new ComParameter('U', value, null, false, false, null);
}
/**
* Create an INPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input(Object value, DataType dataType)
{
return new ComParameter('I', value, dataType, false, false, null);
}
/**
* Create an OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter output(Object value, DataType dataType)
{
return new ComParameter('O', value, dataType, false, false, null);
}
/**
* Create an INPUT-OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter inputOutput(Object value, DataType dataType)
{
return new ComParameter('U', value, dataType, false, false, null);
}
/**
* Create an INPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input(Object value, DataType dataType, boolean isPointer)
{
return new ComParameter('I', value, dataType, isPointer, !isPointer, null);
}
/**
* Create an OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter output(Object value, DataType dataType, boolean isPointer)
{
return new ComParameter('O', value, dataType, isPointer, !isPointer, null);
}
/**
* Create an INPUT-OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter inputOutput(Object value, DataType dataType, boolean isPointer)
{
return new ComParameter('U', value, dataType, isPointer, !isPointer, null);
}
/**
* Create an INPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input(Object value, boolean isPointer)
{
return new ComParameter('I', value, null, isPointer, !isPointer, null);
}
/**
* Create an OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter output(Object value, boolean isPointer)
{
return new ComParameter('O', value, null, isPointer, !isPointer, null);
}
/**
* Create an INPUT-OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter inputOutput(Object value, boolean isPointer)
{
return new ComParameter('U', value, null, isPointer, !isPointer, null);
}
/**
* Create an INPUT parameter with the specified value.
*
* @param value
* The parameter's value.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input(Object value, Consumer<BaseDataType[]> ref)
{
return new ComParameter('I', value, null, false, false, ref);
}
/**
* Create an OUTPUT parameter with the specified value.
*
* @param value
* The parameter's value.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter output(Object value, Consumer<BaseDataType[]> ref)
{
return new ComParameter('O', value, null, false, false, ref);
}
/**
* Create an INPUT-OUTPUT parameter with the specified value.
*
* @param value
* The parameter's value.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter inputOutput(Object value, Consumer<BaseDataType[]> ref)
{
return new ComParameter('U', value, null, false, false, ref);
}
/**
* Create an INPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input(Object value, DataType dataType, Consumer<BaseDataType[]> ref)
{
return new ComParameter('I', value, dataType, false, false, ref);
}
/**
* Create an OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter output(Object value, DataType dataType, Consumer<BaseDataType[]> ref)
{
return new ComParameter('O', value, dataType, false, false, ref);
}
/**
* Create an INPUT-OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter inputOutput(Object value,
DataType dataType,
Consumer<BaseDataType[]> ref)
{
return new ComParameter('U', value, dataType, false, false, ref);
}
/**
* Create an INPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input(Object value,
DataType dataType,
boolean isPointer,
Consumer<BaseDataType[]> ref)
{
return new ComParameter('I', value, dataType, isPointer, !isPointer, ref);
}
/**
* Create an OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter output(Object value,
DataType dataType,
boolean isPointer,
Consumer<BaseDataType[]> ref)
{
return new ComParameter('O', value, dataType, isPointer, !isPointer, ref);
}
/**
* Create an INPUT-OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param dataType
* Parameter's {@code AS data-type} option.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter inputOutput(Object value,
DataType dataType,
boolean isPointer,
Consumer<BaseDataType[]> ref)
{
return new ComParameter('U', value, dataType, isPointer, !isPointer, ref);
}
/**
* Create an INPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter input(Object value, boolean isPointer, Consumer<BaseDataType[]> ref)
{
return new ComParameter('I', value, null, isPointer, !isPointer, ref);
}
/**
* Create an OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter output(Object value, boolean isPointer, Consumer<BaseDataType[]> ref)
{
return new ComParameter('O', value, null, isPointer, !isPointer, ref);
}
/**
* Create an INPUT-OUTPUT parameter with the specified details.
*
* @param value
* The parameter's value.
* @param isPointer
* {@code true} represents {@code BY-POINTER} option, {@code false} represents
* {@code BY-VARIANT-POINTER} option.
* @param ref
* The reference replacement for dynamic extent variables.
*
* @return The created {@link ComParameter} instance.
*/
public static ComParameter inputOutput(Object value,
boolean isPointer,
Consumer<BaseDataType[]> ref)
{
return new ComParameter('U', value, null, isPointer, !isPointer, ref);
}
/**
* Check if this is an OUTPUT parameter.
*
* @return See above.
*/
public boolean isOutput()
{
return 'O' == mode;
}
/**
* Check if this is an INPUT-OUTPUT parameter.
*
* @return See above.
*/
public boolean isInputOutput()
{
return 'U' == mode;
}
/**
* Check the {@link #byPointer} flag.
*
* @return {@code true} if the {@code BY-POINTER} option is used.
*/
public boolean isByPointer()
{
return byPointer;
}
/**
* Set the {@link #byPointer} flag.
*
* @param byPointer
* {@code true} if the {@code BY-POINTER} option is used.
*/
public void setByPointer(boolean byPointer)
{
this.byPointer = byPointer;
}
/**
* Check the {@link #byVariantPointer} flag.
*
* @return {@code true} if the {@code BY-VARIANT-POINTER} option is used.
*/
public boolean isByVariantPointer()
{
return byVariantPointer;
}
/**
* Set the {@link #byVariantPointer} flag.
*
* @param byVariantPointer
* {@code true} if the {@code BY-VARIANT-POINTER} option is used.
*/
public void setByVariantPointer(boolean byVariantPointer)
{
this.byVariantPointer = byVariantPointer;
}
/**
* Get the {@link #dataType} state.
*
* @return {@code null} if no {@code AS data-type} option
*/
public DataType getDataType()
{
return dataType;
}
/**
* Set the parameter's {@link #dataType}.
*
* @param dataType
* The parameter's {@code AS data-type} option or {@code null} if not in use.
*/
public void setDataType(DataType dataType)
{
this.dataType = dataType;
}
/**
* Get the parameter's {@link #value}.
*
* @return See above.
*/
public Object getValue()
{
return value;
}
/**
* Set the parameter's {@link #value}.
*
* @param value
* The parameter's value.
*/
public void setValue(Object value)
{
this.value = value;
}
/**
* Get the parameter's {@link #mode}.
*
* @return See above.
*/
public char getMode()
{
return mode;
}
/**
* Set the parameter's {@link #mode}. Only 'I', 'U' or 'O' characters are accepted.
*
* @param mode
* The parameter's mode.
*
* @throws IllegalArgumentException
* If {@code mode} is not one of 'I', 'U' or 'O' characters.
*/
public void setMode(char mode)
{
if (!(mode == 'I' || mode == 'O' || mode == 'U'))
{
throw new IllegalArgumentException(mode + " can not be used for ComParameter!");
}
this.mode = mode;
}
/**
* Get the parameter's {@link #fwdDataType}.
*
* @return See above.
*/
public String getFwdDataType()
{
return fwdDataType;
}
/**
* Set the parameter's {@link #fwdDataType}.
*
* @param fwdDataType
* The FWD data-type name.
*
* @see com.goldencode.p2j.util.BaseDataType#getTypeName() for possible types.
*/
public void setFwdDataType(String fwdDataType)
{
this.fwdDataType = fwdDataType;
}
/**
* Check if this parameter is an extent parameter.
*
* @return See above.
*/
public boolean isExtent()
{
return extent;
}
/**
* Mark this parameter as an extent.
*
* @param extent
* <code>true</code> if this is an extent variable.
*/
public void setExtent(boolean extent)
{
this.extent = extent;
}
/**
* Get the parameter's length. Used only if {@link #extent} is true.
*
* @return See above.
*/
public int getLength()
{
return length;
}
/**
* Get the reference replacement lambda expression.
*
* @return See above.
*/
public Consumer<BaseDataType[]> getRefReplacement()
{
return refReplacement;
}
/**
* Set the length of an {@link #extent} parameter.
*
* @param length
* The array length.
*/
public void setLength(int length)
{
this.length = length;
}
/**
* Replacement for the default object writing method. The latest state is written to the
* output destination.
*
* @param out
* The output destination to which fields will be saved.
*
* @throws IOException
* In case of I/O errors.
*/
@Override
public void writeExternal(ObjectOutput out)
throws IOException
{
out.writeChar(mode);
out.writeObject(value);
out.writeBoolean(byPointer);
out.writeBoolean(byVariantPointer);
out.writeInt(dataType != null ? dataType.ordinal() : -1);
out.writeObject(fwdDataType);
out.writeBoolean(extent);
out.writeInt(length);
}
/**
* Replacement for the default object reading method. The latest state is read from the
* input source.
*
* @param in
* The input source from which fields will be restored.
*
* @throws IOException
* In case of I/O errors.
* @throws ClassNotFoundException
* If payload can't be instantiated.
*/
@Override
public void readExternal(ObjectInput in)
throws IOException,
ClassNotFoundException
{
mode = in.readChar();
value = in.readObject();
byPointer = in.readBoolean();
byVariantPointer = in.readBoolean();
int dtOrdinal = in.readInt();
if (dtOrdinal != -1)
{
dataType = DataType.values()[dtOrdinal];
}
fwdDataType = (String) in.readObject();
extent = in.readBoolean();
length = in.readInt();
}
}