Package de.willuhn.jameica.hbci.synchronize.hbci

Source Code of de.willuhn.jameica.hbci.synchronize.hbci.HBCISynchronizeBackend$HBCIJobGroup$TaskHandleInit

/**********************************************************************
*
* Copyright (c) by Olaf Willuhn
* All rights reserved
*
**********************************************************************/

package de.willuhn.jameica.hbci.synchronize.hbci;

import java.io.Closeable;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.kapott.hbci.GV.HBCIJob;
import org.kapott.hbci.manager.HBCIHandler;

import de.willuhn.annotation.Lifecycle;
import de.willuhn.annotation.Lifecycle.Type;
import de.willuhn.io.IOUtil;
import de.willuhn.jameica.gui.GUI;
import de.willuhn.jameica.hbci.HBCI;
import de.willuhn.jameica.hbci.HBCIProperties;
import de.willuhn.jameica.hbci.PassportRegistry;
import de.willuhn.jameica.hbci.gui.DialogFactory;
import de.willuhn.jameica.hbci.passport.Passport;
import de.willuhn.jameica.hbci.passport.PassportHandle;
import de.willuhn.jameica.hbci.rmi.Konto;
import de.willuhn.jameica.hbci.server.hbci.AbstractHBCIJob;
import de.willuhn.jameica.hbci.synchronize.AbstractSynchronizeBackend;
import de.willuhn.jameica.hbci.synchronize.SynchronizeJobProvider;
import de.willuhn.jameica.hbci.synchronize.SynchronizeSession;
import de.willuhn.jameica.hbci.synchronize.jobs.SynchronizeJob;
import de.willuhn.jameica.messaging.QueryMessage;
import de.willuhn.jameica.system.Application;
import de.willuhn.jameica.system.OperationCanceledException;
import de.willuhn.logging.Level;
import de.willuhn.logging.Logger;
import de.willuhn.util.ApplicationException;
import de.willuhn.util.ProgressMonitor;

/**
* Synchronize-Backend fuer HBCI.
*/
@Lifecycle(Type.CONTEXT)
public class HBCISynchronizeBackend extends AbstractSynchronizeBackend
{
  /**
   * Queue, ueber die die rohen HBCI-Nachrichten getraced werden koennen.
   */
  public final static String HBCI_TRACE = "hibiscus.sync.hbci.trace";
 
  /**
   * @see de.willuhn.jameica.hbci.synchronize.SynchronizeBackend#getName()
   */
  public String getName()
  {
    return "HBCI";
  }

  /**
   * @see de.willuhn.jameica.hbci.synchronize.AbstractSynchronizeBackend#createJobGroup(de.willuhn.jameica.hbci.rmi.Konto)
   */
  protected de.willuhn.jameica.hbci.synchronize.AbstractSynchronizeBackend.JobGroup createJobGroup(Konto k)
  {
    return new HBCIJobGroup(k);
  }

  /**
   * @see de.willuhn.jameica.hbci.synchronize.AbstractSynchronizeBackend#getJobProviderInterface()
   */
  protected Class<? extends SynchronizeJobProvider> getJobProviderInterface()
  {
    return HBCISynchronizeJobProvider.class;
  }

  /**
   * @see de.willuhn.jameica.hbci.synchronize.AbstractSynchronizeBackend#getSynchronizeKonten(de.willuhn.jameica.hbci.rmi.Konto)
   */
  public List<Konto> getSynchronizeKonten(Konto k)
  {
    List<Konto> list = super.getSynchronizeKonten(k);
    List<Konto> result = new ArrayList<Konto>();

    // Wir wollen nur die Online-Konten haben
    for (Konto konto:list)
    {
      try
      {
        if (!konto.hasFlag(Konto.FLAG_OFFLINE))
          result.add(konto);
      }
      catch (RemoteException re)
      {
        Logger.error("unable to determine flags of konto",re);
      }
    }

    return result;
  }

