ioBroker SENEC Home Adapter

ioBroker ist eine super Möglichkeit um alle Informationen von Systemen an sein Smart Home anzubinden.

Neben des KNX Module welches für den aktuellen Stand der Verfügbaren Schnittstellen geladen werden muss, habe ich mich ein paar Tage hingesetzt und einen Adapter für die Senec Batterie gebaut.

Da es keine offizielle Schnittstelle zum Senec System gibt, wird in meinem Adapter der CGI Service der Batterie angezapft.

SENEC Adapter für ioBroker findet ihr unter github:

https://github.com/jkoeber/ioBroker.senec

Ihr könnt den Adapter über euren ioBroker direkt installieren.

Über den Klick auf das Icon wird direkt ein Dialog geöffnet um externe Module installieren zu können.

Anschließend kopiert ihr euch die URL und fügt diese ein unter dem Reiter „Beliebig“

https://github.com/jkoeber/ioBroker.senec/tarball/master

Sobald der Adapter installiert ist wird dieser in der Übersicht angezeigt und ihr könnt eine Instanz hinzufügen.

Sobald die Instanz zur Verfügung steht werdet ihr automatisch in den Setup- Modus der Instanz geleitet. Hier gebt ihr nur noch die IP eurer Batterie an und schön könnt ihr die Werte nutzen.

Viel Spaß, freue mich über Feedback.

Unser Hausbau …

Eine große Entscheidung im Leben ist wahrscheinlich das eigene Haus oder die eigene Wohnung. Letzteres einfacher umzusetzen als ein eigenes Haus.

Wie hat es begonnen? Kurz nach der Hochzeit überlegt man sich doch mal aus der Wohnung in ein eigenes Zuhause zu ziehen. Platz ist bei uns, im schönen Oberfranken zu genüge vorhanden und preislich durchaus in Ordnung.

04.2017

Angefangen haben wir, in dem wir Freunde, Verwandte und Bekannte abgeklappert haben, die vor kurzem entweder mit dem eigenen Hausbau begonnen haben oder bereits in der Planung waren. Soweit so gut. Leider haben wir nicht bedacht wie viele tausend Kombinationen an Fertig-, Massiv,- Hauskauf-, Bestand- oder Modernisierungsobjekte es gibt. Kurz durchschnaufen und erstmal eine Übersicht verschaffen.

Time is Money… Schon tausendfach gehört und natürlich ist auch ein Funken Wahrheit dahinter. Nicht nur die eigene Firma oder Festanstellung die man parallel begleitet zu den anderen wichtigen Lebensthemen gehört das passende Timing auch beim Hausbau eindeutig dazu. Aber wir fangen erstmal beim Hauskauf an.

Hauskauf

Für uns war die Überlegung gereift, das ein Kauf doch eine ganz gute Alternative zum Bau ist. Leider ist man beim Kauf mittlerweile in Preisregionen dass der Umbau nach eigenen Vorstellungen inkl. des Kaufpreises ebenfalls den Zenit überschreitet und man doch mit dem Bau liebäugelt. In der Stadt eher weniger als auf dem Land, somit ist es doch ganz gut, dass wir eher auf dem Land zu Hause sind.

06.2017

Die Entscheidung, oder doch nicht?! … Langsam werde ich Kirre. Kaufen, Leihen, Mieten oder doch Bauen? … Stetige Diskussionen um das immer gleiche Thema. Meine Entscheidung steht – eigentlich. Da kommt die bessere Hälfte und will das Thema doch wieder von Vorne aufziehen. …

In diesem Monat wird erstmal geheiratet. Somit keine Zeit zu verlieren und Gedanken an den Hausbau wieder verschieben…

07.2017

Nächste Anlauf… Was wollen wir machen? Wohin geht die Reise. Ich bin immer noch davon überzeugt, dass man mit einem vernünftigen Settlement an Handwerkern und Familie und Freunden ein Haus zu vernünftigen Kosten gebaut bekommt. In der Zwischenzeit ist mein Geschäftspartner bereits voll in der Umsetzung und bei uns ist das Blatt Papier noch weiß.

