Dieses Blog durchsuchen

Donnerstag, 5. Dezember 2019

Tagging an AWS Cloud Watch alarm

Tagging an AWS Cloud Watch Alarm

Recently tried to tag an alarm in AWS Cloud Watch. First I took a look at their REST-API documentation:


There are several things I found remarkable when trying to add a tag via the TagResource "action".

First of all there is no example included in the documentation. Not too bad because there is google with a lot of examples out there? Wrong, I couldn't find a single sample of someone doing such a REST call. After a lot of try and error I found a working solution:

The tag has to be included as a query parameter and a GET-request has to be issued in order to create a tag. (Please do not ask me why they are not implementing this as a post or put request like everyone else is doing). A key-value pair of tags has to be provided in this format as query parameters:

...&Tags.member.1.Key=myKey&Tags.member.1.Value=myValue

I am wondering how anyone is able to come up with this solution after reading the API documentation (see link above).

Since I found several other issues when implementing plain REST calls I continued with the Java SDK:


This API is well documented with a lot of examples and it is also easy to use. 

Conclusion: I think Amazon doesn't really want you to use their REST API directly. It is complicated, not well documented and has a strange architecture (GET-request to create data). Unfortunately I have found no hint that you are way better off using the SDKs that are available in multiple languages (C#, Go, JavaScript, Python, PHP, etc)

Freitag, 17. Mai 2019

Positioning of a primefaces dialog (p:dialog)

When using the primefaces dialog on a large page that has a vertical scrollbar, the dialog might not be visible because it is displayed at the top of the page and your current scroll position is too far down.

In order to make the dialog nicely centered on the visible part of the page I have used a small java script function that positions the dialog for me after it is rendered by primefaces:

function positionDialog(dialogId,anchorId) {
    var anchor = $(anchorId);
    PF(dialogId).getJQ().position({
        "my": "center",
        "at": "center",
        "of": $(anchor)
    })
}

In your xhtml page all you have to do is to define the dialog and the anchor to which the dialog has to be moved to. The anchor should be put on the place of the page where the dialog should appear:


<div id="myAnchorId"></div>
<p:dialog id="myId"
          header="My dialog"
          widgetVar="myId"
          onShow="positionDialog(myId','#'+'myAnchorId')"
          modal="true">
          This is the content of my dialog
</p:dialog>

This way the dialog is always nicely centered no matter where your vertical scollbar is positioned at the moment.

Sonntag, 22. Oktober 2017

Autocomplete im IntelliJ

Diese Woche bekam ich eine interessante Mail vom JRebel Produkt-Manager Sander Sõnajalg. Darin wird beschrieben, wie man im Intellij autocompile nutzen kann. Dies war bisher meines Wissens nicht möglich, man musste entweder Strg-F9 (Projekt bauen) oder Strg-Shift-F9 (aktuelle Klasse compilieren) nutzen, um Änderungen wirksam werden zu lassen.

Das Autocompile Feature lässt sich wie folgt nutzen:

  1. Im Intellij die Einstellungen öffnen, Compiler in den Filter eingeben, "Build project automatically" anwählen (obwohl hier die Warnung steht, dass dies nicht beim laufenden oder im Debug-Modus befindlichen Projekt funktioniert)
  2. Strg-Schift-A drücken im Intellij, "Registry..." in den Filter tippen, auswählen und "compiler.automake.allow.when.app.running" Checkbox aktivieren

Mit diesen Einstellungen werden Änderungen am Quelltext sofort im laufenden Programm wirksam, ohne dass eine zusätzliche Eingabe erfolgen muss. Die bisherigen Tests sahen sehr gut aus, sodass ich mich weiterhin über das geniale, wenn auch relativ teure JRebel freue. (gibt es Leute, die nach Nutzung von JRebel noch ohne dieses Tool leben können?)

Freitag, 6. Januar 2017

REST Service Exception Handling


Bei der Implementierung von REST-Services stellt sich der Entwickler früher oder später die Frage, wie eigentlich mit Exceptions umgegangen werden soll. Denn anders als bei der Implementierung von SOAP Services muss sich der Entwickler hier eine eigene Strategie überlegen, wie aufgetretene Fehler dem nutzenden System übermittelt werden sollen.