  /**
   * @see de.willuhn.jameica.hbci.synchronize.SynchronizeBackend#create(java.lang.Class, de.willuhn.jameica.hbci.rmi.Konto)
   */
  public <T> T create(Class<? extends SynchronizeJob> type, Konto konto) throws ApplicationException
  {
    try
    {
      if (konto == null || konto.hasFlag(Konto.FLAG_OFFLINE) || konto.hasFlag(Konto.FLAG_DISABLED))
        throw new ApplicationException(i18n.tr("Das Konto ist ein Offline-Konto oder deaktiviert"));
    }
    catch (RemoteException re)
    {
      Logger.error("unable to check konto flags",re);
      throw new ApplicationException(i18n.tr("Der Gesch�ftsvorfall konnte nicht erstellt werden: {0}",re.getMessage()));
    }

    // aufgrund eines Bugs im SUN compiler muessen wir hier explizit casten.
    // Siehe https://bugs.eclipse.org/bugs/show_bug.cgi?id=98379
    // Ab Java 1.6.0_25 ist das gefixt. Aber es soll ja auch in aelteren Java-Versionen compilieren
    return(T) super.create(type,konto);
  }

  /**
   * @see de.willuhn.jameica.hbci.synchronize.SynchronizeBackend#supports(java.lang.Class, de.willuhn.jameica.hbci.rmi.Konto)
   */
  public boolean supports(Class<? extends SynchronizeJob> type, Konto konto)
  {
    try
    {
      if (konto == null || konto.hasFlag(Konto.FLAG_OFFLINE) || konto.hasFlag(Konto.FLAG_DISABLED))
        return false;
    }
    catch (RemoteException re)
    {
      Logger.error("unable to determine support for job type " + type,re);
      return false;
    }

    return super.supports(type,konto);
  }

  /**
   * @see de.willuhn.jameica.hbci.synchronize.AbstractSynchronizeBackend#execute(java.util.List)
   */
  public synchronized SynchronizeSession execute(List<SynchronizeJob> jobs) throws ApplicationException, OperationCanceledException
  {
    try
    {
      for (SynchronizeJob job:jobs)
      {
        Konto konto = job.getKonto();
        if (konto.hasFlag(Konto.FLAG_OFFLINE))
          throw new ApplicationException(i18n.tr("Das Konto ist ein Offline-Konto: {0}",konto.getLongName()));
      }
    }
    catch (RemoteException re)
    {
      Logger.error("error while performing synchronization",re);
      throw new ApplicationException(i18n.tr("Synchronisierung fehlgeschlagen: {0}",re.getMessage()));
    }

    return super.execute(jobs);
  }


  /**
   * Hilfsklasse, um die Jobs nach Konten zu gruppieren.
   */
  protected class HBCIJobGroup extends JobGroup implements Closeable
  {
    private List<AbstractHBCIJob> hbciJobs = new ArrayList<AbstractHBCIJob>();
    private PassportHandle handle = null;
    private HBCIHandler handler   = null;

    /**
     * ct.
     * @param k das Konto der Job-Gruppe.
     */
    private HBCIJobGroup(Konto k)
    {
      super(k);
    }