08.2017

Wir haben uns mal wieder das ein oder andere Haus zum Kauf angeschaut. Ebenso ein paar Grundstücke die leer stehen. Aber STOPP. Wie wollen wir eigentlich Bauen, wenn wir Bauen wollen? … Massiv oder Fertighaus. Was sind die Vorteile und Nachteile. Wo entsteht ein Mehrwert über Jahrzehnte oder wo überdauer ich mein Leben und hinterlasse nur Sondermüll. Ich glaube allein an diesem Satz dürftet ihr gemerkt haben, dass ich nicht unbedingt der Freund der Fertighäuser bin. Aber zurück zu LOS. Wie wollen wir vorgehen und wofür müssten wir uns entscheiden? Ach, und wo wollen wir Bauen?

In meiner Heimatgemeinde haben wir das ein oder andere schöne Grundstück gefunden. Leider war die Gemeine sehr inflexibel und wollte unter allen Umständen nur das Neubaugebiet anbieten. Jedes andere Grundstück stand laut Gemeinde entweder nicht zum verkauf oder wäre gar nicht verfügbar.

Das Thema Digitalisierung und Arbeitserleichterung durch „Moderne“ Kommunikationsmittel => E-Mail scheint in Gemeinden und öffentlichen Instituten immer noch ein sehr großes Fremdwort zu sein. Merkel hatte schon recht mit ihrem „Neuland“ das wir in der Digitalisierung betreten. Wenn Unternehmen noch mit den gleichen Mitteln arbeiten würden wie der öffentliche Bereich wären wir bereits ein Entwicklungsland und nicht technologisch noch mit einem Hauch an Vorsprung vorn dran.

Meiner Meinung nach werden wir sowieso die kommenden 10 Jahre massive Probleme mit den Chinesen und deren Know- How bekommen. Gegen Alibaba und Amazon hat kein Europäisches Unternehmen nur die Chance mit zu halten!

Zurück zum Thema.

Anstatt uns bei der passenden Grundstücksfindung zu unterstützen hat sich also die Gemeine darauf festgesetzt nur ihr Neubaugebiet anzubieten und anderen Grundstückseigentümern keine Chance gegeben überhaupt mal über einen Verkauf nachdenken zu können, da der Kontakt nie zu Stande gekommen ist. Da haben wir durch Zufall im Neubaugebiet der Nachbargemeinde noch ein schönes Grundstück angeboten bekommen, dass noch nicht verkauft wurde. Es war auch möglich das Grundstück sich ein ganze Quartal zu reservieren. Yeah, genug Zeit um den Hausbau zu planen….

 

Fortsetzung folgt 😉 …

 

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

camunda cdi and multiple datasources

Ich durfte mich die letzten Tage mit einem ziemlich fiesen Fehler rum ärgern.

Wir optimieren unsere Bestellungen und vor allem automatisieren wir unseren gesamten Verarbeitungsprozess mit dem Backend.

Der gesamte Bestand und Bestellverfahren wird automatisch mit dem Shop, dem Backend und dem Versender abgeglichen.

Der Prozess zur Bestellübergabe wurde in camunda definiert. Die Service Tasks greifen auf CDI Beans zu. Diese Beans greifen auf JPA Ressourcen zurück.

Es wurden Projektbedingt 2 Resourceprojekte mit verschiedenen JTA- Resources definiert, die aber aufgrund der Architektur auf die gleiche Datenbank zugreifen.

 

Durch die schnelle Verarbeitung des Prozesses kommt  der Application Server durcheinander und Crasht bei der Verarbeitung der Transaktionen.  Einer der Ressourcenmanager lockt die Tabelle und verhindert das weitere verarbeiten der Daten.

Leider ist es mir nicht gelungen eine andere Lösung zu finden als beiden JPA Projekten der gleichen JNDI- Resource zu geben.  🙁

Jemand noch eine andere Idee?

