Autor Thema: Ralf, jemals versucht (Notes-)Database Obj in eigenen Thread zu cachen?  (Gelesen 10121 mal)

Offline Axel_Janssen

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 769
, oder klammerst du LoNo-Zugriffe aus Applets/Swing grundsätzlich mit stermThread(), sinitThread()?

Ich habs versucht und behaupte nicht der Bär in Thread-Programmierung zu sein.
Unter Standalone Swing funktionierte es ziemlich gut. Unter Applet so gar nicht. Ich vermute es hängt damit zusammen, dass die JVM eine bestimmte Masse an Arbeitsspeicher benötigt, die sie im Browser einfach nicht hat.

- Swing-Objekte sind so nicht Thread-Safe, arbeite mit den Spezialmethoden aus SwingUtilities: invokeAndWait(), invokeLater().
- Applet-Sandbox Sicherheit ist es auch nicht.

Bin gestern leicht wahnsinnig geworden.

Gruß Axel
... design patterns are abstract designs that help identify the structure and elements involved in a specific design solution. From this, a concrete implementation can be produced.
Kyle Brown

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Ich habe bis jetzt die Zugriffe mit init und Term geklammert, habe aber die Objekte wie Session und Database trotzdem wieder verwendet. Funktioniert einwandfrei. Mich würde aber deine Lösung mit einem eigenen Thread für die Zugriffe interessieren. kannst du den Code in der einfachsten Variante posten?

Hier ein Beispiel die überschriebene Methode getValueAt eines JTable Tablemodells

Zur Erklärung docint ist eine Referenz auf das Notesdokument und it ist eine Referenzvariable für ein NotesItem

BTW Das ist Java Code aus meinen ersten Versuchen und zusätzlich gemacht für JDK 1.1. Deshalb teilweise komische Verwendung von Vector.

public Object getValueAt(int param, int param1) {
        Object temp;
        try {
            NotesThread.sinitThread();
            it=docint.getFirstItem((String)NotesFelder.elementAt(param1));
            try{
                temp= it.getValues().elementAt(param);
            }
            catch(Exception y){
                if (it!=null){
                    it.recycle();
                    it=null;
                }
                NotesThread.stermThread();
                return "";
            }
            it.recycle();
            it=null;
            NotesThread.stermThread();
            if (((String)temp).equals("_")){
                return "";
            }
            return temp;
        }
        catch (NotesException e){}
        try {
            it.recycle();
            NotesThread.stermThread();
        }
        catch(Exception x){}
        return "";
    }
Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline Axel_Janssen

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 769
 8) hoffentlich klappt das hier auch.  ::)

