Autor Thema: neues Projekt: Poo Monkey  (Gelesen 3787 mal)

Marinero Atlántico

  • Gast
neues Projekt: Poo Monkey
« am: 05.06.05 - 11:06:36 »
Hi,

es soll nun um einen Webbot für Atnotes gehen.
Für irgendetwas muß die DSL Verbindung ja gut sein.
Das Projekt soll das folgende abbilden:
Ein Webbot namens Poo Monkey soll mit den Login-Daten des Users, der ihn laufen lässt, die neuen Postings im Offtopic-Forum von Atnotes in bestimmten Zeitabständen scannen.
Falls der Webbot in einem Posting den Text "Poo Monkey, how do you do?" (mit Variationen) findet, postet Poo Monkey zurück: "Poo Monkey says: I am fine".

Da ich nicht vermute, dass besonders viele Leute mitmachen, glaube ich nicht dass das Projekt "Poo Monkey" Atnotes lahmlegen wird.

Technisch geht es um die folgenden Themengebiete:
- viel HTTP mit der wie ich finde ziemlich guten HTTPClient-jar von jakarta commons.
- httml-parsing
- scheduling in Java (scheduling ist so was wie zeitgesteuerte Agenten).
- ein bischen OO
- vermutlich ein bischen RegEx
- v.a. auch so allgemeine Dinge, die ich für sinnvoll halte, wie z.B. benutzen von Property-Files, Log4U sowie irgendwann sicher UnitTesting. Das kann dann auch von Leuten benutzt werden, die für Notes Java-Agenten schreiben.
- natürlich Eclipse

Mir ist es zumindest jetzt schon mal in 60 Minuten gelungen, mit dem Java Code authentifiziert als Marinero Atlantico gegen Atnotes ein HTTP-GET abzusetzen und das zurückkommende HTML in eine Datei zu schreiben.

Gruß Axel

Marinero Atlántico

  • Gast
Re: neues Projekt: Poo Monkey
« Antwort #1 am: 05.06.05 - 16:02:30 »
Hier ist schon mal ein bischen Source-Code.
Das Projekt hat 2 Klassen und 2 Konfigurationsdateien:

