Package com.atomikos.icatch.admin.imp

Source Code of com.atomikos.icatch.admin.imp.AdminTool

/**
* Copyright (C) 2000-2010 Atomikos <info@atomikos.com>
*
* This code ("Atomikos TransactionsEssentials"), by itself,
* is being distributed under the
* Apache License, Version 2.0 ("License"), a copy of which may be found at
* http://www.atomikos.com/licenses/apache-license-2.0.txt .
* You may not use this file except in compliance with the License.
*
* While the License grants certain patent license rights,
* those patent license rights only extend to the use of
* Atomikos TransactionsEssentials by itself.
*
* This code (Atomikos TransactionsEssentials) contains certain interfaces
* in package (namespace) com.atomikos.icatch
* (including com.atomikos.icatch.Participant) which, if implemented, may
* infringe one or more patents held by Atomikos.
* It should be appreciated that you may NOT implement such interfaces;
* licensing to implement these interfaces must be obtained separately from Atomikos.
*
* 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.
*/

package com.atomikos.icatch.admin.imp;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ResourceBundle;
import java.util.Vector;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.atomikos.icatch.HeuristicMessage;
import com.atomikos.icatch.TxState;
import com.atomikos.icatch.admin.AdminTransaction;
import com.atomikos.icatch.admin.LogControl;
import com.atomikos.persistence.LogException;
import com.atomikos.swing.ExtensionsFileFilter;
import com.atomikos.swing.PropertiesPanel;
import com.atomikos.swing.PropertiesTableModel;
import com.atomikos.swing.PropertyListener;

/**
*
*
* An inspection tool for viewing and editing log contents. To be used with
* care, since editing can influence the 2PC interactions in the system!
*/

class AdminTool implements PropertyListener, ListSelectionListener
{
    private LogControl control_;
    // the tx service, null if standalone

    private JFrame frame_;

    private LocalLogAdministratorTableModel model_;

    private Vector data_;
    // the data, for easy editing of coordinator states
    // and easy inspection on selection of a row in the table

    private javax.swing.Timer timer_;
    // for refreshing table contents

    private JFileChooser fc_;
    // for keeping context of where to archive

    private PropertyListener pListener_;
    // the property listener
    // that listens on the state list on transaction inspection

    private ResourceBundle messages_;

    // locale-specific text

    /**
     * Check whether more info should be displayed for the given state. Based on
     * this value, a GUI indication will be shown that marks the row as having
     * details.
     */

    static boolean hasDetails ( int state )
    {
        boolean ret = false;
        switch ( state ) {
        case AdminTransaction.STATE_PREPARED:
            ret = true;
            break;
        case AdminTransaction.STATE_HEUR_MIXED:
            ret = true;
            break;
        case AdminTransaction.STATE_HEUR_HAZARD:
            ret = true;
            break;
        case AdminTransaction.STATE_HEUR_COMMITTED:
            ret = true;
            break;
        case AdminTransaction.STATE_HEUR_ABORTED:
            ret = true;
            break;
        case AdminTransaction.STATE_COMMITTING:
            ret = false;
            break;
        case AdminTransaction.STATE_ABORTING:
            ret = false;
            break;
        case AdminTransaction.STATE_TERMINATED:
            ret = false;
            break;

        default:
            break;
        }

        return ret;
    }

    /**
     * Convert the given int state.
     *
     * @param state
     *            The given int state.
     * @return Object The object state, or null if not found.
     */

    static Object convertState ( int state )
    {
        Object ret = TxState.ACTIVE;

        switch ( state ) {
        case AdminTransaction.STATE_PREPARED:
            ret = TxState.IN_DOUBT;
            break;
        case AdminTransaction.STATE_HEUR_MIXED:
            ret = TxState.HEUR_MIXED;
            break;
        case AdminTransaction.STATE_HEUR_HAZARD:
            ret = TxState.HEUR_HAZARD;
            break;
        case AdminTransaction.STATE_HEUR_COMMITTED:
            ret = TxState.HEUR_COMMITTED;
            break;
        case AdminTransaction.STATE_HEUR_ABORTED:
            ret = TxState.HEUR_ABORTED;
            break;
        case AdminTransaction.STATE_COMMITTING:
            ret = TxState.COMMITTING;
            break;
        case AdminTransaction.STATE_ABORTING:
            ret = TxState.ABORTING;
            break;
        case AdminTransaction.STATE_TERMINATED:
            ret = TxState.TERMINATED;
            break;

        default:
            break;
        }

        return ret;
    }

