IMG 2 ASCII

Hier findest Du ein eine JS-Bibliothek die aus “normalen” IMG-Tags ASCII-Art erzeugt und dass Ergebnis sieht ziemlich echt aus.

Rasender Roboter

Unter dieser URL gibt es täglich eine neue Rästelaufgabe für Freunde des wunderbaren Informatikerspiels “Rasender Roboter” :-)

Und hier gibt es noch ein paar mehr Variationen des Spiels, z.B. “Speed Robot” bei der es gilt in einer bestimmten Zeit so viele Boards wie möglich zu lösen. Der aktuelle Rekord liegt bei 38! Boards in 2 Minuten, wobei dieser Rekord wohl eher nicht von einem Menschen selbst aufgestellt wurde oder was meint ihr?

Maven + Eclipse + Spring

Today i show how you can easily develop a Mavenproject with Spring-Beans
in your Eclipse-IDE. You have to add a new plugin to your pom’s
plugins-section:


...

<build>
  <plugins>
    <plugin>
        <artifactId>maven-eclipse-plugin</artifactId>
        <version>2.5.1</version>
        <configuration>
          <projectNameTemplate>[artifactId]</projectNameTemplate>
          <downloadSources>true</downloadSources>
          <downloadJavadocs>true</downloadJavadocs>
          <wtpmanifest>true</wtpmanifest>
          <wtpapplicationxml>true</wtpapplicationxml>
          <wtpversion>2.0</wtpversion>
          <manifest>${basedir}/src/main/resources/META-INF/MANIFEST.MF</manifest>
          <additionalProjectnatures>
            <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
          </additionalProjectnatures>
          <additionalBuildcommands>
            <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
          </additionalBuildcommands>
          <additionalConfig>
            <file>
              <name>.springBeans</name>
              <content>
                <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
  <configExtensions>
    <configExtension>xml</configExtension>
  </configExtensions>
  <configs>
    <config>src/main/resource/services.xml</config>
    <config>src/main/resource/datasource.xml</config>
  </configs>
  <configSets>
    <configSet>
      <name>core</name>
      <allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
      <incomplete>false</incomplete>
      <configs>
       <config>src/main/resource/services.xml</config>
       <config>src/main/resource/datasource.xml</config>
      </configs>
    </configSet>
  </configSets>
</beansProjectDescription>]]>
              </content>
            </file>
            <file>
              <name>.settings/org.springframework.ide.eclipse.core.prefs</name>
              <content>
                <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
eclipse.preferences.version=1
org.springframework.ide.eclipse.core.builders.enable.aopreferencemodelbuilder=true
org.springframework.ide.eclipse.core.enable.project.preferences=true
org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanAlias-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanClass-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanConstructorArgument-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinition-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinitionHolder-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanFactory-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanInitDestroyMethod-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanReference-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.methodOverride-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.parsingProblems-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.requiredProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=true
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.action-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.actionstate-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attribute-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attributemapper-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.beanaction-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationaction-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationresult-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.exceptionhandler-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.import-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.inputattribute-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.mapping-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.outputattribute-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.set-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.state-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.subflowstate-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.transition-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.variable-org.springframework.ide.eclipse.webflow.core.validator=false
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.webflowstate-org.springframework.ide.eclipse.webflow.core.validator=false
]]>
              </content>
            </file>
          </additionalConfig>
        </configuration>
      </plugin>
    </plugins>
  </build>
...

Then you can run mvn eclipse:clean eclipse:eclipse (eclipse:clean is not required). The eclipse-plugin will create/change the .springBean and the .settings/org.springframework.ide.eclipse.core.prefs. Then you can refresh the eclipse-project (F5) from now the project contains a Spring-Builder which will handle the defined spring-configuration-files services.xml and datasource.xml. If you have more Springfiles you have to change the plugin-configuration.

tagesschau.de

Durch Zufall lese ich gerade den Artikel “Serienmörder Fourniret provoziert Gericht” (http://www.tagesschau.de/ausland/fourniret6.html). Dort ist ein Bild des Mannes gezeigt, der Bildtext lautet “Michel Fourniret zeigte zum Prozessauftakt keine Reue.“. Im Archiv findet sich ein weiterer Artikel (http://www.tagesschau.de/ausland/meldung231524.html). Dort ist das Bild ebenfalls zu sehen aber ein kleinerer Ausschnitt und schwarzer Balken über den Augen. Das wäre ja nun nicht weiter interessant wenn die beiden Artikel nicht knapp 4 Jahre auseinanderliegen würden. Wie kann der Mann in 4 Jahren nicht altern, immer noch die gleiche Jeansjacke tragen und er wird immer noch von den gleichen Reportern belagert …

Bild1 http://www.tagesschau.de/ausland/fourniret6.html

Bild 2 http://www.tagesschau.de/ausland/meldung231524.html

JSF, Ajax and file download

Today i show you a example which combines Ajax (Richfaces) and a “normal” Download in a JSF application.
The bean for the download-code is here:


public class DownloadBean {

  // actionListener="#{bean.execute}"
  public void execute (ActionEvent event) {
   download();
  }

  // action="#{bean.download}"
  public String download() {
    final FacesContext facesContext = FacesContext.getCurrentInstance();
    // XXX create temp. filecontent ... resultFile
    writeOutContent(getServletResponse(), new File(this.resultFile), "file.xml");
    facesContext.responseComplete();
    // dont use jsf-navigation-rules
    return null;
  }

  void writeOutContent(final HttpServletResponse res, final File content, final String theFilename) {
    if (content == null)
      return;
    try {
      res.setHeader("Pragma", "no-cache");
      res.setDateHeader("Expires", 0);
      res.setContentType("text/xml");
      res.setHeader("Content-disposition", "attachment; filename=" + theFilename);
      fastChannelCopy(Channels.newChannel(new FileInputStream(content)), Channels.newChannel(res.getOutputStream()));
    } catch (final IOException e) {
    }
  }

  void fastChannelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException {
    final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
    while (src.read(buffer) != -1) {
      buffer.flip();
      dest.write(buffer);
      buffer.compact();
    }
    buffer.flip();
    while (buffer.hasRemaining()){
      dest.write(buffer);
    }
  }
}

Now the facelets snipplets: Not Working - Javascript Error :-(


<h:form>
 <h:commandLink actionListener="#{command.execute}" value="Download"/>
 <h:commandLink action="#{command.download}" value="Download"/>
</h:form> 

Not Working - Download is shown in the current page - the ajax page will replaced with the download-content :-(


<a4j:form>
 <a4j:commandLink actionListener="#{command.execute}" value="Download"/>
 <a4j:commandLink action="#{command.download}" value="Download"/>
</a4j:form>

Working :-)


<a4j:form>
 <a4j:htmlCommandLink actionListener="#{command.execute}" value="Download"/>
 <a4j:htmlCommandLink action="#{command.download}" value="Download"/>
</a4j:form>

<h:form>
 <a4j:htmlCommandLink actionListener="#{command.execute}" value="Download"/>
 <a4j:htmlCommandLink action="#{command.download}" value="Download"/>
</h:form>

The a4j:htmlCommandLink was made for this szenario.

Notice: the fast channel copy routine was introduced by waffel.

JSF behind reverse proxy

The problem “try to run a jsf application behind a reverse proxy” it will not work if you change the context-path.

Imagine a local deployed jsf application “hello-world.war”. You can start browsing at http://localhost:8080/hello-word/. The browser handles the absolute paths for css and javascript-libs correctly and all forms will work. Remeber that all resource-urls converted to a “contex-absolut-url” by the jsf-framework.

If you open http://localhost:8080/hello-world/index.jsf the the client html will contains resources like this:

<link rel=’stylesheet’ type=‘text/css’
href
=’/hello-world/a4j_3_1_3.GAcss/tabPanel.xcss/DATB/eAGTWzQ.BgAD.AG8.jsf’>
<script type=‘text/javascript’ src=‘/hello-world/a4j_3_1_3.GAorg.ajax4jsf.javascript.PrototypeScript.jsf’>
<form id=“j_id14″ name=“j_id14″ method=“post” action=“/hello-world/index.jsf”>

(Note: I use richfaces 3.1.4 in the example)

The browser will append each absolute url (starting with ‘/’) to the host to make the request. And here is the problem if you want to use this jsf-application behind a reverse proxy. Then all absolute URLs pointing to a wrong resource and nothing will work. To try this you can install a local apache web server the following to the httpd.conf:

Listen 9090
ProxyRequests On
ProxyPreserveHost On
ProxyVia full
ProxyPass /external-path/hello-world http://localhost:8080/hello-world/

(This will start the apache at localhost:9090 to avoid port-conflicts)

If you open http://localhost:9090/external-path/hello-world/index.jsf the the client html contains the same absolute urls and the browser try to load these resource from the “wrong server”: http://localhost:9090/hello-world/. If you imagine a real world szenario then the reverse proxy will use a “real world domain” and the urls looks like this http://www.mycompany.de/external-path/hello-world/.

So whats the solution for this? I try my own ViewHandler to convert absolute to relative urls. Two things must be done:

1. Implement the ViewHandler

2. Register the ViewHandler

First the code … we extend javax.faces.application.ViewHandler and overwrite the two methods getActionURL and getResourceURL.

package de.ahoehma.jsf;

public class ReverseProxyViewHandler extends ViewHandler {

 @Override
 public String getActionURL(final FacesContext context, final String viewId) {
  return getRelativeURL(context, this.defaultHandler.getActionURL(context, viewId));
 }

 @Override
 public String getResourceURL(final FacesContext context, final String path) {
  return getRelativeURL(context, this.defaultHandler.getResourceURL(context, path));
 }

 /**
  * Transform the given URL to a relative URL <b>in the context of the current
  * faces request</b>. If the given URL is not absolute do nothing and return
  * the given url. The returned relative URL is "equal" to the original url but
  * will not start with a '/'. So the browser can request the "same" resource
  * but in a relative way and this is important behind reverse proxies!
  *
  * @param context
  * @param theURL
  * @return
  */
 private String getRelativeURL(final FacesContext context, final String theURL) {
  final HttpServletRequest request = ((HttpServletRequest) context.getExternalContext().getRequest());
  String result = theURL;
  if (theURL.startsWith("/")) {
   int subpath = StringUtils.countMatches(getPath(request), "/") - 1;
   String pathPrefix = "";
   if (subpath > 0) {
    while (subpath > 0) {
     pathPrefix += "/..";
     subpath--;
    }
    pathPrefix = StringUtils.removeStart(pathPrefix, "/");
   }
   result = pathPrefix + result;
  }
  return result;
 }

 /**
  * Get the url-path from the given request.
  *
  * @param request
  * @return clean path
  */
 private String getPath(final HttpServletRequest request) {
  try {
   // TODO handle more than two '/'
   return StringUtils.replace(new URI(request.getRequestURI()).getPath(), "//", "/");
  } catch (final URISyntaxException e) {
  // XXX URISyntaxException ignored
  return StringUtils.EMPTY;
  }
 }
}

The absolute2relative-algorithm prepends for each “/” in the current request-url a “../” to the resource/action-url … thats all :D

And last register the view-handler. If you use A4J you have to add this to your web.xml:

<context-param>
<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
<param-value>de.ahoehma.jsf.ReverseProxyViewHandler</param-value>
</context-param>

That’s all :D

Now if you open http://localhost:9090/external-path/hello-world/index.jsf the client html contains only relative urls:

<link rel=’stylesheet’ type=‘text/css’
href
=’../hello-world/a4j_3_1_3.GAcss/tabPanel.xcss/DATB/eAGTWzQ.BgAD.AG8.jsf’>
<script type=‘text/javascript’ src=‘../hello-world/a4j_3_1_3.GAorg.ajax4jsf.javascript.PrototypeScript.jsf’>
<form id=“j_id14″ name=“j_id14″ method=“post” action=“../hello-world/index.jsf”>

Fileupload mit Richfaces

This article shows the usage of a tomahawk-fileupload with richfaces and facelets. The result is a upload-formular where the upload-button is disabled until the user select a file. All this can be done without any line self hacked javascript-code :)

The upload-button depends on a bean-property ‘uploadedFilename’ which is sync via AJAX.

So it is possible to enabled the upload-button before the file is really uploaded to the server.
We have a jsf-bean:

public class FileUploadBean  {

  private UploadedFile uploadedFile;
  private String uploadedFilename;

  // ... setter and getter ...

  public void uploadFile(final ActionEvent event) {
    if (null != this.uploadedFile) {
      LOG.debug("file-size '"+this.uploadedFile.getSize()+"'");
    }
  }
}

and the facelets-page:

<ui:component
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:c="http://java.sun.com/jstl/core"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:rich="http://richfaces.org/rich"
  xmlns:t="http://myfaces.apache.org/tomahawk"
  xmlns:a4j="http://richfaces.org/a4j">

<c:set var="controlId" value="controls" />

<a4j:form>
  <a4j:jsFunction name="updateFilename" reRender="#{controlId}">
   <a4j:actionparam name="filename" assignTo="#{FileUploadBean.uploadedFilename}" />
  </a4j:jsFunction>
</a4j:form>

<h:form enctype="multipart/form-data">
 <t:inputFileUpload id="fileupload"
                    size="40"
                    value="#{FileUploadBean.uploadedFile}"
                    storage="file"
                    required="true"
                    onchange="updateFilename(this.value)"/>

 <h:panelGroup id="#{controlId}">
   <c:choose>
     <c:when test="#{!empty FileUploadBean.uploadedFilename}">
       <!-- User has selected a File - enable Upload-Control -->
       <h:commandLink value="Upload enabled ..."
                      actionListener="#{FileUploadBean.uploadFile}"/>
     </c:when>
     <c:otherwise>
       <!-- User doenst have selected a File - DISABLE Upload-Control -->
       <h:outputText value="Upload disabled"/>
     </c:otherwise>
   </c:choose>
 </h:panelGroup>
</h:form>

</ui:component>

Spass mit Starforce

Letztes Wochenende installierte ich mir das Spiel “Rush for Berlin”. Dabei geschah folgendes … noch bevor ich die erste Grafik zu Gesicht bekam sollte ich den mitgelieferte Starforce-Kopierschutz installieren. Also beherzt JA geklickt und Neustart. Danach ging erstmal garnichts mehr! Vista meinte der sfdrv-blabla sei nicht zertifiziert und ich sollte doch die Windoof-Installations-CD benutzen um Vista zu reparieren. Die Reparatur entfernte schliesslich den Treiber wieder. Also alles von vorn. Lösung war die Installation des neuesten Patchs von RfB und UPDATE von STARFORCE + Neustart (der 3. mittlerweile). Das Spiel hat mich schliesslich auch nicht vom Hocker gehauen! Als ich mich dann näher mit dem Starforce-Kopierschutz beschäftigt hatte (http://de.wikipedia.org/wiki/StarForce) wollte ich das Ding so schnell wie möglich loswerden. Aber wie? Auf der Herstellerseite findet sich zwar ein Tool zum Entfernen … Problem … es funktioniert nicht (unter Vista). Prima! Ich fand dann noch ein anderes Tool was scheinbar irgendwie etwas entfernte. Danach schien mein Rechner aber irgendwie instabil zu laufen und es gab immer noch Registry-Einträge von Starforce.

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\Root\LEGACY_SFDRV***

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\Root\LEGACY_SFHLP***

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\Root\LEGACY_SFSYN***

und die konnte ich auch nicht so einfach löschen, da die Keys dem SYSTEM gehörten. Für alle die also irgendwann auch mal etwas ähnliches erleben hier eine kleine Anleitung:

1. Regedit als Administrator öffnen

2. Key suchen

3. Rechte Maus -> Berechtigungen ändern

4. Erweitert -> Besitzer -> Besitzer der Objekte und untergeordneter Container ersetzen + OK

5. Benutzer “Jeder” anwählen und Vollzugriff einstellen

6. jetzt kann der Registryeintrag + Unterobjekte gelöscht werden

High-Level Nerd

Jetzt ist es offiziell

16 % scored higher (more nerdy),
1 % scored the same, and
83 % scored lower (less nerdy).

What does this mean?
Your nerdiness is:

High-Level Nerd. You are definitely MIT material, apply now!!!.


I am nerdier than 83% of all people. Are you a nerd? Click here to find out!

Und wie sich dass für einen richtigen Nerd gehört … hab ich den Nerd 2.0 Test auch noch gleich gemacht *lol*


NerdTests.com says I'm an Uber Cool Nerd King.  What are you?  Click here!

Die Milch macht’s

Aber was sie macht ist die Frage!

Wenn ich mir die Seite http://www.milchlos.de so ansehe überkommt mich ein seltsames Gefühl dass wir irgendwie vom “milchverarbeitenden Gewerbe” schon längere Zeit verarscht werden. Klingt ein wenig nach “Verschwörungstheorie” :-) Ja! Und?

Mein Fazit: Trinkt weniger Milch!

Zum Thema gestiegene Milchpreise gibt es hier was zu lesen.