Package com.linkedin.databus2.ggParser.XmlStateMachine

Source Code of com.linkedin.databus2.ggParser.XmlStateMachine.TransactionState$PerSourceTransactionalUpdate

package com.linkedin.databus2.ggParser.XmlStateMachine;

/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.apache.log4j.Logger;

import com.linkedin.databus.monitoring.mbean.GGParserStatistics.TransactionInfo;
import com.linkedin.databus2.core.DatabusException;
import com.linkedin.databus2.producers.gg.GGEventGenerationFactory;


public class TransactionState extends AbstractStateTransitionProcessor
{
  public final static String MODULE = TransactionState.class.getName();
  public final static Logger LOG = Logger.getLogger(MODULE);
  public static final String TRANSACTIONTIMESTAMPATTR = "timestamp";
  //when calculating transaction size we need to adjust it for the size of the first element. See parseElement()
  public static final int TRANSACTION_ELEMENT_SIZE = "<transaction timestamp=\"2013-07-29:13:26:15.000000\">".length();
  public TransactionSuccessCallBack _transactionSuccessCallBack;
  private final long  UNINITIALIZEDTS = -1;
  private long _currentTimeStamp = UNINITIALIZEDTS;
  private String _lastSeenTimestampStr = null;
  private long _startTransProcessingTimeNs = 0; //nano seconds
  private long _startTransLocation = 0;
  private long _transactionSize = 0;


  public TransactionState(TransactionSuccessCallBack transactionSuccessCallBack)
  {
    super(STATETYPE.STARTELEMENT,TRANSACTION);
    _transactionSuccessCallBack = transactionSuccessCallBack;
  }

  public long getCurrentTimeStamp()
  {
    return _currentTimeStamp;
  }

  public String getLastSeenTxnTimestampStr()
  {
    return _lastSeenTimestampStr;
  }

  @Override
  public void cleanUpState(StateMachine stateMachine, XMLStreamReader xmlStreamReader)
  {
    _currentTimeStamp = UNINITIALIZEDTS;
    _startTransProcessingTimeNs = 0;
    _transactionSize = 0;
    _startTransLocation = 0;
  }

  @Override
  public void onEndElement(StateMachine stateMachine, XMLStreamReader xmlStreamReader)
      throws Exception
  {

    _currentStateType = STATETYPE.ENDELEMENT;
    if(LOG.isDebugEnabled())
       LOG.debug("The current transaction has " + stateMachine.dbUpdateState.getSourceDbUpdatesMap().size() + " DbUpdates");
    if(_transactionSuccessCallBack == null)
    {
      throw new DatabusException("No callback specified for the transaction state! Cannot proceed without a callback");
    }

    long endTransactionLocation = xmlStreamReader.getLocation().getCharacterOffset();
    _transactionSize =  endTransactionLocation - _startTransLocation;
    // collect stats
    long trTime = System.nanoTime() - _startTransProcessingTimeNs;
    long scn = stateMachine.dbUpdateState.getScn();
    TransactionInfo trInfo = new TransactionInfo(_transactionSize, trTime, _currentTimeStamp, scn);


    if(stateMachine.dbUpdateState.getSourceDbUpdatesMap().size() == 0)
    {
      if(LOG.isDebugEnabled())
         LOG.debug("The current transaction contains no dbUpdates, giving empty callback");
      _transactionSuccessCallBack.onTransactionEnd(null, trInfo);
    }
    else{
      List<PerSourceTransactionalUpdate> dbUpdates = sortDbUpdates(stateMachine.dbUpdateState.getSourceDbUpdatesMap());
      _transactionSuccessCallBack.onTransactionEnd(dbUpdates, trInfo);
    }

    stateMachine.dbUpdateState.cleanUpState(stateMachine,xmlStreamReader);
    cleanUpState(stateMachine,xmlStreamReader);
    xmlStreamReader.nextTag();
    setNextStateProcessor(stateMachine,xmlStreamReader);
  }