An dieser Stelle möchte ich eine Variante aus der Praxis vorstellen, die sich bewährt hat. Und zwar wird dazu die Klasse javax.ws.rs.ext.ExceptionMapper implementiert und mit der @Provider Annotation versehen. Eine weitergehende Konfiguration oder Aktivierung des Mappers ist nicht notwendig. Indem nun die Methode toResponse überschrieben wird, kann definiert werden, wie die Antwort des Servers im Falle einer Exception konkret aussehen soll.

Das Beispiel zeigt den Aufbau einer Nachricht bestehend aus einleitendem Text "An Error occured!", dem aktuellen Datum, dem Namen der Exception-Klasse und der Nachricht. Falls die Exception einen root cause hat, wird auch dieser noch mit ausgegeben.
Zusätzlich ist es sinnvoll, einen passenden HTTP-Status-Code mitzugeben, in diesem Fall Status Code 500 für "Internal Server Error", denn viele Clients fragen diesen Status-Code ab, um entsprechend reagieren zu können.

@Provider
public class RestThrowableExceptionMapper implements ExceptionMapper<Throwable> {

    @Context
    private HttpHeaders headers;

    @Override
    public Response toResponse(Throwable throwable) {
        int status = Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); //defaults to internal server error 500;
        StringBuilder messageBuilder = new StringBuilder();
        messageBuilder.append("An Error occured! ");
        messageBuilder.append(new Date());
        messageBuilder.append(": ");
        messageBuilder.append("Cause -> ");
        messageBuilder.append(throwable.getClass().getName());
        messageBuilder.append(": ");
        messageBuilder.append(throwable.getMessage());
        // also append root cause of exception if present
        Throwable rootCause = ExceptionUtils.getRootCause(throwable);
        if (rootCause != null) {
            messageBuilder.append("; Root Cause -> ");
            messageBuilder.append(rootCause.getClass().getName());
            messageBuilder.append(": ");
            messageBuilder.append(rootCause.getMessage());
        }
        return Response.status(status).
               entity(messageBuilder.toString()).
               type(headers.getMediaType()).build();
    }
}

Dienstag, 27. Dezember 2016

Eigener Authenticator für Basic Authentication in Kombination mit Proxy-Authentifizierung

Sofern ein REST-Client (oder auch SOAP-Client) sich zunächst über einen Proxy authentifizieren soll und anschließend eine Basic-Authentifizierung durchführen muss, bietet es sich an, einen eigenen Authenticator zu schreiben. 
Dieser Authenticator muss von der Klasse java.net.Authenticator ableiten und die Methode getPasswordAuthentication() überschreiben. Erwähnenswert ist nun, wie die implementierung dieser Methode konkret aussieht:

@Override
protected PasswordAuthentication getPasswordAuthentication() {
    String requestingHost = getRequestingHost();
    if (proxyEnabled && requestingHost.equals(proxyHost))    {
        return new PasswordAuthentication(proxyUserName, proxyPassword);
    }   else    {
        return new PasswordAuthentication(serverUserName, serverPassword);
    }
}

Zu sehen ist, wie mithilfe der geerbten Methode getRequestingHost()zunächst der Host ermittelt wird, der eine Authentifizierungsanfrage stellt. Sofern dies der Proxy ist, wird entsprechend der Nutzer und das Passwort des Proxys gesetzt. Handelt es sich jedoch um den Zielserver, werden die Credentials entsprechend für diesen verwendet.

Über die statische Methode Authenticator.setDefault(new MyAuthenticator()); wird der Authenticator schließlich JVM-weit gesetzt und beginnt mit der Arbeit, sobald die ersten Authentifizierungsanfragen eintreffen.

Mittwoch, 15. Juni 2016

REST Service Dokumentation mit Swagger


REST Services erfreuen sich seit einigen Jahren immer größerer Beliebtheit. Während SOAP Services als unflexibel und unnötig kompliziert gelten, sind REST Services schlank und bestehende Schnittstellen sind nicht so "empflindlich" gegenüber Änderungen. Z. B. lassen sich Services und Query-Parameter hinzufügen, ohne dass der Schnittstellenvertrag gebrochen wird.