    /**
     * @see de.willuhn.jameica.hbci.synchronize.AbstractSynchronizeBackend.JobGroup#sync()
     */
    protected void sync() throws Exception
    {
      ////////////////////////////////////////////////////////////////////
      // lokale Variablen
      ProgressMonitor monitor = HBCISynchronizeBackend.this.worker.getMonitor();
     
      Application.getMessagingFactory().getMessagingQueue(HBCI_TRACE).sendMessage(new HBCITraceMessage(HBCITraceMessage.Type.ID,this.getKonto().getID()));
      Application.getMessagingFactory().getMessagingQueue(HBCI_TRACE).sendMessage(new HBCITraceMessage(HBCITraceMessage.Type.INFO,"\n\n" + i18n.tr("{0} Synchronisiere Konto: {1}",HBCI.LONGDATEFORMAT.format(new Date()),this.getKonto().getLongName())));

      // Wir ermitteln anhand der Gesamt-Anzahl von Jobs, wieviel Fortschritt
      // pro Job gemacht wird, addieren das fuer unsere Gruppe, ziehen noch
      // einen Teil fuer Passport-Initialisierung ab (3%) sowie 3% fuer die Job-Auswertung
      // und geben den Rest den Jobs in unserer Gruppe. Wir rechnen am Anfang erstmal mit Double,
      // um die Rundungsdifferenzen etwas kleiner zu halten
      double chunk = 100d / ((double) HBCISynchronizeBackend.this.worker.getSynchronization().size()) * ((double)this.jobs.size());
      int step     = (int) ((chunk - 6) / this.jobs.size());
      ////////////////////////////////////////////////////////////////////

      boolean haveError = false;
      boolean inCatch   = false;

      try
      {
        this.checkInterrupted();

        monitor.log(" ");
        monitor.log(i18n.tr("Synchronisiere Konto: {0}",this.getKonto().getLongName()));

        Passport passport     = new TaskPassportInit().execute();
        this.handle           = new TaskHandleInit(passport).execute();
        this.handler          = new TaskHandleOpen(handle).execute();
        new TaskSepaInfo(handler).execute();

        Logger.info("processing jobs");
        for (SynchronizeJob job:this.jobs)
        {
          this.checkInterrupted();
          AbstractHBCIJob[] list = ((HBCISynchronizeJob)job).createHBCIJobs();
          for (AbstractHBCIJob hbciJob:list)
          {
            this.checkInterrupted();

            monitor.setStatusText(i18n.tr("Aktiviere HBCI-Job: \"{0}\"",job.getName()));
            Logger.info("adding job " + hbciJob.getIdentifier() + " to queue");

            HBCIJob j = handler.newJob(hbciJob.getIdentifier());
            this.dumpJob(j);
            hbciJob.setJob(j);
            j.addToQueue();
            this.hbciJobs.add(hbciJob);
            if (hbciJob.isExclusive())
            {
              Logger.info("job will be executed in seperate hbci message");
              handler.newMsg();
            }
          }
          monitor.addPercentComplete(step);
        }

        ////////////////////////////////////////////////////////////////////////
        // Jobs ausfuehren
        Logger.info("executing jobs");
        monitor.setStatusText(i18n.tr("F�hre HBCI-Jobs aus"));
        this.handler.execute();
        monitor.setStatusText(i18n.tr("HBCI-Jobs ausgef�hrt"));
        //
        ////////////////////////////////////////////////////////////////////////
      }
      catch (Exception e)
      {
        haveError = true;
        inCatch = true;
        throw e;
      }
      finally
      {
        try
        {
          String name = null;

          // Waehrend der Ergebnis-Auswertung findet KEIN "checkInterrupted" Check statt,
          // da sonst Job-Ergebnisse verloren gehen wuerden.

          // //////////////////////////////////////////////////////////////////////
          // Job-Ergebnisse auswerten.
          // checkInterrupted wird hier nicht aufgerufen, um sicherzustellen, dass
          // dieser Vorgang nicht abgebrochen wird.
          for (AbstractHBCIJob hbciJob:this.hbciJobs)
          {
            try
            {
              name = hbciJob.getName();
              monitor.setStatusText(i18n.tr("Werte Ergebnis von HBCI-Job \"{0}\" aus",name));
              Logger.info("executing check for job " + hbciJob.getIdentifier());
              hbciJob.handleResult();
            }
            catch (Throwable t)
            {
              haveError = true;

              // Nur loggen, wenn wir nicht abgebrochen wurden. Waeren sonst nur Folgefehler
              if (!HBCISynchronizeBackend.this.worker.isInterrupted())
              {
                if (t instanceof ApplicationException)
                {
                  monitor.setStatusText(t.getMessage());
                }
                else
                {
                  monitor.setStatusText(i18n.tr("Fehler beim Auswerten des HBCI-Auftrages {0}", name));
                  Logger.error("error while processing job result",t);
                  monitor.log(t.getMessage());
                }
              }
            }
          }

          monitor.addPercentComplete(3);

          if (haveError || HBCISynchronizeBackend.this.worker.isInterrupted())
          {
            Logger.warn("found errors or synchronization cancelled, clear PIN cache");
            DialogFactory.clearPINCache(this.handler != null ? this.handler.getPassport() : null);
          }

          if (!inCatch)
          {
            // Fehler nur werfen, wenn wir nicht abgebrochen wurden - in dem Fall
            // werfen die handleResult-Funktionen naemlich ohnehin Fehler. Die
            // interessieren beim Abbruch aber nicht.
            // Der Abbruch-Check kommt unten drunter
            if (haveError && !HBCISynchronizeBackend.this.worker.isInterrupted())
              throw new ApplicationException(i18n.tr("Fehler beim Auswerten eines HBCI-Auftrages"));
            //
            // //////////////////////////////////////////////////////////////////////

            // Jetzt noch die OperationCancelledException werfen, falls zwischenzeitlich abgebrochen wurde
            this.checkInterrupted();
          }
        }
        finally
        {
          IOUtil.close(this);
        }
      }
    }

