Docker + Netbeans + Liferay

Für eine einfache Integration von Docker für die Entwicklung nutze ich Netbeans IDE in Version 8. Die integrierte Docker Unterstützung vereinfacht es, neue Application Server aufzusetzen und für spätere Anwendungen zu verteilen.

Im Vorfeld muss die lokale Docker Installation angepasst werden. Standardmäßig hört Docker auf keinen TCP Socket, das muss customized werden.

Core OS gibt eine einfache Anleitung hierfür vor:

Customizing docker

The Docker systemd unit can be customized by overriding the unit that ships with the default Container Linux settings. Common use-cases for doing this are covered below.

Enable the remote API on a new socket

Create a file called /etc/systemd/system/docker-tcp.socket to make Docker available on a TCP socket on port 2375.

[Unit]
Description=Docker Socket for the API

[Socket]
ListenStream=2375
BindIPv6Only=both
Service=docker.service

[Install]
WantedBy=sockets.target

Then enable this new socket:

systemctl enable docker-tcp.socket
systemctl stop docker
systemctl start docker-tcp.socket
systemctl start docker

Test that it’s working:

docker -H tcp://127.0.0.1:2375 ps

Quelle: https://coreos.com/os/docs/latest/customizing-docker.html

Netbeans einrichten

Über den Reiter: Services -> Docker könnt ihr mit einem Rechtsklick eine neue Docker Instanz hinzufügen. Hierbei wäre es möglich sogar Remote Systeme anzuschließen, für Teams die auf einer zentralen Installation arbeiten.

Durch die vorhergehende Konfiguration von Docker sollte Successfull beim Test Connection erscheinen.

Docker + Liferay Image

Ich verwende aktuell noch ein Liferay 6.2 Image im Docker Umfeld für ein Projekt.

Daher habe ich auf das bereits erstelle Image von snasello zurück gegriffen.

Das könnt ihr hier https://hub.docker.com/r/snasello/liferay-6.2/

für eure Docker Installation herunterladen.

Liferay in Netbeans

Alle Docker Container werden anschließend im Netbeans gelistet. Ihr könnt den Liferay Container via Rechtsklick „run“ starten. Anschließend wird der Name definiert und das Port- Mapping.

Nachdem ihr „finish“ geklickt habt, wir der Container gestartet. In eurer Console erhaltet ihr dementsprechend den output.

How To Deploy Packages on Liferay Docker Container!

Um Portlets, Themes und Co auf dem Docker Container zu deployen, muss das deployment Verzeichnis lokal gemappt werden. Hierbei könnt ihr folgenden Befehl verwenden:

Laut Docker Dokumentation soll das über den Parameter -v möglich sein.

Quelle: https://docs.docker.com/engine/tutorials/dockervolumes/

Sobald es funktioniert, update ich den Beitrag!

Connect to Docker via Shell

Um den Docker Container zu konfigurieren oder Installationen / Konfigurationen vorzunehmen könnt ihr direkt via Shell auf das System zugreifen.

sudo docker exec -i -t {name-of-docker-container} /bin/bash

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.