Jasper kompilierte Programme beschleunigen.

Jasper hat eine unschöne Seite. Benutzt man in einer JSP eine Direktausgabe von HTML Code, was sehr praktisch ist, kommt es zu einer unschönen Situation. Kleines Beispiel:

<%
<div class=olddefect>
 <table border="0">
      ...
 </table>
 </div>
%>

Je mehr Code man in den <% %> Block hat, desto mehr Zeilen hiervon werden erzeugt :

 out.write("\n");
 out.write("<div class=olddefect>\n");
 out.write("\t<table border=\"0\">\n");
 ...
 out.write("\t</table>\n");
 out.write("</div\n");
 out.write("\n");

Und wie man sehen kann, ist das höllisch inperformant. Zeit es zu optimieren.

Will man nun eine WebApp schneller bekommen, bleiben einem nur zwei Wege:

a) Mehr IO investieren z.b. in Form eines Ladevorgangs. Der kann natürlich im RAM gecacht worden sein, aber je nach Umfang der Webanwendung kann das vielleicht nicht funktionieren.
daher b) man verzichtet auf Zeilenumbrüche im HTML Code, so erzeugt Jasper genau eine Zeile out.write(„…“). Die ist zwar unschön, aber performanter.

Diverse Codeverkürzungstools könnte man dafür einsetzen.

Fall jemand rein zufällig einen Jasper Entwickler kennt, schlagt b) mal zur automatischen Optimierung vor. Danke.

Servlet und JSP verbinden

Kleine Exkursion in die Welt von JavaServerPages und Servlets und wie man dazwischen Daten austauschen kann. Zunächst mal die einfache Seite, die JSP :

<%@ page import="java.net.IDN,misc.*,web.*,java.util.*,rsi.*,hash.*,sendmail.Sendmail,java.io.*,server.*,org.json.JSONArray,org.json.JSONObject,ordb.Pandora_server" pageEncoding="UTF-8"
%><%@ include file="cookies.jsp"
%><jsp:useBean id="daten" scope="session" class="hash.StringHash"
/>

Der JSP:useBean Tag ermöglicht u.a. sessionbasierte Objekte in einer JSP zu verarbeiten. Überall wo man den Tag angibt, ist das Objekt verfügbar. Da kann man dann ganz normal drauf zugreifen und mit arbeiten.

if ( daten.checkContent() ) out.write("Daten wurden geprüft und für OK befunden");

Wenn nun ein zweiter Teil der Anwendung in einem Servlet geschrieben wurde,  möchte man ggf. Daten zwischen beiden Teilen der Anwendung austauschen. Ein Servlet ist nichts anderes als eine Klasse, deren vordefinierte Methoden das Request- und Responseobjekt des Webaufrufes bekommen.

Ein kleines, stark vereinfachtes Beispiel:

public class HTMLDispatcher extends HttpServlet {

public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException {
    doRequest(req,res);
}

public void doPut(HttpServletRequest req, HttpServletResponse res)
throws IOException {
    doRequest(req,res);
}

public void doDelete(HttpServletRequest req, HttpServletResponse res)
throws IOException {
    doRequest(req,res);
}

public void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException {
    doRequest(req,res);
}

...
}

Das Servlet kann man dann im Tomcat ( WebApplicationServer ) als Ziel für verschiedene Webaufrüfe definieren (siehe unten). In meinem Fall habe ich gesagt, daß mein Servlet für HTML Aufrüfe zuständig ist. Mein Servlet wertet dann die URL aus und macht mit dem HTML File noch einiges, bevor es ausgegeben wird.