    private static StateDescriptor getStateDescriptor ( AdminTransaction tx ,
            int heuristicState )
    {
        Object state = convertState ( heuristicState );
        HeuristicMessage[] msgs = tx.getHeuristicMessages ( heuristicState );
        return new StateDescriptor ( state, msgs );
    }

    private static Vector getStateDescriptors ( Object admintx )
    {
        AdminTransaction tx = (AdminTransaction) admintx;
        Vector ret = new Vector ();
        StateDescriptor desc = null;

        desc = getStateDescriptor ( tx, AdminTransaction.STATE_HEUR_MIXED );
        if ( !(desc.messages == null || desc.messages.length == 0) )
            ret.addElement ( desc );

        desc = getStateDescriptor ( tx, AdminTransaction.STATE_HEUR_HAZARD );
        if ( !(desc.messages == null || desc.messages.length == 0) )
            ret.addElement ( desc );

        desc = getStateDescriptor ( tx, AdminTransaction.STATE_HEUR_COMMITTED );
        if ( !(desc.messages == null || desc.messages.length == 0) )
            ret.addElement ( desc );

        desc = getStateDescriptor ( tx, AdminTransaction.STATE_HEUR_ABORTED );
        if ( !(desc.messages == null || desc.messages.length == 0) )
            ret.addElement ( desc );

        desc = getStateDescriptor ( tx, AdminTransaction.STATE_TERMINATED );
        if ( !(desc.messages == null || desc.messages.length == 0) )
            ret.addElement ( desc );

        return ret;
    }

    private static JPanel getMessagePanel ( HeuristicMessage[] msgs )
    {
        MessageTableModel model = new MessageTableModel ( msgs );
        JTable table = new JTable ( model );
        table.setPreferredScrollableViewportSize ( new Dimension ( 300, 70 ) );
        JScrollPane scrollPane = new JScrollPane ( table );
        JPanel ret = new JPanel ();
        ret.setLayout ( new BorderLayout () );
        ret.add ( scrollPane, BorderLayout.CENTER );
        return ret;
    }

    AdminTool ( LogControl control )
    {
        messages_ = ResourceBundle
                .getBundle ( "com.atomikos.icatch.admin.imp.AdminToolResourceBundle" );
        frame_ = new JFrame ( messages_.getString ( "adminToolTitle" ) );
        control_ = control;
        // add timer to reflect updated tx states
        timer_ = new javax.swing.Timer ( 7000, new ActionListener () {
            public void actionPerformed ( ActionEvent evt )
            {
                // System.out.println ( "Timer refresh event" );
                model_.refresh ();
                // System.out.println ( "Timer refresh done" );
            }
        } );
        timer_.start ();
        init ();
    }

    private void init ()
    {
        JTable table = null;
        try {
            table = getJTable ();
        } catch ( LogException e ) {
            throw new RuntimeException ( e.getMessage () );
        }
        // Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane ( table );
        File tmpfile = new File ( "archive.txt" );
        try {
            tmpfile.createNewFile ();
        } catch ( IOException io ) {
            // file creation failed; this merely implies that no default archive
            // file exists
        }
        fc_ = new JFileChooser ( tmpfile );
        String[] extensions = { "txt" };
        fc_.setFileFilter ( new ExtensionsFileFilter ( extensions ) );
        fc_.setDialogTitle ( messages_.getString ( "appendDialogTitle" ) );
        fc_.setFileSelectionMode ( JFileChooser.FILES_ONLY );
        // Add the scroll pane to this window.
        frame_.getContentPane ().add ( scrollPane, BorderLayout.CENTER );

        frame_.addWindowListener ( new WindowAdapter () {

            public void windowClosing ( WindowEvent e )
            {
                if ( timer_ != null )
                    timer_.stop ();

            }
        } );
        frame_.pack ();
        frame_.setVisible ( true );
        pListener_ = this;
    }

    private void forget ( Object part , int row )
    {

        AdminTransaction p = (AdminTransaction) part;
        p.forceForget ();
        model_.rowDeleted ( row );

    }

    private void commit ( Object part , int row )
    {
        try {
            AdminTransaction p = (AdminTransaction) part;
            p.forceCommit ();
            model_.refresh ();
        } catch ( Exception e ) {
            e.printStackTrace ();
        }
    }

    private void rollback ( Object part , int row )
    {
        try {
            AdminTransaction p = (AdminTransaction) part;
            p.forceRollback ();
            model_.refresh ();
        } catch ( Exception e ) {
            e.printStackTrace ();
        }
    }

