Package org.hornetq.tools

Source Code of org.hornetq.tools.XmlDataExporter$PrettyPrintHandler

/*
* Copyright 2010 Red Hat, Inc.
* Red Hat licenses this file to you 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.
*/

package org.hornetq.tools;

import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.hornetq.api.core.HornetQBuffer;
import org.hornetq.api.core.HornetQBuffers;
import org.hornetq.api.core.HornetQException;
import org.hornetq.api.core.Message;
import org.hornetq.api.core.Pair;
import org.hornetq.api.core.SimpleString;
import org.hornetq.api.jms.JMSFactoryType;
import org.hornetq.core.config.Configuration;
import org.hornetq.core.config.impl.ConfigurationImpl;
import org.hornetq.core.journal.Journal;
import org.hornetq.core.journal.PreparedTransactionInfo;
import org.hornetq.core.journal.RecordInfo;
import org.hornetq.core.journal.SequentialFileFactory;
import org.hornetq.core.journal.TransactionFailureCallback;
import org.hornetq.core.journal.impl.JournalImpl;
import org.hornetq.core.journal.impl.NIOSequentialFileFactory;
import org.hornetq.core.message.BodyEncoder;
import org.hornetq.core.paging.PagedMessage;
import org.hornetq.core.paging.PagingManager;
import org.hornetq.core.paging.PagingStore;
import org.hornetq.core.paging.PagingStoreFactory;
import org.hornetq.core.paging.cursor.PagePosition;
import org.hornetq.core.paging.cursor.impl.PagePositionImpl;
import org.hornetq.core.paging.impl.Page;
import org.hornetq.core.paging.impl.PageTransactionInfoImpl;
import org.hornetq.core.paging.impl.PagingManagerImpl;
import org.hornetq.core.paging.impl.PagingStoreFactoryNIO;
import org.hornetq.core.persistence.StorageManager;
import org.hornetq.core.persistence.impl.journal.DescribeJournal;
import org.hornetq.core.persistence.impl.journal.DescribeJournal.MessageDescribe;
import org.hornetq.core.persistence.impl.journal.DescribeJournal.ReferenceDescribe;
import org.hornetq.core.persistence.impl.journal.JournalRecordIds;
import org.hornetq.core.persistence.impl.journal.JournalStorageManager;
import org.hornetq.core.persistence.impl.journal.JournalStorageManager.AckDescribe;
import org.hornetq.core.persistence.impl.journal.JournalStorageManager.CursorAckRecordEncoding;
import org.hornetq.core.persistence.impl.journal.JournalStorageManager.PageUpdateTXEncoding;
import org.hornetq.core.persistence.impl.journal.JournalStorageManager.PersistentQueueBindingEncoding;
import org.hornetq.core.persistence.impl.nullpm.NullStorageManager;
import org.hornetq.core.server.HornetQServerLogger;
import org.hornetq.core.server.JournalType;
import org.hornetq.core.server.LargeServerMessage;
import org.hornetq.core.server.ServerMessage;
import org.hornetq.core.settings.HierarchicalRepository;
import org.hornetq.core.settings.impl.AddressSettings;
import org.hornetq.core.settings.impl.HierarchicalObjectRepository;
import org.hornetq.jms.persistence.config.PersistedConnectionFactory;
import org.hornetq.jms.persistence.config.PersistedDestination;
import org.hornetq.jms.persistence.config.PersistedJNDI;
import org.hornetq.jms.persistence.config.PersistedType;
import org.hornetq.jms.persistence.impl.journal.JMSJournalStorageManagerImpl;
import org.hornetq.utils.Base64;
import org.hornetq.utils.ExecutorFactory;

/**
* Read the journal, page, and large-message data from a stopped instance of HornetQ and save it in an XML format to
* a file.  It uses the StAX <code>javax.xml.stream.XMLStreamWriter</code> for speed and simplicity.  Output can be
* read by <code>org.hornetq.core.persistence.impl.journal.XmlDataImporter</code>.
*
* @author Justin Bertram
*/
public final class XmlDataExporter
{
   // Constants -----------------------------------------------------

   private static final Long LARGE_MESSAGE_CHUNK_SIZE = 1000L;

   // Attributes ----------------------------------------------------

   private final JournalStorageManager storageManager;

   private final Configuration config;

   private final XMLStreamWriter xmlWriter;

   // an inner map of message refs hashed by the queue ID to which they belong and then hashed by their record ID
   private final Map<Long, HashMap<Long, ReferenceDescribe>> messageRefs;

   // map of all message records hashed by their record ID (which will match the record ID of the message refs)
   private final HashMap<Long, Message> messages;

   private final Map<Long, Set<PagePosition>> cursorRecords;

   private final Set<Long> pgTXs;

   final HashMap<Long, PersistentQueueBindingEncoding> queueBindings;

   private final Map<String, PersistedConnectionFactory> jmsConnectionFactories = new ConcurrentHashMap<>();

   private final Map<Pair<PersistedType, String>, PersistedDestination> jmsDestinations = new ConcurrentHashMap<>();

   private final Map<Pair<PersistedType, String>, PersistedJNDI> jmsJNDI = new ConcurrentHashMap<>();


   long messagesPrinted = 0L;

   long bindingsPrinted = 0L;

