Archive for the ‘Java’ Category

Java 7 one-liner to read file into string

24 March 2014

Reading in a file in Java used to require a lot of code. Various things had to wrapped, loops with weird terminating conditions had to be specified and so forth.

In Java 7 we can do a lot better. The actual code to do the reading is just:

String content = new String(readAllBytes(get("test.txt")));

As a full program that echos back the file’s content it looks like this:

import static java.lang.System.out;
import static java.nio.file.Files.readAllBytes;
import static java.nio.file.Paths.get;
 
public class Test {
    public static void main(String[] args) throws Exception {
	out.println(new String(readAllBytes(get("test.txt"))));
    }
}

Of course it we want to be careful that we don’t load a few gigabytes into memory and if we want to pay attention to the character set (it’s the platform default now) we need a little more code, but for quick and dirty file reading this should do the trick.

As a bonus, a version in Scala using the same JDK 7 APIs contributed by my fellow office worker Mark van der Tol:

import java.nio.file.Files.readAllBytes
import java.nio.file.Paths.get
 
object Main extends App {
    println(new String(readAllBytes(get("test.txt"))))
}

Arjan Tijms

WildFly 8 benchmarked

14 February 2014

The final version of WildFly 8 was released this week. WildFly is the new Java EE 7 compliant application server from Red Hat and is the successor to JBoss AS 7. One of the major new features in WildFly is a new high-performance web server called Undertow, which replaces the Tomcat server in previous version of JBoss. As we’ve recently been benchmarking a new application, I was curious as to how WildFly 8 would perform. To find out, I decided to benchmark WildFly using this application and compare it against the latest version of JBoss EAP, version 6.2.

The application used for the benchmark was a simple JSF-based app. For each request a JSF Facelets template, which pulls some data from a backing bean, is being rendered in real-time. The backing bean in turn retrieves the data from a local cache, which is backed by a restful API and periodically refreshed. The refresh happens asynchronously, so as to not block any user’s requests. To achieve a better performance, HTTP sessions were explicitly disabled for this application.

JSF’s stateless mode was activated as well. Although the JSF page that was rendered did not have any forms on it (and thus should not have any state to begin with), this did in fact seem to give a small performance boost. However, the performance boost was so small that it fell within the fluctuation range that we saw between runs and it’s therefor hard to say whether this really mattered.

JMeter was used for the benchmark itself. The application and JMeter were both run on the same computer, which is a 3.4 Ghz quad-core Intel Xeon with 16GB or RAM running Linux Mint 16. As the first release candidate of JDK8 was released last week, I decided to use both JDK7u45 and JDK8b128 in the benchmarks. Both JBoss EAP 6.2 and WildFly 8 were used out of the box; nothing was changed to standalone.xml or any other internal configuration file.

The benchmark itself was performed with 100 concurrent threads, each performing 2000 requests. For each application server and JDK version, four test were performed directly after each other. The results from the first test were discarded, as the JVM was still warming up, and the throughput in requests per second was averaged over the remaining three tests. You can see the average throughput below.

WildFly benchmark average throughput

These averages, however, do not paint the full picture. When taking a closer look at the results from the JBoss EAP benchmarks, the results of the individual benchmark runs fluctuate a lot more than the results from the WildFly benchmarks.

Throughput

JBoss EAP seems to perform best on the second test run in both cases, but this could be a coincidence. What is clear is that the WildFly team have done a great job in creating an application server that, while it might not be outright faster, does achieve a similar level of performance, but with a greater level of consistency. For both JBoss EAP and WildFly, the JDK8 benchmarks still fall within the standard deviation of the JDK7 benchmarks, so also seems to perform on a similar level compared to JDK7. It would be interesting to see how other application servers, like GlassFish, hold up against JBoss EAP and WildFly, so I may revisit this topic sometime soon.

Disabling all EJB timers in Java EE 6

29 October 2013

Java EE 7 has finally added a method to obtain all timers in the system. With the help of this method you can fairly conveniently cancel all timers, or only specific ones.

But Java EE 7 is still fairly new and not many vendors have released a Java EE 7 compatible server yet. So is there any way at all to say disable all scheduled timers in Java EE 6?

As it appears this is possible, with a little help of CDI and the Interceptor spec. The idea is that we install a CDI extension that dynamically adds an interceptor to all @Schedule annotated methods. This interceptor then cancels the timer for which it intercepted the method that handles it. It would be great if the CDI extension was just able to remove the @Schedule annotation and we’d be done with it. Unfortunately this is yet another example why it’s not so great that EJB is not fully alligned with CDI; even if the @Schedule annotation is removed from the so-called AnnotatedType, the EJB container will still start the timer being obvlivious to the CDI representation of the bean.

The first step is to make an annotation that represents the interceptor we need:

@Inherited
@InterceptorBinding
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
public @interface DisableTimers {}

We then proceed to the actual interceptor:

@Interceptor
@DisableTimers
public class DisableTimersInterceptor {
 
    @Inject
    private Logger logger;
 
    @AroundTimeout
    public Object disableTimers(InvocationContext context) throws Exception {
 
        try {
            Object timerObject = context.getTimer();
            if (timerObject instanceof Timer) {
                Timer timer = ((Timer) timerObject);
                logger.info("Canceling timer in bean " + context.getClass().getName() + " for timer " + timer.toString());
                timer.cancel();
            }
        } catch (Exception e) {
            logger.log(SEVERE, "Exception while canceling timer:", e);
        }
 
        return null;
    }
}

Note that while there’s the general concept of an @AroundTimeout and the context has a getTimer() method, the actual type for the timer has not been globally standardized for Java EE. This means we have to resort to instance testing. It would be great if some future version of Java EE could define a standard interface that all eligable timers have to implement.

Also note that there’s isn’t a clean universal way to print the timer details so I’ve used toString() here on the Timer instance. It’s vendor specific what this actually returns.

An alternative would have been here to inject the timer service and use it to cancel all timers for the bean right away. This is perhaps a bit less intuitive though. Also note that at least on JBoss you can not inject the timer service directly but have to specify a JNDI lookup name, e.g.:

@Resource(lookup="java:comp/TimerService")
public TimerService timerService;

Unfortunately in Java EE 6 we have to register the interceptor in beans.xml:

<beans>
    <interceptors>
        <class>com.example.DisableTimersInterceptor</class>
    </interceptors>
</beans>

Next is the actual extension:

public class EjbTimerDisableExtension implements Extension {
 
    private static final Logger logger = Logger.getLogger(EjbTimerDisableExtension.class.getName());
 