    private String getHeuristicDetails ( AdminTransaction p , int heuristicState )
    {
        StringBuffer ret = new StringBuffer ();
        HeuristicMessage[] msgs = p.getHeuristicMessages ( heuristicState );
        for ( int i = 0; i < msgs.length; i++ ) {
            if ( i == 0 )
                ret.append ( convertState ( heuristicState ) + ": " );
            ret.append ( msgs[i] );
            if ( i < msgs.length - 1 )
                ret.append ( " -- " );
        }
        return ret.toString ();
    }

    private String getMessages ( Object part )
    {
        HeuristicMessage[] msgs = null;
        StringBuffer ret = new StringBuffer ();

        AdminTransaction p = (AdminTransaction) part;
        Object state = convertState ( p.getState () );

        // in the general case, no distinction has to be made between different
        // outcomes of different participants.
        msgs = p.getHeuristicMessages ();

        if ( p.wasCommitted () )
            ret.append ( messages_.getString ( "commitAttemptedMessage" ) );
        else if ( p.getState () != AdminTransaction.STATE_PREPARED )
            ret.append ( messages_.getString ( "rollbackAttemptedMessage" ) );

        for ( int i = 0; i < msgs.length; i++ ) {
            ret.append ( msgs[i] );
            if ( i < msgs.length - 1 )
                ret.append ( " -- " );
        }
        if ( p.getState () == AdminTransaction.STATE_HEUR_MIXED
                || p.getState () == AdminTransaction.STATE_HEUR_HAZARD ) {

            // in this case, we should add extra information about
            // which task was in a different outcome
            ret.append ( messages_.getString ( "ofWhichMessage" ) );
            ret.append ( getHeuristicDetails ( p,
                    AdminTransaction.STATE_HEUR_COMMITTED ) );
            ret.append ( getHeuristicDetails ( p,
                    AdminTransaction.STATE_HEUR_ABORTED ) );
            ret.append ( getHeuristicDetails ( p,
                    AdminTransaction.STATE_HEUR_MIXED ) );
            ret.append ( getHeuristicDetails ( p,
                    AdminTransaction.STATE_HEUR_HAZARD ) );

        }

        return ret.toString ();

    }

    /**
     * Gets a JTable with 2 cols (1 for root ID, 1 for the global tx state). The
     * table has a row for each coordinator in the log.
     *
     * @return JTable The table.
     */

    private JTable getJTable () throws LogException
    {
        JTable table = null;
        // this will be the returned table
        Vector coordinators = new Vector ();

        AdminTransaction[] txs = control_.getAdminTransactions ();
        if ( txs != null && txs.length > 0 ) {
            for ( int i = 0; i < txs.length; i++ ) {
                coordinators.addElement ( txs[i] );
            }
        }
        data_ = coordinators;

        LocalLogAdministratorTableModel model = new LocalLogAdministratorTableModel (
                coordinators );

        table = new JTable ( model );
        table.setSelectionMode ( ListSelectionModel.SINGLE_SELECTION );
        // only a single row can be selected at a time
        model_ = model;

        ListSelectionModel rowSM = table.getSelectionModel ();

        rowSM.addListSelectionListener ( this );

        table.setPreferredScrollableViewportSize ( new Dimension ( 500, 70 ) );

        return table;
    }

    /**
     * @see ListSelectionListener
     */

    public void valueChanged ( ListSelectionEvent e )
    {
        processEvent ( e );
    }

    /**
     * Utility method to handle display event of one particular tx.
     *
     */

