Primefaces – web.xml korrekt Konfigurieren

Für Glassfish sind ein paar mehr Einstellungen notwendig um Primefaces Push zu aktivieren und auch korrekt laufen zu lassen.

Im Webprojekt muss die web.xml folgendermaßen erweitert werden:

 

   
    Push Servlet
    org.primefaces.push.PushServlet
    
      org.atmosphere.cpr.sessionSupport
      true
    
    
      org.atmosphere.cpr.broadcasterCacheClass
      org.atmosphere.cache.SessionBroadcasterCache
    
    
      org.atmosphere.cpr.broadcastFilterClasses
      org.atmosphere.client.TrackMessageSizeFilter
    
    
      org.atmosphere.cpr.WebSocketProcessor
      org.atmosphere.cpr.HttpServletRequestWebSocketProcessor
    
    
      org.atmosphere.disableOnStateEvent
      true
    
    
      org.atmosphere.useNative
      true
    
    
      org.atmosphere.useWebSocket
      true
    
    
      org.atmosphere.websocket.maxTextMessageSize
      0
    
    1
    true
  

 

Aktivieren von Comet in Glassfish

Primefaces bietet in der aktuellen Version ein PrimePush an. Leider scheint das ganze nur zu funktionieren wenn diverse Konfigurationen abgestimmt sind. Derzeit läuft es bei mir noch nicht ganz stabil aber ein paar Tipps kann ich gerne schon mal geben.

Es gibt die Möglichkeit Comet, eine Pushvariante im Glassfish bzw. für Pushservices per Parameter zu aktivieren. Aufpassen! Diese Möglichkeit der klassischen Parameter ist tödlich für den Glassfish. Leider wird damit die Antwortzeit ins unermessliche gesteigert und nur schwer ein Aufruf möglich.

Die sichere Variante ist aktivieren von Comet per Administratorconsole und zwar in den einzelenen http-listenern. Anbei ein Screenshot der das Ganze zeigt.

comet_aktivierung

Löschen von Dateien die auch als root nicht gelöscht werden können

Wenn Dateien und Ordner eauch als root nicht gelöscht werden können kann es eine einfache Ursache haben. Dem Ordner oder der Datei wurden weitere Attribute hinzugefügt. Eines davon ist immutable. Dieses kleine Attribute hat mich einige Nerven gekostet und ist auf dem ersten Blick nicht sichtbar.

Mit dem Befehl lsattr -la können alle weiteren attribute im Verzeichnis dargestellt werden. Hier steht dann auch das jeweilige Attribut das dem Ordner neben den Standardrechten noch zugeordnet werden kann.

Über man chattr bekommt ihr eine Übersicht der Attribute die einem Verzeichnis/Datei zugeordnet werden können und auch wie man diese setzte bzw. entfernt.

Abschließend noch der Befehl zum entfernen von immutable. Ein einfaches: chattr -i genügt um alles wieder ordnungsgemäßg löschen zu können.

PDFs in Java erstellen – Open Source

Zur Erstellung von PDFs mit Java gibt es nur wenige wirkliche Open Source Lösungen. Leider wurde eine gute Lösung mittlerweile kostenpflichtig und für kommerzielle Nutzung wirklich teuer wenn man ein paar Nutzer anbinden will. Somit haben wir uns für pdfBox entschieden. Es ist zwar um einiges einfacher und rudimentärer gestaltet als iTextPdf aber dafür noch open source und vor allem Lizenzfrei.

Wir haben vor kurzem eine andere Möglichkeit gefunden. Leider ist es nicht so schön gelöst wie bei iTextPdf. Jede Zeile/Pixel und Polygon wie auch immer man es bezeichnen mag wird per Koordinatensystem bestimmt. Wobei der absolute Nullpunkt immer links unten ist.

Auch unterstützt pdfBox leider keine Tabellen, Hintergründe oder sonstige Features. Wobei ich demnächst eine neue Subklasse euch anbieten möchte in der man ein paar dieser simplen Features nutzen kann. Vorallem mit Background hinterlegter Text oder auch eine Tabelle.

 
Anbei noch ein kleiner UseCase wie pdfBox zu verwenden ist.
 

private int column1 = 30, column2 = 350, column3 = 475;
private int startTop  = 700;
private int spacer = 21;
private float pageWidth = 0;

public void generatePDF() {
            PDDocument document;
	    PDPage page;
	    PDFont font;
	    PDPageContentStream contentStream;
	    PDJpeg logo;
	    InputStream inputLogo;
	    ByteArrayOutputStream output = new ByteArrayOutputStream(); 
	    final ClassLoader cls = Thread.currentThread().getContextClassLoader();
	    
	    // Creating Document
	    document = new PDDocument();

	    page = new PDPage(PDPage.PAGE_SIZE_A4);
	    pageWidth = PDPage.PAGE_SIZE_A4.getWidth();
	    LOG.info("HEIGHT: " + PDPage.PAGE_SIZE_A4.getHeight() + " WIDTH: " + PDPage.PAGE_SIZE_A4.getWidth());
	    
	    // Adding page to document
	    document.addPage(page); 

	    // Adding FONT to document
	    font = PDType1Font.HELVETICA;           

	    // Retrieve Image to be added to the PDF
	    inputLogo = new FileInputStream(new File(cls.getResource("image-default-logo.png").toURI().getPath()));

	    BufferedImage buffLogo = ImageIO.read(inputLogo);
	    logo = new PDJpeg(document, buffLogo);
	    logo.setHeight(32);
	    logo.setWidth(246);

            contentStream = new PDPageContentStream(document, page); 
	    contentStream.drawImage(logo, 339, 770);
	    
	    addBackgroundRectangle(contentStream, Color.GRAY, column1, l-8, 31);
	    addText(contentStream, font, reportuebersicht, 18, column1, newLine());
}

private void addText(PDPageContentStream contentStream,
	    				PDFont font,String text,int size,
	    				int posx,int posy) throws IOException {
	contentStream.beginText();
	contentStream.setFont(font, size);
	contentStream.moveTextPositionByAmount(posx, posy);
	contentStream.drawString(StringEscapeUtils.unescapeHtml4(text));
	contentStream.endText();
}

private void addBackgroundRectangle(PDPageContentStream contentStream, Color color, int posx, int posy, int height) throws IOException {
	 contentStream.setNonStrokingColor(color);
	 contentStream.fillRect(posx-3, posy-3, pageWidth-60, height);
	 contentStream.setNonStrokingColor(Color.BLACK);
}

Remote Logs, Tail Logs in Windows, Log Viewer

Ich habe mich mal wieder auf den Weg gemacht um ein allgegenwärtiges Problem zu lösen. Unschöne Logs in eine Form quetschen um Sie schnell analysieren zu können. Einen schnellen überblick zu haben wo Fehler auftreten oder einfach nur ein paar Debugmessages im Blick zu haben. Dabei bin ich auf ein nützliches Open Source Projekt gestoßen. OtrosLogViewer, hört sich ziemlich chinesisch an ist aber sehr gut zu bedienen wenn es das erste mal läuft.

Super viele Einstellungsmöglichkeiten um wichtige Marken zu setzen oder einfach nur die log am Stücke zu sehen und per „tail“ immer wieder aktualisiert zu bekommen.

Der LogViewer der nicht nur ein tail Ersatz für Windows für mich ist sondern auch eine visuelle Aufbereitung der Ergebnisse mir bringt macht es um einiges leichter Auffälligkeiten zu checken.

Projektseite

http://code.google.com/p/otroslogviewer/

Installation

Ihr müsst euch lediglich die ZIP file aus dem Google Code ziehen. http://code.google.com/p/otroslogviewer/downloads/list

Achtung: Um das ganze System sauber benützen zu können solltet ihr Java JRE6 verwenden. Mit JRE7 werdet ihr massive Probleme bekommen. Habe ich auf alle Fälle festgestellt.

HowTo

Der LogViewer bietet euch die Möglichkeiten eigene Pattern anzulegen. Diese dienen dazu Logfiles verschiedenster Server zu parsen und in eine korrekte Form zu biegen. Ich habe euch hier 2 Pattern für glassfish und tomcat 7 zum download hinterlegt. Die ZIP Datei entpacken und beide Pattern Files einfach in den Ordner: plugins/logimporter kopieren.

Video

Liferay 6.1 – Minifier Error

Ein nerviger Fehler im Liferay ist der Minifier für JavaScript oder CSS Code. Der Fehler ist zwar ziemich banal aber es nervt wenn er immer und immer wieder auftritt nur weil einige Zeilen Code falsch auskommentiert wurden. Richtig, der Fehler tritt auf dern Kommentare falsch gesetzt werden.

Single Line Kommentarblöcke mit doppel Slash werden von Liferay nicht unterstützt und schießen den Minifier leider ab. Somit immer den Blockkommentar verwenden und saubere Kommentarfelder integrieren. Damit sollte dann ein reibungsloser Betrieb wieder möglich sein.

Liferay 6.1 – Webservices – RemoteInterface

Ich habe einen ganzen Tag damit verschwendet fehlerhafte Tutorials von Liferay zu durchforsten um nach dem X- ten Versuch endlich eine passende Lösung zu finden. Das Geheimnis liegt in dern Stub’s die vom Webservice generiert werden. Um eine korrekte Übergabe der User und Passwort Credentials zu erzielen dürft ihr diese nicht in der URL übergeben. Beispiele von Liferay sind hierbei falsch und alle Anfragen werden mit einem 401 Authentication failed zurückgewiesen. Ich werde euch Anhand eines einfachen Webservices zeigen wie es korrekt funktioniert und Axis konform ist. Wir erstellen zunächst ein Standard Liferay Projekt mit Portlet. Das Portlet könnt ihr genau so gut wieder löschen. Oder blank im Projekt lassen. Anschließend könnt ihr über einen Rechtsklick auf euer Projekt.

Nachdem ihr das gemacht habt erscheint ein kleiner Dialog. Eigentlich selbsterklärend. Nachdem ihr auf „Finish“ gedrückt habt, geht es nun an den Service. Hierbei erstellt er euch automatisch die Entity Foo. Es ist eine Erleichterung falls ihr vorhabt persistent Daten in der Liferay Datenbank unter zu bringen. Ich will euch mit diesem Beispiel lediglich zeigen wie RemoteService in Liferay kommunizieren. Zu diesem Zweck habe ich die Entity gelöscht. Anschließend müsst ihr über den Rechtsklick auf die services.xml eure Klassen builden. Wenn der Ant Prozess durchlaufen ist und euch keine Fehler unterlaufen sind, solltet ihr jetzt eine ganze Stange neuer Klassen im src Directory haben. Darin enthalten sind im package impl folgende zwei Klassen zum einen für die local Services „FooLocalServiceImpl“ zum anderen für die RemoteServices die wir später anzapfen wollen. Das heißt, jegliche funktionalität im Service includieren wir in unserer RemoteKlasse: „FooServiceImpl“. Hier habt ihr ein kleines Biespiel für ein simples Ping Pong Beispiel. Anhand eines Zufallwertes. Wichtig! Ihr müsst jetzt wieder die Services erneut builden um Änderungen wirksam zu machen!

Jetzt gehts an den Hauptteil des Blogeintrags. Das Portlet mit der RemoteClient Funktion. Wie ihr euch schon denken könnt müsst ihr ein neues Liferay Projekt erstellen inkl. MVC Portlet.
Zum einen erstellen wir eine eigene Klasse in Abhängigkeit des MVC-Portlets. Hierzu passen wir einfach unsere portlet.xml des neuen WebService Clients an.

Wenn die neue Klasse erstellt ist, wird sie später bearbeitet. Aber zuerst erstellen wir unsere Webclient. Hierbei klicken wir rechts auf unser Portlet und über New -> Other zum WebserviceClient.

Über weiter kommen wir dazu die ServiceURL einzugeben. Hierbei muss beachtet werden dass wir den PortletName nutzen und über, seit liferay 6.0 /api/axis oder /api/secure/axis die Services aufrufen können.

Jetzt können wir unsere erweiterte MVC Klasse aufbauen.

public class RemoteClient extends MVCPortlet {

	private String host = "localhost";
	private String port = "8180";
	private String userId = "test";
	private String password = "test";
	private String portlet = "FooService-portlet";
	private String method = "Plugin_foo_FooService";

	@Override
	public void doView(RenderRequest renderRequest,
			RenderResponse renderResponse) throws IOException, PortletException {
		super.doView(renderRequest, renderResponse);
	}

	@Override
	public void processAction(ActionRequest actionRequest,
			ActionResponse actionResponse) throws IOException, PortletException {

// ACTION - CALL SERVICE
		try {			
			FooServiceSoapServiceLocator locator = new FooServiceSoapServiceLocator();
			FooServiceSoap service = locator.getPlugin_foo_FooService(_getURL(method, false));
			((Plugin_foo_FooServiceSoapBindingStub) service).setUsername(userId);
			((Plugin_foo_FooServiceSoapBindingStub) service).setPassword(password);

			String match = service.match();
                        System.out.println("Match: "+match);

		} catch (AxisFault e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ServiceException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		super.processAction(actionRequest, actionResponse);
	}

        /**
	 * @param serviceName
	 * @param authenticatedUrl
	 * @return
	 * @throws Exception
	 */
	private URL _getURL(String serviceName, boolean authenticatedUrl) throws Exception {
        String url;
        if(portlet != null) { portlet = "/"+portlet; }
        if (authenticatedUrl) {        	
            url = "http://" + userId + ":" + password + "@"+ host+ ":"+port+portlet+"/api/secure/axis/" + serviceName;
        } else {
            url = "http://" + host+":"+port+portlet+"/api/axis/" + serviceName;
        }
    
        return new URL(url);
    }
}

Wichtig! Für alle die Probleme haben über die _getURL zu kommunizieren, was vor allem Auftritt wenn Server zu Server Verbindungen erstellt werden, muss die AXIS User & Passwort Kombination integriert werden. Hierbei sind diese zwei Zeielen verantwortich:

((Plugin_foo_FooServiceSoapBindingStub) service).setUsername(userId);
((Plugin_foo_FooServiceSoapBindingStub) service).setPassword(password);

Ich freue mich Antworten und hoffentlich konnte ich euch helfen! 😉

Liferay 6.1 – Segmentation fault

Probleme mit Tomcat 7 und Liferay? … Kurz nach dem Start läuft der Server nicht mehr. Die Konsole meldet lediglich Segmentation fault. Kein schöner Fehler und unser Lösungsversuch ist lediglich: JDK Update. Nachdem wir die Java 1.6.24 auf 1.6.34 geupdated haben ist der Fehler verschwunden und der Server läuft wieder stabil.

Liferay – Unable to deploy portlet in Liferay Portal

Problem: Unable to deploy portlet in Liferay Portal Server 6.1.0 CE. Während des deploys erhalte ich den Fehler „war does not support this version of Liferay“ oder “ Add war to the blacklist“.

com.liferay.portal.kernel.deploy.auto.AutoDeployException: sample-struts-portlet-6.1.0.1.war does not support this version of Liferay
 at com.liferay.portal.deploy.auto.PortletAutoDeployer.autoDeploy(PortletAutoDeployer.java:99)
 at com.liferay.portal.deploy.auto.PortletAutoDeployListener.deploy(PortletAutoDeployListener.java:78)
 at com.liferay.portal.kernel.deploy.auto.AutoDeployDir.processFile(AutoDeployDir.java:180)
 at com.liferay.portal.kernel.deploy.auto.AutoDeployDir.scanDirectory(AutoDeployDir.java:222)
 at com.liferay.portal.kernel.deploy.auto.AutoDeployScanner.run(AutoDeployScanner.java:50)
Caused by: com.liferay.portal.kernel.deploy.auto.AutoDeployException: sample-struts-portlet-6.1.0.1.war does not support this version of Liferay
 at com.liferay.portal.tools.deploy.BaseDeployer.deployFile(BaseDeployer.java:746)
 at com.liferay.portal.deploy.auto.PortletAutoDeployer.autoDeploy(PortletAutoDeployer.java:96)
 ... 4 more
06:08:32,312 INFO  [AutoDeployDir:203] Add sample-struts-portlet-6.1.0.1.war to the blacklist 

Mein Problem hierbei war nicht das erstellen des Portlets in einer höheren Version oder einer niedrigeren. Es war lediglich ein Eintrag in einer XML File der gefehlt hat.

Lösung:
Bearbeitet die Datei: „docroot\WEB-INF\liferay-plugin-package.properties“ und fügt folgenden Parameter ein bzw. verändert die Version dementsprechend.

liferay-versions=6.1.0

Jetzt müsst ihr den Server neustarten um das Portlet von der Blacklist zu bekommen. Anschließend sollte es wieder deployed werden können. Wenn das nicht der Fall ist, schaut bitte noch in der anderen File nach: „liferay-plugin-package.xml“


        6.1.0+
    

Primefaces Charts

Kleines HowTo für alle die Chartes von Primefaces benützen möchten. Um es vorweg zu nehmen. Es ist leider nicht möglich eine DateTime X Achse zu nutzen. Wir benützen hierzu um dem ganzen Abhilfe zu schaffen KW/Jahr (Kalenderwoche/Jahr). Es ist natürlich auch möglich Monat/Jahr oder ähnliches zu verwenden.

Primefaces arbeitet hierbei im Backend mit jQuery und einer eigens angefertigten charts.js … Leider hatte ich bisher noch keine Zeit mich genauer mit dieser File auseinander setzen zu können.

Auf der JSF Seite ist es ein Einzeiler. Super von den Primefaces Jungs umgesetzt.


Die Java Seite ist etwas umständlicher aber auch hier ist es sehr schlank gehalten.

package org.primefaces.examples.view;  
  
import java.io.Serializable;  
  
import org.primefaces.model.chart.CartesianChartModel;  
import org.primefaces.model.chart.ChartSeries;  
import org.primefaces.model.chart.LineChartSeries;  
  
public class ChartBean implements Serializable {  
  
    private CartesianChartModel categoryModel;  
  
    private CartesianChartModel linearModel;  
  
    public ChartBean() {  
        createCategoryModel();  
        createLinearModel();  
    }  
  
    public CartesianChartModel getCategoryModel() {  
        return categoryModel;  
    }  
  
    public CartesianChartModel getLinearModel() {  
        return linearModel;  
    } 
    private void createLinearModel() {  
        linearModel = new CartesianChartModel();  
  
        LineChartSeries series1 = new LineChartSeries();  
        series1.setLabel("Series 1");  
  
        series1.set(1, 2);  
        series1.set(2, 1);  
        series1.set(3, 3);  
        series1.set(4, 6);  
        series1.set(5, 8);  
  
        LineChartSeries series2 = new LineChartSeries();  
        series2.setLabel("Series 2");  
        series2.setMarkerStyle("diamond");  
  
        series2.set(1, 6);  
        series2.set(2, 3);  
        series2.set(3, 2);  
        series2.set(4, 7);  
        series2.set(5, 9);  
  
        linearModel.addSeries(series1);  
        linearModel.addSeries(series2);  
    }  
}

Ich habe hier zu großen Teilen das Tutorial von Primefaces benützt weil es super einfach beschrieben ist und übersichtlich. Hier gehts zum Orginalbeitrag.