PayOne + JEE Application

PayOne ist ziemlich umständlich zu integrieren. Für einen der großen Zahlungsdienstleister haben die Macher von PayOne ganz schön was nachzuholen. Ich persönliche finde PayOne vom Aufbau her ziemlich altmodisch. Man merkt, das dass Webportal des Zahlungsdienstleisters schon etwas in die Jahre gekommen ist. Ebenso der Komfort für die Kunden. Einen großen Pluspunkt hat PayOne. Die Integration in bestehende Systeme. Siehe magento – commerce, shopware, oxid, demandware oder intershop. Dadurch das sie in zahlreichen Großen Unternehmen zum Bestand zählen bietet eine feste Kundenbasis ein regelmäßigen Zahlungsfluss.

Wir sind gerade dabei die Schnittstellen für eine JEE- Anwendung anzubinden. Leider ist mir keine fertige Library im Netz über die Füße gefallen die ich nutzen hätte können. Somit kann ich wieder von vorne anfangen.

PayOne bietet seit einiger Zeit eine „Frontend“ – Lösung an. Hierbei wird über eine dynamische URL ein iFrame inkludiert oder die Seite aufgerufen über der die Zahlung abgewickelt werden kann. Dabei sind mir, im Gegensatz zur Konkurrenz z.B. Adyen wieder einige Nachteile aufgefallen.

  • Es kann lediglich eine Zahlungsart angeboten werden.
  • Die Implementierung ist ziemlich aufwendig da sehr genau Reihenfolgen eingehalten werden müssen.
  • Standard für die Implementierung ist PHP.
  • Relativ langsame Abwicklung des Zahlungsprozesses.

Ich hatte die letze Zeit öfters Gelegenheit einige der Zahlungsdienstleister ausprobieren zu können. Deren Schnittstellen zu testen und wie man darauf reagieren kann. Mir ist aufgefallen das Adyen an dieser Stelle sehr stark ist und mit einfachsten Mechanismen gute Zahlungsmöglichkeiten anbietet.

Unsere Entscheidung ist etwas ungewöhnlich. Wir haben uns trotz der Nachteile für PayOne entschieden. Folgende Gründe haben dafür gesprochen:

  • Unser Sachbearbeiter war stets bemüht alle Informationen die nötig waren zu bekommen
  • Kooperativ mit uns zusammen zu arbeiten
  • Gebühren und Kosten zu minimieren, so das wir als StartUp ebenfalls eine Chance haben
  • Schnelle Reaktion bei Support-Anfragen
  • Unterstützung beim Implementierungsaufwand

Trotz der gestiegenen Aufwände bei der Implementierung sollte es möglich sein in kurzer Zeit eine kleine Library für euch zur Verfügung stellen zu können die die Zahlungsabwicklung mit dem Frontend-Interface abzubilden.

 

Bis dahin

Euer Johannes

Android – HowTo Intent Service

Was ist ein IntentService?

Ein Intent Service ist eine abgekapselte Art des Services. Viel kleiner und schlankter als der ServiceLayer und somit einfacher zu bedienen.

Wozu benötige ich einen IntentService?

Der IntentService wird benötigt um z.B. einfache Downloads bzw. Uploads zu starten. Wenn nur eine Aktion ausgeführt werden soll ohne die Activity zu verlassen. z.B. Downloaden von Bibiliotheken, Bilder oder ähnlichen Aktionen ohne die Applikation dabei zu verlassen. Der Service wird beendet sobald onPause oder onStop ausgeführt wird.

Wie setzte ich einen IntentService ein / HowTo Setup an IntentService?

Prepare ActivityView

Um einen IntentService aufrufen zu können benötigt man relativ wenig Vorbereitung. Da der Service nur gebunden zu einer Activity aufgerufen werden kann wird er ähnlich einer Activity gestartet.

Es können dem Service per Extra werte übergeben werden die anschließend ausgelesen werden.