    void processEvent ( ListSelectionEvent e )
    {
        // Ignore extra messages.
        if ( e.getValueIsAdjusting () )
            return;

        try {
      ListSelectionModel lsm = (ListSelectionModel) e.getSource ();
      if ( lsm.isSelectionEmpty () ) {
          // no rows are selected
      } else {
          int selectedRow = lsm.getMinSelectionIndex ();
          AdminTransaction rec = (AdminTransaction) data_
                  .elementAt ( selectedRow );
          Object id = null;
          Object state = null;

          id = rec.getTid ();
          state = convertState ( rec.getState () );

          if ( !state.equals ( TxState.IN_DOUBT ) ) {
              if ( hasDetails ( rec.getState () ) ) {
                  Object[] options = {
                          messages_.getString ( "forgetNoArchiveOption" ),
                          messages_.getString ( "forgetAndArchiveOption" ),
                          messages_.getString ( "keepInLogOption" ) };
                  Vector descriptors = getStateDescriptors ( rec );
                  StateTableModel table = new StateTableModel ( descriptors );
                  PropertiesPanel panel = new PropertiesPanel ( table, true );
                  String outcome = null;
                  if ( rec.wasCommitted () )
                      outcome = messages_.getString ( "commitOutcomeMessage" );
                  else
                      outcome = messages_
                              .getString ( "rollbackOutcomeMessage" );
                  panel.addPropertyListener ( pListener_ );
                  int n = JOptionPane.showOptionDialog ( frame_, panel
                          .getPanel (), outcome + id.toString (),
                          JOptionPane.YES_NO_CANCEL_OPTION,
                          JOptionPane.QUESTION_MESSAGE, null, options,
                          options[2] );

                  if ( n == JOptionPane.YES_OPTION
                          || n == JOptionPane.NO_OPTION ) {
                      // System.out.println ( "Terminating transaction" );
                      if ( n == JOptionPane.NO_OPTION ) {
                          // ask user where to archive
                          fc_.setDialogTitle ( messages_
                                  .getString ( "appendDialogTitle" ) );
                          int ret = fc_.showOpenDialog ( frame_ );
                          if ( ret == JFileChooser.APPROVE_OPTION ) {
                              try {
                                  File file = fc_.getSelectedFile ();
                                  FileWriter writer = new FileWriter ( file
                                          .getPath (), true );
                                  writer
                                          .write ( messages_
                                                  .getString ( "rootTransactionMessage" )
                                                  + id.toString () + " " );
                                  writer.write ( getMessages ( data_
                                          .elementAt ( selectedRow ) ) );
                                  writer.write ( "\r" );
                                  writer.flush ();
                                  writer.close ();
                                  forget ( data_.elementAt ( selectedRow ),
                                          selectedRow );
                              } catch ( Exception err ) {
                                  err.printStackTrace ();
                              }
                          }
                      }

                      else {
                          // Forget no archive
                          forget ( data_.elementAt ( selectedRow ),
                                  selectedRow );
                      }
                  } else {
                      // CANCEL option -> just invalidate selection, to allow
                      // next pop-up to happen
                      lsm.removeSelectionInterval ( selectedRow, selectedRow );
                  }
              } else {
                //no details available -> show warning for the user
                String message = messages_.getString ( "noDetailsAvailableMessage" );
                String title = messages_.getString( "noDetailsAvailableTitle" );
                JOptionPane.showMessageDialog (
                          frame_ , message , title , JOptionPane.INFORMATION_MESSAGE );
              }
          } else {
              // indoubt instance -> present commit/rollback/keep option
              Object[] options = { messages_.getString ( "commitOption" ),
                      messages_.getString ( "rollbackOption" ),
                      messages_.getString ( "keepInLogOption" ) };
              AdminTransaction tx = (AdminTransaction) data_
                      .elementAt ( selectedRow );
              JPanel panel = getMessagePanel ( tx.getHeuristicMessages () );

              int n = JOptionPane
                      .showOptionDialog ( frame_, panel, messages_
                              .getString ( "selectedTransactionMessage" )
                              + id.toString (),
                              JOptionPane.YES_NO_CANCEL_OPTION,
                              JOptionPane.QUESTION_MESSAGE, null, options,
                              options[2] );

              if ( n == JOptionPane.YES_OPTION ) {
                  commit ( data_.elementAt ( selectedRow ), selectedRow );
              } else if ( n == JOptionPane.NO_OPTION ) {
                  rollback ( data_.elementAt ( selectedRow ), selectedRow );
              }
              // CANCEL option -> just invalidate selection, to allow next
              // pop-up to happen
              lsm.removeSelectionInterval ( selectedRow, selectedRow );
          }

          // clear the selection in order to allow new selection events
          // IMPORTANT to allow re-selection events!
          lsm.clearSelection ();
      }
    } catch ( Exception err ) {
      err.printStackTrace();
    }

    }

    /**
     * @see PropertyListener
     */

    public void newProperty ( PropertiesTableModel model )
    {
        throw new RuntimeException ( "Should not be called" );
    }

    /**
     * @see PropertyListener
     */

    public void deleteProperty ( PropertiesTableModel model , int index )
    {
        throw new RuntimeException ( "Should not be called" );
    }

    /**
     * @see PropertyListener
     */

    public void editProperty ( PropertiesTableModel model , int index )
    {
        Vector data = ((StateTableModel) model).getData ();
        StateDescriptor desc = (StateDescriptor) data.elementAt ( index );
        JPanel panel = getMessagePanel ( desc.messages );
        int answer = JOptionPane.showConfirmDialog ( frame_, panel, messages_
                .getString ( "stateDetailsTitle" ), JOptionPane.PLAIN_MESSAGE );

    }

}
TOP

Related Classes of com.atomikos.icatch.admin.imp.AdminTool

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.