    public <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> processAnnotatedType, BeanManager beanManager) {
        if (hasScheduleMethods(processAnnotatedType.getAnnotatedType())) {
 
            logger.log(INFO, "Disabling timer in " + processAnnotatedType.getAnnotatedType().getJavaClass().getName());
 
            AnnotatedTypeWrapper<T> annotatedTypeWrapper = new AnnotatedTypeWrapper<>(processAnnotatedType.getAnnotatedType());
 
            for (AnnotatedMethod<? super T> annotatedMethod : processAnnotatedType.getAnnotatedType().getMethods()) {
                if (annotatedMethod.isAnnotationPresent(Schedule.class)) {
 
                    AnnotatedMethodWrapper<? super T> annotatedMethodWrapper = new AnnotatedMethodWrapper<>(annotatedMethod);
                    annotatedMethodWrapper.addAnnotation(createAnnotationInstance(DisableTimers.class));
 
                    annotatedTypeWrapper.getMethods().remove(annotatedMethod);
                    annotatedTypeWrapper.getMethods().add(annotatedMethodWrapper);
                }
            }
 
            processAnnotatedType.setAnnotatedType(annotatedTypeWrapper);
        }
    }
 
    private <T> boolean hasScheduleMethods(AnnotatedType<T> annotatedType) {
        for (AnnotatedMethod<?> annotatedMethod : annotatedType.getMethods()) {
            if (annotatedMethod.isAnnotationPresent(Schedule.class)) {
                return true;
            }
        }
 
        return false;
    }
}

In this extension we check if a bean has methods with an @Schedule annotation, and if it indeed has one we wrap the passed-in annotated type and wrap any method representation that has this annotation. Via these wrappers we can remove the existing method and then add our own method where we dynamically add the interceptor annotation.

We need to register this extension in /META-INF/services/javax.enterprise.inject.spi.Extension by putting its FQN there:

com.example.EjbTimerDisableExtension

It’s perhaps unfortunately that CDI 1.0 doesn’t offer many convenience methods for wrapping its most important types (which e.g. JSF does do) and doesn’t provide an easy way to create an annotation instance.

Luckily my co-worker Jan Beernink had already created some convenience types for those, which I could use:

The CDI type wrappers:

public class AnnotatedMethodWrapper<X> implements AnnotatedMethod<X> {
 
    private AnnotatedMethod<X> wrappedAnnotatedMethod;
 
    private Set<Annotation> annotations;
 
    public AnnotatedMethodWrapper(AnnotatedMethod<X> wrappedAnnotatedMethod) {
        this.wrappedAnnotatedMethod = wrappedAnnotatedMethod;
 
        annotations = new HashSet<>(wrappedAnnotatedMethod.getAnnotations());
    }
 
    @Override
    public List<AnnotatedParameter<X>> getParameters() {
        return wrappedAnnotatedMethod.getParameters();
    }
 
    @Override
    public AnnotatedType<X> getDeclaringType() {
        return wrappedAnnotatedMethod.getDeclaringType();
    }
 
    @Override
    public boolean isStatic() {
        return wrappedAnnotatedMethod.isStatic();
    }
 
    @Override
    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
        for (Annotation annotation : annotations) {
            if (annotationType.isInstance(annotation)) {
                return annotationType.cast(annotation);
            }
        }
 
        return null;
    }
 
    @Override
    public Set<Annotation> getAnnotations() {
        return Collections.unmodifiableSet(annotations);
    }
 
    @Override
    public Type getBaseType() {
        return wrappedAnnotatedMethod.getBaseType();
    }
 
    @Override
    public Set<Type> getTypeClosure() {
        return wrappedAnnotatedMethod.getTypeClosure();
    }
 
    @Override
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
        for (Annotation annotation : annotations) {
            if (annotationType.isInstance(annotation)) {
                return true;
            }
        }
 
        return false;
    }
 
    @Override
    public Method getJavaMember() {
        return wrappedAnnotatedMethod.getJavaMember();
    }
 
    public void addAnnotation(Annotation annotation) {
        annotations.add(annotation);
    }
 
    public void removeAnnotation(Annotation annotation) {
        annotations.remove(annotation);
    }
 
    public void removeAnnotation(Class<? extends Annotation> annotationType) {
        Annotation annotation = getAnnotation(annotationType);
        if (annotation != null ) {
            removeAnnotation(annotation);
        }
    }
 
}
public class AnnotatedTypeWrapper<T> implements AnnotatedType<T> {
 
    private AnnotatedType<T> wrappedAnnotatedType;
 
    private Set<Annotation> annotations = new HashSet<>();
    private Set<AnnotatedMethod<? super T>> annotatedMethods = new HashSet<>();
    private Set<AnnotatedField<? super T>> annotatedFields = new HashSet<>();
 
    public AnnotatedTypeWrapper(AnnotatedType<T> wrappedAnnotatedType) {
        this.wrappedAnnotatedType = wrappedAnnotatedType;
 
        annotations.addAll(wrappedAnnotatedType.getAnnotations());
        annotatedMethods.addAll(wrappedAnnotatedType.getMethods());
        annotatedFields.addAll(wrappedAnnotatedType.getFields());
    }
 
    @Override
    public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
        return wrappedAnnotatedType.getAnnotation(annotationType);
    }
 
    @Override
    public Set<Annotation> getAnnotations() {
        return annotations;
    }
 
    @Override
    public Type getBaseType() {
        return wrappedAnnotatedType.getBaseType();
    }
 
    @Override
    public Set<AnnotatedConstructor<T>> getConstructors() {
        return wrappedAnnotatedType.getConstructors();
    }
 
    @Override
    public Set<AnnotatedField<? super T>> getFields() {
        return annotatedFields;
    }
 
    @Override
    public Class<T> getJavaClass() {
        return wrappedAnnotatedType.getJavaClass();
    }
 
    @Override
    public Set<AnnotatedMethod<? super T>> getMethods() {
        return annotatedMethods;
    }
 
    @Override
    public Set<Type> getTypeClosure() {
        return wrappedAnnotatedType.getTypeClosure();
    }
 
    @Override
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
        for (Annotation annotation : annotations) {
            if (annotationType.isInstance(annotation)) {
                return true;
            }
        }
 
        return false;
    }
 
}

And the utility code for instantiating an annotation type:

public class AnnotationUtils {
 
    private AnnotationUtils() {
    }
 
    /**
     * Create an instance of the specified annotation type. This method is only suited for annotations without any properties, for annotations with
     * properties, please see {@link #createAnnotationInstance(Class, InvocationHandler)}.
     *
     * @param annotationType
     *            the type of annotation
     * @return an instance of the specified type of annotation
     */
    public static <T extends Annotation> T createAnnotationInstance(Class<T> annotationType) {
        return createAnnotationInstance(annotationType, new AnnotationInvocationHandler<>(annotationType));
    }
 