   // Static --------------------------------------------------------

   // Constructors --------------------------------------------------

   public XmlDataExporter(OutputStream out, String bindingsDir, String journalDir, String pagingDir,
                          String largeMessagesDir) throws Exception
   {
      config = new ConfigurationImpl();
      config.setBindingsDirectory(bindingsDir);
      config.setJournalDirectory(journalDir);
      config.setPagingDirectory(pagingDir);
      config.setLargeMessagesDirectory(largeMessagesDir);
      config.setJournalType(JournalType.NIO);
      final ExecutorService executor = Executors.newFixedThreadPool(1);
      ExecutorFactory executorFactory = new ExecutorFactory()
      {
         public Executor getExecutor()
         {
            return executor;
         }
      };

      storageManager = new JournalStorageManager(config, executorFactory);

      messageRefs = new HashMap<>();

      messages = new HashMap<>();

      cursorRecords = new HashMap<>();

      pgTXs = new HashSet<>();

      queueBindings = new HashMap<>();

      XMLOutputFactory factory = XMLOutputFactory.newInstance();
         XMLStreamWriter rawXmlWriter = factory.createXMLStreamWriter(out, "UTF-8");
         PrettyPrintHandler handler = new PrettyPrintHandler(rawXmlWriter);
         xmlWriter = (XMLStreamWriter) Proxy.newProxyInstance(
               XMLStreamWriter.class.getClassLoader(),
               new Class[]{XMLStreamWriter.class},
               handler);
   }

   // Public --------------------------------------------------------