Intent intent = new Intent(this, IntentTestService.class);
intent.putExtra(IntentTestService.EXTRA_TEST,"test");
startService(intent);

 

Prepare IntentService

 

package de.good.study.app.android.service;

import android.app.Activity;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

/**
 * Created by jkoeber on 06.03.14.
 */
public class IntentTestService extends IntentService {
    private static final String CLASS_NAME = IntentTestService .class.getName();
    public static final String CUSTOM_INTENT = IntentTestService .class.getName()+".Receiver";
    public static final String RESULT = "serviceResult";
    public static final String STATUS = "serviceStatus";
    public static final int STATE_FINAL = 20;

    public DatabaseService() {
        super("IntentTestService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        int i = 0;

        Log.i(CLASS_NAME,"==> Service Started!");
        long endTime = 2*1000;
        while (i < STATE_FINAL) {
            synchronized (this) {
                try {
                    i += 1;
                    publishStatus(i);
                    wait(endTime);
                } catch (Exception e) {
                    Log.e(this.getClass().getName(),"Error by executing the service");
                }
            }
        }
    }

    /**
     * publish status
     * @param status
     */
    private void publishStatus(int status) {
        Intent intent = new Intent(CUSTOM_INTENT);
        intent.putExtra(STATUS, status);

        if(status == STATE_FINAL) {
            intent.putExtra(RESULT, Activity.RESULT_OK);
        } else {
            intent.putExtra(RESULT, Activity.RESULT_CANCELED);
        }

        sendBroadcast(intent);
    }
}

 

Response konsumieren

 

Die Activity kann anschließend den Response vom Service verarbeiten und abfangen über einen BroadcastListener. Hier ein Beispiel

    /**
     * BroadcastReceiver will execute IntentService and handle Reponse
     */
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Bundle bundle = intent.getExtras();
            Log.i(CLASS_NAME,"Receive from Broadcast!");
            if (bundle != null) {
                int resultCode = bundle.getInt(IntentTestService.RESULT);
                int resultStatus = bundle.getInt(IntentTestService.STATUS);

                mProgressbar.setProgress(resultStatus);
                if (resultCode == RESULT_OK) {
                    Log.i(CLASS_NAME, "RESULT IS 100%, redirect to next Activity!");
                    Intent overviewIntent = new Intent(MainActivity.this, NextActivity.class);
                    startActivity(overviewIntent);
                }
            }
        }
    };

osRetail – Primefaces 4 Upgrade

Wir sind wieder einen Schritt weiter. osRetail in der finalen Primefaces 4.0 Version. Und als Maven Projekt. osRetail das erste open Source ERP System für den Handel. Wir versuchen das starre Korsett eines fertigen ERP System aufzubrechen. Dem Kunden eine möglichst große Vielfalt an Standardfunktionalität zu bieten und auch kostspielige Funktionen wie der Katalogerstellung frei Haus mitzuliefern.

Vor ca. einem Jahr haben wir uns dazu entschlossen ein großes Refactoring der Software durchzuführen. So haben wir nicht nur die Entwicklungsumgebung von Netbeans auf Eclipse geändert. Wir haben auch IceFaces ausgetauscht und – mit dem leistungsstarken Framework – Primefaces einen weiteren Schritt zu einer moderneren Arbeitoberfläche geebnet.

jee7-standard

Ebenso wurde der Code überarbeitet. Derzeit verwenden wir den JEE7 Standard um den aktuellsten Stand der Enterprise Entwicklung von Java nutzen zu können. Autodeployments über Jenkins erleichtern uns die Arbeit erheblich da wir alle Code Commits und Änderungen auf den Testsystem schnellst möglich dem publishen können.

maven-overview-plugin

Maven unterstützt uns bei der Library Auswahl. Mit einfachsten Mitteln ist es möglich neue oder ältere Bibliotheken auszuwählen und automatisch in der Entwicklung und beim Deployment zu verwenden.

