private DataChunk readSamples(String channelName, Timestamp from) throws Exception {
    DataChunk chunk = new DataChunk(chunkSize);

    BufferedReader br = null;
    String currentLine = "";
    Timestamp lastIndex = indexes.floorKey(from);
    Integer lineToStart = lastIndex == null ? 1 : indexes.get(lastIndex);
    Integer lineNumber = -1;
    try {
      br = new BufferedReader(new FileReader(csvFile));
      while ((currentLine = br.readLine()) != null) {
        lineNumber++;
        if (lineNumber < lineToStart) continue;
        String[] columns = getColumns(currentLine);
        if (columns[channel_name] != null && columns[channel_name].equals(channelName)) {
          // Get time stamp
          final java.sql.Timestamp stamp = java.sql.Timestamp.valueOf(columns[smpl_time]);
          stamp.setNanos(Integer.valueOf(columns[nanosecs]));
          final Timestamp time = fromSQLTimestamp(stamp);
          if (time.compareTo(from) >= 0) {
            final VType value = decodeValue(columns, time);
            SourceData data = new SourceData(time, value);
            if (!chunk.add(data)) {
              TimeInterval i = chunk.getInterval();
              if (i != null) indexes.put(i.getEnd(), lineNumber);
              break;
            }
          }
        }
      }
    } finally {
      if (br != null) br.close();
    }
    return chunk;
  }
 /**
  * Add given info value to buffer, tweaking its time stamp if necessary
  *
  * @param value Value to archive
  * @return Value that was actually added, which may have adjusted time stamp
  */
 protected final VType addInfoToBuffer(VType value) {
   synchronized (this) {
     if (last_archived_value != null) {
       final Timestamp last = VTypeHelper.getTimestamp(last_archived_value);
       if (last.compareTo(VTypeHelper.getTimestamp(value)) >= 0) { // Patch the time stamp
         final Timestamp next = last.plus(TimeDuration.ofMillis(100));
         value = VTypeHelper.transformTimestamp(value, next);
       }
       // else: value is OK as is
     }
   }
   addValueToBuffer(value);
   return value;
 }
 /**
  * Check a received value for basic problems before passing it on to the sample mechanism
  *
  * @param value Value as received from network layer
  * @return Value to be used for archive
  */
 private VType checkReceivedValue(VType value) {
   if (value instanceof Time) {
     try {
       final Time time = (Time) value;
       // Invoke time.getTimestamp() to detect RuntimeError in VType 2013/11/01
       if (time.isTimeValid() && time.getTimestamp() != null) return value;
       else {
         trouble_sample_log.log("'" + getName() + "': Invalid time stamp ");
         value = VTypeHelper.transformTimestamp(value, Timestamp.now());
       }
     } catch (RuntimeException ex) {
       Logger.getLogger(getClass().getName())
           .log(Level.WARNING, "'" + getName() + "': Exception getting time stamp", ex);
       value = VTypeHelper.transformTimestamp(value, Timestamp.now());
     }
   } else trouble_sample_log.log("'" + getName() + "': Received no time information for " + value);
   return value;
 }
  /**
   * Given the time and first element of the sample, see if there are more array elements.
   *
   * @param stamp Time stamp of the sample
   * @param dbl0 Value of the first (maybe only) array element
   * @param severity Severity of the sample
   * @return Array with given element and maybe more.
   * @throws Exception on error, including 'cancel'
   */
  private double[] readArrayElements(
      final Timestamp stamp, final double dbl0, final AlarmSeverity severity) throws Exception {
    // For performance reasons, only look for array data until we hit a scalar sample.
    if (is_an_array == false) return new double[] {dbl0};

    // See if there are more array elements
    if (sel_array_samples == null) { // Lazy initialization
      sel_array_samples =
          reader.getConnection().prepareStatement(reader.getSQL().sample_sel_array_vals);
    }
    sel_array_samples.setInt(1, channel_id);
    sel_array_samples.setTimestamp(2, TimestampHelper.toSQLTimestamp(stamp));
    // MySQL keeps nanoseconds in designated column, not TIMESTAMP
    if (!reader.isOracle()) sel_array_samples.setInt(3, stamp.getNanoSec());

    // Assemble array of unknown size in ArrayList ....
    final ArrayList<Double> vals = new ArrayList<Double>();
    reader.addForCancellation(sel_array_samples);
    try {
      final ResultSet res = sel_array_samples.executeQuery();
      vals.add(new Double(dbl0));
      while (res.next()) vals.add(res.getDouble(1));
      res.close();
    } finally {
      reader.removeFromCancellation(sel_array_samples);
    }
    // Convert to plain double array
    final int N = vals.size();
    final double ret[] = new double[N];
    for (int i = 0; i < N; i++) ret[i] = vals.get(i).doubleValue();
    // Check if it's in fact just a scalar, and a valid one
    if (N == 1 && severity != AlarmSeverity.UNDEFINED) { // Found a perfect non-array sample:
      // Assume that the data is scalar, skip the array check from now on
      is_an_array = false;
    }
    return ret;
  }
 /**
  * @param time Timestamp to check
  * @return <code>true</code> if time is too far into the future; better ignore.
  */
 private boolean isFuturistic(final Timestamp time) {
   final long threshold =
       System.currentTimeMillis() / 1000 + EngineModel.getIgnoredFutureSeconds();
   return time.getSec() >= threshold;
 }
 private Timestamp fromSQLTimestamp(final java.sql.Timestamp sql_time) {
   final long millisecs = sql_time.getTime();
   final long seconds = millisecs / 1000;
   final int nanoseconds = sql_time.getNanos();
   return Timestamp.of(seconds, nanoseconds);
 }
