org.eclipse.persistence.eis.interactions.EISInteraction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.eis.interactions;
import java.io.*;
import java.util.*;
import javax.resource.*;
import javax.resource.cci.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.databaseaccess.Accessor;
import org.eclipse.persistence.internal.databaseaccess.DatasourceCall;
import org.eclipse.persistence.eis.*;
/**
* Defines the specification for a call to a JCA interaction.
* Builds the input and output records from the arguments.
*
* @author James
* @since OracleAS TopLink 10g (10.0.3)
*/
public abstract class EISInteraction extends DatasourceCall {
/** Adapter specific interaction spec. */
protected InteractionSpec interactionSpec;
/** Name of the function the interaction describes. */
protected String functionName;
/** Name to pass to the input record creation. */
protected String inputRecordName;
/** Adapter specific properties may be added. */
protected Map properties;
/** Holds database row of input values. */
protected AbstractRecord inputRow;
/** Defines the arguments to the interaction, these can be the values or argument names/fields the values come from. */
protected Vector arguments;
/**
* Defines the output argument names as defined in the output record for the interaction.
* This is shared as indexed interaction may still have mapped results.
*/
protected Vector outputArgumentNames;
/** Defines the field values the output arguments of the interaction map to. These are order dependent with the names. */
protected Vector outputArguments;
/** Path to the desired output record if nested. */
protected String outputResultPath;
/**
* PUBLIC:
* Default constructor.
*/
public EISInteraction() {
super();
this.functionName = "";
this.inputRecordName = "";
this.outputResultPath = "";
}
/**
* PUBLIC:
* Define the output argument to the interaction and the field/argument name to be substitute for it.
* This is only required if an output row is not used.
* The parameterAndArgumentFieldName is the name of the output record argument expected,
* and is the field or argument name to be used to be used for it.
* These names are assumed to be the same, if not this method can be called with two arguments.
*/
public void addOutputArgument(String parameterAndArgumentFieldName) {
addOutputArgument(parameterAndArgumentFieldName, parameterAndArgumentFieldName);
}
/**
* PUBLIC:
* Define the output argument to the interaction and the field/argument name to be substitute for it.
* This is only required if an output row is not used.
* The parameterName is the name of the output record argument expected.
* The argumentFieldName is the field or argument name to be used to be used for it.
* If these names are the same (as they normally are) this method can be called with a single argument.
*/
public void addOutputArgument(String parameterName, String argumentFieldName) {
getOutputArgumentNames().addElement(parameterName);
getOutputArguments().addElement(new DatabaseField(argumentFieldName));
}
/**
* The argument fields or values to the interaction that map into the input record.
*/
public Vector getArguments() {
// This is lazy initialized to conserv space on calls that have no parameters.
if (arguments == null) {
arguments = new Vector();
}
return arguments;
}
/**
* INTERNAL:
* The argument fields or values to the interaction that map into the input record.
*/
public void setArguments(Vector arguments) {
this.arguments = arguments;
}
/**
* Return if argumented.
*/
public boolean hasArguments() {
return (arguments != null) && (!arguments.isEmpty());
}
public boolean isEISInteraction() {
return true;
}
/**
* PUBLIC:
* The output result path defines the root key for the MappedRecord that
* the desired interaction result is nested into.
* This is required for read interactions that need a nested record to build from the mapped object.
*/
public String getOutputResultPath() {
return outputResultPath;
}
/**
* PUBLIC:
* The output result path defines the root key for the MappedRecord that
* the desired interaction result is nested into.
* This is required for read interactions that need a nested record to build from the mapped object.
*/
public void setOutputResultPath(String outputResultPath) {
this.outputResultPath = outputResultPath;
}
/**
* The argument names for the output record.
*/
public Vector getOutputArgumentNames() {
// This is lazy initialized to conserv space on calls that have no parameters.
if (outputArgumentNames == null) {
outputArgumentNames = new Vector();
}
return outputArgumentNames;
}
/**
* The argument fields to the interaction that map into the output record.
*/
public Vector getOutputArguments() {
// This is lazy initialized to conserv space on calls that have no parameters.
if (outputArguments == null) {
outputArguments = new Vector();
}
return outputArguments;
}
/**
* The output arguments.
*/
public void setOutputArguments(Vector outputArguments) {
this.outputArguments = outputArguments;
}
/**
* Set the output argument names.
*/
public void setOutputArgumentNames(Vector outputArgumentNames) {
this.outputArgumentNames = outputArgumentNames;
}
/**
* Return if argumented.
*/
public boolean hasOutputArguments() {
return (outputArguments != null) && (!outputArguments.isEmpty());
}
/**
* Set the default record name from the descriptor.
*/
public void prepare(AbstractSession session) {
if (getInputRecordName().length() == 0) {
if ((getQuery() != null) && (getQuery().getDescriptor() instanceof EISDescriptor)) {
EISDescriptor descriptor = (EISDescriptor)getQuery().getDescriptor();
setInputRecordName(descriptor.getDataTypeName());
} else {
setInputRecordName("input");
}
}
super.prepare(session);
}
/**
* Create the appropriate record element for the data value.
* If the value is a collection, create a collection of elements,
* if the value is a map, create a nested map,
* otherwise just return the value (primitive data).
*/
public Object createRecordElement(String elementName, Object value, EISAccessor accessor) {
try {
Object element = value;
// Handle nested collections.
if (element instanceof List) {
// Convert each element in the list.
List values = (List)element;
List elements = new Vector(values.size());
for (int index = 0; index < values.size(); index++) {
elements.add(createRecordElement(elementName, values.get(index), accessor));
}
element = elements;
// Handle nested rows.
} else if (value instanceof AbstractRecord) {
AbstractRecord valuesRow = (AbstractRecord)value;
// The record name for the row must be determined,
// currently the SDK uses the table name of the row's field for this,
// ideally this would be a property on the row.
String recordName = elementName;
if (valuesRow.size() > 0) {
recordName = valuesRow.getFields().get(0).getTableName();
}
MappedRecord record = accessor.getRecordFactory().createMappedRecord(recordName);
for (Iterator keysIterator = valuesRow.getFields().iterator();
keysIterator.hasNext();) {
DatabaseField field = (DatabaseField)keysIterator.next();
Object elementValue = createRecordElement(field.getName(), valuesRow.get(field), accessor);
accessor.getEISPlatform().setValueInRecord(field.getName(), elementValue, record, accessor);
}
element = record;
}
return element;
} catch (ResourceException exception) {
throw EISException.resourceException(exception, accessor, null);
}
}
/**
* PUBLIC:
* Return the JCA InteractionSpec that defines this EIS interaction.
* The InteractionSpec is JCA adapter specific and typically
* defines the function name.
*/
public InteractionSpec getInteractionSpec() {
return interactionSpec;
}
/**
* PUBLIC:
* Set the JCA InteractionSpec that defines this EIS interaction.
* The InteractionSpec is JCA adapter specific and typically
* defines the function name.
*/
public void setInteractionSpec(InteractionSpec interactionSpec) {
this.interactionSpec = interactionSpec;
}
/**
* Return the string for logging purposes.
*/
public String getLogString(Accessor accessor) {
StringWriter writer = new StringWriter();
writer.write("Executing ");
writer.write(toString());
writer.write(Helper.cr());
writer.write("\tspec => ");
writer.write(String.valueOf(getInteractionSpec()));
writer.write(Helper.cr());
writer.write("\tproperties => ");
writer.write(String.valueOf(getProperties()));
writer.write(Helper.cr());
writer.write("\tinput => [");
if (!getParameters().isEmpty()) {
for (Iterator iterator = getParameters().iterator(); iterator.hasNext();) {
Object parameter = iterator.next();
writer.write(String.valueOf(parameter));
if (iterator.hasNext()) {
writer.write(", ");
} else {
writer.write("]");
}
}
} else {
writer.write(String.valueOf(getInputRow()));
writer.write("]");
}
return writer.toString();
}
/**
* Arguments to the interaction can be passed two ways.
* The entire argument row can be converted to the input record,
* or the arguments from the row can be translated into the interaction parameters.
*/
public void translate(AbstractRecord translationRow, AbstractRecord modifyRow, AbstractSession session) {
if (modifyRow != null) {
// Avoid clearing a prepared row.
setInputRow(modifyRow);
}
if (hasArguments()) {
List parametersValues = new ArrayList(getArguments().size());
for (int index = 0; index < getArguments().size(); index++) {
Object argument = getArguments().elementAt(index);
// The argument is either a value or a databasefield that needs to be translated.
if ((argument != null) && (argument instanceof DatabaseField)) {
DatabaseField field = (DatabaseField)argument;
Object value = translationRow.get(field);
//BUG#12345:modifyRow is null for reads
if ((value == null) && (modifyRow != null)) {
value = modifyRow.get(field);
}
parametersValues.add(value);
} else {
parametersValues.add(argument);
}
}
setParameters(parametersValues);
}
}
/**
* Create the appropriate input record for this interaction.
* Populate the data into the record from this interaction's arguments.
*/
public abstract javax.resource.cci.Record createInputRecord(EISAccessor accessor);
/**
* INTERNAL:
* Build a database row from the record returned from the interaction.
*/
public abstract AbstractRecord buildRow(javax.resource.cci.Record record, EISAccessor accessor);
/**
* Build a collection of database rows from the Record returned from the interaction.
* This handles IndexedRecords used as sets of result records,
* and a single MappedRecord with a list of result records.
*/
public Vector buildRows(javax.resource.cci.Record record, EISAccessor accessor) {
Vector rows = null;
if (record instanceof IndexedRecord) {
IndexedRecord indexedRecord = (IndexedRecord)record;
rows = new Vector(indexedRecord.size());
for (int index = 0; index < indexedRecord.size(); index++) {
Object element = indexedRecord.get(index);
if (element instanceof javax.resource.cci.Record) {
rows.addElement(buildRow((javax.resource.cci.Record)element, accessor));
} else {
// It is a single row record.
rows.add(buildRow(record, accessor));
return rows;
}
}
} else if (record instanceof MappedRecord) {
MappedRecord mappedRecord = (MappedRecord)record;
// Handle the case of a single output argument of the entire row contained within the return record.
if (getOutputResultPath().length() > 0) {
Object element = mappedRecord.get(getOutputResultPath());
// Handles nested rows inside an IndexedRecord, MappedRecord or List.
if (element instanceof IndexedRecord) {
return buildRows((IndexedRecord)element, accessor);
} else if (element instanceof MappedRecord) {
mappedRecord = (MappedRecord)element;
} else if (element instanceof List) {
List elements = (List)element;
rows = new Vector(elements.size());
for (int index = 0; index < elements.size(); index++) {
Object elementValue = elements.get(index);
if (elementValue instanceof javax.resource.cci.Record) {
rows.addElement(buildRow((javax.resource.cci.Record)elementValue, accessor));
} else {
rows.add(elementValue);
}
}
return rows;
}
}
rows = new Vector(1);
AbstractRecord row = new EISMappedRecord(mappedRecord, accessor);
rows.add(row);
} else {
rows = new Vector(1);
}
return rows;
}
/**
* PUBLIC:
* Return the function name of the interaction.
* A function name is a common properties for a CCI InteractionSpec.
* This cannot be generically set on the spec as it is not in the interface
* however the EIS platform may make use of this in build the interaction spec.
*/
public String getFunctionName() {
return functionName;
}
/**
* PUBLIC:
* Set the function name of the interaction.
* A function name is a common properties for a CCI InteractionSpec.
* This cannot be generically set on the spec as it is not in the interface
* however the EIS platform may make use of this in build the interaction spec.
*/
public void setFunctionName(String functionName) {
this.functionName = functionName;
}
/**
* PUBLIC:
* Return the input record name.
* This is used as the name passed to the adapter when creating the input record.
*/
public String getInputRecordName() {
return inputRecordName;
}
/**
* PUBLIC:
* Set the input record name.
* This is used as the name passed to the adapter when creating the input record.
*/
public void setInputRecordName(String recordName) {
this.inputRecordName = recordName;
}
/**
* Returns the adapter specific properties.
*/
public Map getProperties() {
if (properties == null) {
properties = new HashMap(5);
}
return properties;
}
/**
* PUBLIC:
* Returns the adapter property associated the given name.
* If the interaction is associated with a query that has a descriptor,
* The descriptor's properties are automatically inherited.
*/
public Object getProperty(String name) {
Object value = getProperties().get(name);
// Check descriptor property if available.
if ((value == null) && (getQuery() != null) && (getQuery().getDescriptor() != null)) {
value = getQuery().getDescriptor().getProperty(name);
}
return value;
}
/**
* Set the adapter specific properties.
*/
public void setProperties(Map properties) {
this.properties = properties;
}
/**
* PUBLIC:
* Set the adapter specific property.
*/
public void setProperty(String name, Object value) {
getProperties().put(name, value);
}
/**
* INTERNAL:
* Return the input database row.
*/
public AbstractRecord getInputRow() {
return inputRow;
}
/**
* PUBLIC:
* Set the input database row.
*/
public void setInputRow(AbstractRecord inputRow) {
this.inputRow = inputRow;
}
public String toString() {
return Helper.getShortClassName(getClass()) + "(" + getFunctionName() + ")";
}
}