JEE + Microservices, ein neuer IT- Kosmus

Wie man des öfteren ließt werden Micro-Services so etwas wie das nächste größere Ding sein für Moderne IT- Infrastruktur. Weg von großen Anwendungen die viele Daten zentralisiert speichern und nur im eigenen Universum zur Verfügung stellen. Es werden immer mehr Artikel über Micro-Services veröffentlicht. Kleine Datenmengen die sehr schnell zur Verfügung gestellt werden können. Dabei wird die Infrastruktur ziemlich zerrissen – und meiner Meinung nach – eine Art gewollte Unübersichtlichkeit geschaffen.

Da ich mich stetig mit der Entwicklung im JEE Umfeld beschäftige und eigentlich nur über Podcasts, Tutorials und Do-It-Yourself Lerne und meinen Wissensstand erweitere finde ich es nur fair, euch das leben an dieser Stelle etwas einfacher zu machen 😉

Im JEE7 Umfeld und der Verbindung von CDI- Beans ist es sehr einfach JAX-RS Web- Services zu erstellen. Ich werde die Tage ein Tutorial schreiben um euch zeigen zu können, wie einfach man die Kombination von

  • Maven
  • JEE7
  • JAX-RS

funktioniert.

Bis dahin.

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

Neues Jahr, neues Glück

Ich habe es nicht mehr geschafft letztes Jahr den ein oder anderen Beitrag zu verfassen. Dafür noch an alle die meinen Blog seit Jahr und Tag verfolgen.

!!! SORRY !!!

Ich freue mich dennoch darüber das immer wieder neue Besucher meinen Block finden und auch lesen. Es wird die nächste Zeit mal wieder das ein oder andere Tutorial geben. Speziell im Bereich Android versuche ich euch wieder das ein oder andere zu zeigen. Die neuen Benutzeroberfläche für das wohl meist verbreitete mobile Betriebssystem weltweit ist ziemlich cool, übersichtlich und scheint relativ intuitiv bedienbar zu sein.

Ich freue mich das ich endlich mal wieder geschafft habe ein paar Zeilen zu schreiben. Bis die Tage. Jo. 😉

Kurz in eigener Sache und zum Sport

Hey zusammen, wie der ein oder andere mittlerweile mitbekommen hat bin ich aktiver Crossfitter, Nein, ich mache das nicht weil ich meine Urinstinkte wecken lassen möchte oder weil es mir gefällt mich täglich anbrüllen zu lassen. Auch finde ich Aussagen wie Weichei eher für unangepasst in Boxen.

Es geht um Teamgeist, seine Leistung zu verbessern ein besseres Körpergefühl für sich zu entwickeln und vor allem dem eigenen Schweinehund den Kampf anzusagen.

Games2013_WomenZigZagSprintDaher bin auch ich nicht vollkommen unvoreingenommen, aber ich finde es gut als Allrounder, der mittlerweile über die Jahre sehr viele verschiedene Sportarten (Fussball, Handball, Kickboxen, All-Style-Karate, Mountainbiken, Skifahren, Inlinern, klassiches Fitnessstudio, Laufen, Hindernislaufen etc.) ausgeübt hat, sagen zu können das es fast keine bessere Alternative gibt sowohl Herz und Kreislauf zu festigen, seine Muskulatur zu stabilisieren und das unter Aufsicht!

1899473_1443735389195655_1895774167_o

Letzes Jahr hat mich ein kleiner Bandscheibenvorfall erwischt, leider sitze ich auch den ganzen Tag zu meist gegen 10 -12 Stunden vor dem Rechner und Tippe unverständliche Zeichen zu tausenden in den Flimmerkasten. Wenn die Tippse vorüber ist kann es auch noch dazu kommen das diverse Onlinegames und Shooter den Abend füllen können wenn man mal wieder nichts anderes zu tun hat. Quasi weiter sitzend. Ich liebe es aber auch an die frische Luft zu kommen. Mountenbiken, Laufen, Skifahren, Bouldern, Inlinern, Paintballspielen und was einem sonst noch einfällt. Meistens habe ich auch den Drang dazu es etwas zu übertreiben und somit – meine Crossfiter Kollegen der Box Kulmbach können das bezeugen – artet es ab und an mal in dem einen oder anderen Unfall aus. 😉