    /**
     * Gibt Informationen ueber den Job im Log aus.
     * @param job Job.
     */
    private void dumpJob(HBCIJob job)
    {
      Logger.debug("Job restrictions for " + job.getName());
      Properties p = job.getJobRestrictions();
      Iterator it = p.keySet().iterator();
      while (it.hasNext())
      {
        String key = (String) it.next();
        Logger.debug("  " + key + ": " + p.getProperty(key));
      }
    }

    /**
     * Schliesst die waehrend der Ausfuehrung geoeffneten Ressourcen.
     * @see java.io.Closeable#close()
     */
    public void close() throws IOException
    {
      Logger.info("closing resources");
      if (this.handle != null)
      {
        try
        {
          this.handle.close();
        }
        catch (Throwable t)
        {
          Logger.write(Level.DEBUG,"unable to close handle",t);
        }
      }
    }

    /**
     * Task fuer die Initialisierung des Passport.
     */
    private class TaskPassportInit extends AbstractTaskWrapper<Passport>
    {
      /**
       * @see de.willuhn.jameica.hbci.synchronize.hbci.HBCISynchronizeBackend.HBCIJobGroup.AbstractTaskWrapper#internalExecute()
       */
      public Passport internalExecute() throws Throwable
      {
        checkInterrupted();

        ////////////////////////////////////////////////////////////////////
        // lokale Variablen
        ProgressMonitor monitor = HBCISynchronizeBackend.this.worker.getMonitor();
        Konto konto             = getKonto();
        ////////////////////////////////////////////////////////////////////

        try
        {
          Passport passport = PassportRegistry.findByClass(konto.getPassportClass());
          if (passport == null)
            throw new ApplicationException(i18n.tr("Kein HBCI-Sicherheitsmedium f�r das Konto gefunden"));

          monitor.setStatusText(i18n.tr("Initialisiere HBCI-Sicherheitsmedium"));
          passport.init(konto);
          monitor.addPercentComplete(1);

          return passport;
        }
        catch (Exception e)
        {
          throw HBCIProperties.getCause(e);
        }
      }
    }

    /**
     * Task fuer die Initialisierung des Handle.
     */
    private class TaskHandleInit extends AbstractTaskWrapper<PassportHandle>
    {
      private Passport passport = null;

      /**
       * ct.
       * @param passport
       */
      private TaskHandleInit(Passport passport)
      {
        this.passport = passport;
      }

      /**
       * @see de.willuhn.jameica.hbci.synchronize.hbci.HBCISynchronizeBackend.HBCIJobGroup.AbstractTaskWrapper#internalExecute()
       */
      public PassportHandle internalExecute() throws Throwable
      {
        checkInterrupted();

        ////////////////////////////////////////////////////////////////////
        // lokale Variablen
        ProgressMonitor monitor = HBCISynchronizeBackend.this.worker.getMonitor();
        ////////////////////////////////////////////////////////////////////

        monitor.setStatusText(i18n.tr("Erzeuge HBCI-Handle"));
        PassportHandle handle = this.passport.getHandle();

        if (handle == null)
          throw new ApplicationException(i18n.tr("Fehler beim Erzeugen der HBCI-Verbindung"));

        monitor.addPercentComplete(1);
        return handle;
      }
    }

    /**
     * Task fuer das Oeffnen des Handle.
     */
    private class TaskHandleOpen extends AbstractTaskWrapper<HBCIHandler>
    {
      private PassportHandle handle = null;

