神刀安全网

Customizing Vaadin HTML Template

This week, I had an interesting question on Twitter : "How in  Vaadin do you add a lang attribute to the  html element?", like this:

<html lang="fr">

While it’s quite easy to customize individual components on the page, the outer HTML tag is outside our control. In this article, I’ll describe a possible solution to this problem. Note that I think this is too specialized for morevaadin.com . However, this should still be my reference site for all things Vaadin.

My first (wrong) thought, was that the html element is generated by the UI widget client-side. It’s not the case—as there’s no such widget. In order to find the answer, I had to understand how the framework works. Here’s a short summary of the sequence when one makes a request to a Vaadin application.

Customizing Vaadin HTML Template

Basically, the Vaadin Servlet delegates to the Vaadin Service. In turn, the service loops over its internal list of Request Handlers until one of them is able to handle the request. By default, the Vaadin Service registers the following handlers:

  1. ConnectorResourceHandler
  2. UnsupportedBrowserHandler: returns a specific message if the browser is not supported by Vaadin
  3. UidlRequestHandler: handles RPC communication between client and server
  4. FileUploadHandler: handles file uploads achieved with the  FileUpload  component
  5. HeartbeatHandler: handles heartbeat requests
  6. PublishedFileHandler
  7. SessionRequestHandler: delegates in turn to request handlers that have been registered in the session

This is implemented in VaadinService.createRequestHandlers() . However, notice that  VaadinService is abstract. There’s a subtle change introduced in the concrete  VaadinServletService subclass that is used. It registers a new request handler–the ServletBootstrapHandler , in order for Vaadin to run transparently in both a servlet and a portlet context. In this later case, only a fragment :

Customizing Vaadin HTML Template

The servlet bootstrap handler is responsible for generating the initial HTML page at the start of the application, including the desired outer html tag. Next, requests to the application will just update part of the page via AJAX, but the outside HTML won’t change. Thus, this is the class that needs to be updated if one wishes to add a  lang attribute. A quick glance at the  class makes it very clear that it’s quite hard to extend. Besides, it delegates HTML generation to the  JSoup and more precisely to the  Document.createShell() static method.

At this point, you have 3 options:

  1. Forget about it, what is it worth anyway?
  2. Rewrite a large portion of the BootstrapHandler and add it before the BootstrapHandler in the handlers sequence
  3. Be lazy and apply Ockham’s razor: just use a simple  AOP ‘s aspect

In order to be of any use, I chose the latest option. It’s quite straightforward and very concise, you only need the following steps.

Create the aspect itself. Note that I’m using Kotlin to be coherent with the existing project but Java or any other JVM-based language would be the same.

@Aspect open class UpdateLangAspect {      @Pointcut("execution(static * org.jsoup.nodes.Document.createShell(..))")     fun callDocumentCreateShell(): Unit {}      @AfterReturning(pointcut = "callDocumentCreateShell()", returning = "document")     fun setLangAttribute(document: Document): Unit {         document.childNode(0).attr("lang", "fr")     } }

As the method to instrument is static, it’s not possible to use simple Spring proxies, but we need AspectJ class instrumentation via LTW . In order to activate it in Spring Boot, I just have to update the application.properties file:

spring.aop.proxy-target-class=true

Also, one has to tell Aspect’s weaver what needs to be instrumented in the META-INF/aop.xml :

<?xml version="1.0" encoding="UTF-8"?> <aspectj>   <aspects>     <aspect name="ch.frankel.blog.bootvaadinkotlin.UpdateLangAspect" />   </aspects>   <weaver options="-XnoInline -Xlint:ignore -verbose -showWeaveInfo">     <include within="org.jsoup.nodes.Document" />     <include within="ch.frankel.blog.bootvaadinkotlin.UpdateLangAspect" />   </weaver> </aspectj> 

The first section is about the aspect, the second is about what classes need to be instrumented. Note that weaving section needs also to reference the aspect too.

Finally, one has to update the POM so that launching the application through the Spring Boot Maven plugin will also use the aspect.

<plugin>   <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-maven-plugin</artifactId>   <configuration>     <agent>${settings.localRepository}/org/aspectj/aspectjweaver/1.8.8/aspectjweaver-1.8.8.jar</agent>   </configuration> </plugin>

For the sake of completeness, the code is available on Github on the manage-lang branch.

At this point, generating the page will display the desired change. Job done!

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Customizing Vaadin HTML Template

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