    public static <T extends Annotation> T createAnnotationInstance(Class<T> annotationType, InvocationHandler invocationHandler) {
        return annotationType.cast(Proxy.newProxyInstance(AnnotationUtils.class.getClassLoader(), new Class<?>[] { annotationType },
                invocationHandler));
    }
}
/**
 * {@link InvocationHandler} implementation that implements the base methods required for a parameterless annotation. This handler only implements the
 * following methods: {@link Annotation#equals(Object)}, {@link Annotation#hashCode()}, {@link Annotation#annotationType()} and
 * {@link Annotation#toString()}.
 *
 * @param <T>
 *            the type of the annotation
 */
class AnnotationInvocationHandler<T extends Annotation> implements InvocationHandler {
 
    private Class<T> annotationType;
 
    /**
     * Create a new {@link AnnotationInvocationHandler} instance for the given annotation type.
     *
     * @param annotationType
     *            the annotation type this handler is for
     */
    public AnnotationInvocationHandler(Class<T> annotationType) {
        this.annotationType = annotationType;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        switch (method.getName()) {
        case "toString":
            return "@" + annotationType.getName() + "()";
        case "annotationType":
            return annotationType;
        case "equals":
            return annotationType.isInstance(args[0]);
        case "hashCode":
            return 0;
        }
 
        return null;
    }
 
}

Conclusion

This approach is by far not as elegant as just injecting an @Startup @Singleton with the timer service and canceling all timers in a simple loop as we can do in Java EE 7, but it does work on Java EE 6. Timers are canceled one by one as they fire and their handler methods are never invoked.

The approach of dynamically adding interceptors to specific methods can however be used for other things as well (e.g. logging exceptions from @Asynchronous methods that return void, just to name something) so it’s a generally useful technique.

Arjan Tijms

Eclipse 4.3 SR1 again silently released!

28 September 2013

Again rather silently, the Eclipse organization yesterday released the first maintenance release of Eclipse 4.3; Eclipse 4.3.1 aka Eclipse Kepler SR1.

Surprisingly (or maybe not), this event again isn’t noted on the main homepage at eclipse.org or at the recent activity tracker. There also don’t seem to be any release notes, like the ones we had for the 4.3 release.

It seems these days the Eclipse home page is about anything and nothing except the thing we most closely associate with the term “Eclipse”; the Eclipse IDE. Seemingly the IDE itself is by far not as important as “Concierge Creation Review Scheduled” and “Web-based BPM with Stardust”.

Once again, fiddling with Bugzilla gave me a list of 112 bugs that are fixed in core packages.

Hopefully this fix will remedy the random crashes I’ve experienced in Ubuntu 13.04, but I’m not holding my breath.

The good people at the WTP project did feel like posting about this event on their homepage with a link and short description to the 3.5.1 release of WTP. Again, the new and noteworthy keeps pointing to the previous release, but there’s a list of 51 fixed bugs available.

Community reporting seems to have reached a historically low. There’s one enthusiastic user who created a rather minimalistic forum post about it, and that’s pretty much it. Maybe a few lone tweets, but nothing major.

Is the community and the Eclipse organization loosing interesting in Eclipse, or is it just that SR releases aren’t that exciting?

Serving multiple images from database as a CSS sprite

31 July 2013

Introduction

In the first public beta version of ZEEF which was somewhat thrown together (first get the minimum working using standard techniques, then review, refactor and improve it), all favicons were served individually. Although they were set to be agressively cached (1 year, whereby a reload is when necessary forced by the timestamp-in-query-string trick with the last-modified timestamp of the link), this resulted in case of an empty cache in a ridiculous amount of HTTP requests on a subject page with relatively a lot of links, such as Curaçao by Bauke Scholtz:

Yes, 209 image requests of which 10 are not for favicons, which nets as 199 favicon requests. Yes, that much links are currently on the Curaçao subject. The average modern webbrowser has only 6~8 simultaneous connections available on a specific domain. That’s thus a huge queue. You can see it in the screenshot, it took on an empty cache nearly 5 seconds to get them all (on a primed cache, it’s less than 1 second).

If you look closer, you’ll see that there’s another problem with this approach: links which doesn’t have a favicon re-requests the very same default favicon again and again with a different last-modified timestamp of the link itself, ending up in copies of exactly same image in the browser cache. Also, links from the same domain which share the same favicon, have their favicons duplicated this way. In spite of the agressive cache, this was simply too inefficient.

Converting images to common format and size

The most straightforward solution would be to serve all those favicons as a single CSS sprite and make use of CSS background-position to reference the right favicon in the sprite. This however requires that all favicons are first parsed and converted to a common format and size which allows easy manipulation by standard Java 2D API (ImageIO and friends) and easy generation of the CSS sprite image. PNG was chosen as format as that’s the most efficient and lossless format. 16×16 was chosen as default size.

As first step, a favicon parser was created which verifies and parses the scraped favicon file and saves every found image as PNG (the ICO format can store multiple images, usually each with a different dimension, e.g. 16×16, 32×32, 64×64, etc). For this, Image4J (a mavenized fork with bugfix) has been of a great help. The original Image4J had only a minor bug, it ran in an infinite loop on favicons with broken metadata, such as this one. This was fixed by vijedi/image4j. However, when an ICO file contained multiple images, this fix discarded all images, instead of only the broken one. So, another bugfix was done on top of that (which by the way just leniently returned the “broken” image — in fact, only the metadata was broken, not the image content itself). Every single favicon will now be parsed by ICODecoder and BMPDecoder of Image4J and then ImageIO#read() of standard Java SE API in this sequence. Whoever returned the first non-null BufferedImage(s) without exceptions, this will be used. This step also made us able to completely bypass the content-type check which we initially had, because we discovered that a lot of websites were doing a bad job in this, some favicons were even served as text/html which caused false negatives.

As second step, if the parsing of a favicon resulted in at least one BufferedImage, but no one was in 16×16 dimension, then it will be created based on the firstnext dimension which is resized back to 16×16 with help of thebuzzmedia/imgscalr which yielded high quality resizings.

Finally all formats are converted to PNG and saved in the DB (and cached in the local disk file system).

Serving images as CSS sprite

For this a simple servlet was been used which does basically ultimately the following in doGet() (error/cache checking omitted for simplicity):

Long pageId = Long.valueOf(request.getPathInfo().substring(1));
Page page = pageService.getById(pageId);
long lastModified = page.getLastModified();
byte[] content = faviconService.getSpriteById(pageId, lastModified);
 
if (content != null) { // Found same version in disk file system cache.
    response.getOutputStream().write(content);
    return;
}
 
Set<Long> faviconIds = new TreeSet<>();
faviconIds.add(0L); // Default favicon, appears as 1st image of sprite.
faviconIds.addAll(page.getFaviconIds());
 
int width = Favicon.DEFAULT_SIZE; // 16px.
int height = width * faviconIds.size();
 
BufferedImage sprite = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = sprite.createGraphics();
graphics.setBackground(new Color(0xff, 0xff, 0xff, 0)); // Transparent.
graphics.fillRect(0, 0, width, height);
 
int i = 0;
 
for (Long faviconId : faviconIds) {
    Favicon favicon = faviconService.getById(faviconId); // Loads from disk file system cache.
    byte[] content = favicon.getContent();
    BufferedImage image = ImageIO.read(new ByteArrayInputStream(content));
    graphics.drawImage(image, 0, width * i++, null);
}
 
ByteArrayOutputStream output = new ByteArrayOutputStream();
ImageIO.write(sprite, "png", output);
content = output.toByteArray();
faviconService.saveSprite(pageId, lastModified, content); // Store in disk file system cache.
response.getOutputStream().write(content);

To see it in action, you can get all favicons of the page Curaçao by Bauke Scholtz (which has page ID 18) as CSS sprite on the following URL: https://zeef.com/favicons/page/18.

Serving the CSS file containing sprite-image-specific selectors

In order to present the CSS sprite images at the right places, we should also have a simple servlet which generates the desired CSS stylesheet file containing sprite-image-specific selectors with the right background-position. The servlet should basically ultimately do the following in doGet() (error/cache checking omitted to keep it simple):

Long pageId = Long.valueOf(request.getPathInfo().substring(1));
Page page = pageService.getById(pageId);
 
Set<Long> faviconIds = new TreeSet<>();
faviconIds.add(0L); // Default favicon, appears as 1st image of sprite.
faviconIds.addAll(page.getFaviconIds());
 
long lastModified = page.getLastModified().getTime();
int height = Favicon.DEFAULT_SIZE; // 16px.
 
PrintWriter writer = response.getWriter();
writer.printf("[class^='favicon-']{background-image:url('../page/%d?%d')!important}", 
    pageId, lastModified);
int i = 0;
 
for (Long faviconId : faviconIds) {
    writer.printf(".favicon-%s{background-position:0 -%spx}", faviconId, height * i++);
}

To see it in action, you can get the CSS file of the page Curaçao by Bauke Scholtz (which has page ID 18) on the following URL: https://zeef.com/favicons/css/18.

Note that the background-image URL has the page’s last modified timestamp in the query string which should force a browser reload of the sprite whenever a link has been added/removed in the page. The CSS file itself has also such a query string as you can see in HTML source code of the ZEEF page, which is basically generated as follows:

<link id="favicons" rel="stylesheet" 
    href="//zeef.com/favicons/css/#{zeef.page.id}?#{zeef.page.lastModified.time}" />

Also note that the !important is there to overrule the default favicon for the case the serving of the CSS sprite failed somehow. The default favicon is specified in general layout CSS file layout.css as follows:

#blocks .link.block li .favicon,
#blocks .link.block li [class^='favicon-'] {
    position: absolute;
    left: -7px;
    top: 4px;
    width: 16px;
    height: 16px;
}
 
#blocks .link.block li [class^='favicon-'] {
    background-image: url("#{resource['zeef:images/default_favicon.png']}");
}

Referencing images in HTML

It’s rather simple, the links were just generated in a loop whereby the favicon image is represented via a plain HTML <span> element basically as follows:

<a id="link_#{linkPosition.id}" href="#{link.targetURL}" title="#{link.defaultTitle}">
    <span class="favicon-#{link.faviconId}" />
    <span class="text">#{linkPosition.displayTitle}</span>
</a>

The HTTP requests on image files have been reduced from 209 to 12 (note that 10 non-favicon requests have increased to 11 non-favicon requests due to changes in social buttons, but that’s not further related to the matter):

It took on an empty cache on average only half a second to download the CSS file and another half a second to download the CSS sprite. Per saldo, that’s thus 5 times faster with 197 connections less! On a primed cache it’s even not requested at all. Noted should be that I’m here behind a relatively slow network and that the current ZEEF production server on a 3rd party host isn’t using “state of the art” hardware yet. The hardware will be handpicked later on once we grow.

Reloading CSS sprite by JavaScript whenever necessary

When you’re logged in as page owner, you can edit the page by adding/removing/drag’n’drop links and blocks. This all takes place by ajax without a full page reload. Whenever necessary, the CSS sprite can during ajax oncomplete be forced to be reloaded by the following script which references the <link id="favicons">:

function reloadFavicons() {
    var $favicons = $("#favicons");
    $favicons.attr("href", $favicons.attr("href").replace(/\?.*/, "?" + new Date().getTime()));
}

Basically, it just updates the timestamp in the query string of the <link href> which in turn forces the webbrowser to request it straight from the server instead of from the cache.

Note that in case of newly added links which do not exist in the system yet, favicons are resolved asynchronously in the background and pushed back via Server-Sent Events. In this case, the new favicon is still downloaded individually and explicitly set as CSS background image. You can find it in the global-push.js file:

function updateLink(data) {
    var $link = $("#link_" + data.id);
    $link.attr("title", data.title);
    $link.find(".text").text(data.text);
    $link.find("[class^='favicon-']").attr("class", "favicon")
        .css("background-image", "url(/favicons/link/" + data.icon + "?" + new Date().getTime() + ")");
    highlight($link);
}

But once the HTML DOM representation of the link or block is later ajax-updated after an edit or drag’n’drop, then it will re-reference the CSS sprite again.

The individual favicon request is also done in “Edit link” dialog. The servlet code for that is not exciting, but for the case you’re interested, the URL is like https://zeef.com/favicons/link/354 and all the servlet basically does is (error/cache checking omitted for brevity):

Long linkId = Long.valueOf(request.getPathInfo().substring(1));
Link link = linkService.getById(linkId);
Favicon favicon = faviconService.getById(link.getFaviconId());
byte[] content = favicon.getContent();
response.getWriter().write(content);

Note that individual favicons are not downloaded by their own ID, but instead by the link ID, because a link doesn’t necessarily have any favicon. This way the default favicon can easily be returned.


This article is also posted on balusc.blogspot.com.

Switching between data sources when using @DataSourceDefinition

21 May 2013

Prior to Java EE 6 setting up and configuring data sources had to be done in a proprietary (vendor specific) way. In many cases this meant a data source had to be created inside the application server.

This may make sense when such an application server runs a multitude of applications and/or those applications are externally obtained ones. In such case it’s great that all those applications can share the same data source and applications themselves don’t dictate which database is being used (via hard-coded referenced to a specific driver).

However, when you run one application per server and especially when that one application is your primary in-house developed code, it’s not always that convenient; you will have to store your data source definitions somewhere away from your code (e.g. in a CFEngine managed repository) and changes to the data source won’t be pulled in together with new code when you pull from your SCM.

For those situations, especially when working in agile and devops centered teams, Java EE 6 introduced the @DataSourceDefinition annotation and data-source element for usage in deployment descriptors such as web.xml.

Although some vendors were supposedly slightly reluctant to support this, it now works reasonably well.

A typical example:

web.xml

<data-source>
    <name>java:app/KickoffApp/kickoffDS</name>
    <class-name>org.h2.jdbcx.JdbcDataSource</class-name>
    <url>jdbc:h2:mem:test</url>
    <user>sa</user>
    <password>sa</password>
    <transactional>true</transactional>
    <isolation-level>TRANSACTION_READ_COMMITTED</isolation-level>
    <initial-pool-size>2</initial-pool-size>
    <max-pool-size>10</max-pool-size>
    <min-pool-size>5</min-pool-size>
    <max-statements>0</max-statements>
</data-source>

Source

One small issue remained though. How do you easily change the settings of such a data source for different stages (e.g. DEV, QA, Production)?

The official way in Java EE is by providing different versions of deployment descriptors like web.xml, but this has two problems:

  • The entire file needs to be swapped, even when only a few changes are needed
  • The file is embedded in the .war/.ear archive. Prying it open, changing the file and closing it again is tedious

One solution is to use build tools to swap in different versions of the deployment descriptor and/or use placeholders that are replaced at build time. Although this is certainly an option, it doesn’t always play nice with incremental builds in IDEs such as Eclipse and can be tricky (but not impossible) to fit into CI pipelines, where the build is tested on some local test server and then as-is automatically deployed to another server.

Another solution that I would like to present here is making use of a data source wrapper that loads its settings from a user defined location (which can be parametrized) and passes it on to the real data source.

Design

Creating a wrapper is by itself simple enough, but one challenge lies in the way how properties are set on a DataSource. There are hardly any properties defined via an interface and there’s no universal setter or map available. Instead, the server inspects the DataSource for JavaBeans properties via reflection and calls those via reflection as well. Obviously a wrapper cannot dynamically at run time add properties to itself.

Fortunately, there are some standard properties that are defined in the JDBC spec that we can statically implement. It’s perhaps a question if we really need them, since we’ll be setting most properties ourselves on the wrapped real data source, but it might be convenient to have them anyway.

We’ll start off with a wrapper for the CommonDataSource, which is the base class for the most important data source types, such as plain DataSource and XADataSource. The most important methods of this wrapper are initDataSource, get and set, and setWithConversion, which are discussed below. The full code is given at the end of this article.

In initDataSource we set the wrapped data source and collect its properties. There are many reflection libraries that make it easier to work reflectively with properties, but using the venerable java.beans.Introspector proved to be good enough here. The only extra thing that was needed was storing the obtained properties in a map (JDK 8 lambdas would sure make this particular task even more straightforward).

public void initDataSource(CommonDataSource dataSource) {
    this.commonDataSource = dataSource;
 
    try {
        Map<String, PropertyDescriptor> mutableProperties = new HashMap<>();
        for (PropertyDescriptor propertyDescriptor : getBeanInfo(dataSource.getClass()).getPropertyDescriptors()) {
            mutableProperties.put(propertyDescriptor.getName(), propertyDescriptor);
        }
 
        dataSourceProperties = unmodifiableMap(mutableProperties);
 
    } catch (IntrospectionException e) {
        throw new IllegalStateException(e);
    }
}

The next thing we do is creating a get and set method for the obtained properties. Calling getReadMethod().invoke(…) on a given property isn’t actually that bad, but the multitude of checked exceptions spoil the party a little. It would be really cool if there was just a Property in the JDK with a simple unchecked get and set method, but as shown it’s nothing a little helper code can’t fix:

@SuppressWarnings("unchecked")
public <T> T get(String name) {
    try {
        return (T) dataSourceProperties.get(name).getReadMethod().invoke(commonDataSource);
    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        throw new IllegalStateException(e);
    }
}
 
public void set(String name, Object value) {
    try {
        dataSourceProperties.get(name).getWriteMethod().invoke(commonDataSource, value);
    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        throw new IllegalStateException(e);
    }
}

Next we come to setWithConversion. This allows us to set a property with the correct type using a string representation of the value (which is what you typically have when reading such values from a property file). It appears this can be done with just a few lines of code using the java.beans.PropertyEditorManager class. You can obtain a kind of converter called a PropertyEditor from this based on a class type, which you can feed a String and will return a converted value for the target type.

It stands to reason PropertyEditor was originally designed for a rather different environment, seeing that it contains methods for usage with AWT such as paintValue(Graphics gfx, Rectangle box) and a really obscure method called getJavaInitializationString() that generates a Java code fragment :X. It’s a tad scary to realize these methods are present in code that runs deep inside a Java EE server with not a graphics card in sight, but alas, it’s part of the JDK and as it appeared used quite a lot on the server side by code that works with beans (like e.g. expression language).

Anyway, here’s the implementation:

public void setWithConversion(String name, String value) {
 
    PropertyDescriptor property = dataSourceProperties.get(name);
 
    PropertyEditor editor = findEditor(property.getPropertyType());
    editor.setAsText(value);
 
    try {
        property.getWriteMethod().invoke(commonDataSource, editor.getValue());
    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        throw new IllegalStateException(e);
    }
}

Next we’ll create a sub class that does the actual switching for a CommonDataSource. Unfortunately there is not really any notion of a lifecyle for a DataSource. The application server just creates an instance using a no-arguments constructor, calls setters on it, and then eventually retrieves a connection from it. If we want to be capable of accepting properties from the @DataSourceDefinition annotation or data-source element in addition to the ones we read from our own file, we have to use a little trick.

Initially we collect properties in a temporary map:

public void set(String name, Object value) {
    if (init) {
        super.set(name, value);
    } else {
        tempValues.put(name, value);
    }
}

When we receive the special property “configFile” we start the initialization:

public void setConfigFile(String configFile) {
    this.configFile = configFile;
    doInit();
}

In this initialization method we load our own properties, and from those fetch another special property called “className”, which is the fully qualified class name of the actual data source. Using the setter methods shown above we set the properties that we collected earlier as well as the properties we read our selves:

public void doInit() {
 
    // Get the properties that were defined separately from the @DataSourceDefinition/data-source element
    Map<String, String> properties = PropertiesUtils.getFromBase(configFile);
 
    // Get & check the most important property; the class name of the data source that we wrap.
    String className = properties.get("className");
    if (className == null) {
        throw new IllegalStateException("Required parameter 'className' missing.");
    }
 
    initDataSource(newInstance(className));
 
    // Set the properties on the wrapped data source that were already set on this class before doInit()
    // was possible.
    for (Entry<String, Object> property : tempValues.entrySet()) {
        super.set(property.getKey(), property.getValue());
    }
 
    // Set the properties on the wrapped data source that were loaded from the external file.
    for (Entry<String, String> property : properties.entrySet()) {
        if (!property.getKey().equals("className")) {
            setWithConversion(property.getKey(), property.getValue());
        }
    }
 
    // After this properties will be set directly on the wrapped data source instance.
    init = true;
}

Because of the JDBC distinction between different data source types, the one more thing left to do is to create the sub class that contains the methods specific for that data source type. This is a small nuisance, but otherwise rather straightforward. For an XA data source it contains the two getXAConnection methods, e.g.

public XADataSource getWrapped() {
    return (XADataSource) super.getWrapped();
}
 
public XAConnection getXAConnection() throws SQLException {
    return getWrapped().getXAConnection();
}

Finally via PropertiesUtils.getFromBase(configFile) a config file is loaded from some location based on a system property (-D commandline option). At the end of the article a somewhat hacky example is shown for loading this from the root of an EAR archive. Unfortunately the root of an EAR is not on the classpath and neither is its META-INF, therefor the chosen solution is rather hacky. It works on JBoss AS 7.x though.

For a WAR archive there’s no super convenient location. /conf in the root would be ideal, but unfortunately in a WAR the root is also not on the classpath and instead directly contains the resources that are made available to web clients. WEB-INF/classes/conf or WEB-INF/classes/META-INF/conf would be the most practical location.

Usage

Having created all the classes, the wrapper class can be specified in e.g. application.xml as follows:

<data-source>
    <name>java:app/myDS</name>
    <class-name>com.example.SwitchableXADataSource</class-name>
 
    <property>
        <name>configFile</name>
        <value>datasource-settings.xml</value>
    </property>
 
</data-source>

Specific settings can be put in e.g. an XML properties files as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
 
    <entry key="className">org.postgresql.xa.PGXADataSource</entry>
 
    <entry key="user">user</entry>
    <entry key="password">password</entry>
 
    <entry key="serverName">database.example.com</entry>
    <entry key="databaseName">example_db</entry>
    <entry key="portNumber">5432</entry>
 
</properties>

Source

CommonDataSourceWrapper

package com.example;
 
import static java.beans.Introspector.getBeanInfo;
import static java.beans.PropertyEditorManager.findEditor;
import static java.util.Collections.unmodifiableMap;
 
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
 
import javax.sql.CommonDataSource;
 
public class CommonDataSourceWrapper implements CommonDataSource {
 
    private CommonDataSource commonDataSource;
    private Map<String, PropertyDescriptor> dataSourceProperties; 
 
    public void initDataSource(CommonDataSource dataSource) {
        this.commonDataSource = dataSource;
 
        try {
            Map<String, PropertyDescriptor> mutableProperties = new HashMap<>();
            for (PropertyDescriptor propertyDescriptor : getBeanInfo(dataSource.getClass()).getPropertyDescriptors()) {
                mutableProperties.put(propertyDescriptor.getName(), propertyDescriptor);
            }
 
            dataSourceProperties = unmodifiableMap(mutableProperties);
 
        } catch (IntrospectionException e) {
            throw new IllegalStateException(e);
        }
    }
 
    @SuppressWarnings("unchecked")
    public <T> T get(String name) {
        try {
            return (T) dataSourceProperties.get(name).getReadMethod().invoke(commonDataSource);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new IllegalStateException(e);
        }
    }
 
    public void set(String name, Object value) {
        try {
            dataSourceProperties.get(name).getWriteMethod().invoke(commonDataSource, value);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new IllegalStateException(e);
        }
    }
 
 
    public void setWithConversion(String name, String value) {
 
        PropertyDescriptor property = dataSourceProperties.get(name);
 
        PropertyEditor editor = findEditor(property.getPropertyType());
        editor.setAsText(value);
 
        try {
            property.getWriteMethod().invoke(commonDataSource, editor.getValue());
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new IllegalStateException(e);
        }
    }
 
    public CommonDataSource getWrapped() {
        return commonDataSource;
    }
 
 
    // ------------------------- CommonDataSource-----------------------------------
 
    @Override
    public java.io.PrintWriter getLogWriter() throws SQLException {
        return commonDataSource.getLogWriter();
    }
 
    @Override
    public void setLogWriter(java.io.PrintWriter out) throws SQLException {
        commonDataSource.setLogWriter(out);
    }
 
    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
        commonDataSource.setLoginTimeout(seconds);
    }
 
    @Override
    public int getLoginTimeout() throws SQLException {
        return commonDataSource.getLoginTimeout();
    }
 
    // ------------------------- CommonDataSource JDBC 4.1 -----------------------------------
 
    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return commonDataSource.getParentLogger();
    }
 
 
    // ------------------------- Common properties -----------------------------------
 
    public String getServerName() {
        return get("serverName");
    }
 
    public void setServerName(String serverName) {
        set("serverName", serverName);
    }
 
    public String getDatabaseName() {
        return get("databaseName");
    }
 
    public void setDatabaseName(String databaseName) {
        set("databaseName", databaseName);
    }
 
    public int getPortNumber() {
        return get("portNumber");
    }
 
    public void setPortNumber(int portNumber) {
        set("portNumber", portNumber);
    }
 
    public void setPortNumber(Integer portNumber) {
        set("portNumber", portNumber);
    }
 
    public String getUser() {
        return get("user");
    }
 
    public void setUser(String user) {
        set("user", user);
    }
 
    public String getPassword() {
        return get("password");
    }
 
    public void setPassword(String password) {
        set("password", password);
    }
 
    public String getCompatible() {
        return get("compatible");
    }
 
    public void setCompatible(String compatible) {
        set("compatible", compatible);
    }
 
    public int getLogLevel() {
        return get("logLevel");
    }
 
    public void setLogLevel(int logLevel) {
        set("logLevel", logLevel);
    }
 
    public int getProtocolVersion() {
        return get("protocolVersion");
    }
 
    public void setProtocolVersion(int protocolVersion) {
        set("protocolVersion", protocolVersion);
    }
 
    public void setPrepareThreshold(int prepareThreshold) {
        set("prepareThreshold", prepareThreshold);
    }
 
    public void setReceiveBufferSize(int receiveBufferSize) {
        set("receiveBufferSize", receiveBufferSize);
    }
 
    public void setSendBufferSize(int sendBufferSize) {
        set("sendBufferSize", sendBufferSize);
    }
 
    public int getPrepareThreshold() {
        return get("prepareThreshold");
    }
 
    public void setUnknownLength(int unknownLength) {
        set("unknownLength", unknownLength);
    }
 
    public int getUnknownLength() {
        return get("unknownLength");
    }
 
    public void setSocketTimeout(int socketTimeout) {
        set("socketTimeout", socketTimeout);
    }
 
    public int getSocketTimeout() {
        return get("socketTimeout");
    }
 
    public void setSsl(boolean ssl) {
        set("ssl", ssl);
    }
 
    public boolean getSsl() {
        return get("ssl");
    }
 
    public void setSslfactory(String sslfactory) {
        set("sslfactory", sslfactory);
    }
 
    public String getSslfactory() {
        return get("sslfactory");
    }
 
    public void setApplicationName(String applicationName) {
        set("applicationName", applicationName);
    }
 
    public String getApplicationName() {
        return get("applicationName");
    }
 
    public void setTcpKeepAlive(boolean tcpKeepAlive) {
        set("tcpKeepAlive", tcpKeepAlive);
    }
 
    public boolean getTcpKeepAlive() {
        return get("tcpKeepAlive");
    }
 
    public void setBinaryTransfer(boolean binaryTransfer) {
        set("binaryTransfer", binaryTransfer);
    }
 
    public boolean getBinaryTransfer() {
        return get("binaryTransfer");
    }
 
    public void setBinaryTransferEnable(String binaryTransferEnable) {
        set("binaryTransferEnable", binaryTransferEnable);
    }
 
    public String getBinaryTransferEnable() {
        return get("binaryTransferEnable");
    }
 
    public void setBinaryTransferDisable(String binaryTransferDisable) {
        set("binaryTransferDisable", binaryTransferDisable);
    }
 
    public String getBinaryTransferDisable() {
        return get("binaryTransferDisable");
    }
 
}

SwitchableCommonDataSource

package com.example;
 
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
 
import javax.sql.CommonDataSource;
 
public class SwitchableCommonDataSource extends CommonDataSourceWrapper {
 
    private boolean init;
    private String configFile;
    private Map<String, Object> tempValues = new HashMap<>();
 
    @Override
    public void set(String name, Object value) {
        if (init) {
            super.set(name, value);
        } else {
            tempValues.put(name, value);
        }
    }
 
    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(String name) {
        if (init) {
            return super.get(name);
        } else {
            return (T) tempValues.get(name);
        }
    }
 
    public String getConfigFile() {
        return configFile;
    }
 
    public void setConfigFile(String configFile) {
        this.configFile = configFile;
 
        // Nasty, but there's not an @PostConstruct equivalent on a DataSource that's called
        // when all properties have been set.
        doInit();
    }
 
    public void doInit() {
 
        // Get the properties that were defined separately from the @DataSourceDefinition/data-source element
        Map<String, String> properties = PropertiesUtils.getFromBase(configFile);
 
        // Get & check the most important property; the class name of the data source that we wrap.
        String className = properties.get("className");
        if (className == null) {
            throw new IllegalStateException("Required parameter 'className' missing.");
        }
 
        initDataSource(newInstance(className));
 
        // Set the properties on the wrapped data source that were already set on this class before doInit()
        // was possible.
        for (Entry<String, Object> property : tempValues.entrySet()) {
            super.set(property.getKey(), property.getValue());
        }
 
        // Set the properties on the wrapped data source that were loaded from the external file.
        for (Entry<String, String> property : properties.entrySet()) {
            if (!property.getKey().equals("className")) {
                setWithConversion(property.getKey(), property.getValue());
            }
        }
 
        // After this properties will be set directly on the wrapped data source instance.
        init = true;
    }
 
    private CommonDataSource newInstance(String className) {
        try {
            return (CommonDataSource) Class.forName(className).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            throw new IllegalStateException(e);
        }
    }
 
}

SwitchableXADataSource

package com.example;
 
import java.sql.SQLException;
 
import javax.sql.XAConnection;
import javax.sql.XADataSource;
 
public class SwitchableXADataSource extends CommonDataSourceWrapper implements XADataSource {
 
    public XADataSource getWrapped() {
        return (XADataSource) super.getWrapped();
    }
 
 
    // ------------------------- XADataSource-----------------------------------
 
    @Override
    public XAConnection getXAConnection() throws SQLException {
        return getWrapped().getXAConnection();
    }
 
    @Override
    public XAConnection getXAConnection(String user, String password) throws SQLException {
        return getWrapped().getXAConnection();
    }
 
}

PropertiesUtils

package com.example;
 
import static java.lang.System.getProperty;
import static java.util.Collections.unmodifiableMap;
import static java.util.logging.Level.SEVERE;
 
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
 
public class PropertiesUtils {
 
    private static final Logger logger = Logger.getLogger(PropertiesUtils.class.getName());
 
    public static Map<String, String> getFromBase(String base) {
        String earBaseUrl = getEarBaseUrl();
        String stage = getProperty("example.staging");
        if (stage == null) {
            throw new IllegalStateException("example.staging property not found. Please add it, e.g. -Dexample.staging=dev");
        }
 
        Map<String, String> settings = new HashMap<>();
 
        loadXMLFromUrl(earBaseUrl + "/conf/" + base, settings);
        loadXMLFromUrl(earBaseUrl + "/conf/" + stage + "/" + base, settings);
 
        return unmodifiableMap(settings);
    }
 
    public static String getEarBaseUrl() {
        URL dummyUrl = Thread.currentThread().getContextClassLoader().getResource("META-INF/dummy.txt");
        String dummyExternalForm = dummyUrl.toExternalForm();
 
        int ejbJarPos = dummyExternalForm.lastIndexOf(".jar");
        if (ejbJarPos != -1) {
 
            String withoutJar = dummyExternalForm.substring(0, ejbJarPos);
            int lastSlash = withoutJar.lastIndexOf('/');
 
            return withoutJar.substring(0, lastSlash);
        }
 
        throw new IllegalStateException("Can't derive EAR root from: " + dummyExternalForm);
    }
 
    public static void loadXMLFromUrl(String url, Map<String, String> settings) {
 
        try {
            Properties properties = new Properties();
            properties.loadFromXML(new URL(url).openStream());
 
            logger.info(String.format("Loaded %d settings from %s.", properties.size(), url));
 
            settings.putAll(asMap(properties));
 
        } catch (IOException e) {
            logger.log(SEVERE, "Eror while loading settings.", e);
        }
    }
 
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static Map<String, String> asMap(Properties properties) {
        return (Map<String, String>)( (Map) properties);
    }
 
}

Future

It would be great if Java EE had some more support for easily switching between different configurations, without necessarily having to install such configuration on a dedicated server. A while back I created JAVAEE_SPEC-19 for this.

A somewhat cleaner Property in Java SE and a simple Converter that functions like the existing PropertyEditor but doesn’t have the AWT paint related baggage would be a small but still welcome improvement as well.

