Friday, August 29, 2014

CORS XMLHttpRequest in IE10 and newer: "access is denied" caused by Sarissa/Richfaces

If you receive the message "access is denied" when using a CORS XMLHttpRequest in IE10 and newer when using JSF/Richfaces 3.x or Sarissa alone, it is most likely that Sarissa has overridden your window.XMLHttpRequest object.

From the latest Sarissa source code:

if (Sarissa._SARISSA_IS_IE) {
[...]
    // commenting the condition out; we need to redefine XMLHttpRequest 
    // anyway as IE7 hardcodes it to MSXML3.0 causing version problems 
    // between different activex controls 
    //if(!window.XMLHttpRequest){

    Sarissa.originalXMLHttpRequest = window.XMLHttpRequest;

    /**
     * Emulate XMLHttpRequest
     * @constructor
     */
    XMLHttpRequest = function() {
        if (!_SARISSA_XMLHTTP_PROGID) {
            _SARISSA_XMLHTTP_PROGID = Sarissa.pickRecentProgID(["Msxml2.XMLHTTP.6.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]);
        }
        return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
    };

As you can see, the original method is still available as Sarissa.originalXMLHttpRequest = window.XMLHttpRequest;. I tried adding a condition to prevent Sarissa from creating its own request when an HTML5 XMLHttpRequest2 is available. Sadly, this breaks Richfaces/a4j because of some invalid property being set. I guess this can be fixed too, but I did not have time to dig further. So the easiest workarround now is to use new Sarissa.originalXMLHttpRequest() instead of new window.XMLHttpRequest() if Sarissa.originalXMLHttpRequest is defined.

A note for Richfaces 3.3.3: In my case, the newest Sarissa version was included after the one from Richfaces to fix https://issues.jboss.org/browse/RF-9485, so I had to backup the original request manually before loading Sarissa a second time as it would have been overridden twice and the old Sarissa request would have erased the original window.XMLHttpRequest backup.

Edit (some days later): I modified Sarissa to leave IEs greater than 9 completely alone and patched the richfaces jar. The newer IEs seem to work fine with RF this way as they support the majority of APIs by their own. Feel free to comment if further information is wanted.

Monday, February 24, 2014

Capture a video from a webcam using vlc (cvlc) and dump a frame grap image periodically on a linux server

Use this if you want to capture a video from a webcam while dumping a frame grap image periodically every 300 frames. This way you can still upload a plain old webcam image to your webserver without losing the ability to capture a higher framerate video at the same time. Webcam settings are set in the v4l2-url at the beginning. I am not really sure about the mkv file name ending or if the video is already in a mkv container, but that's not the point here. Note that the image is roateted by 180 degrees in this example. This all works in a linux console without X. The parameters should be similar for other OS than Linux, though.
cvlc v4l2:///dev/video0:width=640:height=480:fps=30 --noaudio --sout '#transcode{vcodec=h264,acodec=none,vb=4096}:file{dst=output.mkv}}' --sout-transcode-vfilter="rotate{angle=180}:scene{path=scene/,prefix=out,ratio=300,replace}"

Sunday, February 16, 2014

PropertiesMapper - Java library to map java.lang.Properties to Object fields via annotations

I created a small java library called PropertiesMapper to map the values from java.util.Properties objects to abitrary java.lang.Object fields and vice versa using annotations and reflection. This is especially useful to populate your java objects with the contents of .properties files while maintaing a good code readability. For more information, see the git repository for PropertiesMapper. Code examples are available in the project's README.md.

Friday, March 22, 2013

Low cost sous vide cooker for under 50 Euros

This time I am writing about a private project of mine which is completely different to the IT bushwah you normally find here.

Since some time now, I have been fancying with sous vide cooking (see en.wikipedia.org) and so I was trying to find a way to get it done at home. The main problem is to find an affordable device to control and hold the temperature of the cooking water. My best clue so far was to get an old/used/broken/something laboratory thermostat. But even if you can get your finger on one of those, they are still a bit too expensive and in my opinion also somewhat oversized and bulky. The situation changed when I finally stumbled upon this fine asian fellow on Ebay:

This is a low budget (about 15 Euros) temperature controlling unit able to switch up to 5A at 230V in order to heat (or cool) "something" with any electrical device meeting the specs. You can find a manual explaining the details here which also reveals the official name of the device: "WH7016C Thermostat".

Besides the controller, you need two other main ingredients for a true sous vide cooker: A heater (duh!) and something to circulate the cooking water to maintain an equal temperature distribution within the pan. The heater I use is a 300W travel water boiler which can easily be connected to the relais on the controller by cutting of the power plug and applying some cable end sleeves (to add a bit of professionality to the whole thing).
The white cord goes to the heater and the black one ends with a german "Schuko" power plug for a normal 230V power outlet. The smaller cable on the right belongs to the attached temperature probe. Don't ask me what pins 5 and 6 are for... Secret Chinese stuff, i guess.

These travel heaters can be found on Amazon or Ebay for about 10 to 15 Euros and are quite sufficient to reach and hold the required temperature even in larger pans. 

The third part to be acquired is, as mentioned, something to provide water circulation within the pan. A small aquarium pump suits just fine for this task. For example, the Eheim compact 300 pump is often recommended for this special case and seems to withstand temperatures up to 90 degrees celsius and even above.

This is all you need. Here is a picture of the whole bunch together,  including some reasonable additions:
Nice to have but not required are: A vacuum sealer (You should be able to suck the air out of a freezing bag with your mouth and seal it tight with a clip. But that's not the real deal, is it?), a "LURCH" butan torch to add some roasting flavor to the finished but always a bit pale food and a large 1/2 sized gastronomy container with cover plate to cook in. A normal cooking pot should do just fine, though.

I am really pleased with the outcome of this project. The essentials cost under 50 Euros and the additions around 75. The temperature controller is astonishingly accurate for its price - It keeps the water within 1 degree under the defined target temperature which I scientifically confirmed using another digital thermometer. I was a bit concerned about the heater only having 300 watts but it turned out to be quite enough.

As the parts are in place, the only thing missing now is some basic knowledge. I really, really recommend the excellent A Practical Guide to Sous Vide Cooking by Douglas Baldwin. You can get the document and many translations for free from his website (Scroll down a bit and/or buy the complete book). I love it for giving many (mainly scientific) explanations about how and why sous vide works and what different aspects it has. It provides you with the basic information required to calculate temperatures and cooking times by yourself. This is an important point, because with these low temperatures and possible hygienic dangers I really would not trust any recipe (for time and temperature) found on the internet without questioning.

To finish this post, I'll add some final pictures of my new sous vide cooker in action:


Monday, December 3, 2012

Preventing double clicks / duplicate submits on JSF h:commandButtons

For some time now I was getting sparse exception reports which all happened after form submits. Of course, the users did never do anything unusual (or so they told me) and I kept struggling finding the cause for the exceptions. Being frustrated after another report today, I started randomly opening and submitting some forms until I accidentally clicked twice on the submit buttons before the request was completed and... BAM! There it was.

In most cases, I have three kinds of submit buttons on my forms: submit, submit and return (to previous view) and cancel and return. The latter both call an action which ends the current conversation and redirects to the last view of the previous one, which also invalidates the current bean containing the actions. So when first clicking one of those terminating buttons, a second click would cause an action on a bean/conversation which was invalidated just before.

The obvious solution is to prevent duplicate form submissions, which is more complicated than thought in JSF. Seam provides the s:token-tag which should also be able to prevent multiple submissions but it seems to be bugged at the moment and only produced NPEs after double clicks (see https://issues.jboss.org/browse/JBSEAM-4717).

Some other sources suggested disabling the buttons via JavaScript using the onclick event. This, of course, is client side code and not that robust than s:token should be, but in my application's case JavaScript is mandatory and expected to be enabled. Most suggestions, though, only contained onclick="this.disabled = true;" which firstly only works for one button and secondly does not work at all because disabling the button also prevents the form from being submitted. Others noted that adding a delayed execution using JS-timers might help, which, to make it short, is as crappy and fragile as it sounds.

So I came up with my one variant of this solution. I introduced a global boolean variable (yeah, hate me and feel free to add some form based scope) which is toggled after the first submit button is clicked. All subsequent click events on the submit buttons are caught and stopped using event.preventDefault(); which seems to work fine for now. Notably, form submission still works if the user indeed has JavaScript disabled - of course multiple times then.

<script>
var formSubmitted = false;
function onSubmitButton() { 
    if (!formSubmitted) {
        formSubmitted = true;
    } else {
        // disable event propagation if form is already submitted
        event.preventDefault();
    }
}
</scrip>
<h:commandButton action="#{bean.store}" value="#{msg.store}" onclick="onSubmitButton();"/>
<h:commandButton action="#{bean.storeAndRedirect}" value="#{msg.store_and_back}" onclick="onSubmitButton();"/>
<h:commandButton action="#{bean.endAndRedirect}" value="#{msg.cancel}" immediate="true" onclick="onSubmitButton();"/>

Friday, November 2, 2012

Using sequences in non-ID hibernate properties

Sometimes, you want to provide non-technical but still unique sequence based properties for your hibernate managed entities without making them the table's index. In my case, I find it really convenient to have globally unique IDs within my whole database and don't want to make exceptions for a single table.

For example, one requirement for a project of mine was to have an auto-incremented immutable numeric property in a certain entity. IF you are willing to make this field your database index, you're fine using hibernates @GeneratedValue annotation, which won't work on non-Id fields. The solution in this case is to make the field non-insertable and let the database provide a default value on the first insert using the custom sequence:

@Column(nullable = false, insertable=false, updatable=false,
        columnDefinition = "integer DEFAULT nextval('my_sequence')")
@Generated(GenerationTime.INSERT) // this is important
private Integer sequencedNumber;


You have to keep in mind, though, that this will break db-vendor independancy, as the columnDefinition syntax is vendor specific. (In this case it's postgres.)

Thursday, March 17, 2011

Removing context path for seam based applications

As stated earlier, a java web application behind any proxy is not aware that its context path is not required and tries to propagate it for redirects and links.

The solution I provided before by simply ignoring the context path when proxying to the application works, but only fights the symptoms. After spending some time with google and the seam and jsf documentation I found a way to get to the cause of the problem. It still does not cover all cases but works very well for seam based applications. For example, <s:link> now omits the context path while <h:outputLink> still preserves it. So the first workaround is still necessary but it doesn't hurt anyways.

The main idea is based on this post - use a Filter and a HttpServletResponseWrapper to modify the URL passed to all servlet responses by simply removing the context path. This magically applies also to all urls created by seam and leads to a more context-free url for your virtual host.

One thing you have to take care of is to set your cookiepath manually to keep cookies accessible whether your context path is active or not. For glassfish, you can do this in sun-web.xml:


    ...
    
        
            
        
    
    ...


Now without further comment the two required source files and the changes required for web.xml:

package eu.rbecker.util.servlet;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 *
 * @author Roben
 */
public class FakeContext extends HttpServletResponseWrapper {

    private String originalContext;

    public FakeContext(HttpServletResponse response, String originalContext) {
        super(response);
        this.originalContext = originalContext;
    }

    @Override
    public String encodeURL(String url) {
        // preserve original URL encoding
        String out = super.encodeURL(url);
        // remove original context path from url
        if (originalContext != null && !originalContext.isEmpty() && out.startsWith(originalContext)) {
            out = out.substring(originalContext.length());
        }
        return out;
    }
}

package eu.rbecker.util.filter;

import eu.rbecker.util.servlet.FakeContext;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author Roben
 */
public class MyResponseFilter implements Filter {

    private boolean omitContextPath = false;

    @Override
    public void init(FilterConfig fc) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) throws IOException, ServletException {
        if (sr1 instanceof HttpServletResponse) {
            // create new wrapped response with fake context path
            FakeContext fake = new FakeContext((HttpServletResponse) sr1, ((HttpServletRequest) sr).getContextPath());
            // apply filter
            fc.doFilter(sr, fake);
        }
    }

    @Override
    public void destroy() {
    }
}


    myResponseFilter
    eu.rbecker.util.filter.MyResponseFilter


    myResponseFilter
    /*
    REQUEST
    FORWARD
    INCLUDE