blob: 19809e4c6ef978843af14488b94c06d4cf221236 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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.util.*;
import jakarta.resource.*;
import jakarta.resource.cci.*;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.sessions.DatabaseRecord;
import org.eclipse.persistence.eis.*;
/**
* Defines the specification for a call to a JCA interaction using Mapped records.
* Builds the input and output records from the arguments.
*
* @author James
* @since OracleAS TopLink 10<i>g</i> (10.0.3)
*/
public class MappedInteraction extends EISInteraction {
protected String inputResultPath;
protected Vector<String> argumentNames;
/**
* Default constructor.
*/
public MappedInteraction() {
super();
this.inputResultPath = "";
}
/**
* PUBLIC:
* Define the argument to the interaction and the field/argument name to be substitute for it.
* This is only required if an input row is not used.
* The parameterAndArgumentFieldName is the name of the input record argument,
* and is the field or argument name to be used to pass to the interaction.
* These names are assumed to be the same, if not this method can be called with two arguments.
*/
public void addArgument(String parameterAndArgumentFieldName) {
addArgument(parameterAndArgumentFieldName, parameterAndArgumentFieldName);
}
/**
* PUBLIC:
* Define the argument to the interaction and the field/argument name to be substitute for it.
* This is only required if an input row is not used.
* The parameterName is the name of the input record argument.
* The argumentFieldName is the field or argument name to be used to pass to the interaction.
* If these names are the same (as they normally are) this method can be called with a single argument.
*/
public void addArgument(String parameterName, String argumentFieldName) {
getArgumentNames().addElement(parameterName);
getArguments().addElement(new DatabaseField(argumentFieldName));
}
/**
* PUBLIC:
* Define the argument to the interaction and the value name to be input for it.
* This is only required if an input row is not used.
* The parameterName is the name of the input record argument.
* The argumentValue is the value of the input record argument.
*/
public void addArgumentValue(String parameterName, Object argumentValue) {
getArgumentNames().addElement(parameterName);
getArguments().addElement(argumentValue);
}
/**
* PUBLIC:
* The input result path defines the root key for the MappedRecord that
* the interaction argument is nested into.
* This is required for write interaction that take the row build from the mapped object
* and need the input to contain that row record as part of the input, instead of the entire input.
*/
public String getInputResultPath() {
return inputResultPath;
}
/**
* PUBLIC:
* The input result path defines the root key for the MappedRecord that
* the interaction argument is nested into.
* This is required for write interaction that take the row build from the mapped object
* and need the input to contain that row record as part of the input, instead of the entire input.
*/
public void setInputResultPath(String inputResultPath) {
this.inputResultPath = inputResultPath;
}
/**
* The argument names for the input record.
*/
public Vector<String> getArgumentNames() {
// This is lazy initialized to conserv space on calls that have no parameters.
if (argumentNames == null) {
argumentNames = new Vector<>();
}
return argumentNames;
}
/**
* INTERNAL:
* The argument names for the input record.
*/
public void setArgumentNames(Vector<String> argumentNames) {
this.argumentNames = argumentNames;
}
/**
* Create a mapped input record for this interaction.
* Populate the data into the record from this interaction's arguments.
*/
@Override
public jakarta.resource.cci.Record createInputRecord(EISAccessor accessor) {
try {
MappedRecord record = null;
// The input record can either be build from the interaction arguments,
// or the modify row.
if ((getInputRow() != null) && (!hasArguments())) {
if (getInputResultPath().length() == 0) {
record = (MappedRecord)createRecordElement(getInputRecordName(), getInputRow(), accessor);
} else {
record = accessor.getRecordFactory().createMappedRecord(getInputRecordName());
Object nestedRecord = createRecordElement(getInputResultPath(), getInputRow(), accessor);
accessor.getEISPlatform().setValueInRecord(getInputResultPath(), nestedRecord, record, accessor);
}
} else {
record = accessor.getRecordFactory().createMappedRecord(getInputRecordName());
for (int index = 0; index < getArgumentNames().size(); index++) {
String parameterName = getArgumentNames().get(index);
Object parameter = getParameters().get(index);
// If no arguments were passed to the call execution find the parameter from the row.
if ((parameter == null) && (getInputRow() != null)) {
parameter = getInputRow().get(parameterName);
}
// Allow for conversion of nested rows into nested records.
parameter = createRecordElement(parameterName, parameter, accessor);
// Allow for the platform to perform any platform specific record access.
accessor.getEISPlatform().setValueInRecord(parameterName, parameter, record, accessor);
}
}
return record;
} catch (ResourceException exception) {
throw EISException.resourceException(exception, accessor, null);
}
}
/**
* Create a mapped input record for this interaction.
* Populate the data into the record from this interaction's translation row.
*/
public jakarta.resource.cci.Record createTranslationRecord(AbstractRecord transaltionRow, EISAccessor accessor) {
return (MappedRecord)createRecordElement(getInputRecordName(), transaltionRow, accessor);
}
/**
* Build a database row from the record returned from the interaction.
*/
@Override
public AbstractRecord buildRow(jakarta.resource.cci.Record record, EISAccessor accessor) {
if (record == null) {
return null;
}
AbstractRecord row = null;
if (record instanceof IndexedRecord) {
IndexedRecord indexedRecord = (IndexedRecord)record;
if (indexedRecord.isEmpty()) {
return null;
}
if (indexedRecord.get(0) instanceof jakarta.resource.cci.Record) {
return buildRow((jakarta.resource.cci.Record)indexedRecord.get(0), accessor);
}
}
// If not a mapped record then just put it as a result value in the row.
if (!(record instanceof MappedRecord)) {
row = new DatabaseRecord(1);
row.put(getOutputResultPath(), record);
return row;
}
MappedRecord mappedRecord = (MappedRecord)record;
// The desired result is either the entire output record,
// or a translation of the output with the output arguments.
if (hasOutputArguments()) {
row = new DatabaseRecord(getOutputArgumentNames().size());
for (int index = 0; index < getOutputArgumentNames().size(); index++) {
DatabaseField field = getOutputArguments().get(index);
row.put(field, mappedRecord.get(getOutputArgumentNames().get(index)));
}
return row;
} else if (getOutputResultPath().length() > 0) {
// Extract the desired nested record from the output.
mappedRecord = (MappedRecord)mappedRecord.get(getOutputResultPath());
}
// Wrapped the record in a database to avoid lossing any information in conversion to database row,
// also gets around problem of some adatpers not supporting keySet or entrySet.
row = new EISMappedRecord(mappedRecord, accessor);
return row;
}
}