      /**
       * ct.
       * @param handle
       */
      private TaskHandleOpen(PassportHandle handle)
      {
        this.handle = handle;
      }

      /**
       * @see de.willuhn.jameica.hbci.synchronize.hbci.HBCISynchronizeBackend.HBCIJobGroup.AbstractTaskWrapper#internalExecute()
       */
      public HBCIHandler internalExecute() throws Throwable
      {
        checkInterrupted();

        ////////////////////////////////////////////////////////////////////
        // lokale Variablen
        ProgressMonitor monitor = HBCISynchronizeBackend.this.worker.getMonitor();
        ////////////////////////////////////////////////////////////////////

        try
        {
          monitor.setStatusText(i18n.tr("�ffne HBCI-Verbindung"));
          HBCIHandler handler = this.handle.open();

          if (handler == null)
            throw new ApplicationException(i18n.tr("Fehler beim �ffnen der HBCI-Verbindung"));

          monitor.addPercentComplete(1);
          return handler;
        }
        catch (Exception e)
        {
          throw HBCIProperties.getCause(e);
        }
      }
    }

    /**
     * Task fuer das Ermitteln der SEPA-Infos.
     */
    private class TaskSepaInfo extends AbstractTaskWrapper<Void>
    {
      private HBCIHandler handler = null;

      /**
       * ct.
       * @param handler
       */
      private TaskSepaInfo(HBCIHandler handler)
      {
        this.handler = handler;
      }

      /**
       * @see de.willuhn.jameica.hbci.synchronize.hbci.HBCISynchronizeBackend.HBCIJobGroup.AbstractTaskWrapper#internalExecute()
       */
      public Void internalExecute() throws Throwable
      {
        if (this.handler.getSupportedLowlevelJobs().getProperty("SEPAInfo") == null)
        {
          Logger.info("Fetching of SEPA infos not supported");
          return null;
        }

        checkInterrupted();

        try
        {
          Properties p = this.handler.getLowlevelJobRestrictions("SEPAInfo");
          Enumeration keys = p.keys();
          Logger.debug("sepa infos:");
          while (keys.hasMoreElements())
          {
            String s = (String) keys.nextElement();
            Logger.debug("  " + s + ", value: " + p.getProperty(s));
          }
          p.put("konto.id",getKonto().getID()); // Damit klar ist, zu welchem Konto das gehoert

          // Wir verschicken das per Messaging - dann koennen wir das an anderer Stelle verarbeiten, falls benoetigt
          Application.getMessagingFactory().getMessagingQueue("hibiscus.sepainfo").sendMessage(new QueryMessage(p));
        }
        catch (Exception e)
        {
          // Nur Loggen, nicht weiterwerfen
          Logger.error("unable to fetch SEPA info",e);
        }
        return null;
      }
    }


    /**
     * Wrappt einen Task als Runnable, damit es je nach Laufzeit-Umgebung direkt oder im GUI-Thread ausgefuehrt werden kann.
     */
    private abstract class AbstractTaskWrapper<T> implements Runnable
    {
      private Exception exception = null;
      private T result            = null;

      /**
       * Fuehrt den Task je nach Laufzeit-Umgebung passend aus.
       * @return der Rueckgabewert des Tasks.
       * @throws Exception
       */
      T execute() throws Exception
      {
        if (Application.inServerMode())
          this.run();
        else
          GUI.getDisplay().syncExec(this);

        if (this.exception != null)
          throw this.exception;

        return this.result;
      }

      /**
       * Fuehrt den Task aus.
       * @return T der Rueckgabewert des Tasks.
       * @throws Throwable
       */
      protected abstract T internalExecute() throws Throwable;

      /**
       * @see java.lang.Runnable#run()
       */
      @Override
      public void run()
      {
        try {
          this.result = this.internalExecute();
        }
        catch (Exception e) { // wir fangen nur Exceptions, keine Errors
          this.exception = e;
        }
        catch (Throwable t) {
          if (t instanceof Error)
            throw (Error) t;
          throw new Error(t);
        }
      }
    }
  }
}

TOP

Related Classes of de.willuhn.jameica.hbci.synchronize.hbci.HBCISynchronizeBackend$HBCIJobGroup$TaskHandleInit

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.