Categories
SEAM Tomcat

Restrict access to inner Facelets with SEAM

Sometimes you could have some facelets, which are no entry-sites and which should never be called directly by the user. Typical types are template-files.
Seam provides here an easy function to restrict the access to such pages. You can define this restriction in the pages.xml or the associated *.page.xml.
For the pages.xml you have to add:

1
2
3
4
5
6
7
8
< ?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
	<page view-id="/templates/template.xhtml">
		<restrict />
	</page>
...
</pages>

Because you also can use wildcards, it is also possible to restrict a whole directory:

1
2
3
4
5
6
7
8
< ?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
	<page view-id="/templates/*">
		<restrict />
	</page>
...
</pages>

Seam will now throw an exception, if a user will access this page, but instead we want to send the typical HTTP-error 403. So we have to define some more rules in pages.xml:

1
2
3
4
5
6
7
8
9
10
11
< ?xml version="1.0" encoding="UTF-8"?>
<pages xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
	<exception class="org.jboss.seam.security.NotLoggedInException">
		<http -error error-code="403" />
	</exception>
	<exception class="org.jboss.seam.security.AuthorizationException">
		<http -error error-code="403" />
	</exception>
...
</pages>

Another way would be an own Servlet or Servlet-Filter, which would send the errorcode directly.

Categories
Javascript SEAM XHTML

The XHTML and document.write / innerHTML story

If you use XHTML as HTML-Standard, which is recommended, to build your sites and you use JavaScript, you could have problems with document.write. Especially third-party JavaScript extensions like GoogleMaps or CKEditor use document.write to easily inject own JavaScript code.

But this is denied by specification for XHTML-Documents delivered with content-type application/xhtml+xml instead of text/html. You will receive the DOM Exception #7 by calling document.write or while using innerHTML (Example in Safari: “Error: NO_MODIFICATION_ALLOWED_ERR: DOM Exception 7”; in Firefox: uncaught exception: [Exception… “Component returned failure code: 0x80004003 (NS_ERROR_INVALID_POINTER) [nsIDOMNSHTMLElement.innerHTML]”  nsresult: “0x80004003 (NS_ERROR_INVALID_POINTER)”  location: … ]). The solution is to deliver the Website with content-type “text/html” instead of “application/xhtml+xml”.
Errormessage Safari
In SEAM using Facelets (with JSF) as View, you can set the content-type in the f:view-Tag. This would look like:

1
2
3
4
5
...
<f :view contentType="text/html">
....
</f>
...
Categories
SEAM Tomcat

Defining a ServletFilter – the SEAM way

SEAM doesn’t only extends JSF and Facelets, but also gives you a possibility to define other resources or components via annotations. To define a simple Servlet Filter you only need to annotate a class with the @Filter-annotation. There is no need to extend the web.xml or other.

One simple Filter would be:

1
2
3
4
5
6
7
8
9
10
@Scope(ScopeType.APPLICATION)
@Name("myFilter")
@Install(precedence = Install.FRAMEWORK)
@BypassInterceptors
@Filter(within = { "org.jboss.seam.web.rewriteFilter" })
public class MyFilter extends AbstractFilter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(request, response);
    }
}

With the parameters within or around of the @Filter annotation, you can define when you filter will be called.

Categories
Tomcat

Disable JSESSIONID in Tomcat

Like PHP also the Servlet Containers try to attach a request to a session. If the client doesn’t support cookies it is realized via an suffix ;JESSSIONID= in every URL. Unfortunately this is not good in relation to SEO. The problem is that Tomcat doesn’t provide any configuration option to disable the use of JSESSIONID in URLs. So the only way is an own Filter, which disables the behaviour. You will find an example at: http://randomcoder.com/articles/jsessionid-considered-harmful

Categories
JBoss

Classloading problems with injected @EJB-Beans

Yesterday I wrote how to define Quartz-Jobs in JBoss AS. Generally such jobs try to use business logic, which is injected via @EJB. Currently in Version 5.1.0.GA this is not possible if you use the classloader-isolation. You will get the following (or similar) exception:

1
2
3
4
5
6
7
8
9
Caused by: java.lang.RuntimeException: Can not find interface declared by Proxy in our CL + BaseClassLoader@92c904{vfsfile:...}
at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.redefineProxyInTcl(ProxyObjectFactory.java:343)
at org.jboss.ejb3.proxy.impl.objectfactory.session.SessionProxyObjectFactory.createProxy(SessionProxyObjectFactory.java:134)
at org.jboss.ejb3.proxy.impl.objectfactory.session.stateless.StatelessSessionProxyObjectFactory.getProxy(StatelessSessionProxyObjectFactory.java:79)
at org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory.getObjectInstance(ProxyObjectFactory.java:158)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)
at org.jnp.interfaces.NamingContext.getObjectInstance(NamingContext.java:1479)
at org.jnp.interfaces.NamingContext.getObjectInstanceWrapFailure(NamingContext.java:1496)
... 39 more