(Notes)-Session, (Notes)Database sowie docint erzeugst du im Constructor des JTableModels ?
Und recycle() für diese Instanzvariablen wird dann von irgendeiner gui-Exit Call-Back Methode aufgerufen (sowas wie applet.stop() ?

Ich poste den code später. Bin jetzt ziemlich unter Zeitdruck und werd das dann irgendwie vereinfachen.

Gruß Axel
« Letzte Änderung: 29.07.03 - 12:24:06 von Axel_Janssen »
... design patterns are abstract designs that help identify the structure and elements involved in a specific design solution. From this, a concrete implementation can be produced.
Kyle Brown

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Das Dok wird als Parameter an den Konstruktor des Tablemodels übergeben. In Applet.stop müsste es reichen, wenn du die Session recycelst, da das alle abhängigen Objekte mit recycelt.. Konnte selber kau mglauben, dass es funktioniert, aber in der Firma in der ich arbeite ist das jetzt seit ca. einem halben Jahr im Echt Einsatz. Ist Teil eines Content Management System.

Kannst du deinen Code posten?

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline Axel_Janssen

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 769
Ich habe bis jetzt die Zugriffe mit init und Term geklammert, habe aber die Objekte wie Session und Database trotzdem wieder verwendet.


Genau das funktioniert bei mir nämlich nicht.
Ich bekomme eine NotesException Object has been removed or recycled.

Hier ist code (mit dem das JTableModel kommuniziert):

A. Konstruktor (wird selbstverständlich zuerst aufgerufen).  
Code
 private NotesConnection(HashMap appletParameters) {
        //System.out.println("appletParameters=" + appletParameters);
         serverName = (String) appletParameters.get("dbServerName");
         serverPath = (String) appletParameters.get("dbPathName");
         
        this.serverName = serverName;
        this.serverPath = serverPath;
        
        try {
            NotesThread.sinitThread();
            // die ganzen Objekte werden in Instanzvariablen gecasht. 
            nSession = NotesFactory.createSessionWithFullAccess(); 
            nDbCurrent = nSession.getDatabase (serverName, serverPath);
            nViewMAs = nDbCurrent.getView("V_MP");
            testDoc = nViewMAs.getFirstDocument();
            nViewEntriesByWeek = nDbCurrent.getView("EntriesByWeek2");
            System.out.println("neueste");
        } catch(Exception e) {
            e.printStackTrace();
        }
   
        finally {
            NotesThread.stermThread();
        }

Methode, die immer wieder aufgerufen wird:
Code
   public String[][] getMAsData (int week, int year) {
        Vector vecMAs = new Vector();
        if ((week == lastWeek) && (year == lastYear)) return arResult;
        DocumentCollection nColMAs = null;
        DocumentCollection nColEntriesByWeek = null;
        try {
            
            NotesThread.sinitThread();
            // BEREITS IN DER NÄCHSTEN ZEILE ERHALTE ICH DIE OBEN ANGESPROCHENE EXCEPTION
            System.out.println(testDoc.getItemValueString("userNameAbb"));
            nColMAs = nViewMAs.getAllDocumentsByKey("doc");
            
            int colCount = nColMAs.getCount();
            int expectedUsers = (int) (100*(1/0.75));
            HashMap userNamesIndex = new HashMap(expectedUsers);
            String arResult [][] = new String [colCount][7]; 
            Document nDoc = null;
            int i = 0;
            nDoc = nViewMAs.getFirstDocument();
            
            while (nDoc != null) {
                 
        String user = nDoc.getItemValueString("userNameAbb");
      userNamesIndex.put(user, new Integer(i));             
      arResult[i][0] = user;
      i +=1; 
                nDoc = nViewMAs.getNextDocument(nDoc);   
            }
            
            
            
            Document nDocWeek = null;
         /*
         Vector key = new Vector();
         key.add(new Integer(2003));
         key.add(new Integer(28));
         */         
            String key = year + "-" + week;
            nColEntriesByWeek = nViewEntriesByWeek.getAllDocumentsByKey(key);         
            //System.out.println("count=" + nColEntriesByWeek.getCount());
            nDocWeek = nColEntriesByWeek.getFirstDocument();
         
            while (nDocWeek != null) {
                int datum = nDocWeek.getItemValueInteger("Datum");
      int tagInWoche = nDocWeek.getItemValueInteger("TagInWoche");
      String userName = nDocWeek.getItemValueString("KUserNameAbb");
      //System.out.println("datum=" + datum + ",tagInWoche=" + tagInWoche + ",userName=" + userName);
      //System.out.println("userNamesIndex=" + userNamesIndex);
      int userIndex = ((Integer)userNamesIndex.get(userName)).intValue();
                arResult [userIndex][tagInWoche] = "x";              
      nDocWeek = nColEntriesByWeek.getNextDocument(nDocWeek);
            
            }
   
            return arResult;
        } catch(Exception e) {
            e.printStackTrace();
            return null;
        }
   
        finally {
            try {
                if (nColMAs != null) {  
                    nColMAs.recycle();
                    nColMAs = null;
                }
            
                if (nColEntriesByWeek != null) {
                    nColEntriesByWeek.recycle();
                    nColEntriesByWeek = null;
                }
            } catch (Exception e) {e.printStackTrace(); }
            NotesThread.stermThread();
            lastWeek = week;
            lastYear = year;
            this.arResult = arResult;
            return null;
        }
    }

Gibts irgendeinen Trick? So kann ich hier aber offenbar keine Notes-Objekte cachen?

Gruß Axel
« Letzte Änderung: 29.07.03 - 15:41:11 von Axel_Janssen »
... design patterns are abstract designs that help identify the structure and elements involved in a specific design solution. From this, a concrete implementation can be produced.
Kyle Brown

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Hallo Axel!

Kannst du die ganze Konsolenausgabe mit Stacktrace posten. Ich würde nämlich schon sagen, dass das so funktioniert.

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline Axel_Janssen

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 769
Ralef, isch hau hier gleisch alles kapott...
« Antwort #6 am: 29.07.03 - 15:52:57 »
Kann es sein, dass es funktionieren könnte, wenn ich im Constructor einfach darauf verzichte
Code
NotesThread.stermThread();
aufzurufen?  ??? >:(  :(

Es sieht fast so aus, wobei ich noch weitere Probleme im code habe.
Das wäre natürlich gut.  ;D
Dann hätte ich mir aber meine MultiThreading Forschung sparen können.  

Gruß Axel
... design patterns are abstract designs that help identify the structure and elements involved in a specific design solution. From this, a concrete implementation can be produced.
Kyle Brown

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
NotesThread.strerm nicht zu machen, hat sich bei mir nicht bewährt, immer wenn ich es einmal vergessen habe,  hatte ich immer wieder plötzlich mal eine Schutzverletzung oder einen Red Box Fehler in Notes. Wie gesagt, ich verwende das ganz gleich wie du nur das mit den Threads was du erwähnst ist mir nicht ganz klar. Laufen die beiden Sachen in verschiedenen Threads?

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline Axel_Janssen

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 769
Hallo Axel!

Kannst du die ganze Konsolenausgabe mit Stacktrace posten. Ich würde nämlich schon sagen, dass das so funktioniert.

Grüße

Ralf


hier ist alter Stacktrace:
Code
neueste

NotesException: Object has been removed or recycled

   at lotus.domino.local.NotesBase.CheckObject(NotesBase.java:1063)

   at lotus.domino.local.Document.getItemValueString(Unknown Source)

   at de.aja.db.NotesConnection.getMAsData(NotesConnection.java:75)

   at de.aja.gui.model.AbwesenheitTableModelApplet.retrieveNotesData(AbwesenheitTableModelApplet.java:88)

   at de.aja.gui.TableAbwesenheit.doChangeWeek(TableAbwesenheit.java:328)

   at de.aja.gui.TableAbwesenheit.cbWocheActionPerformed(TableAbwesenheit.java:241)

   at de.aja.gui.TableAbwesenheit.access$100(TableAbwesenheit.java:27)

   at de.aja.gui.TableAbwesenheit$2.actionPerformed(TableAbwesenheit.java:162)

   at javax.swing.JComboBox.fireActionEvent(JComboBox.java:1196)

   at javax.swing.JComboBox.setSelectedItem(JComboBox.java:561)

   at javax.swing.JComboBox.setSelectedIndex(JComboBox.java:597)

   at de.aja.gui.TableAbwesenheit.replaceSelectionWeeks(TableAbwesenheit.java:367)

   at de.aja.gui.TableAbwesenheit.init(TableAbwesenheit.java:98)

   at sun.applet.AppletPanel.run(AppletPanel.java:348)

   at java.lang.Thread.run(Thread.java:536)

Die Zeile 75 war das:
Code
System.out.println(testDoc.getItemValueString("userNameAbb"));
Alls ich nun im Konstruktor das NotesStread.stermThread(); auskommentiert habe, treten diese Probleme offenbar nicht mehr auf.
... design patterns are abstract designs that help identify the structure and elements involved in a specific design solution. From this, a concrete implementation can be produced.
Kyle Brown

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Ich glaube ich verstehe das Problem jetzt.

Das NotesThread.sinitThread zieht ja nur für einen Thread.  Wenn man einen Thread mit StermThread beendet, werden alle Objekte die in diesem Thread erzeugt worden sind beschädigt. Du musst deine Objekte die du cachen willst in einem Thread erzeugen, der weiterläuft. Während du im AWT Thread dann mit diesen Objekten arbeitest.

Habe das jetzt auch in der Hilfe gefunden:

When child objects are used on threads other than the parent, keep the parent thread alive until all child threads terminate. This is particularly important when using Domino Objects in AWT event handlers.

Ein Beispiel warum es bei mir funktioniert.

/*
 * Test.java
 *
 * Created on 1. November 2002, 11:56
 */

package GuiComponents;
import lotus.domino.*;
import GuiComponents.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
 *
 * @author  petter_r
 */
public class Test {
    static JDialog dialog;
    static NotesTablePanel ntds;
    /** Creates a new instance of Test */
    public Test() {
    }
   
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {            
        try {
            NotesThread.sinitThread();
            Session session = NotesFactory.createSession();
            Database cdb=session.getDatabase("","web.nsf");
            Document doc=cdb.getDocumentByID("9BE");
            ntds=new NotesTablePanel(session,cdb,doc,"Feld1g;Feld2;Feld3;Feld4","1;2;3;4","Feld1;Feld2;Feld3;Feld4","100");
            dialog=new JDialog((Frame)null,"Test",true);
            dialog.getContentPane().setLayout(new FlowLayout());
            dialog.getContentPane().add(ntds,BorderLayout.CENTER);
            JButton ok=new JButton("OK");
            ok.setPreferredSize(new Dimension(100,25));
            JButton abbrechen=new JButton("abbrechen");
            abbrechen.setPreferredSize(new Dimension(100,25));
            dialog.getContentPane().add(ok,BorderLayout.SOUTH);
            dialog.getContentPane().add(abbrechen,BorderLayout.SOUTH);
            dialog.pack();
            ok.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e){
                    System.out.println("Ok wurde ausgewählt");
                   
                        ntds.tableStopEditing();
                        dialog.dispose();
                   
                   
                }
            });
            abbrechen.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e){
                    System.out.println("abbrechen wurde ausgewählt");
                    dialog.dispose();
                }
            });
            dialog.show();
            doc.save(true,false);
            System.out.println("disposed");
            session.recycle();
           
           
        } catch(Exception e) {
            e.printStackTrace();
        }
        finally{
            NotesThread.stermThread();
        }
    }
   
   
   
}
Schwierig ist natürlich dann wo man wenn man keinen gebundenen Dialog wie in meinem Fall hat  die Notes Objekte wie Session, DB, view usw erstellt. Ich würde empfehlen einen eigenen Thread dafür zu machen, den mit NotesThread.sinitThread initialisieren, die Objekte erstellen. denn Thread dann schlafenlegen bis zu einer Unterbrechung und wenn Programm fertig die Unterbrechung des Threads machen, damit er Session recyceln kann und das NotesThreadStermthread machen kann. Was hälst du davon?