Aber ich lenke zu sehr vom Thema ab. Ich habe heute durch Zufall einen Blogeintrag vom Stern gelesen. Alexandra Kraft, scheinbar (ich spekuliere) selbst nie in einer Crossfit Box teilgenommen da sie über Preise in New York schwadruliert die 100 Dollar oder mehr kosten können. Abwertend über – als Drillsergeant betitelte – Trainer oder gar Weicheiermentalität. Für meine Verhältnisse finde ich diesen Artikel ziemlich belustigend, Crossfit kommt viel härter rüber als es ist. Natürlich kann es sein das es mal lauter wird, aber das dient der Motivation – wie es auch im Blogeintrag von Alexandra richtig, aber auch abwertend erkannt wurde. Um die letzen Reserven den Schweinehund aus seinem Häuschen zu jagen fehlt einem selbst ab und an die Überwindung und da kommt der Teamgeist der Crossfitter heraus. Anfeuern, nicht locker lassen und seine Mitstreiter so lange unter die Arme kitzeln bis die letze Übung, die letze Wiederholung vollendet wurde. Gehört dazu, egal bei welcher Sportart. Ich kann nicht im Wettkampf ab der Hälfte aufhören und gehen. Ich werde auch bei einem Turnier vermeiden vorzeitig auszuscheiden oder im Fall eines Läufers einen Marathon nicht nach 10 Kilometern abbrechen. Im Fall von Crossfit ist jedes WOD sein eigener kleiner Wettkampf, in meiner Leistungsgruppe. Kann ich keine Liegestütze mache ich sie auf den Knien. Kann ich keine Klimmzüge, gehe ich an die Ringe und skaliere mir mein Gewicht so zu Recht das ich es schaffe mein WOD durchzuhalten. Natürlich sollte das Ganze auch anstrengend sein, immerhin will man keine 2Stunden dafür in Kauf nehmen.

c2e0e164d9124a2a2e6551b895635ea0-1684ced9cba38c8aea3c3773fabd59ba

Wenn ich dagegen Abschnitte wie den folgenden Lese, weiß ich wirklich nicht ob sich Alexandra schon ernsthaft mit der Materie beschäftigt hat.

Heute dagegen ist Fitness harte Arbeit. Der Spaß ist vorbei. Es geht um maximalen Muskelaufbau in kürzeste Zeit. Doppelt gut, wenn das alle noch in die Mittagspause passt. Es gilt: Kein Schmerz, kein Gewinn.

 

Das Prinzip ist einfach und schmerzhaft. Durch systematische Überbelastung soll maximaler Trainingserfolg erzielt werden. Ob das gesund für Muskeln, Herz und Kreislauf ist, hat noch keiner vernünftig belegt. Die Zahl der Anhänger wächst aber trotzdem dramatisch. Das wird auch nicht davon gebremst, dass zahlreiche Kardiologen vor der Überlastung, vor allem für Ungeübte, warnen.

 

Lustig ist das längst nicht mehr. Wer nicht durchhält, gilt als Weichei. Und wer es lieber entspannt mag, als Zeitverschwender. Wenn ich theoretisch in sieben Minuten fit werden kann, warum soll ich dann eine halbe Stunde meiner wertvollen Zeit dafür hergeben? Der perfekte Sport für ein Land wie die USA, in dem es für Arbeitnehmer keinen gesetzlichen Urlaub gibt.

Der Schlusssatz verrät alles 😉

Und umso öfter ich dabei zuschaue, umso sicherer bin ich, dass Cross Fit nichts für mich ist.

Alle Sportarten haben ihre Eigenheiten, alles macht unterschiedlich Spaß und fördert, fordert seinen Körper. Aber man sollte nicht so herablassend über eine Sportart schreiben die man selbst nur aus der Ferne beäugt.

JSPWiki in glassfish

Ich habe vor kurzem einen Application- Server von glassfish 4 auf 4.1 geupdatet. Problem, Jspwiki weigert sich Umlaute korrekt dar zu stellen.

Hat schon mal jemand ähnliche Probleme mit dem aktuellen glassfish und eine Lösung parat?

Meine Lösung derzeit ist ein aktueller tomcat 8 mit einer jdk 7. Leider wird von jspwiki kein Java 8 voll unterstützt.

Für Tipps wäre ich dankbar.

PS: Konfiguriert ist das gesamte System mit UTF-8. Sowohl in custom.properties als auch auf dem application server. Auch das local File encoding steht auf UTF-8. Das gesamte JSPWiki wird falsch dargestellt. Sowohl die Inhalte als auch die Seiten.

WildFly HttpServlet Alternative zu glassfish alternatedocroot_1

Glassfish bietet die Möglichkeit einfach und schnell neue Ordner ins System einzubinden und diese per URL- Pattern anzusprechen.

Die Parameter werden in der: glassfish-web.xml angegeben. Für mehr Details können sie gerne bei Oracle in die Details gehen.

<property name="alternatedocroot_1" value="from=/my.jpg dir=/srv/images/jpg"/>
<property name="alternatedocroot_2" value="from=*.jpg dir=/srv/images/jpg"/>
<property name="alternatedocroot_3" value="from=/jpg/* dir=/src/images"/>

Leider unterstützt jboss seit einigen Versionen eine ähnliche Funktion nicht mehr. Dafür kann per HttpServlet ein Ordner eingebunden werden der ebenfalls per Pattern angesprochen wird.

package de.kuw.jee.kuwbid.servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLDecoder;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import de.kuw.jee.core.ejb.ParameterBean;
import de.kuw.jee.kuwbid.mb.ApplicationBean;

@WebServlet(urlPatterns = "/images/*", initParams = { 
		@WebInitParam(name = "basePath", value = "/home/jskoeber/server/wildfly/uploads/documents") }
)
public class ImageServlet extends HttpServlet {
	private static final long serialVersionUID = -3522881745170031638L;
	private String basePath = "";
	
	@Inject
	private ApplicationBean app;
	
	@Inject
	private ParameterBean parameter;
    
    public void init() throws ServletException {
        this.basePath = getInitParameter("basePath");
        
        if(!parameter.getParameter("uri.images", app.getMandant()).getWert().isEmpty()) {
        	basePath = parameter.getParameter("uri.images", app.getMandant()).getWert(); 
        }
        
        // Validate base path.
        if (this.basePath == null) {
            throw new ServletException("FileServlet init param 'basePath' is required.");
        } else {
            File path = new File(this.basePath);
            if (!path.exists()) {
                throw new ServletException("FileServlet init param 'basePath' value '" + this.basePath + "' does actually not exist in file system.");
            } else if (!path.isDirectory()) {
                throw new ServletException("FileServlet init param 'basePath' value '" + this.basePath + "' is actually not a directory in file system.");
            } else if (!path.canRead()) {
                throw new ServletException("FileServlet init param 'basePath' value '" + this.basePath + "' is actually not readable in file system.");
            }
        }
    }
    

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String requestedFile = request.getPathInfo();
		
		File file = new File(basePath, URLDecoder.decode(requestedFile, "UTF-8"));
		if (!file.exists()) {
            // Throw 404, redirect to error page may is another selection
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
		
		// write via response's OutputStream
		FileInputStream inputStream = null;

		try {
			inputStream = new FileInputStream(file);
			byte[] buffer = new byte[1024];
			int bytesRead = 0;

			do {
				bytesRead = inputStream.read(buffer, 0, buffer.length);
				response.getOutputStream().write(buffer, 0, bytesRead);
			} while (bytesRead == buffer.length);

			response.getOutputStream().flush();
		} finally {
			if (inputStream != null)
				inputStream.close();
		}
	}
}