The reason for this ist that the Quartz-Service has another classloader as your application and the started job contains to the classloader of the Quartz-Service. There is also a bug posted. Maybe this will be possible in the near future.
One solution is to call a MBean from the job and this MBean injects the business logic via @EJB. The advantage of this solution is that you also can control and monitor the cronjob itselfs and can run the logic on demand via JMX-Console.
An example job would look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@MessageDriven(messageListenerInterface = StatefulJob.class, activationConfig = { @ActivationConfigProperty(propertyName = "cronTrigger", propertyValue = "0 0 0 ? * MON-SAT") })
@ResourceAdapter("quartz-ra.rar")
@Depends(ImportDataManagement.ID)
public class DailyUpdateJob implements StatefulJob {
    private static final Logger log = Logger
            .getLogger(DailyUpdateJob.class);
 
    public void execute(JobExecutionContext context)
            throws JobExecutionException {
        try {
            MBeanServer server = MBeanServerLocator.locate();
            ImportDataManagement bp = (ImportDataManagement) MBeanProxyExt
                    .create(ImportDataManagement.class,
                            ImportDataManagement.ID, server);
            bp.importDaily();
        } catch (Exception e) {
            log.error("run", e);
        }
    }
}

Helpful links:

Categories
JBoss

Cronjobs using Quartz in JBossAS

With the introduction of EJB3 a new method for implementing cronjobs was added. These jobs uses quartz as framework and there are two ways to setup:

1. Variant: Defining a MDB-Consumer

The preferred way is the definition of an MDB-Consumer. The only thing you need is to implement the Job-Interface (org.quartz.Job) and add some Annotations to it:

1
2
3
4
5
6
7
8
9
@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "cronTrigger", propertyValue = "0/2 * * * * ?") })
@ResourceAdapter("quartz-ra.rar")
public class MySampleCronJob implements Job {
 
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("job is called");
    }
 
}

If this job should only be called once at a specific time, you can use the interface StatefulJob. When the job is called is defined in the property cronTrigger. A full documentation can be found at the Quartz-API-Documentation.
Pay attention that the Component only implements one interface or you have to define the property “messageListenerInterface” at @MessageDriven. Otherwise the deployer cannot find the using type. Especially if you use AspectJ this is important.

2. Variant: Using a Quartz-Service

This is the old version. You can define a managed-bean via an XML which instantiate a Quartz-Service.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
< ?xml version="1.0" encoding="UTF-8"?>
<server>
  <mbean code="org.quartz.ee.jmx.jboss.QuartzService" name="user:service=QuartzService,name=QuartzService">
    <attribute name="Properties">
      org.quartz.scheduler.instanceName = DefaultQuartzScheduler
      org.quartz.scheduler.rmi.export = false
      org.quartz.scheduler.rmi.proxy = false
      org.quartz.scheduler.xaTransacted = false
      org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
      org.quartz.threadPool.threadCount = 5
      org.quartz.threadPool.threadPriority = 4
    </attribute>
  </mbean>
</server>

Then you can use this managed bean to add a new trigger and to assign a job to this trigger. This code can be used in an own managed bean, which setups the application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class CronManagementBean {
    @Resource(mappedName = "/Quartz")
    private Scheduler scheduler;
 
    public void start() {
        try {
            Trigger trigger = new CronTrigger("myTrigger",
                    "mygroup",
                    "0 0 4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 ? * *");
 
            JobDetail jobDetail = new JobDetail("myJob",
                    "myjobgroup", StatusJob.class);
            scheduler.scheduleJob(jobDetail, trigger);
 
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
 
    public void stop() {
        try {
            scheduler.deleteJob("myJob", "myjobgroup");
        } catch (SchedulerException e) {
            log.warn("shutdown fails", e);
        }
    }
}
Categories
Java JBoss

Using multiple PersistenceUnits with same name

To be really flexible in my CMS I decided to use a persistence unit with one name which will be configured in the final webapplication. This means I have a persistence unit “cms” in my business-components in my cms.jar and this unit is configured via persistence.xml in the including web-application, which uses my “cms.jar”. So every webapplication has its own database and I can reuse my businesslogic for the cms (retrieve content, or images and so on).
The problem now is that I have some problems with deploying two applications on JBoss 5.1.0.GA which includes my cms, because there is a bug in this application-server. I hope this will be fixed in the one of the next versions.