Grüße

Ralf

Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Übrigens vielleich sollten wir das Forum umbenennen auf Notes Java für Fortgeschrittene bei diesem Thread. ;D
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline Axel_Janssen

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 769
Ralf,

Yo. Das sieht jetzt gut aus   ;D

<am_rande>
Ich habe das da oben einfach zu schnell geschrieben und 2 ziemlich dämliche Fehler gemacht. Der spannende Augenblick wartet also noch.

1. return null; in finally ist natürlich völlig heftig.
2. hab ArrayResult nochmal als lokale Variable deklariert, was dann zu "instance-shadowing-Verwirrung" führt.
</am_rande>

Ich habe offenbar die Wundermethoden NotesThread.sinitThread() und NotesThread.stermThread() der genialen Lotus-Programmierer deutlich unterschätzt.

Man bildet so quasi Layer von NotesThreads. Der eine wird gestartet im Konstruktor von der NotesConnection Klasse und erst in applet.stop() geschlossen --> da rufe ich nämlich ein stermThread() auf.
Der andere Layer wird in getMAsData() gestartet und gestoppt und kommuniziert mit dem "globalen" Thread. getMAsData() wird mehrmals aus der GUI aufgerufen (als Reaktion von GUI-Events).

Ist das so advanced? Eigentlich habe ich doch die Funktionsweise von sinitThread() und stermThread einfach nicht richtig verstanden.