   public static void main(String arg[])
   {
      if (arg.length < 4)
      {
         System.out.println("Use: java -cp hornetq-core.jar <bindings directory> <message directory> <page directory> <large-message directory>");
         System.exit(-1);
      }

      try
      {
         XmlDataExporter xmlDataExporter = new XmlDataExporter(System.out, arg[0], arg[1], arg[2], arg[3]);
         xmlDataExporter.writeXMLData();
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }

   public void writeXMLData() throws Exception
   {
      long start = System.currentTimeMillis();
      getBindings();
      getJmsBindings();
      processMessageJournal();
      printDataAsXML();
      HornetQServerLogger.LOGGER.debug("\n\nProcessing took: " + (System.currentTimeMillis() - start) + "ms");
      HornetQServerLogger.LOGGER.debug("Output " + messagesPrinted + " messages and " + bindingsPrinted + " bindings.");
   }

   /**
    * Read through the message journal and stuff all the events/data we care about into local data structures.  We'll
    * use this data later to print all the right information.
    *
    * @throws Exception will be thrown if anything goes wrong reading the journal
    */
   private void processMessageJournal() throws Exception
   {
      ArrayList<RecordInfo> acks = new ArrayList<>();

      List<RecordInfo> records = new LinkedList<>();

      // We load these, but don't use them.
      List<PreparedTransactionInfo> preparedTransactions = new LinkedList<>();

      Journal messageJournal = storageManager.getMessageJournal();

      HornetQServerLogger.LOGGER.debug("Reading journal from " + config.getJournalDirectory());

      messageJournal.start();

      // Just logging these, no action necessary
      TransactionFailureCallback transactionFailureCallback = new TransactionFailureCallback()
      {
         @Override
         public void failedTransaction(long transactionID, List<RecordInfo> records1, List<RecordInfo> recordsToDelete)
         {
            StringBuilder message = new StringBuilder();
            message.append("Encountered failed journal transaction: ").append(transactionID);
            for (int i = 0; i < records1.size(); i++)
            {
               if (i == 0)
               {
                  message.append("; Records: ");
               }
               message.append(records1.get(i));
               if (i != (records1.size() - 1))
               {
                  message.append(", ");
               }
            }

            for (int i = 0; i < recordsToDelete.size(); i++)
            {
               if (i == 0)
               {
                  message.append("; RecordsToDelete: ");
               }
               message.append(recordsToDelete.get(i));
               if (i != (recordsToDelete.size() - 1))
               {
                  message.append(", ");
               }
            }

            HornetQServerLogger.LOGGER.debug(message.toString());
         }
      };

      ((JournalImpl) messageJournal).load(records, preparedTransactions, transactionFailureCallback, false);

      // Since we don't use these nullify the reference so that the garbage collector can clean them up
      preparedTransactions = null;

      for (RecordInfo info : records)
      {
         byte[] data = info.data;

         HornetQBuffer buff = HornetQBuffers.wrappedBuffer(data);

         Object o = DescribeJournal.newObjectEncoding(info, storageManager);
         if (info.getUserRecordType() == JournalRecordIds.ADD_MESSAGE)
         {
            messages.put(info.id, ((MessageDescribe) o).getMsg());
         }
         else if (info.getUserRecordType() == JournalRecordIds.ADD_LARGE_MESSAGE)
         {
            messages.put(info.id, ((MessageDescribe) o).getMsg());
         }
         else if (info.getUserRecordType() == JournalRecordIds.ADD_REF)
         {
            ReferenceDescribe ref = (ReferenceDescribe) o;
            HashMap<Long, ReferenceDescribe> map = messageRefs.get(info.id);
            if (map == null)
            {
               HashMap<Long, ReferenceDescribe> newMap = new HashMap<>();
               newMap.put(ref.refEncoding.queueID, ref);
               messageRefs.put(info.id, newMap);
            }
            else
            {
               map.put(ref.refEncoding.queueID, ref);
            }
         }
         else if (info.getUserRecordType() == JournalRecordIds.ACKNOWLEDGE_REF)
         {
            acks.add(info);
         }
         else if (info.userRecordType == JournalRecordIds.ACKNOWLEDGE_CURSOR)
         {
            CursorAckRecordEncoding encoding = new CursorAckRecordEncoding();
            encoding.decode(buff);

            Set<PagePosition> set = cursorRecords.get(encoding.queueID);

            if (set == null)
            {
               set = new HashSet<>();
               cursorRecords.put(encoding.queueID, set);
            }

            set.add(encoding.position);
         }
         else if (info.userRecordType == JournalRecordIds.PAGE_TRANSACTION)
         {
            if (info.isUpdate)
            {
               PageUpdateTXEncoding pageUpdate = new PageUpdateTXEncoding();

               pageUpdate.decode(buff);
               pgTXs.add(pageUpdate.pageTX);
            }
            else
            {
               PageTransactionInfoImpl pageTransactionInfo = new PageTransactionInfoImpl();

               pageTransactionInfo.decode(buff);

               pageTransactionInfo.setRecordID(info.id);
               pgTXs.add(pageTransactionInfo.getTransactionID());
            }
         }
      }

      messageJournal.stop();

      removeAcked(acks);
   }

   /**
    * Go back through the messages and message refs we found in the journal and remove the ones that have been acked.
    *
    * @param acks the list of ack records we got from the journal
    */
   private void removeAcked(ArrayList<RecordInfo> acks)
   {
      for (RecordInfo info : acks)
      {
         AckDescribe ack = (AckDescribe)DescribeJournal.newObjectEncoding(info, null);
         HashMap<Long, ReferenceDescribe> referenceDescribeHashMap = messageRefs.get(info.id);
         referenceDescribeHashMap.remove(ack.refEncoding.queueID);
         if (referenceDescribeHashMap.size() == 0)
         {
            messages.remove(info.id);
            messageRefs.remove(info.id);
         }
      }
   }

   private void getJmsBindings() throws Exception
   {
      SequentialFileFactory bindingsJMS = new NIOSequentialFileFactory(config.getBindingsDirectory());

      Journal jmsJournal = new JournalImpl(1024 * 1024,
            2,
            config.getJournalCompactMinFiles(),
            config.getJournalCompactPercentage(),
            bindingsJMS,
            "hornetq-jms",
            "jms",
            1);

      jmsJournal.start();

      List<RecordInfo> data = new ArrayList<>();

      ArrayList<PreparedTransactionInfo> list = new ArrayList<>();

      HornetQServerLogger.LOGGER.debug("Reading jms bindings journal from " + config.getBindingsDirectory());

      jmsJournal.load(data, list, null);

      for (RecordInfo record : data)
      {
         long id = record.id;

         HornetQBuffer buffer = HornetQBuffers.wrappedBuffer(record.data);

         byte rec = record.getUserRecordType();

         if (rec == JMSJournalStorageManagerImpl.CF_RECORD)
         {
            PersistedConnectionFactory cf = new PersistedConnectionFactory();
            cf.decode(buffer);
            cf.setId(id);
            HornetQServerLogger.LOGGER.info("Found JMS connection factory: " + cf.getName());
            jmsConnectionFactories.put(cf.getName(), cf);
         }
         else if(rec == JMSJournalStorageManagerImpl.DESTINATION_RECORD)
         {
            PersistedDestination destination = new PersistedDestination();
            destination.decode(buffer);
            destination.setId(id);
            HornetQServerLogger.LOGGER.info("Found JMS destination: " + destination.getName());
            jmsDestinations.put(new Pair<>(destination.getType(), destination.getName()), destination);
         }
         else if (rec == JMSJournalStorageManagerImpl.JNDI_RECORD)
         {
            PersistedJNDI jndi = new PersistedJNDI();
            jndi.decode(buffer);
            jndi.setId(id);
            Pair<PersistedType, String> key = new Pair<>(jndi.getType(), jndi.getName());
            StringBuilder builder = new StringBuilder();
            for (String binding : jndi.getJndi())
            {
               builder.append(binding).append(" ");
            }
            HornetQServerLogger.LOGGER.info("Found JMS JNDI binding data for " + jndi.getType() + " " + jndi.getName() + ": " + builder.toString());
            jmsJNDI.put(key, jndi);
         }
         else
         {
            throw new IllegalStateException("Invalid record type " + rec);
         }

      }
   }

   /**
    * Open the bindings journal and extract all bindings data.
    *
    * @throws Exception will be thrown if anything goes wrong reading the bindings journal
    */
   private void getBindings() throws Exception
   {
      List<RecordInfo> records = new LinkedList<>();

      Journal bindingsJournal = storageManager.getBindingsJournal();

      bindingsJournal.start();

      HornetQServerLogger.LOGGER.debug("Reading bindings journal from " + config.getBindingsDirectory());

      ((JournalImpl) bindingsJournal).load(records, null, null, false);

      for (RecordInfo info : records)
      {
         if (info.getUserRecordType() == JournalRecordIds.QUEUE_BINDING_RECORD)
         {
            PersistentQueueBindingEncoding bindingEncoding =
                     (PersistentQueueBindingEncoding)DescribeJournal.newObjectEncoding(info, null);
            queueBindings.put(bindingEncoding.getId(), bindingEncoding);
         }
      }

      bindingsJournal.stop();
   }

   private void printDataAsXML()
   {
      try
      {
         xmlWriter.writeStartDocument(XmlDataConstants.XML_VERSION);
         xmlWriter.writeStartElement(XmlDataConstants.DOCUMENT_PARENT);
         printBindingsAsXML();
         printJmsConnectionFactoriesAsXML();
         printJmsDestinationsAsXML();
         printAllMessagesAsXML();
         xmlWriter.writeEndElement(); // end DOCUMENT_PARENT
         xmlWriter.writeEndDocument();
         xmlWriter.flush();
         xmlWriter.close();
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }

   private void printBindingsAsXML() throws XMLStreamException
   {
      xmlWriter.writeStartElement(XmlDataConstants.BINDINGS_PARENT);
      for (Map.Entry<Long, PersistentQueueBindingEncoding> queueBindingEncodingEntry : queueBindings.entrySet())
      {
         PersistentQueueBindingEncoding bindingEncoding = queueBindings.get(queueBindingEncodingEntry.getKey());
         xmlWriter.writeEmptyElement(XmlDataConstants.BINDINGS_CHILD);
         xmlWriter.writeAttribute(XmlDataConstants.BINDING_ADDRESS, bindingEncoding.getAddress().toString());
         String filter = "";
         if (bindingEncoding.getFilterString() != null)
         {
            filter = bindingEncoding.getFilterString().toString();
         }
         xmlWriter.writeAttribute(XmlDataConstants.BINDING_FILTER_STRING, filter);
         xmlWriter.writeAttribute(XmlDataConstants.BINDING_QUEUE_NAME, bindingEncoding.getQueueName().toString());
         xmlWriter.writeAttribute(XmlDataConstants.BINDING_ID, Long.toString(bindingEncoding.getId()));
         bindingsPrinted++;
      }
      xmlWriter.writeEndElement(); // end BINDINGS_PARENT
   }

   private void printJmsConnectionFactoriesAsXML() throws XMLStreamException
   {
      xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORIES);
      for (String jmsConnectionFactoryKey : jmsConnectionFactories.keySet())
      {
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY);
         PersistedConnectionFactory jmsConnectionFactory = jmsConnectionFactories.get(jmsConnectionFactoryKey);
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_NAME);
         xmlWriter.writeCharacters(jmsConnectionFactory.getName());
         xmlWriter.writeEndElement();
         String clientID = jmsConnectionFactory.getConfig().getClientID();
         if (clientID != null)
         {
            xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CLIENT_ID);
            xmlWriter.writeCharacters(clientID);
            xmlWriter.writeEndElement();
         }

         long callFailoverTimeout = jmsConnectionFactory.getConfig().getCallFailoverTimeout();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CALL_FAILOVER_TIMEOUT);
         xmlWriter.writeCharacters(Long.toString(callFailoverTimeout));
         xmlWriter.writeEndElement();

         long callTimeout = jmsConnectionFactory.getConfig().getCallTimeout();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CALL_TIMEOUT);
         xmlWriter.writeCharacters(Long.toString(callTimeout));
         xmlWriter.writeEndElement();

         long clientFailureCheckPeriod = jmsConnectionFactory.getConfig().getClientFailureCheckPeriod();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CLIENT_FAILURE_CHECK_PERIOD);
         xmlWriter.writeCharacters(Long.toString(clientFailureCheckPeriod));
         xmlWriter.writeEndElement();

         int confirmationWindowSize = jmsConnectionFactory.getConfig().getConfirmationWindowSize();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CONFIRMATION_WINDOW_SIZE);
         xmlWriter.writeCharacters(Integer.toString(confirmationWindowSize));
         xmlWriter.writeEndElement();

         long connectionTTL = jmsConnectionFactory.getConfig().getConnectionTTL();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CONNECTION_TTL);
         xmlWriter.writeCharacters(Long.toString(connectionTTL));
         xmlWriter.writeEndElement();

         long consumerMaxRate = jmsConnectionFactory.getConfig().getConsumerMaxRate();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CONSUMER_MAX_RATE);
         xmlWriter.writeCharacters(Long.toString(consumerMaxRate));
         xmlWriter.writeEndElement();

         long consumerWindowSize = jmsConnectionFactory.getConfig().getConsumerWindowSize();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CONSUMER_WINDOW_SIZE);
         xmlWriter.writeCharacters(Long.toString(consumerWindowSize));
         xmlWriter.writeEndElement();

         String discoveryGroupName = jmsConnectionFactory.getConfig().getDiscoveryGroupName();
         if (discoveryGroupName != null)
         {
            xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_DISCOVERY_GROUP_NAME);
            xmlWriter.writeCharacters(discoveryGroupName);
            xmlWriter.writeEndElement();
         }

         int dupsOKBatchSize = jmsConnectionFactory.getConfig().getDupsOKBatchSize();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_DUPS_OK_BATCH_SIZE);
         xmlWriter.writeCharacters(Integer.toString(dupsOKBatchSize));
         xmlWriter.writeEndElement();

         JMSFactoryType factoryType = jmsConnectionFactory.getConfig().getFactoryType();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_TYPE);
         xmlWriter.writeCharacters(Integer.toString(factoryType.intValue()));
         xmlWriter.writeEndElement();

         String groupID = jmsConnectionFactory.getConfig().getGroupID();
         if (groupID != null)
         {
            xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_GROUP_ID);
            xmlWriter.writeCharacters(groupID);
            xmlWriter.writeEndElement();
         }

         String loadBalancingPolicyClassName = jmsConnectionFactory.getConfig().getLoadBalancingPolicyClassName();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_LOAD_BALANCING_POLICY_CLASS_NAME);
         xmlWriter.writeCharacters(loadBalancingPolicyClassName);
         xmlWriter.writeEndElement();

         long maxRetryInterval = jmsConnectionFactory.getConfig().getMaxRetryInterval();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_MAX_RETRY_INTERVAL);
         xmlWriter.writeCharacters(Long.toString(maxRetryInterval));
         xmlWriter.writeEndElement();

         long minLargeMessageSize = jmsConnectionFactory.getConfig().getMinLargeMessageSize();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_MIN_LARGE_MESSAGE_SIZE);
         xmlWriter.writeCharacters(Long.toString(minLargeMessageSize));
         xmlWriter.writeEndElement();

         long producerMaxRate = jmsConnectionFactory.getConfig().getProducerMaxRate();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_PRODUCER_MAX_RATE);
         xmlWriter.writeCharacters(Long.toString(producerMaxRate));
         xmlWriter.writeEndElement();

         long producerWindowSize = jmsConnectionFactory.getConfig().getProducerWindowSize();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_PRODUCER_WINDOW_SIZE);
         xmlWriter.writeCharacters(Long.toString(producerWindowSize));
         xmlWriter.writeEndElement();

         long reconnectAttempts = jmsConnectionFactory.getConfig().getReconnectAttempts();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_RECONNECT_ATTEMPTS);
         xmlWriter.writeCharacters(Long.toString(reconnectAttempts));
         xmlWriter.writeEndElement();

         long retryInterval = jmsConnectionFactory.getConfig().getRetryInterval();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_RETRY_INTERVAL);
         xmlWriter.writeCharacters(Long.toString(retryInterval));
         xmlWriter.writeEndElement();

         double retryIntervalMultiplier = jmsConnectionFactory.getConfig().getRetryIntervalMultiplier();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_RETRY_INTERVAL_MULTIPLIER);
         xmlWriter.writeCharacters(Double.toString(retryIntervalMultiplier));
         xmlWriter.writeEndElement();

         long scheduledThreadPoolMaxSize = jmsConnectionFactory.getConfig().getScheduledThreadPoolMaxSize();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_SCHEDULED_THREAD_POOL_MAX_SIZE);
         xmlWriter.writeCharacters(Long.toString(scheduledThreadPoolMaxSize));
         xmlWriter.writeEndElement();

         long threadPoolMaxSize = jmsConnectionFactory.getConfig().getThreadPoolMaxSize();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_THREAD_POOL_MAX_SIZE);
         xmlWriter.writeCharacters(Long.toString(threadPoolMaxSize));
         xmlWriter.writeEndElement();

         long transactionBatchSize = jmsConnectionFactory.getConfig().getTransactionBatchSize();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_TRANSACTION_BATCH_SIZE);
         xmlWriter.writeCharacters(Long.toString(transactionBatchSize));
         xmlWriter.writeEndElement();

         boolean autoGroup = jmsConnectionFactory.getConfig().isAutoGroup();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_AUTO_GROUP);
         xmlWriter.writeCharacters(Boolean.toString(autoGroup));
         xmlWriter.writeEndElement();

         boolean blockOnAcknowledge = jmsConnectionFactory.getConfig().isBlockOnAcknowledge();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_BLOCK_ON_ACKNOWLEDGE);
         xmlWriter.writeCharacters(Boolean.toString(blockOnAcknowledge));
         xmlWriter.writeEndElement();

         boolean blockOnDurableSend = jmsConnectionFactory.getConfig().isBlockOnDurableSend();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_BLOCK_ON_DURABLE_SEND);
         xmlWriter.writeCharacters(Boolean.toString(blockOnDurableSend));
         xmlWriter.writeEndElement();

         boolean blockOnNonDurableSend = jmsConnectionFactory.getConfig().isBlockOnNonDurableSend();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_BLOCK_ON_NON_DURABLE_SEND);
         xmlWriter.writeCharacters(Boolean.toString(blockOnNonDurableSend));
         xmlWriter.writeEndElement();

         boolean cacheLargeMessagesClient = jmsConnectionFactory.getConfig().isCacheLargeMessagesClient();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CACHE_LARGE_MESSAGES_CLIENT);
         xmlWriter.writeCharacters(Boolean.toString(cacheLargeMessagesClient));
         xmlWriter.writeEndElement();

         boolean compressLargeMessages = jmsConnectionFactory.getConfig().isCompressLargeMessages();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_COMPRESS_LARGE_MESSAGES);
         xmlWriter.writeCharacters(Boolean.toString(compressLargeMessages));
         xmlWriter.writeEndElement();

         boolean failoverOnInitialConnection = jmsConnectionFactory.getConfig().isFailoverOnInitialConnection();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_FAILOVER_ON_INITIAL_CONNECTION);
         xmlWriter.writeCharacters(Boolean.toString(failoverOnInitialConnection));
         xmlWriter.writeEndElement();

         boolean ha = jmsConnectionFactory.getConfig().isHA();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_HA);
         xmlWriter.writeCharacters(Boolean.toString(ha));
         xmlWriter.writeEndElement();

         boolean preAcknowledge = jmsConnectionFactory.getConfig().isPreAcknowledge();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_PREACKNOWLEDGE);
         xmlWriter.writeCharacters(Boolean.toString(preAcknowledge));
         xmlWriter.writeEndElement();

         boolean useGlobalPools = jmsConnectionFactory.getConfig().isUseGlobalPools();
         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_USE_GLOBAL_POOLS);
         xmlWriter.writeCharacters(Boolean.toString(useGlobalPools));
         xmlWriter.writeEndElement();

         xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CONNECTORS);
         for (String connector : jmsConnectionFactory.getConfig().getConnectorNames())
         {
            xmlWriter.writeStartElement(XmlDataConstants.JMS_CONNECTION_FACTORY_CONNECTOR);
            xmlWriter.writeCharacters(connector);
            xmlWriter.writeEndElement();
         }
         xmlWriter.writeEndElement();

         xmlWriter.writeStartElement(XmlDataConstants.JMS_JNDI_ENTRIES);
         PersistedJNDI jndi = jmsJNDI.get(new Pair<>(PersistedType.ConnectionFactory, jmsConnectionFactory.getName()));
         for (String jndiEntry : jndi.getJndi())
         {
            xmlWriter.writeStartElement(XmlDataConstants.JMS_JNDI_ENTRY);
            xmlWriter.writeCharacters(jndiEntry);
            xmlWriter.writeEndElement();
         }
         xmlWriter.writeEndElement(); // end jndi-entries
         xmlWriter.writeEndElement(); // end JMS_CONNECTION_FACTORY
      }
      xmlWriter.writeEndElement();
   }

   private void printJmsDestinationsAsXML() throws XMLStreamException
   {
      xmlWriter.writeStartElement(XmlDataConstants.JMS_DESTINATIONS);
      for (Pair<PersistedType, String> jmsDestinationsKey : jmsDestinations.keySet())
      {
         PersistedDestination jmsDestination = jmsDestinations.get(jmsDestinationsKey);
         xmlWriter.writeStartElement(XmlDataConstants.JMS_DESTINATION);

         xmlWriter.writeStartElement(XmlDataConstants.JMS_DESTINATION_NAME);
         xmlWriter.writeCharacters(jmsDestination.getName());
         xmlWriter.writeEndElement();

         String selector = jmsDestination.getSelector();
         if (selector != null && selector.length() != 0)
         {
            xmlWriter.writeStartElement(XmlDataConstants.JMS_DESTINATION_SELECTOR);
            xmlWriter.writeCharacters(selector);
            xmlWriter.writeEndElement();
         }

         xmlWriter.writeStartElement(XmlDataConstants.JMS_DESTINATION_TYPE);
         xmlWriter.writeCharacters(jmsDestination.getType().toString());
         xmlWriter.writeEndElement();


         xmlWriter.writeStartElement(XmlDataConstants.JMS_JNDI_ENTRIES);
         PersistedJNDI jndi = jmsJNDI.get(new Pair<>(jmsDestination.getType(), jmsDestination.getName()));
         for (String jndiEntry : jndi.getJndi())
         {
            xmlWriter.writeStartElement(XmlDataConstants.JMS_JNDI_ENTRY);
            xmlWriter.writeCharacters(jndiEntry);
            xmlWriter.writeEndElement();
         }
         xmlWriter.writeEndElement(); // end jndi-entries
         xmlWriter.writeEndElement(); // end JMS_CONNECTION_FACTORY
      }
      xmlWriter.writeEndElement();
   }

   private void printAllMessagesAsXML() throws XMLStreamException
   {
      xmlWriter.writeStartElement(XmlDataConstants.MESSAGES_PARENT);

      // Order here is important.  We must process the messages from the journal before we process those from the page
      // files in order to get the messages in the right order.
      for (Map.Entry<Long, Message> messageMapEntry : messages.entrySet())
      {
         printSingleMessageAsXML((ServerMessage) messageMapEntry.getValue(), extractQueueNames(messageRefs.get(messageMapEntry.getKey())));
      }

      printPagedMessagesAsXML();

      xmlWriter.writeEndElement(); // end "messages"
   }

   /**
    * Reads from the page files and prints messages as it finds them (making sure to check acks and transactions
    * from the journal).
    */
   private void printPagedMessagesAsXML()
   {
      try
      {
         ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1);
         final ExecutorService executor = Executors.newFixedThreadPool(10);
         ExecutorFactory executorFactory = new ExecutorFactory()
         {
            public Executor getExecutor()
            {
               return executor;
            }
         };
         final StorageManager sm = new NullStorageManager();
         PagingStoreFactory pageStoreFactory =
                  new PagingStoreFactoryNIO(sm, config.getPagingDirectory(), 1000l, scheduled, executorFactory, false,
                                            null);
         HierarchicalRepository<AddressSettings> addressSettingsRepository = new HierarchicalObjectRepository<>();
         addressSettingsRepository.setDefault(new AddressSettings());
         PagingManager manager = new PagingManagerImpl(pageStoreFactory, addressSettingsRepository);

         manager.start();

         SimpleString stores[] = manager.getStoreNames();

         for (SimpleString store : stores)
         {
            PagingStore pageStore = manager.getPageStore(store);

            if (pageStore != null)
            {
               String folder = pageStore.getFolder();
               HornetQServerLogger.LOGGER.debug("Reading page store " + store + " folder = " + folder);

               int pageId = (int) pageStore.getFirstPage();
               for (int i = 0; i < pageStore.getNumberOfPages(); i++)
               {
                  HornetQServerLogger.LOGGER.debug("Reading page " + pageId);
                  Page page = pageStore.createPage(pageId);
                  page.open();
                  List<PagedMessage> messages = page.read(sm);
                  page.close();

                  int messageId = 0;

                  for (PagedMessage message : messages)
                  {
                     message.initMessage(sm);
                     long queueIDs[] = message.getQueueIDs();
                     List<String> queueNames = new ArrayList<>();
                     for (long queueID : queueIDs)
                     {
                        PagePosition posCheck = new PagePositionImpl(pageId, messageId);

                        boolean acked = false;

                        Set<PagePosition> positions = cursorRecords.get(queueID);
                        if (positions != null)
                        {
                           acked = positions.contains(posCheck);
                        }

                        if (!acked)
                        {
                           queueNames.add(queueBindings.get(queueID).getQueueName().toString());
                        }
                     }

                     if (queueNames.size() > 0 && (message.getTransactionID() == -1 || pgTXs.contains(message.getTransactionID())))
                     {
                        printSingleMessageAsXML(message.getMessage(), queueNames);
                     }

                     messageId++;
                  }

                  pageId++;
               }
            }
            else
            {
               HornetQServerLogger.LOGGER.debug("Page store was null");
            }
         }
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }

   private void printSingleMessageAsXML(ServerMessage message, List<String> queues) throws XMLStreamException
   {
      xmlWriter.writeStartElement(XmlDataConstants.MESSAGES_CHILD);
      printMessageAttributes(message);
      printMessageProperties(message);
      printMessageQueues(queues);
      printMessageBody(message);
      xmlWriter.writeEndElement(); // end MESSAGES_CHILD
      messagesPrinted++;
   }

   private void printMessageBody(ServerMessage message) throws XMLStreamException
   {
      xmlWriter.writeStartElement(XmlDataConstants.MESSAGE_BODY);

      if (message.isLargeMessage())
      {
         printLargeMessageBody((LargeServerMessage) message);
      }
      else
      {
         int size = message.getEndOfBodyPosition() - message.getBodyBuffer().readerIndex();
         byte[] buffer = new byte[size];
         message.getBodyBuffer().readBytes(buffer);

         xmlWriter.writeCData(encode(buffer));
      }
      xmlWriter.writeEndElement(); // end MESSAGE_BODY
   }

   private void printLargeMessageBody(LargeServerMessage message) throws XMLStreamException
   {
      xmlWriter.writeAttribute(XmlDataConstants.MESSAGE_IS_LARGE, Boolean.TRUE.toString());
      BodyEncoder encoder = null;

      try
      {
         encoder = message.getBodyEncoder();
         encoder.open();
         long totalBytesWritten = 0;
         Long bufferSize;
         long bodySize = encoder.getLargeBodySize();
         for (long i = 0; i < bodySize; i += LARGE_MESSAGE_CHUNK_SIZE)
         {
            Long remainder = bodySize - totalBytesWritten;
            if (remainder >= LARGE_MESSAGE_CHUNK_SIZE)
            {
               bufferSize = LARGE_MESSAGE_CHUNK_SIZE;
            }
            else
            {
               bufferSize = remainder;
            }
            HornetQBuffer buffer = HornetQBuffers.fixedBuffer(bufferSize.intValue());
            encoder.encode(buffer, bufferSize.intValue());
            xmlWriter.writeCData(encode(buffer.toByteBuffer().array()));
            totalBytesWritten += bufferSize;
         }
         encoder.close();
      }
      catch (HornetQException e)
      {
         e.printStackTrace();
      }
      finally
      {
         if (encoder != null)
         {
            try
            {
               encoder.close();
            }
            catch (HornetQException e)
            {
               e.printStackTrace();
            }
         }
      }
   }

   private void printMessageQueues(List<String> queues) throws XMLStreamException
   {
      xmlWriter.writeStartElement(XmlDataConstants.QUEUES_PARENT);
      for (String queueName : queues)
      {
         xmlWriter.writeEmptyElement(XmlDataConstants.QUEUES_CHILD);
         xmlWriter.writeAttribute(XmlDataConstants.QUEUE_NAME, queueName);
      }
      xmlWriter.writeEndElement(); // end QUEUES_PARENT
   }

   private void printMessageProperties(ServerMessage message) throws XMLStreamException
   {
      xmlWriter.writeStartElement(XmlDataConstants.PROPERTIES_PARENT);
      for (SimpleString key : message.getPropertyNames())
      {
         Object value = message.getObjectProperty(key);
         xmlWriter.writeEmptyElement(XmlDataConstants.PROPERTIES_CHILD);
         xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_NAME, key.toString());
         if (value instanceof byte[])
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_VALUE, encode((byte[]) value));
         }
         else
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_VALUE, value.toString());
         }

         if (value instanceof Boolean)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_BOOLEAN);
         }
         else if (value instanceof Byte)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_BYTE);
         }
         else if (value instanceof Short)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_SHORT);
         }
         else if (value instanceof Integer)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_INTEGER);
         }
         else if (value instanceof Long)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_LONG);
         }
         else if (value instanceof Float)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_FLOAT);
         }
         else if (value instanceof Double)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_DOUBLE);
         }
         else if (value instanceof String)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_STRING);
         }
         else if (value instanceof SimpleString)
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_SIMPLE_STRING);
         }
         else if (value instanceof byte[])
         {
            xmlWriter.writeAttribute(XmlDataConstants.PROPERTY_TYPE, XmlDataConstants.PROPERTY_TYPE_BYTES);
         }
      }
      xmlWriter.writeEndElement(); // end PROPERTIES_PARENT
   }

   private void printMessageAttributes(ServerMessage message) throws XMLStreamException
   {
      xmlWriter.writeAttribute(XmlDataConstants.MESSAGE_ID, Long.toString(message.getMessageID()));
      xmlWriter.writeAttribute(XmlDataConstants.MESSAGE_PRIORITY, Byte.toString(message.getPriority()));
      xmlWriter.writeAttribute(XmlDataConstants.MESSAGE_EXPIRATION, Long.toString(message.getExpiration()));
      xmlWriter.writeAttribute(XmlDataConstants.MESSAGE_TIMESTAMP, Long.toString(message.getTimestamp()));
      byte rawType = message.getType();
      String prettyType = XmlDataConstants.DEFAULT_TYPE_PRETTY;
      if (rawType == Message.BYTES_TYPE)
      {
         prettyType = XmlDataConstants.BYTES_TYPE_PRETTY;
      }
      else if (rawType == Message.MAP_TYPE)
      {
         prettyType = XmlDataConstants.MAP_TYPE_PRETTY;
      }
      else if (rawType == Message.OBJECT_TYPE)
      {
         prettyType = XmlDataConstants.OBJECT_TYPE_PRETTY;
      }
      else if (rawType == Message.STREAM_TYPE)
      {
         prettyType = XmlDataConstants.STREAM_TYPE_PRETTY;
      }
      else if (rawType == Message.TEXT_TYPE)
      {
         prettyType = XmlDataConstants.TEXT_TYPE_PRETTY;
      }
      xmlWriter.writeAttribute(XmlDataConstants.MESSAGE_TYPE, prettyType);
      if (message.getUserID() != null)
      {
         xmlWriter.writeAttribute(XmlDataConstants.MESSAGE_USER_ID, message.getUserID().toString());
      }
   }

   private List<String> extractQueueNames(HashMap<Long, ReferenceDescribe> refMap)
   {
      List<String> queues = new ArrayList<>();
      for (ReferenceDescribe ref : refMap.values())
      {
         queues.add(queueBindings.get(ref.refEncoding.queueID).getQueueName().toString());
      }
      return queues;
   }

   private static String encode(final byte[] data)
   {
      return Base64.encodeBytes(data, 0, data.length, Base64.DONT_BREAK_LINES | Base64.URL_SAFE);
   }

   // Inner classes -------------------------------------------------

   /**
    * Proxy to handle indenting the XML since <code>javax.xml.stream.XMLStreamWriter</code> doesn't support that.
    */
   static class PrettyPrintHandler implements InvocationHandler
   {
      private final XMLStreamWriter target;

      private int depth = 0;

      private static final char INDENT_CHAR = ' ';

      private static final String LINE_SEPARATOR = System.getProperty("line.separator");

      boolean wrap = true;


      public PrettyPrintHandler(XMLStreamWriter target)
      {
         this.target = target;
      }

      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
      {
         String m = method.getName();

         switch (m) {
            case "writeStartElement":
               target.writeCharacters(LINE_SEPARATOR);
               target.writeCharacters(indent(depth));

               depth++;
               break;
            case "writeEndElement":
               depth--;
               if (wrap) {
                  target.writeCharacters(LINE_SEPARATOR);
                  target.writeCharacters(indent(depth));
               }
               wrap = true;
               break;
            case "writeEmptyElement":
            case "writeCData":
               target.writeCharacters(LINE_SEPARATOR);
               target.writeCharacters(indent(depth));
               break;
            case "writeCharacters":
               wrap = false;
               break;
         }

         method.invoke(target, args);

         return null;
      }

      private String indent(int depth)
      {
         depth *= 3; // level of indentation
         char[] output = new char[depth];
         while (depth-- > 0)
         {
            output[depth] = INDENT_CHAR;
         }
         return new String(output);
      }
   }
}
TOP

Related Classes of org.hornetq.tools.XmlDataExporter$PrettyPrintHandler

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.