Einen großen Nachteil haben REST Services jedoch gegenüber SOAP mit WSDL: die WSDL definiert die Schnittstelle und ermöglicht es einem Client so, das Interface sehr einfach mit wenigen Zusatzinformationen anzusprechen. Es gibt Tools die anhand einer WSDL Stubs (Client Klassen) erstellen können, sodass schnell klar wird, wie die Schnittstelle zu bedienen ist. Zwar gibt es auch bei REST vergleichbare Ansätze (siehe z. B. WADL), diese konnten sich jedoch in der Praxis nicht wirklich durchsetzen.

Umso wichtiger ist es daher, die REST Services umfassend zu dokumentieren und die Doku auch aktuell zu halten. Genau hier setzt Swagger an. Mit Swagger lassen sich die Services sehr komfortabel über Annotations beschreiben. Dadurch dass zur Erstellung der Doku Informationen direkt aus dem Quelltext zu Rate gezogen werden, ist stets Aktualität gewährleistet. Des weiteren bietet Swagger eine HTML Oberfläche, um die Doku zu präsentieren und die Services direkt auszuprobieren.

Im Folgenden werden die wenigen notwendigen Schritte beschrieben, um Swagger im eigenen Projekt nutzen zu können. (basierend auf einem JAX-RS und Maven Projekt)

Zunächst muss die Swagger-Lib als Dependency aufgenommen werden: 

<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-jaxrs
    <version>1.5.9</version>
    <scope>compile</scope>
</dependency>

Anschließend muss die Rest- "Application" Klasse um folgenden Konstruktor ergänzt werden (falls JAX-RS verwendet wird): 

//Swagger initialization
public Application() {
    BeanConfig beanConfig = new BeanConfig();
    beanConfig.setVersion("1.0");
    beanConfig.setTitle("Meine REST services");
    beanConfig.setBasePath("/anwendung/service");
    //Hier befinden sich die Rest-Services
    beanConfig.setResourcePackage
    ("de.stahl.restservice");
    beanConfig.setScan(true);
}