Gruß Axel
« Letzte Änderung: 29.07.03 - 18:03:15 von Axel_Janssen »
... design patterns are abstract designs that help identify the structure and elements involved in a specific design solution. From this, a concrete implementation can be produced.
Kyle Brown

Offline Axel_Janssen

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 769
L.Ä.U.F.T.  8)

Danke Ralf, das hat echt weitergeholfen. ;)

Mir fällt übrigens kein Anwendungsfall an, wo man ein eigenes Multi-Threading-Framework aufbauen sollte um auf Notes zuzugreifen. Dieses multi-layerige sinitThread()/stermThread() ist schon ziemlich optimal würde ich sagen. Werde es trotzdem am nächsten Wochenende mal posten.
Der kompliziertere Teil war eigentlich MultiThreading aus Swing heraus. Dafür gibt es sicher Verwendung.

Gruß Axel  
... design patterns are abstract designs that help identify the structure and elements involved in a specific design solution. From this, a concrete implementation can be produced.
Kyle Brown

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Ich meinte auch nur deshalb, dass das Forum schön langsam zu einem Privatforum zwischen uns zwei wird. Die Postings von anderen halten sich in letzter Zeit etwas in Grenzen. Sollen wir etwas advertisen für das Notes Java Forum?

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline Axel_Janssen

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 769
Hallo Ralf,