Die überhaupt nicht objektorientierte Klasse "FirstTest" baut sich zunächst einen HTTP Get Request zusammen.
Dieser enthält:
- die URL des Requests.
- den HTTP-Parameter action=recent (damit geht er gegen die: die neuesten 10 Posting Seite von atnotes.
- das Cookie, das atnotes zum einloggen benötigt (YaBBSE140usernamev14). Ihr findet diesen Wert in eurem Browser. Ganz praktisch ist in Mozilla Web Developer-plugin: Information: View Cookie Information.

Httpclient sendet den Request.
Atnotes erhält diesen Request und schickt die Seite der 10 neuesten Postings das von httpClient gesendete Cookie und ein neues php-session Cookie zurück.
Die Werte der Cookies sowie ein http Statuscheck werden per log4j an der Konsole ausgegeben.
Der HttpStream der zurückgelieferten Seite wird in eine Datei gespeichert (namens atnotes.de in <projekt-root>/genFiles.
Im Quellcode steht eindeutig das Hallo, Marinero Atlántico. Also hat die Authentifizierung mit dem Cookie geklappt. Wenn jemand anders das ausprobiert, sieht er natürlich nicht Hallo Marinero Atlántico sondern seinen eigenen Namen.


Klasse 1:
Code
package de.aja.commons.dabbling;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.log4j.Logger;

import de.aja.dabbling.commons.utils.DabblingHelpers;

/*
 * Created on 05.06.2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

/**
 * @author Axel
 * 
 * simply dabbling with jakarta httpClient
 */
public class FirstTest {

	final static Logger logger = Logger
			.getLogger(de.aja.commons.dabbling.FirstTest.class);

	/** requested base url without Query String */
	private String urlToRequest;

	/** an instance of apache jarkarta HttpClient. */
	private HttpClient client;

	protected void setUrlToRequest(String urlToRequest) {
		this.urlToRequest = urlToRequest;
	}

	FirstTest() {
		client = new HttpClient();

	}

	/**
	 * here's where the action takes place.
	 * 
	 */
	void doGetRequest() {
		logger.info("doGetRequest start.");
		DabblingHelpers.setStartTime();
		HttpMethod method = new GetMethod(urlToRequest);
		// name value pair für HTTP-GET

		NameValuePair nvp1 = new NameValuePair("action", "recent");
		method.setQueryString(new NameValuePair[] { nvp1 });

		// user spezifischer Wert aus properties File lesen
		Properties props = new Properties();
		InputStream iStr = getClass().getClassLoader().getResourceAsStream(
				"config.properties");
		try {
			props.load(iStr);
		} catch (IOException e1) {
			logger
					.error(
							"Properties File \"config.properties\" konnte nicht geladen werden",
							e1);
			System.exit(0);
		} catch (NullPointerException npe) {
			logger
					.error(
							"Properties File \"config.properties\" konnte nicht gefunden werden.",
							npe);
			System.exit(0);

		}

		// folgende für Cookie setzen:
		Cookie cookie = new Cookie("217.160.137.156", "YaBBSE140usernamev14",
				props.getProperty("user.cookie.YaBBSE140usernamev14"), "/", -1,
				false);
		HttpState initialState = new HttpState();
		initialState.addCookie(cookie);
		initialState.setCookiePolicy(CookiePolicy.COMPATIBILITY);
		client.setState(initialState);

		try {

			int statusCode = client.executeMethod(method);
			logger.info("Query String>>>=" + method.getQueryString());
			logger
					.info("Status Text>>>"
							+ HttpStatus.getStatusText(statusCode));

			// cookie stuff
			logger.info("Start Cookies------------------>");
			Cookie[] cookies = client.getState().getCookies();
			for (int i = 0; i < cookies.length; i++) {
				logger.info("A Cookie");
				logger.info("Name=" + cookies[i].getName());
				logger.info("Value=" + cookies[i].getValue());
				logger.info("Domain=" + cookies[i].getDomain());
			}
			logger.info("End Cookie<------------------");
			// System.out.println(method.getResponseBodyAsString());
			InputStream is = new BufferedInputStream(method
					.getResponseBodyAsStream());
			// byte [] res = method.getResponseBody();

			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream("genFiles\\atnotes.de"));
			// fos.write(is);
			byte[] buf = new byte[4096];
			int len;
			while ((len = is.read(buf)) > 0) {
				bos.write(buf, 0, len);
			}
			bos.close();
			is.close();
			method.releaseConnection();
			method = null;

		} catch (IOException e) {
			logger.error(e);

		} catch (Throwable t) {
			logger.error(t);
		}

		finally {
			if (method != null) {
				logger
						.debug("connection of object \"method\" closed in finally!");
				method.releaseConnection();

			}
		}
		logger.info("doGetRequest end. This method took more or less:"
				+ DabblingHelpers.getTimeDifInSeconds() + " seconds to run.");

	}

	public static void main(String[] args) {
		FirstTest fTest = new FirstTest();
		fTest.setUrlToRequest("http://www.atnotes.de/index.php");
		fTest.doGetRequest();
	}
}

Globale Helper-Klasse. Zur Zeit nur zum Zeitstoppen:
Code
/*
 * Created on 05.06.2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package de.aja.dabbling.commons.utils;

/**
 * @author Axel
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class DabblingHelpers {
	private static long startTime;
	
	
	
	public static void setStartTime() { 
		startTime = System.currentTimeMillis();
	}
	
	public static double getTimeDifInSeconds() {
		if (startTime == 0) {
			throw new RuntimeException("startTime not set");
		}
		return System.currentTimeMillis() / 1000;
	}

}

1 Konfigurationsdatei für log4j.xml
Code
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-4r [%t.%L] %-5p %c %x.%M - %m%n"/>
</layout>
</appender>
<appender name="pooMonkey" class="org.apache.log4j.FileAppender">
<param name="File" value="C:\\funLogs\\PooMonkey.log"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-4r [%t.%L] %-5p %c %x.%M - %m%n"/>
</layout>
</appender>

<logger name="de">
<level value="info"/>
<appender-ref ref="STDOUT"/>
</logger>



</log4j:configuration>

1 Properties Datei config.properties
Code
user.cookie.YaBBSE140usernamev14=a%3A3%3Avonmirgeändert
« Letzte Änderung: 05.06.05 - 16:14:13 von Marinero Atlántico »

Marinero Atlántico

  • Gast
Re: neues Projekt: Poo Monkey
« Antwort #2 am: 05.06.05 - 19:39:43 »
Jetzt noch ein paar Zusatzdinge, die man benötigt. Inklusive ein paar nicht so schlechter Ideen bzgl. der Strukturierung von Projekten in Eclipse.

1. Folgende jars werden benötigt:
von Jakarta.commons
http://jakarta.apache.org/commons/index.html und können dort runtergeladen werden:
-httpclient (ich verwende 3.0 Release Candidate 2)
-codecs (ich verwende eine vermutlich veraltete Version, die auf meiner Festplatte rumlag--> kann zu Problemen führen)
- commons-logging (hab auch veraltete Version, aber ihr könnt euch neue runterladen).
Die Projekte haben einen Downloadlink und im Download ist auch die recht umfangreiche Dokumentation mit Beispielen dabei.

- Log4j. Ich benutze hier auch noch die ältere 1.2.8. Hier gibts noch was neueres: http://logging.apache.org/log4j/docs/

Externe Jars können in Eclipse imho am saubersten so eingebunden werden.
Rechte Maustaste auf lib Verzeichnis des Projekts (sollte standardmässig da sein). Dann Import im PopupMenü hinter der wie gesagt rechten Maustaste wählen und der folgende Dialog ist selbsterklärend.
Das erstmal so machen.

2. Die beiden Config-Files müssen in einem Classpath Root liegen und die Namen besitzen wie oben angegeben. Ich find es am besten, mehrere Classpath Roots in einem Projekt zu haben. Mit Eclipse kann man das problemlos hinkriegen.

Die restlichen Einstellungen befinden sich alle im Projekt-Properties Dialog. Rechte Maustaste auf den Projekt Stammordner im linken Navigator und dort den letzten Eintrag Properties wählen.
Alle Einstellungen im Punkt Java Build Path:
Erstmal Libraries aus Lib in den Projekt-Buildpath eintragen. Also: 3. Reiter "Libraries" und hier mit Button "Add Jars". Sofern wie bisher beschrieben gemacht, selbsterklärend.

Dann auf Tab Source wechseln.
Hier können nun neben dem standardmässigen src 3 Folder angelegt werden.
Ich verwende: config, genFiles und test.
Unter src kommen die .java Dateien. In config alle Konfigurationsdateien (log4j.xml, config.properties, etc.), in test die unitTests (bisher gibts da keinen) und in genFiles die aus der Anwendung heraus generierten Dateien.
Das sieht dann am Ende so aus:
Bei größeren Projekten mit mehreren Config-Files, erhöht sich dadurch die Übersicht immens. Die kompilierten Dateien landen alle in classes. 
 

« Letzte Änderung: 05.06.05 - 19:41:19 von Marinero Atlántico »

Marinero Atlántico

  • Gast
Re: neues Projekt: Poo Monkey
« Antwort #3 am: 05.06.05 - 20:08:02 »
Das Projekt ist bisher überhaupt nicht OO. Aber das kann zu einem späteren Zeitpunkt noch refaktoriert werden. Ich hab nicht so viel Erfahrung mit httpClient und dann ist es sinnvoll erstmal in einer Art proof of concept alles nach Altvätersitte in eine Methode zu packen. Wenn ich mich ein bischen sicherer fühle, wie diese Library aufgebaut ist, mach ich das OO.

Das Projekt benutzt konsequent log4j und nicht irgendwelche babarischen System.out.println Statements. Das wird zwar bisher alles auf der Konsole wie System.out.print ausgegeben, kann aber über log4j.xml jederzeit auf Filelogging umgestellt werden.
Weiterhin gibt es ein externes .properties File, wo Konfigurationsdinge hin ausgelagert werden können. Ähnlich wie Konfigurationsdokumente in Notes. Die Klasse Properties und v.a. wie die Datei über getClass().getClasspath().getRessourceAsStream(String fileName) eingebunden wird ist auch nicht unbedingt offensichtlich aber gut zu wissen.

Gruß Axel

Offline TMC

  • Freund des Hauses!
  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 3.660
  • Geschlecht: Männlich
  • meden agan
Re: neues Projekt: Poo Monkey
« Antwort #4 am: 05.06.05 - 22:45:40 »
Axel,

nur als Anregung:
Vielleicht möchtest Du auch noch berücksichtigen, RSS auszuwerten bzw. aufzubereiten.

Siehe: Getting the Most Out of SMF - XML, RSS and RSS2 feeds

Ist vermutlich aber sehr viel einfacher umzusetzen, als das was Du hier als Workshop / Projekt machst (als Bot mit User-Login-Daten zugreifen).
Matthias

A good programmer is someone who looks both ways before crossing a one-way street.


Marinero Atlántico

  • Gast
Re: neues Projekt: Poo Monkey
« Antwort #5 am: 05.06.05 - 23:32:57 »
Hi Mathias,

Du kannst ja ein Gegenprojekt starten  ;D
Wo erzeugt atnotes rss  ???
Dies soll ein kleines fokussiertes Projekt sein, wo ich einige grundsätzlich als sinnvoll erachtete *allgemeine* Projekt-Praktiken zur Diskussion stelle.
Es geht nicht um das Programm an sich.
Ich bin z.Zt. an Prozessen interessiert. Nicht jeden Monat eine neue coole Technologie, die Probleme löst, die es nicht gibt.

Ausserdem gehe ich davon aus, dass das von atnotes generierte html sauber genug ist, so dass die vorhandenen java-html parser ausreichend sind, um das Thema easy abzufrühstücken. Für die oben von mir beschriebene Ausgabenstellung wäre sogar String-Parsing völlig ausreichend.
Ausserdem interessiert es mich wie weit ich mit html parsing komme.
Rss ist mit seinen 3 oder noch mehr konkurrierenden Standards halte ich z.Zt. für ein bischen overhyped. Ich müsste mich da auch ernsthaft einarbeiten und ich will ein paar certis machen, bin Consultant, interessiere mich mehr für J2EE als xml und ausserdem möchte ich ein 15 kyo Go-Spieler werden.

Gruß Axel


« Letzte Änderung: 05.06.05 - 23:35:37 von Marinero Atlántico »

Offline TMC

  • Freund des Hauses!
  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 3.660
  • Geschlecht: Männlich
  • meden agan
Re: neues Projekt: Poo Monkey
« Antwort #6 am: 05.06.05 - 23:47:09 »
Axel, war mir schon klar, das das AtNotes nur als Beispiel dienen soll. Denn ansonsten gibt's da von SMF schon mitgelieferte Möglichkeiten AFAIK (SSIs z.B.).

Werde Dein Projekt auf jeden Fall verfolgen, wenn auch wohl eher erstmal passiv.

Matthias

P.S. RSS gibt es:
http://www.atnotes.de/index.php?action=.xml
http://www.atnotes.de/index.php?action=.xml;type=rss;limit=10

Doku: siehe mein Link oben.
Matthias

A good programmer is someone who looks both ways before crossing a one-way street.


Marinero Atlántico

  • Gast
Re: neues Projekt: Poo Monkey
« Antwort #7 am: 06.06.05 - 00:05:05 »
Ich glaub die Funktion ist gebunden an Mozilla oder?
Benutze ja http-client von apache-jakarta für die http-Kommunikation und keinen Browser.
"Funktionalität schon mitgeliefert" ist imho der am häuftesten mißbrauchte Satz in dieser Branche.  ;D
Ich habs nicht ausprobiert, aber ich gehe stark davon aus, dass apache.jakarta HttpClient locker in einen Domino Java Agenten eingebunden werden kann.
Wie willst du das SMF in Domino nutzbar machen.


Passiv bringt nichts. Es ist nicht so schwierig. Wobei die Beschreibung relativ reduktionistisch und damit tuff ist. Aber wer will, kann Fragen stellen.

ach ja. Und hier ist der SMF Feed auf das offtopic forum:
http://www.atnotes.de/index.php?board=12.0&action=.xml
Überzeugt irgendwie auch nicht.

Gruß Axel
« Letzte Änderung: 06.06.05 - 00:17:37 von Marinero Atlántico »

Offline TMC

  • Freund des Hauses!
  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 3.660
  • Geschlecht: Männlich
  • meden agan
Re: neues Projekt: Poo Monkey
« Antwort #8 am: 06.06.05 - 23:12:05 »
Ich glaub die Funktion ist gebunden an Mozilla oder?

Du meinst das AtNotes-RSS? Hmm, nein, ist valides RSS, zumindest wenn ich diese URL bei http://feedvalidator.org eingebe:
Zitat
Congratulations! This is a valid RSS feed.


ach ja. Und hier ist der SMF Feed auf das offtopic forum:
http://www.atnotes.de/index.php?board=12.0&action=.xml
Überzeugt irgendwie auch nicht.

Stimmt, irgendwie sehr leer  ::)

Wie willst du das SMF in Domino nutzbar machen.
Indem man die MySQL-DB anzapft? Geht natürlich nur, wenn man den Zugang hat, als TMC oder Marinero Atlantico natürlich keine Chance, dann bietet sich natürlich Deine Vorgehensweise an.

Matthias
Matthias

A good programmer is someone who looks both ways before crossing a one-way street.


Marinero Atlántico

  • Gast
Re: neues Projekt: Poo Monkey
« Antwort #9 am: 07.06.05 - 09:56:35 »

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz