Jersey, Pydio & the next Big thing – Part II

Ja, es hat länger gedauert als erwartet. Nicht nur Jersey steckt voller Ungereimtheiten, auch Pydio hat tolle Bugs auf Lager. Kombiniert man das, verschwendet man richtig viel Zeit.

Status: Es geht.

Update der verwendeten Tools: Jersey 1.18 ( jsr311-api-1.1.jar, asm-3.1.jar, jersey-bundle-1.18.jar, NEU: jersey-multipart-1.18.jar)

Der Fileupload:

Der FileUpload stellt sich in Jersey schwieriger dar, als man annehmen sollte, denn die spärlichen Beispiele sind einfach mal falsch, solange man nicht die Suchbegriffe benutzt,
die einen ohnehin schon auf die richtige Fährte gebracht haben : MultiPart.

Aber auch da gibt es Fallstricke die es zu umschiffen geht und weil das einfach nur nervt, gibts hier gleich die Lösung der Probleme:

Schritt 1:

                FormDataMultiPart form = new FormDataMultiPart();
                FormDataBodyPart p = new FormDataBodyPart(
                            FormDataContentDisposition
                                .name("userfile_0")
                                .fileName("Dateiname")
                                .build()
                            , new File("Dateiname")
                            , MediaType.MULTIPART_FORM_DATA_TYPE);
                form.bodyPart(p);

Damit man FormDataMultiPart benutzen kann, muß oben erwähntes JAR-File zum Projekt hinzugefügt werden. Danach ist es aber ganz einfach das File dann wirklich per REST hochzuladen. Wobei REST hier wohl der falsche Ausdruck ist, denn es ist ein simples MultiPart-Form, daß per POST hochgeladen wird. Das macht jeder Webbrowser genauso.

Schritt 2:

                response = resource.queryParam("get_action","upload")
                           .queryParam("dir","/")
                           .queryParam("secure_token", securetoken )
                           .header("Cookie", cookieheader )
                           .accept(MediaType.APPLICATION_XML)
                           .type(MediaType.MULTIPART_FORM_DATA)
                           .post(ClientResponse.class, form);

Jetzt muß man natürlich noch den Share Call per API iniziieren werden, damit ein Downloadlink für die Datei erzeugt wird. Das sagt sich jetzt so leicht, denn Pydio 5.2.0 und 5.2.1 sind an der Stelle einfach mal defekt. Da wir mit der REST API arbeiten, erwartet unser Client zurecht auch eine korrekt formulierte Antwort und dazu gehört auch die korrekte Länge der Antwort vom Server. Die Entwickler von Pydio haben es nun geschafft diesen Teil der API erfolgreich zu entschärfen. Statt der korrekten Länge des Links, kommt ein

Content-Length:  0

und damit kann Jersey nicht umgehen. Daher darf man nun erstmal das Pydio Quickfixen.Von der Isolation des Fehlers bis zum funktionierenden Fix der PHP Anwendung, vergingen rund 80 Minuten.

Ich hege ja die Hoffnung, daß mein Bugreport gelesen und bearbeitet wird. Zur Sicherheitslücke die ich letzte Woche an das Team von Charles geschickt habe, kam nur ein : „Wir schicken Dir Deine Mail zurück-kam also an“ Nachricht zurück. Ein Umgang mit Securityproblemen muß sich wohl erst noch entwickeln. Was übrigens für den an sich sicheren Code von Pydio spricht. „Gut“ ist allerdings was anderes. Kommentare fehlen da fast vollständig 🙂

Nachdem nun diese Klippen umschifft sind, kann die eigentliche Arbeit an der Anwendung beginnen.

JAXB XML Parsing kann man übrigens getrost vergessen, der XML Code der von Pydio kommt überfordert den Parser, so daß Elemente einfach verloren gehen. Ob da der Fehler bei Pydio liegt, oder der Parser Bugs hat, mag ich nicht beurteilen. Ich habe mir dann flugs einen eigenen SimpleXML-Parser mit XML-zu-Objekt Komponente geschrieben. Reflektion ist ne schöne Sache in Java.

Wenn Sie also vorhaben sollten, für Pydio in Java zu entwickeln, kommt einiges auf Sie zu. Sie dürfen sich aber gern melden, wenn Sie Fragen haben. Aufgrund der Bots die mein Blog zum Abladen von Schrott missbrauchen wollen, kann ich leider keine Kommentarfunktion freischalten 🙁

 

Jersey, Pydio & the next Big thing

Wer schon immer Pydio(formerly known as AjaXplorer) über Jersey in Java per API ansprechen wollte sollte nun weiterlesen, für alle Anderen die Kurzform: Tun Sie es nicht, niemals, nie, nicht, auf keinen Fall!