Glassfish 4 bietet uns einen schnellen Application- Server der leicht zu handeln ist. Skalierbarkeit, effizientes Arbeiten und schnelle Deployments standen dabei im Vordergrund. Durch einfache Erweiterbarkeit ist es uns möglich schnell auf Kundenwünsche zu reagieren.

JEE Anwendung: QUAT

Es ist ein attraktives Entwicklungsumfeld im JEE Bereich. Webapplications mit EJB3 Anbindung und Managed- Beans.

Im Standard JEE6 wurde viel Aufmerksamkeit auf Annotations gelenkt und die vereinfachte Kommunikations der Beans mit dem Frontend. Der neue JEE7 Standard, erst ein paar Wochen alt wird jetzt speziell die Ausrichtung im Bereich Ajax im Blick haben. Light- Weight Communication mit dem Backend wenn man so will. Wenige Daten die geliefert werden und somit die Performance von Applikationen beschleunigt.

Ich werde euch hier ein kleines Beispiel für eine JEE Anwendung erstellen inkl. der aktuellen Version von Eclipse Kepler und Glassfish 4.

Die JEE Anwendung wird mit dem Plugin von Primefaces 3.5 laufen. Einem leistungsstarken Ajax- Framework das basierend auf jQuery UI viel interaktive Bearbeitungsmöglichkeiten bietet.

Nachteil von Primefaces. Die jQuery UI hat, meines erachtens nicht gerade ein business orientiertes Interfaces Design. Die Buttons und Eingabemasken wirken sehr groß und für ein schlankeres Aussehen müssen einige CSS Classes überarbeitet werden.

Auch muss man sich vor Augen führen das durch den zusätzlichen CSS und Javascript Aufwand die einzelnen Seiten etwas Content- lastiger werden und somit die Ladezeit im Gegensatz zu reinem JSF2 länger sein können. Da man aber sehr viele Daten nachladen kann wird nur der Erstaufruf etwas länger benötigen. Sobald alle Daten Clientseitig gecached wurden wird die Performance deutlich besser sein.

Maven wird in diesem kleinen Projekt eine weiter Rolle spielen. Um möglichst einfach alle Komponenten bauen zu lassen ohne sich um die Libraries kümmern zu müssen oder die Libraries im SVN bereit zu stellen werde ich mich darum kümmern das das Projekt mit Maven gebaut werden kann.

Vorteile:

  • Versionierung des Projektes anhand von Maven- einstellungen.
  • Einfaches Updaten von Libraries
  • Schnelles Bauen von Projekten

Nachteil:

Langwieriges einstellen der Maven Poms um einen erfolgreichen Build zu generieren. Mittlerweile habe ich auch festgestellt das nicht alle POM Einstellungen Plattformunabhängig sind. Es kann sein das Builds teilweise unter Windows laufen und auf dem Mac Fehler verursachen weil Abhängigkeiten fehlen.

Projektname: QUAT

Das Projekt das ich seit längerem realisiere nennt sich QUAT. Mittlerweile stecken knappe 2 Jahre Entwicklung in dem System. Angefangen hat es mit einer einfachen PHP Anwendung die mittlerweile ihre Alter erreicht hat und dank unzähliger PHP Updates auch einiges an Funktionen nicht mehr unterstützen bzw. nur noch per Workaround laufen.

QUAT wird z.B. für ein Callcenter verwendet werden können das sich mit der Qualitätssicherung von Mitarbeiter beschäftigt. Überall wo die Leistung vom Mitarbeiter eine Bewertung benötigt und die Qualität in Gesprächen oder direkter Kommunikation am Telefon geprüft werden muss um den Erfolg der Firma zu steigern oder gezielt Schulungen für Mitarbeiter anzubieten.

Aber erstmal genug um den Nutzen der Software. Wir möchten uns die technische Seite etwas genauer ansehen und somit den Aufbau der Software.

[HIER WERDEN ALLE ZUKÜNFTIGEN ARTIKEL ZU QUAT GELISTET UND VERLINKT|

 

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! 😉