Swagger UI wird benötigt, um die Dokumentation als Web-App bereitzustellen. Dazu muss die Web-Anwendung heruntergeladen werden (http://swagger.io/swagger-ui/) und der Inhalt des "dist" Ordners (swagger-ui/dist) in den Ordner "src/main/webapp" bereitgestellt werden. 

Damit die Dokumentation schließlich auch erstellt wird, müssen die Services noch mit den passenden Annotations versehen werden, die eine Beschreibung der Funktionalität beinhalten, zum Beispiel:


  •  Auf Klassenebene: 
@Api(value="Mein REST Service")
  •  Auf Methodenebene: 
@ApiOperation(value = "Beschreibung der API Operation") @ApiParam(value = "ein wichtiger Parameter", required = true) 


Diese Schritt reichen aus, um die Dokumentation zu erstellen. Detailliertere Informationen zu den verfügbaren Annotations gibt es hier: https://github.com/swagger-api/swagger-core/wiki/Annotations

Offline-Nutzung

Es könnte notwendig sein, eine Schnittstellendokumentation zu erstellen, obwohl der Quelltext noch gar nicht fertiggestellt wurde, z.B. wenn ein externe Komponente frühzeitig Informationen über eine sich in der Entwicklung befindliche Schnittstelle benötigt. Auch dies ist mit Swagger möglich.

Dazu wird zunächst die Swagger-Definition (JSON-File) erstellt. Dies kann mit Hilfe des Swagger Editors geschehen: http://editor.swagger.io/#/
Dann wird das resultierende JSON in die index.html der Swagger-Web-Anwendung eingefügt und das SwaggerUi-Objekt initialisiert: 

var spec = {"json":"test"};

window.swaggerUi = new SwaggerUi({
   url:url,
   spec: spec,
   ...
Da die Swagger Web-App ausschließlich auf HTML und Javascript basiert, kann diese anschließend, z.B. als Zip-Archiv and die potenziellen Clients verteilt werden.

JRebel Support

Als JRebel Fan möchte ich noch erwähnen, dass Swagger nun auch von JRebel wunderbar unterstützt wird. (siehe https://zeroturnaround.com/forums/topic/support-for-swagger/) Dies ist sehr hilfreich, um die Änderungen an der Dokumentation und den Annotations direkt in der Oberfläche nachvollziehen zu können.

Sonntag, 21. Juni 2015

Responsive Web Design

Anfang des Jahres bekam ich eine Nachricht von Google, dass meine Web Seite Probleme mit der mobilen Nutzerfreundlichkeit aufweist. Dies hat mich nicht sonderlich überrascht, da ich die Seite gar nicht für die Smartphone-Nutzung optimiert hatte. Da ich die Problematik aber sehr spannend finde und die mobile Nutzung von Web-Seiten auch beruflich immer mehr in den Vordergrund rückt, habe ich die Mail zum Anlass genommen, mich näher mit der Thematik zu befassen.

Also habe ich mir das Buch "The responsive web" meines Lieblingsverlags Manning bestellt (The responsive web) und mir das erste Kapitel durchgelesen.

Kurze Zusammenfassung:

Man sollte seine Web-Seite zunächst für die mobile Nutzung optimieren (leider zu spät für meine Seite) und dann Schritt für Schritt für größere Screens optimieren. Da meine Seite nun einmal schon da war, habe ich angefangen, sie für kleinere Auflösungen anzupassen. Das zentrale Element für das Design auf Basis von CSS sind die sogenannten Media queries und Breakpoints. Ich habe mich dazu entschlossen, die Seite sowohl für Screens ab 1200px zu optimieren, als auch für alles darunter bis zu einer minimalen Größe von 200px. Die zentrale Anweisung im CSS sieht so aus:

@media only screen and (min-width: 1200px) {
     div#Mainpage {
         width: 1024px;
     }
}

Dies bedeutet, dass das div-Element mit der ID "Mainpage" eine breite von 1024px haben soll; aber nur dann, wenn der Screen 1200px breit ist. (Bei den 1200px handelt es sich um einen sogenannten Breakpoint) Für alle Bildschirme unter 1200px soll die Web-Seite die komplette Bildschirmbreite einnehmen:

div#Mainpage {
    width: 100%;
}

Auf diese Weise nimmt die Seite auf kleineren Bildschirmen die größtmögliche Bildschirmfläche ein, während sie auf großen Wide-Screens zentriert auf 1024px begrenzt wird. Die Media queries sind sehr mächtig, denn nun ist es möglich, alle möglichen Designs auf die entsprechenden Bildschirmgrößen hin zu optimieren. So ist es z.B. auf einem Smartphone sinnvoll, die Navigation mit großen Links zu präsentieren, die nicht zu nahe zusammenstehen. Auch horizontales Scrollen sollte möglichst vermieden werden.

In nächster Zeit gibt es noch einiges zu tun, bis sich meine Web-Seite vollständig "responsive" verhält. Leider ist es nämlich so, dass die CSS Optimierungen viel Zeit kosten und ein perfektes Ergebnis extrem aufwändig ist. Daher ist es durchaus eine Überlegung wert, Content-Management Systeme wie Joomla einzusetzen, die diesen Mechanismus über Plugins bereits mitbringen - dies kann eine Menge Arbeit ersparen.

Abschließend möchte ich noch auf die Google Webmaster Tools hinweisen. Sie geben viele wertvolle Tipps und analysieren die Web-Seite auf Knopfdruck.
Im Hinblick auf die mobile Optimierung der Seite gibt es unter folgendem Link konkrete Hinweise und Lösungsvorschläge:
Mobile Usability 

Wer sich stärker auf die Performance der eigenen Web-Seite konzentrieren möchte, ist hier gut aufgehoben:
Pagespeed insight 

Die Tipps sind umfassend und wertvoll, sodass man sich eine teure, intellektuelle Analyse der eigenen Website sparen kann und sich sofort auf die Beseitigung der Problemfelder konzentrieren kann. Google vergibt einen Score für die Seite, bei 100 Punkten ist die Seite optimal implementiert.

Zulange sollte man die Thematik "Responsive Design" auf die lange Bank schieben, denn Google könnte nicht optimierte Seiten abstrafen. In der Hinweismail von Google klingt das so: "Diese Seiten werden von der Google-Suche als nicht für Mobilgeräte optimiert eingestuft, und werden entsprechend in den Suchergebnissen für Smartphone-Nutzer dargestellt."