gt:             MappedRecord mappedRecord = (MappedRecord)record;
context: /*******************************************************************************
   * Copyright (c) 1998, 2015 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 v1.0 and Eclipse Distribution License v. 1.0
   * which accompanies this distribution.
   * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
   * and the Eclipse Distribution License is available at
   * http://www.eclipse.org/org/documents/edl-v10.php.
   *
   * 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 10<i>g</i> (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 Record createInputRecord(EISAccessor accessor);
  
      /**
       * INTERNAL:
       * Build a database row from the record returned from the interaction.
       */
      public abstract AbstractRecord buildRow(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(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 Record) {
                      rows.addElement(buildRow((Record)element, accessor));
                  } else {
                      // It is a single row record.
                      rows.add(buildRow(record, accessor));
                      return rows;
                  }
              }
          } else if (record instanceof MappedRecord) {
  