was wenn wir hier mit 20 newbie Fragen am Tag überschwemmt würden?
Ich finde das soweit o.k.
Verschrecken solche threads wie dieser newbies?
Alles was ich machen kann, ist diese mit [advanced] zu kennzeichnen.
Aus Notes-Sicht ist Java (noch) ein Spezialthema.

Ich finde es extrem gut, dass ich hier antworten für meine Fragestellungen bekomme. Ich sehe das egoistisch.

Gruß Axel
... design patterns are abstract designs that help identify the structure and elements involved in a specific design solution. From this, a concrete implementation can be produced.
Kyle Brown

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Hm ja mein Ansatz ist ein ein wenig anders. Ich versuche womöglichst viele Leute für Java im Notes Umfeld zu begeistern. Denn die Regel bei Computerprogrammen ist relativ einfach. Je mehr Leute diese Funktionen verwenden, umso mehr Bugs werden an Lotus gemeldet und um so mehr Bugs werden gefixt. Wenn eine Funktion nicht verwendet wird, werden auch keine Bugs gefixt.  Deshalb meine Hoffnung, dass sich mehr Leute hier im Forum engagieren. Eventuell sollten wir eine kleine Demonstration für Java in Notes entwickeln, die sich vielleicht auch in Real life anwenden lässt. Ich denke das könnte mehr Leute für  Java in Notes begeistern.

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

Offline qojote

  • Aktives Mitglied
  • ***
  • Beiträge: 229
  • I love YaBB 1G - SP1!
Hi,

ich kann mich ja im Moment leider noch nicht an euren wilden Diskussionen beteiligen ( hoffe das kommt noch ) aber trotzdem finde ich es lehrreich diese einfach zu verfolgen und hier und da eine Idee zubekommen wie mann etwas realisieren kann.

Ich hab jetzt zwei drei Java Agents geschrieben und vielleicht hat ja einer von euch Lust sich den Code mal anzuschauen um mir zu zeigen was man besser machen kann. Das wäre bestimmt auch für andere Anfänger in dem Bereich interessant.

Gruß
qojote

Offline Ralf_M_Petter

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.879
  • Geschlecht: Männlich
  • Jeder ist seines eigenen Glückes Schmied
    • Ralf's Blog
Hallo qojote!

Gerne poste Sie einfach in einen neuen Thread mit einer kurzen Erklärung was sie machen, dann schaue ich sie mir gerne an.

Grüße

Ralf
Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz