<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package org.pentaho.pac.server.biplatformproxy.xmlserializer;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.pac.client.scheduler.model.Schedule;
import org.pentaho.pac.common.SchedulerServiceException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SubscriptionXmlSerializer {

  private static final Log logger = LogFactory.getLog(SubscriptionXmlSerializer.class);
  private static final ThreadLocal&lt;SAXParserFactory&gt; SAX_FACTORY = new ThreadLocal&lt;SAXParserFactory&gt;();

  public SubscriptionXmlSerializer() {
    
  }
  
  public Map&lt;String,Schedule&gt; getSubscriptionSchedulesFromXml( String strXml ) throws XmlSerializerException, SchedulerServiceException
  {
    SubscriptionScheduleParserHandler subscriptionSchedHandler = null;
    try {
      detectSubscriptionExceptionInXml( strXml );
      subscriptionSchedHandler = parseSubscriptionScheduleJobsXml( strXml );
    } catch (SAXException e) {
      logger.error( e.getMessage() );
      throw new XmlSerializerException( e.getMessage() );
    } catch (IOException e) {
      logger.error( e.getMessage() );
      throw new XmlSerializerException( e.getMessage() );
    } catch (ParserConfigurationException e) {
      logger.error( e.getMessage() );
      throw new XmlSerializerException( e.getMessage() );
    }
    return subscriptionSchedHandler.schedules;
  }
  
  public void detectSubscriptionExceptionInXml( String strXml ) throws SchedulerServiceException {

    SubscriptionExceptionParserHandler exceptionHandler;
    try {
      exceptionHandler = parseSubscriptionExceptionXml( strXml );
    } catch (SAXException e) {
      logger.error( e.getMessage() );
      throw new SchedulerServiceException( e.getMessage() );
    } catch (IOException e) {
      logger.error( e.getMessage() );
      throw new SchedulerServiceException( e.getMessage() );
    } catch (ParserConfigurationException e) {
      logger.error( e.getMessage() );
      throw new SchedulerServiceException( e.getMessage() );
    }
    if ( null != exceptionHandler.exceptionMessage ) {
      throw new SchedulerServiceException( exceptionHandler.exceptionMessage );
    }
  }
  
  public void detectSubscriptionErrorInXml( String strXml ) throws SchedulerServiceException {

    SubscriptionErrorParserHandler errorHandler;
    try {
      errorHandler = parseSubscriptionErrorXml( strXml );
    } catch (SAXException e) {
      logger.error( e.getMessage() );
      throw new SchedulerServiceException( e.getMessage() );
    } catch (IOException e) {
      logger.error( e.getMessage() );
      throw new SchedulerServiceException( e.getMessage() );
    } catch (ParserConfigurationException e) {
      logger.error( e.getMessage() );
      throw new SchedulerServiceException( e.getMessage() );
    }
    if ( null != errorHandler.errorMessage ) {
      throw new SchedulerServiceException( errorHandler.errorMessage );
    }
  }

  /**
   * Get a SAX Parser Factory. This method implements a thread-relative
   * singleton.
   * 
   * NOTE: Need sax parser factory per thread for thread safety.
   * See: http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/parsers/SAXParserFactory.html
   * @return
   */
  private static SAXParserFactory getSAXParserFactory() {
    SAXParserFactory threadLocalSAXParserFactory = SAX_FACTORY.get();
    if ( null == threadLocalSAXParserFactory )
    {
      threadLocalSAXParserFactory = SAXParserFactory.newInstance();
      SAX_FACTORY.set( threadLocalSAXParserFactory );
    }
    return threadLocalSAXParserFactory;
  }
  
  private SubscriptionScheduleParserHandler parseSubscriptionScheduleJobsXml( String strXml ) throws SAXException, IOException, ParserConfigurationException
  {
      SAXParser parser = getSAXParserFactory().newSAXParser();
      SubscriptionScheduleParserHandler h = new SubscriptionScheduleParserHandler();
      // TODO sbarkdull, need to set encoding
//      String encoding = CleanXmlHelper.getEncoding( strXml );
//      InputStream is = new ByteArrayInputStream( strXml.getBytes( encoding ) );
      InputStream is = new ByteArrayInputStream( strXml.getBytes( "UTF-8" ) ); //$NON-NLS-1$
     
      parser.parse( is, h );
      return h;
  }
/*
  &lt;subscriptionAdmin&gt;
  &lt;listSchedules&gt;
    &lt;scheduledJobs&gt;
      &lt;job subscriberCount="0" triggerState="0"&gt;
        &lt;schedId&gt;eb7ef4b4-4867-11dd-8266-ff19a6feec31&lt;/schedId&gt;
        &lt;schedRef&gt;snb name 2&lt;/schedRef&gt;
        &lt;title&gt;snb title 2&lt;/title&gt;
        &lt;desc&gt;snb description 2&lt;/desc&gt;
        &lt;group&gt;snb group 2&lt;/group&gt;
        &lt;cron&gt;0 0 12 3 * ?&lt;/cron&gt;
        &lt;content&gt;
          &lt;action solution="samples" path="getting-started" action="HelloWorld.xaction" /&gt;
        &lt;/content&gt;
        &lt;nextFireTime&gt;Thu Jul 03 12:00:00 EDT 2008&lt;/nextFireTime&gt;
        &lt;prevFireTime&gt;Never&lt;/prevFireTime&gt;
        &lt;jobId&gt;snb name 2&lt;/jobId&gt;
      &lt;/job&gt;
    &lt;/scheduledJobs&gt;
    &lt;unScheduledJobs&gt;
      &lt;job subscriberCount="0" triggerState="-1"&gt;
        &lt;schedId&gt;da95463f-4867-11dd-8266-ff19a6feec31&lt;/schedId&gt;
        &lt;schedRef&gt;snb name&lt;/schedRef&gt;
        &lt;title&gt;snb title&lt;/title&gt;
        &lt;desc&gt;snb description&lt;/desc&gt;
        &lt;group&gt;snb group&lt;/group&gt;
        &lt;cron&gt;0 0 12 3 * *&lt;/cron&gt;
      &lt;/job&gt;
    &lt;/unScheduledJobs&gt;
    &lt;message result="WARNING"&gt;There are subscriptions that are not scheduled to run.&lt;/message&gt;
  &lt;/listSchedules&gt;
  &lt;message result="INFO"&gt;There is no subscription content defined.&lt;/message&gt;
  &lt;schedulerStatus state="0" /&gt;
  &lt;returnURL&gt;&amp;amp;schedulerAction=listSchedules&amp;amp;_TRUST_USER_=joe&lt;/returnURL&gt;
&lt;/subscriptionAdmin&gt;
*/
  private static class SubscriptionScheduleParserHandler extends DefaultHandler {

    public String currentText = null;
    public Map&lt;String,Schedule&gt; schedules = new HashMap&lt;String,Schedule&gt;();
    private Schedule currentSchedule = null;
    private boolean isInSubscriptionAdmin = false;
    private boolean isInListSchedules = false;
    private boolean isInScheduledJobs = false;
    private boolean isInContent = false;
    private List&lt;String&gt; actionList = null;
    
    public SubscriptionScheduleParserHandler()
    {
    }
  
    public void characters( char[] ch, int startIdx, int length )
    {
      currentText = String.valueOf( ch, startIdx, length );
    }
    
    public void endElement(String uri, String localName, String qName ) throws SAXException
    {
      if ( qName.equals( "subscriptionAdmin" ) ) { //$NON-NLS-1$
        isInSubscriptionAdmin = false;
      } else if ( qName.equals( "listSchedules" ) ) { //$NON-NLS-1$
        isInListSchedules = false;
      } else if ( qName.equals( "scheduledJobs" ) ) { //$NON-NLS-1$
        isInScheduledJobs = false;
      } else {
        if ( isInSubscriptionAdmin &amp;&amp; isInListSchedules &amp;&amp; isInScheduledJobs ) {
          if ( qName.equals( "job" ) ) { //$NON-NLS-1$
            assert currentSchedule.getJobName() != null : "Error, job name cannot be null."; //$NON-NLS-1$
            schedules.put( currentSchedule.getJobName(), currentSchedule );
            currentSchedule = null;
          } else if ( qName.equals( "schedId" ) ) { //$NON-NLS-1$
            currentSchedule.setSchedId( currentText );
          } else if ( qName.equals( "schedRef" ) ) { //$NON-NLS-1$
            currentSchedule.setJobName( currentText );
            currentSchedule.setTriggerName( currentText );
          } else if ( qName.equals( "title" ) ) { //$NON-NLS-1$
            currentSchedule.setTitle( currentText );
          } else if ( qName.equals( "desc" ) ) { //$NON-NLS-1$
            currentSchedule.setDescription( currentText );
          } else if ( qName.equals( "group" ) ) { //$NON-NLS-1$
            currentSchedule.setJobGroup( currentText );
          } else if ( qName.equals( "cron" ) ) { //$NON-NLS-1$
            currentSchedule.setCronString( currentText );
          } else if ( qName.equals( "repeat-count" ) ) { //$NON-NLS-1$
            currentSchedule.setRepeatCount( currentText );
          } else if ( qName.equals( "repeat-time-millisecs" ) ) { //$NON-NLS-1$
            currentSchedule.setRepeatInterval( currentText );
          } else if ( qName.equals( "nextFireTime" ) ) { //$NON-NLS-1$
            currentSchedule.setNextFireTime( currentText );
          } else if ( qName.equals( "prevFireTime" ) ) { //$NON-NLS-1$
            currentSchedule.setPrevFireTime( currentText );
          } else if ( qName.equals( "jobId" ) ) { //$NON-NLS-1$
            currentSchedule.setJobName( currentText );
          } else if ( qName.equals( "start-date" ) ) { //$NON-NLS-1$
            currentSchedule.setStartDate( currentText );
          } else if ( qName.equals( "end-date" ) ) { //$NON-NLS-1$
            currentSchedule.setEndDate( currentText );  
          } else if ( qName.equals( "content" ) ) { //$NON-NLS-1$
            isInContent = false;
            currentSchedule.setActionsList( actionList );
            actionList = null;
          }
        }
      }
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    {
      if ( qName.equals( "subscriptionAdmin" ) ) { //$NON-NLS-1$
        isInSubscriptionAdmin = true;
      } else if ( qName.equals( "listSchedules" ) ) { //$NON-NLS-1$
        isInListSchedules = true;
      } else if ( qName.equals( "scheduledJobs" ) ) { //$NON-NLS-1$
        isInScheduledJobs = true;
      } else {
        if ( isInSubscriptionAdmin &amp;&amp; isInListSchedules &amp;&amp; isInScheduledJobs ) {
          if ( qName.equals( "job" ) ) { //$NON-NLS-1$
            currentSchedule = new Schedule();

            String val = attributes.getValue( "subscriberCount" ); //$NON-NLS-1$
            currentSchedule.setSubscriberCount( val );
            val = attributes.getValue( "triggerState" ); //$NON-NLS-1$
            currentSchedule.setTriggerState( XmlSerializerUtil.triggerInt2Name( val ) );
          } else if ( qName.equals( "content" ) ) { //$NON-NLS-1$
            isInContent = true;
            actionList = new ArrayList&lt;String&gt;();
          } else if ( qName.equals( "action" ) ) { //$NON-NLS-1$
            if ( isInContent ) {
              String solution = attributes.getValue( "solution" ); //$NON-NLS-1$
              String path = attributes.getValue( "path" ); //$NON-NLS-1$
              String action = attributes.getValue( "action" ); //$NON-NLS-1$
              actionList.add( makePath( solution, path, action ));
            }
          }
        }
      }
    }
    private static String makePath( String solution, String path, String action ) {
      return solution + "/" + path + "/" + action;  //$NON-NLS-1$//$NON-NLS-2$
    }
  }
  
  private SubscriptionExceptionParserHandler parseSubscriptionExceptionXml( String strXml ) throws SAXException, IOException, ParserConfigurationException
  {
      SAXParser parser = getSAXParserFactory().newSAXParser();
      SubscriptionExceptionParserHandler h = new SubscriptionExceptionParserHandler();
      // TODO sbarkdull, need to set encoding
//      String encoding = CleanXmlHelper.getEncoding( strXml );
//      InputStream is = new ByteArrayInputStream( strXml.getBytes( encoding ) );
      InputStream is = new ByteArrayInputStream( strXml.getBytes( "UTF-8" ) ); //$NON-NLS-1$
     
      parser.parse( is, h );
      return h;
  }

  /**
   * &lt;exception&gt;
   *   &lt;message result="ERROR"&gt;
   *     Error, these parameters are missing: actionRefs
   *   &lt;/message&gt;
   * &lt;/exception&gt;
   *  
   * @author Steven Barkdull
   *
   */
  private static class SubscriptionExceptionParserHandler extends DefaultHandler {

    private String currentText = null;
    public String exceptionMessage = null;
    private boolean isException = false;
    private boolean isMessage = false;
    
    public SubscriptionExceptionParserHandler()
    {
    }
  
    public void characters( char[] ch, int startIdx, int length )
    {
      currentText = String.valueOf( ch, startIdx, length );
    }
    
    public void endElement(String uri, String localName, String qName ) throws SAXException
    {
      if ( qName.equals( "exception" ) ) { //$NON-NLS-1$
        isException = false;
      } else if ( qName.equals( "message" ) ) { //$NON-NLS-1$
        if ( isException &amp;&amp; isMessage ) {
          exceptionMessage = currentText;
        }
        isMessage = false;
      }
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    {
      if ( qName.equals( "exception" ) ) { //$NON-NLS-1$
        isException = true;
      } else if ( qName.equals( "message" ) ) { //$NON-NLS-1$
        isMessage = true;
      }
    }
  }
  
  private SubscriptionErrorParserHandler parseSubscriptionErrorXml( String strXml ) throws SAXException, IOException, ParserConfigurationException
  {
      SAXParser parser = getSAXParserFactory().newSAXParser();
      SubscriptionErrorParserHandler h = new SubscriptionErrorParserHandler();
      // TODO sbarkdull, need to set encoding
//      String encoding = CleanXmlHelper.getEncoding( strXml );
//      InputStream is = new ByteArrayInputStream( strXml.getBytes( encoding ) );
      InputStream is = new ByteArrayInputStream( strXml.getBytes( "UTF-8" ) ); //$NON-NLS-1$
     
      parser.parse( is, h );
      return h;
  }
  
  /**
   * &lt;?xml version="1.0" encoding="UTF-8"?&gt;
   * &lt;commandResult result="ERROR"&gt;
   *   &lt;message result="ERROR"&gt;
   *     Unable to complete request:
   *     org.hibernate.exception.ConstraintViolationException: could not
   *     delete:
   *     [org.pentaho.platform.repository.subscription.SubscribeContent#34c6b532-5cd5-11dd-9b0d-53348ed62413]
   *   &lt;/message&gt;
   * &lt;/commandResult&gt;
   * @author Steven Barkdull
   *
   */
  private static class SubscriptionErrorParserHandler extends DefaultHandler {

    private String currentText = null;
    public String errorMessage = null;
    private boolean isCommandResult = false;
    private boolean isErrorMessage = false;
    private boolean isMessage = false;
    
    public SubscriptionErrorParserHandler()
    {
    }
  
    public void characters( char[] ch, int startIdx, int length )
    {
      currentText = String.valueOf( ch, startIdx, length );
    }
    
    public void endElement(String uri, String localName, String qName ) throws SAXException
    {
      if ( qName.equals( "commandResult" ) ) { //$NON-NLS-1$
        isCommandResult = false;
      } else if ( qName.equals( "message" ) ) { //$NON-NLS-1$
        if ( isCommandResult &amp;&amp; isMessage &amp;&amp; isErrorMessage ) {
          errorMessage = currentText;
          isErrorMessage = false;
        }
        isMessage = false;
      }
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    {
      if ( qName.equals( "commandResult" ) ) { //$NON-NLS-1$
        isCommandResult = true;
      } else if ( qName.equals( "message" ) ) { //$NON-NLS-1$
        isMessage = true;
        // result="ERROR"
        isErrorMessage = attributes.getValue( "result" ).equals( "ERROR" ); //$NON-NLS-1$  //$NON-NLS-2$
      }
    }
  }

}</pre></body></html>