Wenn man alleine zum Coden des Logins 6 Stunden braucht, kann es nicht gut enden. Für alle Wagemutigen hier ein paar Tips wie es klappt. Ja, „klappt“, nicht klappen könnte. Ich werde allerdings keine konkrete Implementierung vorstellen, dafür hat mich das einfach zuviel Geld gekostet 😉

verwendete Tools: Jersey 1.18 ( jsr311-api-1.1.jar, asm-3.1.jar, jersey-bundle-1.18.jar )

Schritt 1: Client mit DefaultClientConfig erstellen.

DefaultClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);

WebResource resource = client.resource("http://Ihre.domain/pathtopydio/index.php");

Schritt 2: Session Cookie besorgen

String cookieheader = getSession( response );

Schritt 3: LoginSeed besorgen

String seed = resource.queryParam("action", "get_seed")
 .header("Cookie", cookieheader )
 .accept(MediaType.APPLICATION_XML).post(String.class);

Schritt 4: Einloggen

response = resource.queryParam("userid", loginname )
 .queryParam("password", loginpasswort)
 .queryParam("login_seed", seed )
 .queryParam("action", "login")
 .header("Cookie", cookieheader )
 .accept(MediaType.APPLICATION_XML).post(ClientResponse.class);

Schritt 5: SecureToken auslesen

String secureToken = getSecureToken( response );

Schritt 6: offen … Was auch immer Sie jetzt machen wollen :

result = resource.queryParam("get_action","ls")
 .queryParam("dir","/")
 .queryParam("secure_token", secureToken )
 .header("Cookie", cookieheader )
 .accept(MediaType.APPLICATION_XML).post(String.class);

Was auch immer Sie im Pydio Forum dazu lesen, vergessen Sie es einfach:

– die rest.php geht nicht und wenn nur für einen hartgecodeten User ( :facepalm: )
– Irgendwelche Force-Header sind völlig überflüssig
– Jersey brauchen Sie auch nicht, wenn Sie gleich einen eigenen HTTP-Request nebst Parser bauen, haben Sie mehr Spaß und sind schneller. Sie müssen eh das Gleiche machen wie mit Jersey: Cookies und Securetoken auslesen.
– JSON ? … per Api ? … muharhar !
Mit anderen Worten, da kommt XML, selbst wenn Sie APPLICATION_JSON als Medientyp schicken ( Pydio 5.2 )

Vorteile von Jersey: bis auf die etwas übersichtlichere Schreibweise .. keine 🙂

Eigentlich hat es nur Nachteile. Es ist schlecht dokumentiert, keine Eclipseunterstützung, verbraucht unnötig Platz, keine Beispiele im Netz usw. usw.
Da muß man ergänzen, Beispiele gibt es schon, aber fast nur für die Serverseite, wenn man in JavaEE einen netten WebService auf Rest aufbauen möchte.

Also das geht bestimmt besser.

Eins muß ich entschuldigend für Jersey sagen, ich habe die 1.x Release verwendet, weil dies auf einer Webseite so mit Links erklärt wurde. Jersey selbst meint allerdings auch, wer Maven nicht will/kann, soll 1.18 nehmen. Tja, dann…

Morgen gehts weiter mit Fileupload per Pydio API.

Javaprogramme könnten schneller laufen

Mal wieder fiel sofort auf, als ich einmal mehr strace bemühen mußte um festzustellen,
was genau das von Java aus gestartete Bashscript so treibt.

Dabei weckten wieder diese Zeilen meine Aufmerksamkeit:

[pid  3488] gettimeofday({1371633845, 44988}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 45163}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 45283}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 45401}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 45648}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 45776}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 45917}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 46044}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 46156}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 46286}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 46509}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 46629}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 46746}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 46857}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 46967}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 47120}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 47231}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 47343}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 47465}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 47612}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 47750}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 47870}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 48008}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 48121}, NULL) = 0
[pid  3488] gettimeofday({1371633845, 48232}, NULL) = 0

Wie man leicht erkennen kann, finden diese Zugriffe im Milli- bis Microsekundentakt statt.

Wenn man sich das strace log vornimmt, kommt das dabei raus:

[root]# wc --lines  /tmp/log
38896 /tmp/log
[root]# grep -c gettimeofday /tmp/log
25366

Also rund 2/3 aller Logzeilen entfallen nur auf gettimeofday() . Auch wenn der Aufruf an sich nur wenige Takte der CPU benötigen sollte, die Masse der Aufrüfe an sich stellt ein nicht zu verachtendes Problem dar. Vermutlich ist das völlig unnötig. Mal sehen, ob sich Oracle der Meinung anschliesst.

Im Einsatz war Java 6 latest.