public void doRequest(HttpServletRequest request, HttpServletResponse res)
throws IOException {

res.setContentType("text/html");
Writer out = new BufferedWriter(new OutputStreamWriter(res.getOutputStream(), "UTF-8"));

String method = request.getMethod();
String uri = request.getRequestURI();
String[] args = uri.split("/",-1); // Alles splitten, auch wenn es leer ist

StringHash daten = (StringHash) request.getSession().getAttribute("daten");
if ( daten == null ) daten = new StringHash();

Um an die Daten aus der JSP zu kommen, setze ich „request.getSession().getAttribute(„daten“)“ ein. Das geht aber nur mit Sessionobjekten so. Da die Methode getAttribute() ein klassenloses Objekt zurück gibt, muß selbst den TypeCast machen. Wenn noch keine Session aufgebaut wurde, kann es auch noch kein Bean geben, das wir uns krallen könnten. Damit die Anwendung dann nicht abschmiert, lege ich hier ein Objekt an. Natürlich kann man an der Stelle auch eine Fehlermeldung oder einen Redirect auslösen. Das ist situationsabhängig.

O== Warum überhaupt Servlet und JSP mischen ?

Servlets müssen kompiliert und der WAS Server üblicherweise neu gestartet werden, um die Änderungen anzunehmen. Wenn man JSP Seiten benutzt kümmert sich Jasper darum. Das spart im Einzelfall eine Menge Zeit und man verliert dabei auch keine Sessionobjekte, d.h. kleinere Fehler kann man direkt beheben und weitermachen. Zweifelsfrei eine zeitsparende Methode seine Webseiten zu bauen.

O== Wofür setzt man ein Servlet ein ?

Servlets können auf spezielle Webanfragen eingestellt werden, d.b. bspw. alle Files die auf .jos enden, könnten eine serialisierte Repräsentation des JavaObjekts einer Seite ausgeben, statt HTML Code. Das bekommt man mit reinen JSP Seiten nicht hin.

O== Wie aktiviert man ein Servlet ?

Im WEB-INF Verzeichnis der Anwendung liegt die web.xml Datei. In dieser Datei kann man ein Servlet ganz leicht hinzufügen:

    <servlet>
        <servlet-name>HTMLDispatcher</servlet-name>
        <servlet-class>servlet.HTMLDispatcher</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>HTMLDispatcher</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

Die nötigen Klassen müssen dann im dortigen classes Verzeichnis hinterlegt sein.

Tip: Update der Inhalte eines SQL Views

In einer Datenbank wie MySQL kann man sich Selects als Pseudotabellen anlegen und dann selbst wieder über den diese Tabelle einen Select bauen. So etwas nennt man einen View.

Beispiel:

SELECT a.vorname,a.name,b.beruf as beruf FROM Personen as a,Berufe as b WHERE a.berufsid=b.id;

Wenn man diesen Select als View anlegt, hat man drei Felder : Vorname,Name,Beruf

Nennen wir den View mal Test, wäre dieser Select möglich :

SELECT vorname,name FROM Test WHERE beruf = „Bäcker“;

Wenn man nun versucht den VIEW mit UPDATE zu ändern, geht das eigentlich nicht, weil es eine nicht eindeutige Beziehung der Datensätze untereinander ist.

Für mein aktuelles Pandora Projekt habe ich nun einen View gebaut, bei dem das Update tatsächlich möglich ist:

select `pa`.`id` AS `id`,`pa`.`vorname` AS `vorname`,`pa`.`nachname` AS `nachname`,`pa`.`server` AS `server`,`pc`.`value` AS `friendmode` from (`pandora`.`pandora_config` `pc` join `pandora`.`pandora_account` `pa`) where ((`pa`.`id` = `pc`.`uid`) and (`pc`.`name` = ‚michsuchen‘))

Das funktioniert aufgrund dieser Beziehung „((`pa`.`id` = `pc`.`uid`)“ , denn in beiden Tabellen gibt es exakt einen eindeutigen Datensatz. d.b. :

Für jede Person gibt es exakt einen Config Eintrag in der anderen Tabelle. Damit kann der Datenbankserver jetzt die logische Verbindung der Datensätze „rückwärts“ auflösen und in der richtigen Tabelle den richtigen Eintrag ändern:

UPDATE `pandora_userliste` SET friendmode = ‚erlauben‘ WHERE vorname =’meinvorname‘;

Damit ist der View Read/Writeable geworden was es man mit Hilfe des ORDB Frameworks ausnutzen kann, denn Views werden ein Java Datenobjekte erzeugt. Über Views lassen sich schlanke Strukturen und Datenbankobjekte erzeugen, die dazu noch updatefähig sein können (aber nicht müssen). Als Folge davon erhält man übersichtliche Datenbankstrukturen, die von einem Menschen leicht gelesen und verstanden werden können, aber trotzdem Datenbanktechnisch höchst performant gestaltet sein können.