/**
 * Represents the connection payload, which consists of the actual JCA Channel and the JCADataSource
 * (which can be used to extract configuration parameters).
 *
 * @author carcassi
 */
public class JCAConnectionPayload {
  private final JCADataSource jcaDataSource;
  private final Channel channel;
  private final boolean connected;
  private final boolean longString;
  private final DBRType fieldType;
  private final Timestamp eventTime = Timestamp.now();

  public JCAConnectionPayload(
      JCAChannelHandler channleHandler, Channel channel, JCAConnectionPayload previousPayload) {
    this.jcaDataSource = channleHandler.getJcaDataSource();
    this.channel = channel;
    this.connected =
        channel != null && channel.getConnectionState() == Channel.ConnectionState.CONNECTED;
    this.longString = channleHandler.isLongString();
    if (channel.getFieldType().getClass() == null && previousPayload != null) {
      // JNI sets the type to unknown on disconnect. We need
      // to remember the type before the disconnection
      this.fieldType = previousPayload.fieldType;
    } else {
      this.fieldType = channel.getFieldType();
    }
  }

  /**
   * The JCADataSource that is using the channel.
   *
   * @return the JCA data source
   */
  public JCADataSource getJcaDataSource() {
    return jcaDataSource;
  }

  /**
   * The JCA channel.
   *
   * @return JCA channel
   */
  public Channel getChannel() {
    return channel;
  }

  public DBRType getFieldType() {
    return fieldType;
  }

  /**
   * True if the channel is not null and the connection state is connected.
   *
   * @return ture if channel exists and is connected
   */
  public boolean isChannelConnected() {
    return connected;
  }

  /**
   * True if the channel is not null, connected, and can be written to.
   *
   * @return true if the channel is ready for write
   */
  public boolean isWriteConnected() {
    return isChannelConnected() && channel.getWriteAccess();
  }

  /**
   * Whether the message payload should be handled as a long string.
   *
   * @return true if long string support should be used
   */
  public boolean isLongString() {
    return longString;
  }

  /**
   * Returns the local time of the connection event.
   *
   * @return client connection/disconnection time
   */
  public Timestamp getEventTime() {
    return eventTime;
  }

  @Override
  public String toString() {
    return "JCAConnection [connected: "
        + isChannelConnected()
        + " writeConnected: "
        + isWriteConnected()
        + " channel: "
        + channel
        + "]";
  }
}