For programmatic access to configuration files it would be really helpful if the root of an EAR archive or at least its META-INF folder could be put on the classpath. For a WAR, an archive type where the web resources where in a sub folder (e.g. web-resources) and the root or WEB-INF was on the classpath would be great as well, although such a big change is rather unlikely to happen anytime soon.

Specifically for data sources it would also be a sure improvement if the Java EE spec mandated that the data sources referenced by @DataSourceDefinition can be loaded from the WAR/EAR archive. Currently it doesn’t do that. Most vendors support it anyway, but GlassFish doesn’t.

As mentioned above, it would be great if Java EE had support for switching configuration, but for now the switchable data source as presented in this article can be used as an alternative.

Arjan Tijms

Eclipse 4.2 SR2 released!

2 March 2013

Today the Eclipse organization released the second maintenance release of Eclipse 4.2; Eclipse 4.2.2 aka Eclipse Juno SR2.

This time around the event is actually noted on the main homepage at eclipse.org, where it briefly says:

The packages for the Juno SR2 release are now available for download.

Lists of bugs that were resolved can be found when clicking on the details link for a specific Eclipse variant on the above mentioned download page.

I didn’t see a complete list anywhere, but some fiddling with Bugzilla again revealed a list of 162 bugs that are fixed in core packages.

For the second time in a row the WTP project also posted about this event on their homepage. Following the Eclipse 4.2.2 release train, WTP was upgraded from 3.4.1 to 3.4.2. There’s again no release specific “new and noteworthy”, but there are release notes, which point to a matrix that shows no less than 77 bugs were fixed.

Community reporting about 4.2 SR2 is a little underwhelming again. DZone has a highly voted Eclipse 4.2 sr2 news blurb, and there’s the lone tweet on twitter, but that seems to be about it.

Of course the highlight of this release is the much awaited answer to the abysmal performance that has plagued the 4.2 series since it was released last year. A separate patch has been available for some time, but this has now been integrated into the ready-to-download official release.

Reports about the patch have been largely positive, so it’s to be expected that Eclipse 4.2 SR2 will indeed perform better. Further performance improvements are promised for Eclipse 4.3 (Kepler).

Waarom bij ons werken?

19 February 2013

Providing alternatives for JSF 2.3’s injected artifacts

6 November 2012

At the JSF 2.3 EG we’re currently busy with introducing the ability to inject several of JSF’s own artifacts in your own beans.

On the implementation side this is done via a dynamic CDI producer. There’s for instance a producer for the FacesContext, which is then registered via a CDI extension.

This can be tested via a simple test application. See these instructions for how to obtain a JSF 2.3 snapshot build and update GlassFish with it.

The test application will consist of the following code:

WEB-INF/faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config 
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
	version="2.3"
>
</faces-config>

This file is needed to activate injection of JSF artefacts. For backwards compatibility reasons this feature is only activated when running with a JSF 2.3 deployment descriptor. The second purpose of a (near) empty faces-config.xml is to signal JSF to automatically map the FacesServlet, so we don’t have to create a more verbose web.xml with an explicit mapping. (however the default mappings are not the best ones as the most obvious one, *.xhtml is missing. This is something we hope to rectify in JSF 2.3 as well)

WEB-INF/beans.xml
(empty)

An empty beans.xml is still needed in GlassFish 4.1 to actually enable CDI in a web archive.

index.xhtml

<!DOCTYPE html>
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:jsf="http://xmlns.jcp.org/jsf"
>
    <head jsf:id="head">
        <title>FacesContext inject test app</title>
    </head>
 
    <body jsf:id="body">
	   #{testBean.test}
    </body>
</html>

[java src]/test/TestBean.java

package test;
 
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
 
@Named
@RequestScoped
public class TestBean {
 
    @Inject
    private FacesContext context;
 
    public String getTest() {
        return context.toString();
    }
}

Deploying this to our updated GlassFish and requesting http://localhost:8080/itest/index.jsf will result in something like the following:

com.sun.faces.context.FacesContextImpl@7c46fc07 

So injection works! Now what if we want to “override” the default producer provided by JSF, e.g. what if we want to provide our own alternative implementation?

The answer is to provide your own producer, but mark it as @Dependent, @Alternative and @Priority. E.g. add the following class to the files shown above:

[java src]/test/ContextProducer.java

package test;
 
import static javax.interceptor.Interceptor.Priority.APPLICATION;
 
import javax.annotation.Priority;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextWrapper;
 
@Dependent
@Alternative
@Priority(APPLICATION)
public class ContextProducer {
 
    @Produces
    public FacesContext producer() {
        return new FacesContextWrapper() {
 
            @Override
            public String toString() {
                return "Still ours";
            }
 
            @Override
            public FacesContext getWrapped() {
                return FacesContext.getCurrentInstance();
            }
        };
    }
}

Then deploying this again and request http://localhost:8080/itest/index.jsf once more, will now result in the following:

Still ours 

As we see, the JSF provided producer can be overridden by standard CDI means.

The feature is not finalized yet so things may still change, but hopefully this gives some idea of what direction JSF 2.3 is moving in.

Arjan Tijms

Eclipse 4.2 SR1 silently released!

30 September 2012

Rather silently, the Eclipse organization 2 days ago released the first maintenance release of Eclipse 4.2; Eclipse 4.2.1 aka Eclipse Juno SR1.

Surprisingly, this event isn’t noted on the main homepage at eclipse.org or at the recent activity tracker. There also don’t seem to be any release notes, like the ones we had for the 4.2 release.

Fiddling with Bugzilla gave me a list of 80 bugs that are fixed in core packages.

This time around, the WTP project did feel obliged to post about this event on their homepage. Following the Eclipse 4.2.1 release train, WTP was upgraded from 3.4.0 to 3.4.1. The famous “new and noteworthy” of WTP 3.4.1 unfortunately still points to the previous 3.4.0 release, but there is a list of fixed bugs available that luckily does point to the right version.

Community reporting about 4.2 SR1 has been equally underwhelming, although just today Steffen Schäfer posted about this release focussing on the new JGit/Git 2.1 versions. Besides him there’s a Chinese post about 4.2.1, which just says the following:

To enhance performance, fixed many bug and the export of war with java source code bug fixes!

Is it perhaps so that with the increasing size, complexity and sheer number of plug-ins and projects on eclipse.org, the one thing that we all simply call “Eclipse” becomes more and more difficult to identify as a specific product on that site and as such harder to report about?

And what about the adoption of the Eclipse 4.2 platform? There has been much debate recently about the abysmal performance of the new platform. Is SR1 a step in the right direction, or do we have to wait for 4.2 SR2, or possibly even 4.3?

css.php best counter