  @Override
  public void onStartElement(StateMachine stateMachine, XMLStreamReader xmlStreamReader)
      throws DatabusException, XMLStreamException
  {

    _currentStateType = STATETYPE.STARTELEMENT;
    for(int i = 0; i < xmlStreamReader.getAttributeCount() ; i++)
    {
      if(xmlStreamReader.getAttributeName(i).getLocalPart().equals(TRANSACTIONTIMESTAMPATTR))
      {
        StringBuilder timeStamp = new StringBuilder(xmlStreamReader.getAttributeValue(i));
        _lastSeenTimestampStr = timeStamp.toString();
        String correctedTimestamp = timeStamp.append("000").toString(); //The timestamp given by golden gate does not have nanoseconds accuracy needed by oracle timestamp
        _currentTimeStamp = GGEventGenerationFactory.ggTimeStampStringToNanoSeconds(correctedTimestamp);
      }
    }


    if(_currentTimeStamp == UNINITIALIZEDTS)
      throw new DatabusException("Unable to locate timestamp in the transaction tag in the xml");

    // start of new transaction
    if(_startTransProcessingTimeNs == 0) {
      _startTransProcessingTimeNs = System.nanoTime();
      _startTransLocation = xmlStreamReader.getLocation().getCharacterOffset();
      // this is location of the END of the <transaction timestamp="..."> entity
      // so we need to adjust the size of the transactions in bytes
      _startTransLocation -= TRANSACTION_ELEMENT_SIZE;
    }


    //create dbupdates list
    stateMachine.dbUpdateState.setSourceDbUpdatesMap(new HashMap<Integer, HashSet<DbUpdateState.DBUpdateImage>>());
    xmlStreamReader.nextTag();
    setNextStateProcessor(stateMachine,xmlStreamReader);
  }

  public void setCallBack(TransactionSuccessCallBack transactionSuccessCallBack)
  {
    _transactionSuccessCallBack = transactionSuccessCallBack;
  }

  private List<PerSourceTransactionalUpdate> sortDbUpdates(HashMap<Integer, HashSet<DbUpdateState.DBUpdateImage>> dbUpdates)
  {
    List<PerSourceTransactionalUpdate> sourceTransactionalUpdates = new ArrayList<PerSourceTransactionalUpdate>(dbUpdates.size());
    for(Map.Entry<Integer,HashSet<DbUpdateState.DBUpdateImage>> _entry: dbUpdates.entrySet())
    {
      sourceTransactionalUpdates.add(new PerSourceTransactionalUpdate(_entry.getKey(),_entry.getValue()));
    }
    Collections.sort(sourceTransactionalUpdates);
    return sourceTransactionalUpdates;
  }

  /**
   * The class is to hold the data associated with a particular source and the corrosponding dbUpdate
   */
  public static class PerSourceTransactionalUpdate implements Comparable<PerSourceTransactionalUpdate>{

    private int _sourceId;
    private Set<DbUpdateState.DBUpdateImage> _dbUpdate;


    public int getSourceId()
    {
      return _sourceId;
    }

    public Set<DbUpdateState.DBUpdateImage> getDbUpdatesSet()
    {
      return _dbUpdate;
    }

    public int getNumDbUpdates()
    {
      if ( null == _dbUpdate)
        return 0;

      return _dbUpdate.size();
    }

    public PerSourceTransactionalUpdate(int sourceId, Set<DbUpdateState.DBUpdateImage> dbUpdate)
    {
      this._sourceId = sourceId;
      this._dbUpdate = dbUpdate;
    }

    @Override
    public int compareTo(PerSourceTransactionalUpdate perSourceTransactionalUpdate)
    {
      if(this.getSourceId() == perSourceTransactionalUpdate.getSourceId())
      {
        LOG.error("The transactional update list cannot contain duplicate source IDs");
        return 0;
      }
      else if (this.getSourceId() < perSourceTransactionalUpdate.getSourceId())
        return -1;
      else
        return 1;
    }

    @Override
    public boolean equals(Object o)
    {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;

      PerSourceTransactionalUpdate that = (PerSourceTransactionalUpdate) o;

      if (_sourceId != that._sourceId) return false;
      if (_dbUpdate != null ? !_dbUpdate.equals(that._dbUpdate) : that._dbUpdate != null) return false;

      return true;
    }

    @Override
    public int hashCode()
    {
      int result = _sourceId;
      result = 31 * result + (_dbUpdate != null ? _dbUpdate.hashCode() : 0);
      return result;
    }
  }
}
TOP

Related Classes of com.linkedin.databus2.ggParser.XmlStateMachine.TransactionState$PerSourceTransactionalUpdate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.