RESTFul Calculator With JavaScript And ...EJB 3.1

You only have to annotate a @Stateless EJB 3.1 with the JAX-RS annotation to expose it via REST: 

 @Stateless

@Path("calculator/")

public class Calculator {

    private static final String ENGINE_NAME = "JavaScript"; //AppleScriptEngine

    private ScriptEngine scriptEngine = null;


    @PostConstruct

    public void initScripting() {

        ScriptEngineManager engineManager = new ScriptEngineManager();

        this.scriptEngine = engineManager.getEngineByName(ENGINE_NAME);

        if (this.scriptEngine == null) {

            throw new IllegalStateException("Cannot create ScriptEngine: " + ENGINE_NAME);

        }

    }

    @GET

    @Path("{formula}/")

    @Produces(MediaType.TEXT_PLAIN)

    public String calculate(@PathParam("formula") String formula) {

        Object retVal = null;

        try {

            Bindings binding = this.scriptEngine.createBindings();

            binding.put("FIVE", 5);

            this.scriptEngine.setBindings(binding, ScriptContext.GLOBAL_SCOPE);

            retVal = this.scriptEngine.eval(formula);

        } catch (Exception e) {

            throw new IllegalStateException("Exception during evaluating script: " + e, e);

        }

        return retVal.toString();

    }

The method calculate is annotated with @GET and so accessible through the following URL: http://localhost:8080/FluidLogic/resources/calculator/FIVE

The path FIVE is used as a method parameter and directly evaluated by the script. You can pass more sophisticated formulas as well: http://localhost:8080/FluidLogic/resources/calculator/6*7

EJB 3.1 can be directly exposed via JAX-RS (JSR-311) without any plumbing like XML, configuration etc. An EJB 3 can use, as any other Java class, the "Scripting For The Java Platform" (JSR-223), to load and execute over 100 scripting languages (JavaScript, Groovy, JRuby, Jython Scala etc). This makes it interesting for the the implementation of simple to configure and maintain plugins and extensions. EJB 3.1 are transactional, so you could even manipulate managed JPA entities in the script and all the changes will be automatically synchronized with the database during the commit of the transaction.

An EJB 3.1 can be directly injected e.g. into a Servlet or managed bean in addition as well:

public class CalculatorView extends HttpServlet {

    @EJB

    private Calculator calculatorBean; 

A deployable, working example was tested with Glassfish v3 and NetBeans 6.8m2 and pushed into http://kenai.com/projects/javaee-patterns/

[See Fluid Logic pattern, page 117 in "Real World Java EE Patterns Rethinking Best Practices" book for more in-depth discussion]

Comments:

thank for helpful post

Posted by JavaScript Countdown Timer on October 14, 2009 at 06:43 AM CEST #

I have a question regarding injection of resources.
I am using the Jersey implementation of JSR-311.

I use EJB 3.0 (not 3.1). I have exposed a stateless session bean as a RESTful web service.

@Path("/blabla")
@Stateless
public class MyBean implements MyBeanRemote{

@PersistenceContext
private EntityManager em;
...
}

I try to inject a persistence context but it is not working. em is null.

So my question is :
do injection of resources (@PersistenceContext, @EJB ...) cease to work in a stateless session bean that has been exposed as a RESTful web service ?

Thanks

Posted by Celinio Fernandes on December 11, 2009 at 02:27 PM CET #

Hi Celino,

DI doesn't work for JSR-311 resources in Java EE 5 (EJB 3.0).

Please be aware, that EntityManager isn't thread safe. See also: http://www.adam-bien.com/roller/abien/entry/jsf_jpa_ejb_bloat for explanation.

The easiest possible solution is to inject the EntityManager into an EJB 3 which can be then wrapped with JSR-311 REST resource. EJB 3.1 can be exposed directly as REST resources...

enjoy the lightweight stuff!,

adam

Posted by Adam Bien on December 11, 2009 at 03:12 PM CET #

thanks very much Adam, I needed that confirmation.

So inside my EJB that i have exposed as a Resource (RESTful Web Service), instead of @PersistenceContext, I will use :
emFactory = Persistence.createEntityManagerFactory("UnitEJB");

I am using JBoss 5.1.0 GA, which does not yet support EJB 3.1 unfortunately.

Vielen Dank :)

Posted by Celinio Fernandes on December 11, 2009 at 03:29 PM CET #

@Celinio,

don't forget to catch all exceptions, close the entity manager properly etc. after every call. ...or just introduce a single EJB 3.0 and delete a bunch of superfluous code :-).

JBoss 6.0 should be available soon...

thanks!,

adam

Posted by Adam Bien on December 11, 2009 at 03:34 PM CET #

hey Adam,
I have another question.
It is working now however it is only working for GET HTTP methods. I have tried PUT and POST, I get the same error : 405 Method not allowed

I have tried the most simple method ever :

@PUT
@Path("/MAJ")
@Consumes("text/plain")
public void putBlabla() {
log.info("Body of the method);
}

I invoke it using the URL :
http://localhost:8085/MyWebApp/MAJ

I get the error :
405 Method not allowed

how come ? It works fine with the @GET method.
Is there a setting to modify in JBoss AS to make it work ?
It does not work with @PUT, @POST ...

Thanks for helping.

Posted by Celinio Fernandes on December 12, 2009 at 03:40 PM CET #

More information regarding my previous question:

I modified the web.xml file to allow any user to call the HTTP methods but it did not change anything :

<security-constraint>
<web-resource-collection>
<web-resource-name>Ressources REST</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>OPTIONS</http-method>
<http-method>PUT</http-method>
<http-method>POST</http-method>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>

Any idea ? Thanks

Posted by Celinio Fernandes on December 13, 2009 at 01:44 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License