Showing posts with label rest. Show all posts
Showing posts with label rest. Show all posts

Friday, 10 May 2024

Caching REST Resources In Jakarta REST

I found the following blog post on caching interesting. See reference [1]

I like caching, but I understand there's a very real danger of seeing outdated results. The Blogpost highlights this quite good.

HTTP Caching has several great options, apparently:

  • Expired Header (HTTP 1.0) - ResponseBuilder.expires
  • Cache-Control Header (HTTP 1.1) - CacheControl class for more control
  • ETags - EntityTag class, indicates a kind of hashcode to verify if a Resource has changed, without actually accessing the resource

Nice.

References

[1] Caching REST Resources In Jakarta REST (formerly JAX-RS)
https://blog.payara.fish/caching-rest-resources-in-jakarta-rest-formerly-jax-rs?hs_preview=dxtFzcIy-164496731149

Thursday, 22 December 2022

Upgrading to Jakarta 10

Writing some notes here on what I had to do to get things running on Jakarta 10.

I've started upgrading as my application server (Payara) came out with a version that is Jakarta 10 compatible (release 6). See [1].

I'm using the Payara Micro to deploy my apps.

Things done

Change imports

Here's a list of all the imports I had to change. It's likely not interesting, but sometimes I just like to write stuff down.

Type Javax import Jakarta import
Jakarta Persistenceimport javax.persistence.*import jakarta.persistence.*
Jakarta Securityimport javax.security.enterprise.credential.*import jakarta.security.enterprise.credential.*
import javax.security.enterprise.*import jakarta.security.enterprise.*
import javax.security.enterprise.authentication.mechanism.http.*import jakarta.security.enterprise.authentication.mechanism.http.*
import javax.security.enterprise.credential.*import jakarta.security.enterprise.credential.*
import javax.security.enterprise.identitystore.*import jakarta.security.enterprise.identitystore.*
import javax.annotation.security.*import jakarta.annotation.security.*
Jakarta CDIimport javax.enterprise.context.*import jakarta.enterprise.context.*
import javax.inject.*import jakarta.inject.*
import javax.annotation.*import jakarta.annotation.*
import javax.ejb.Singleton;import jakarta.inject.Singleton;
Jakarta Servletsimport javax.servlet.http.*import jakarta.servlet.http.*
import javax.servlet.*import jakarta.servlet.*
import javax.servlet.annotation.*;import jakarta.servlet.annotation.*;
Jakarta Validationimport javax.validation.constraints.*;import jakarta.validation.constraints.*;
Jakarta Restimport javax.ws.rs.*;import jakarta.ws.rs.*;
import javax.ws.rs.core.*;import jakarta.ws.rs.core.*;
import javax.ws.rs.ext.*;import jakarta.ws.rs.ext.*;
Jakarta XML bindimport javax.xml.bind.annotation.*;import jakarta.xml.bind.annotation.*;
Jakarta Websocketsimport javax.websocket.*;import jakarta.websocket.*;

The most changes are due to persistence as it kind of spreads throughout a lot of the code, mainly annotations on entities.

Changed beans.xml

The old:

<?xml version="1.0" encoding="UTF-8"?>
<beans 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/beans_1_1.xsd"
       bean-discovery-mode="annotated">
</beans>

The new:

<?xml version="1.0" encoding="UTF-8"?>
<beans version="3.0" bean-discovery-mode="all"
       xmlns="https://jakarta.ee/xml/ns/jakartaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd">
</beans>

Changed web.xml

The old:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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 webapp_4_0.xsd"
         version="4.0">
  <display-name>Mrbear Website</display-name>
</web-app>

The new:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
  version="5.0"
  metadata-complete="false"
>
  <display-name>Mrbear Website</display-name>
</web-app>

Changed persistence.xml

The old:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="mrbearPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/mrbear</jta-data-source>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="none"/>
      <property name="eclipselink.cache.shared.default" value="false"/>
      <property name="eclipselink.logging.level" value="INFO"/>
      <!-- line below is for logging of sql, set to FINE if you need to see it-->
      <property name="eclipselink.logging.level.sql" value="INFO"/>
      <property name="eclipselink.target-database" value="MySQL4"/>
    </properties>
  </persistence-unit>
</persistence>

The new:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="3.0" xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
>
  <persistence-unit name="mrbearPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/mrbear</jta-data-source>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="jakarta.persistence.schema-generation.database.action" value="none"/>
      <property name="eclipselink.cache.shared.default" value="false"/>
      <property name="eclipselink.logging.level" value="INFO"/>
      <!-- line below is for logging of sql, set to FINE if you need to see it-->
      <property name="eclipselink.logging.level.sql" value="INFO"/>
      <property name="eclipselink.target-database" value="MySQL4"/>
    </properties>
  </persistence-unit>
</persistence>

Maven POM files

<properties>
    <maven.compiler.release>17</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.encoding>UTF-8</project.encoding>
    <jakartaee.version>10.0.0</jakartaee.version>
    <!-- XmlRootElement and all that stuff -->
    <jakarta-xml-bind.version>4.0.0</jakarta-xml-bind.version>
    <microprofile.version>5.0</microprofile.version>
    <!-- used for EclipseLink extentions, for example Customizer/QueryHints -->
    <eclipselink.version>4.0.0</eclipselink.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.eclipse.microprofile</groupId>
      <artifactId>microprofile</artifactId>
      <version>${microprofile.version}</version>
      <type>pom</type>
      <scope>provided</scope>
    </dependency>
    <!-- used for EclipseLink extentions, for example Customizer/QueryHints -->
    <dependency>
      <groupId>org.eclipse.persistence</groupId>
      <artifactId>org.eclipse.persistence.jpa</artifactId>
      <version>${eclipselink.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>jakarta.platform</groupId>
      <artifactId>jakarta.jakartaee-web-api</artifactId>
      <version>${jakartaee.version}</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>jakarta.xml.bind</groupId>
      <artifactId>jakarta.xml.bind-api</artifactId>
      <version>${jakarta-xml-bind.version}</version>
    </dependency>
  </dependencies>

Also upgraded the java compiler plugin to use Java 17:

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.8.1</version>
  <configuration>
  <release>17</release>
  </configuration>
</plugin>

Removed things like XmlRootElement and XmlTransient

I've replaced them with POJOs that I just create using JsonbBuilder.create().fromJson(json, clazz) and jsonify using JsonbBuilder.create().toJson(object). Not everywhere yet, but I'm getting there.

Javax import
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

Also means I could get rid of this in my pom files:

    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.3.0</version>
    </dependency>

Removed EJB

I've decided to get rid of all the EJB stuff.

This isn't related to the Jakarta 10 upgrade per se, but thought I'd mention it.

Javax import
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.Singleton;
import javax.security.enterprise.SecurityContext;
import javax.ejb.EJB;
import javax.ejb.EJBAccessException;
import javax.ejb.SessionContext;

Replaced javax.security.enterprise.SecurityContext and javax.ejb.SessionContext with rs.core.SecurityContext. So using Rest functionality, instead of EJB functionality.

Problems

Problems with cookies

JASPIC: http msg authentication fail
java.lang.IllegalArgumentException: rfc6265CookieProcessor.invalidCharInValue 44
at org.glassfish.grizzly.http.util.CookieHeaderGenerator.validateCookieValue(CookieHeaderGenerator.java:176)
at org.glassfish.grizzly.http.util.CookieHeaderGenerator.generateHeader(CookieHeaderGenerator.java:85)

Apparently, the cookie spec no longer allowed special characters, like commas.

Problems with JavaScript

Exception in thread "main" java.lang.IllegalArgumentException: A language with id 'js' is not installed. Installed languages are: [].
at org.graalvm.truffle/com.oracle.truffle.polyglot.PolyglotEngineException.illegalArgument(PolyglotEngineException.java:131)

After some research, I found that GraalVM does not ship automatically with JavaScript since version 22. A separate GraalVM Component needs to be installed, like so:

% gu install js
Downloading: Component catalog from www.graalvm.org
Processing Component: Graal.js
Downloading: Component js: Graal.js from github.com
Installing new component: Graal.js (org.graalvm.js, version 22.3.0)

Public methods are unreachable

org.graalvm.polyglot.PolyglotException: TypeError: invokeMember (sendMessage) on mmud.scripting.entities.Person failed due to: Unknown identifier: sendMessage

Fixed by allowing access to public methods.

Also, direct access to properties using the .<name> convention no longer works, so for instance person.room must be replaced with person.getRoom().

Unable to load class named io.jsonwebtoken.impl.DefaultJwtBuilder

UnknownClassException: Unable to load class named [io.jsonwebtoken.impl.DefaultJwtBuilder] from the thread context, current, or system/application ClassLoaders. All heuristics have been exhausted. Class could not be found. Have you remembered to include the jjwt-impl.jar in your runtime classpath?

Key is too small.

io.jsonwebtoken.security.WeakKeyException: The specified key byte array is 64 bits which is not secure enough for any JWT HMAC-SHA algorithm. The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a size >= 256 bits (the key size must be greater than or equal to the hash output size). Consider using the io.jsonwebtoken.security.Keys#secretKeyFor(SignatureAlgorithm) method to create a key guaranteed to be secure enough for your preferred HMAC-SHA algorithm. See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.

So, yeah, let's make the key bigger, ey?

Now what?

UnknownClassException: Unable to find an implementation for interface io.jsonwebtoken.io.Serializer using java.util.ServiceLoader. Ensure you include a backing implementation .jar in the classpath, for example jjwt-impl.jar, or your own .jar for custom implementations.

So I didn't want to import an implementation of Gson or Jackson, as Microprofile already has an implementation, (Yasson) and who cares about implementations, eh? Just use the API!

Luckily I found an article on the internet, on how to make your own Serializer and Deserializer.

IllegalStateException: Illegal invocation type for EJB Context : SERVLET_INVOCATION

Servlet.service() for servlet mmud.MudApplication threw exception java.lang.IllegalStateException: Illegal invocation type for EJB Context : SERVLET_INVOCATION

EJB Circular references

One other thing I encountered, was when removing/replacing the EJB Beans with just @Inject, it is no longer allowed to create circular dependencies.

I didn't mind, as creating circular dependencies is a good thing to entirely avoid, so I was pleased with the error message.

Some moving around, and things worked properly.

References

[1] Payara Micro - Downloads
https://www.payara.fish/downloads/payara-platform-community-edition/
YouTube - IntelliJ IDEA by Netbrains - Migrating from javax to jakarta namespace
https://youtu.be/mukr2Q_zBm4
ProgrammerSought - Possible issues with cookies after upgrading to Tomcat 8
https://www.programmersought.net/article/334704011.html
GraalVM - Migration Guide from Nashorn to GraalVM JavaScript
https://www.graalvm.org/22.2/reference-manual/js/NashornMigrationGuide/
GraalVM - GraalVM JavaScript Implementation
https://www.graalvm.org/22.3/reference-manual/js/
Using JJWT with the Jakarta JSON Binding API
https://blog.bmarwell.de/2022/05/12/using-jjwt-with-jakarta-jsonb.html

Thursday, 1 April 2021

StreamingOutput : streaming large json responses in REST API

So I had to move a large number of database objects into a JSON response, and I was looking for a neat way to do it.

Originally, I already had the idea of having the database generate JSON responses for me. You can find more information on this here1.

But then I thought it would make sense to, instead of loading all those json strings from the database in memory, streaming them to the JSON generator in my REST Service.

It looked quite easy.

Database streaming

Now, I found out that instead of getResultList(), I could use getResultStream(). Unfortunately, the default implementation of getResultStream() just delegates to getResultList(), which doesn't help at all2.

Also, there seems to be a number of other pitfalls to fall into as well2, 3. So, my first attempt displayed here just might be flawed, or might be flawed if you're using something other than MariaDB.

My attempt at a scrolling cursor, instead of just dumping the entire thing in our lap.

Streaming as a REST Service

So I found some information on how to do this at [4].

@GET
@Produces(
{
  "application/json"
})
public Response findAll(@Context UriInfo info)
{
  StreamingOutput stream = StreamerHelper.getStream(getEntityManager(), AdminItem.GET_QUERY);   return Response.ok(stream).build();
}

I think I could use the Fetch way5 on the client side, but in my case it's not needed.

References

[1] Using SQL to generate JSON output
http://randomthoughtsonjavaprogramming.blogspot.com/2020/01/using-sql-to-generate-json-output.html
[2] JPA 2.2’s new getResultStream() method and how you should NOT use it
https://thorben-janssen.com/jpa-2-2s-new-stream-method-and-how-you-should-not-use-it/
[3] Vlad Mihalcea - Hibernate performance tuning tips
https://vladmihalcea.com/hibernate-performance-tuning-tips/
[4] Response streaming between JAX-RS and Web-Components (Part 1)
https://schoeffm.github.io/posts/response-streaming-between-jaxrs-and-webcomponents-part1/
[5] Response streaming between JAX-RS and Web-Components (Part 2)
https://schoeffm.github.io/posts/response-streaming-between-jaxrs-and-webcomponents-part2/

Thursday, 5 December 2019

Uploading a file in Angular

I wanted my users to have the ability to upload an image via de Angular App that I provide for them.

So let me explain the process.

First, of course, there's the HTML that needs to be added to support File Uploads.

You can add these to your app.component.html file.

Then, once it is submitted it needs to be handled by your Angular app, in the app.component.ts file.

Then it gets transmitted to your rest service on the backend.

And that stashes it into the database using JPA.

All done.

References

StackOverflow - Angular File Upload
https://stackoverflow.com/questions/47936183/angular-file-upload
StackOverflow - Angular 5: How to upload an image
https://stackoverflow.com/questions/48343853/angular-5-how-to-upload-an-image?noredirect=1&lq=1

Thursday, 22 June 2017

MessageBodyWriter not found!

I got the following (unhelpful) message in my server log, when I changed some of my Java classes that are translated to JSON (and vice versa).
Severe: MessageBodyWriter not found for media type=application/json, type=class java.util.ArrayList, genericType=java.util.List

Turns out that I added a specific constructor to one of my Java classes, effectively removing the unspecified Default Constructor that Java always adds.

This default constructor is however essential to the proper working of JSON-Java mapping.

Thursday, 15 June 2017

REST-EJB AccessLocalException causes BadRequest(500) instead of Unauthorized(401)

I am using EJBs as REST Services. It works pretty well. I added security on the EJB, by means of security definitions in the web.xml file and appropriate annotations on the EJB (@DeclareRoles and @RolesAllowed).

Unfortunately, when I try to access the methods in the EJB without being properly authorized, I received a 500 BadRequest. Instead I would really like to have a 401 Unauthorized.

I posted a question on StackOverflow1, but I have found the solution2 in the mean time, which I also posted, and will repost here.

It is possible to add an ExceptionMapper to your Application, which can map between an Exception and an appropriate HTTP Response.

Note

My ApplicationConfig has now been expanded with a
resources.add(mmud.exceptions.EJBAccessExceptionMapper.class);
.

References

[1] StackOverflow - REST-EJB AccessLocalException causes BadRequest(500) instead of Unauthorized(401)
https://stackoverflow.com/questions/44351224/rest-ejb-accesslocalexception-causes-badrequest500-instead-of-unauthorized401
[2] RESTfu­­l Jav­a­ wit­h ­JAX­-­­RS 2.­0­ (Second Edition) - Exception Handling
https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-2rd-edition/en/part1/chapter7/exception_handling.html
StackOverflow -
https://stackoverflow.com/questions/3297048/403-forbidden-vs-401-unauthorized-http-responses

Thursday, 4 May 2017

REST-assured

I am a card-carrying member of the NLJUG0, which provides Java Magazine (not the Oracle one) six times per year.

One of the issues contained an article about REST-assured1.

I have been using SoapUI5 to test my REST services, and that works fine. It's a nice graphical userinterface for me to fiddle with parameters and urls and HTTP requests and even write tests.

I am aware that it is probably possible to integrate SoapUI into my Build Pipeline, but I was really looking for something different. Something more in the line of programming, which is of course my forte. Something I could use in my unit-tests.

REST-assured was exactly what I needed and let me tell you, it's great!

Usage

I will provide an example of how I use it.

As you can see, REST-assured is a very nice DSL (Domain Specific Language) and reads easily.

Some explanation of the above:
log().ifValidationFails()
I wish to log stuff, if the validation/test fails, so I can find out what is wrong. The output looks like
param(name, value)
for setting parameters at the end of the url, like ?stuff=value
pathParam(tag, value)
replaces {tag} in your url with the values. Convenient!
request methods
in the example above, we are using the PUT HTTP Request.
As it is used for testing, it is possible to verify the values afterwards. In the above this is visible as we expect to receive a 204 (NO_CONTENT).

We can extract the response, as is done above, to verify for example the json payload (if there is one) or get cookie values.

In the above example it is essential for the followup calls that we get the JSESSIONID cookie out of the request.

In subsequent REST calls, it is obvious that we need to send along the same JSESSIONID cookie.

See for more information reference [4].

Some notes

I tried to send parameters, but a POST defaults to FORM parameters in the body, but I already have a BODY. But using "queryParam" instead of "param" fixes this problem.

I do enjoy using the "prettyPrint" method on a Response, to properly format a JSON body and dump it to standard output and see what I get. It's nice.

Getting some values out of your JSON formatted response body does require some serious work, though. Needs more research.

I am not entirely sure, I do not enjoy using http status codes like 200 or 204. I prefer something more readable like "NO_CONTENT", but I suppose I can deal with it myself. No biggy.

Update 14/05/2017: I'm also slightly sorry to find out that rest-assured includes Hamcrest. I prefer AssertJ at the moment myself.

Postscriptum

The article in Java Magazine also mentioned WireMock3.

Though I do not use it, it seems excellent for testing the other side of the communications, if you need to test a client that communicates with a server via rest calls.

References

[0] NLJUG
http://www.nljug.org/
[1] REST-assured
Teije van Sloten Java Magazine | 01 2017
[2] GitHub - Java DSL for easy testing of REST services
https://github.com/rest-assured/rest-assured
[3] WireMock
http://wiremock.org/
[4] GitHub - RestAssured Usage
https://github.com/rest-assured/rest-assured/wiki/usage
[5] SoapUI
https://www.soapui.org/
Testing REST Endpoints Using REST Assured
https://semaphoreci.com/community/tutorials/testing-rest-endpoints-using-rest-assured
RFC2616 - HTTP status codes
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html



Thursday, 3 December 2015

Richardson Maturity Model

The Richardson Maturity Model1 gives a very clear idea of how far you are in following the REST software architectural style.

Unfortunately, I seem, personally, in my home projects, to have serious problems reaching the HATEOAS level (level 3). Is that even a problem2?

Does anyone else have the same issue?

Is the last level actually in common use, except for those frameworks that already have it built in, or not?

References

[1] Martin Fowler - Richardson Maturity Model
http://martinfowler.com/articles/richardsonMaturityModel.html

[2] The timeless repository - Haters gonna HATEOAS
http://timelessrepo.com/haters-gonna-hateoas

Wednesday, 3 December 2014

REST + Angular = Restangular

JQuery and REST

I have already mentioned calling REST services using JQuery1 in my entry on REST and Error messages at my blog.

At the risk of being redundant, here it is:

Unfortunately, it requires a lot of settings and a lot of DOM manipulation to create the view and make it work as it should.

I was looking for an alternative, something that's easy to use without a lot of boilerplate.

I would prefer something like JSF, but solely on the client side, and which fully supports REST. I found something to my liking in Angular.

Angular

AngularJS is, according to their website2, a Superheroic JavaScript MVW Framework.
“AngularJS is what HTML would have been, had it been designed for building web-apps. Declarative templates with data-binding, MVW, MVVM, MVC, dependency injection and great testability story all implemented with pure client-side JavaScript!”
As far as I can tell, you add Angular specific xml attributes to your html tags, and Angular takes care of the updating of those tags, depending on what's changed. Of course, that's just the tip of the proverbial iceberg.

Angular and REST

The Angular version of the JQuery $.ajax call is called $http3, and is about what you would expect.
Both in JQuery and in Angular, it is a wrapper around the XMLHttpRequest.

This is not really a REST-aware API, to say the least. Therefore Angular also provides a $resource service. This service creates resource objects that makes it easy to communicate with RESTful backends.

It is an optional module in Angular, called ngResource, and needs to be installed.

Restangular and REST

However, I have opted to make use of Restangular4. It seems to be more self-evident how it works, follows the guideline of Angular more closely and seems to abstract away a lot of the boilerplate, for example URLs.

In the example above there are numerous interesting tidbits:
  • In the config call, I set the base url. All consequent calls to REST resources have this url as root.
  • In the config call, I needed to set the "id" of the resource accessed, otherwise Restangular assumes that the "id" is a field called "id". In this case it was "name"5 6.
  • var restBase = Restangular.all("worldattributes") sets a resource (in this case for world attributes).
  • restBase.getList()
            .then(function(worldattributes) 
            {
              // returns a list of worldattributes
              $scope.worldattributes = worldattributes;
              $scope.setFilter();
              $scope.isNew = false;
            });
    This creates a GET XMLHttpRequest for url "/karchangame/resources/administration/worldattributes" and retrieves all objects. It assumes JSON. As you see, I promptly put all info into the Angular scope, so it can be reached in the HTML file (see below).
  • The objects returned by Restangular, are themselves also REST resources, therefore contain methods such as put() which updates it (causing an automatic HTTP PUT request).
  • The call remove is translated to a DELETE XMLHttpRequest.
  • And my update method decides on a POST or PUT depending on wether it is a new or a changed world attribute.
  • The Restangular.copy call is convenient, as it makes a deep copy of the object.
  • Sometimes, the backend REST urls are not standard, in which case you wish to turn from the default, and start making calls with a bit more control. An example of such is visible with the customDELETE in the disown function.
The HTML part of the Angular looks like follows:

Notice that the HTML file looks almost exactly as a simple HTML file would, besides the added Angular attributes and the references to the $scope object (by means of {{ and }}).

References

[1] JQuery.ajax() | JQuery API Documentation
http://api.jquery.com/jquery.ajax/
[2] AngularJS - Main Website
https://angularjs.org/
[3] ngbook - The Complete Book on AngularJS
Ari Lerner
[4] Github - Restangular
https://github.com/mgonto/restangular
[5] Stackoverflow - Restangular put loses part of the url
http://stackoverflow.com/questions/24262949/restangular-put-loses-part-of-the-url
[6] Restangular - GitHub : What if each of my models has a different ID name like CustomerID for Customer?
https://github.com/mgonto/restangular#what-if-each-of-my-models-has-a-different-id-name-like-customerid-for-customer
Foundation 5
http://foundation.zurb.com/

Sunday, 12 October 2014

REST and Error Messages

WebApplicationException

In Java REST you can throw a WebApplicationException, which indicates that something went wrong. You can add the HTTP Status to the exception, to indicate what went wrong.
throw new WebApplicationException(Response.Status.BAD_REQUEST);
But that amount of information is in most cases too little. Sure, a HTTP Status of 404 (Not Found) is quite clear, but you'd like some more information.

Luckily, I found out that we can add an entity in the Response and add the Response to the WebApplicationException.

In fact, it is the most convenient to just create your own subclass of WebApplicationException to handle this automatically.

Your own WebApplicationException


An Error Entity

The entity that gets translated into JSON and passed over the line, in my case called ErrorDetails, can provide all the information you need.

The getResponse method is the one that creates the Response, which is used to provide the HTTP Status code and the error payload for the WebApplicationException.

The json generated looks like:
{ 
    timestamp="2014-09-21T21:34:01.831", 
    errormessage="sdsgsdgsgd was not found.", 
    stacktrace=””,
    user="sdsgsdgsgd"
}

JQuery

It just took a little effort to retrieve the ErrorDetail object from the Xqhr object in the JQuery Ajax call. This should be done during error processing, as shown in the JQuery Ajax call below.

The webError in the code above is a function to parse the JSON containing ErrorDetails object, provided below.

It parses the jqXHR.responseText, to be precise. And if a stacktrace is provided, the details are put into a HTML tag with id "warning". An 'alert' is always provided.

References

Whatever can go wrong … Error Handling and RESTful Services
http://djna.wordpress.com/2009/12/07/whatever-can-go-wrong-error-handling-and-restful-services/
RESTful API Design: what about errors?
https://blog.apigee.com/detail/restful_api_design_what_about_errors
How to get the jQuery $.ajax error response text?
http://stackoverflow.com/questions/1637019/how-to-get-the-jquery-ajax-error-response-text
Use jQuery to catch and display ASP.NET AJAX service errors
http://encosia.com/use-jquery-to-catch-and-display-aspnet-ajax-service-errors/

Wednesday, 29 February 2012

JDK7 EJB3.1 and Netbeans Project (Part II) - Hibernate and Transactions

Part I - Introduction, Part II - Hibernate and Transactions, Part III - Testing

Hibernate LazyInitializationException


In a Model-View-Controller pattern, the part that deals primarily with Transactions and Hibernate is the Model. This means the View, that needs the data to render the result to the user, is outside the transaction and in Hibernate this often causes LazyInitializationExceptions. Especially when traversing to proxies of collections inside the entities. In order to prevent this there are several solutions described in Open Session In View(1) article.

They are summarized below.
  1. use an interceptor, when the server is hit automatically start a transaction, when the result is transmitted back, automatically close/commit the transaction
  2. just make sure the Model provides all the data to the View, so the view does not run into the LazyInitializationException.
  3. have the view open a new transaction to retrieve the data, after the model is finished (which is a really really bad idea)
  4. have the framework deal with it
I prefer the last option, have the framework deal with it. At work, for example, this is done by using JBoss Seam and I must say, I've never had to deal with LazyInitializationExceptions.

Enterprise Java Beans - The Old Way


The good part of Enterprise Java Beans is that they provide the transaction support on the container level, so you, as a developer, do not need to be concerned with it. The bad part is that to access a Enterprise Java Bean requires either another Enterprise Java Bean or a call to the InitialContext. Like in the code below.

/**
 * Retrieve my gamebean.
 */

private GameBeanLocal lookupGameBeanLocal()
{
    GameBeanLocal gbl = null;
    try
    {
        javax.naming.Context c = new InitialContext();
        gbl = (GameBeanLocal) c.lookup("java:global/game/game-ejb/GameBean!mmud.beans.GameBeanLocal");
    } catch (NamingException ne)
    {
        itsLog.throwing(this.getClass().getName(), "lookupGameBeanLocal", ne);
        throw new RuntimeException(ne);
    }
    itsLog.exiting(this.getClass().getName(), "lookupGameBeanLocal");
    if (gbl == null)
    {
        throw new NullPointerException("unable to retrieve GameBean");
    }
    return gbl;
}
This is the code usually used in the WAR file of your EAR file to contact your Enterprise Java Beans. Any Hibernate entities the EJBs return suffer from the LazyInitializationException.

Enterprise Java Beans 3.1


But now, there's Enterprise Java Beans 3.1 which solves this problem, by the following new items:
  • EJBs can be contained inside your WAR
  • Context and Dependency Injection works in most (more) cases

For example the following Enterprise Java Bean was put inside the WAR, and annotated with REST Annotations and uses Hibernate Entities.

/**
 * Comment Enterprise Bean, maps to a Comment Hibernate Entity.
 * @author mr. Bear
 */

@Stateless
@Path("/comments")
public class CommentBean
{
    @PersistenceContext(unitName = "myDataSource")
    private EntityManager em;

    @EJB
    JobBean jobBean;

    protected EntityManager getEntityManager()
    {
        return em;
    }

    public CommentBean()
    {
    }

    @POST
    @Override
    @Consumes(
    {
        "application/xml", "application/json"
    })
    public void create(Comment entity)
    {
        getEntityManager().persist(entity);
    }

    @PUT
    @Override
    @Consumes(
    {
        "application/xml", "application/json"
    })
    public void edit(Comment entity)
    {
        getEntityManager().merge(entity);
    }

    @DELETE
    @Path("{id}")
    public void remove(@PathParam("id") Long id)
    {
        getEntityManager().remove(find(id));
    }

    @GET
    @Path("{id}")
    @Produces(
    {
        "application/xml", "application/json"
    })
    public Comment find(@PathParam("id") Long id)
    {
        return getEntityManager().find(Comment.class, id);
    }
}

The Entity has appropriate annotations to indicate it can be converted to JSON and/or XML.
/**
 * Comment Entity mapped to the Comment table in the database.
 * @author mr. bear
 */

@Entity
@Table(name = "Comment")
@XmlRootElement
public class Comment implements Serializable
{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Long id;
    @Size(max = 255)
    @Column(name = "author")
    private String author;
    @Basic(optional = false)
    @NotNull
    @Column(name = "submitted")
    @Temporal(TemporalType.TIMESTAMP)
    private Date submitted;
    @Lob
    @Size(max = 65535)
    @Column(name = "comment")
    private String comment;
    @JoinColumn(name = "galleryphotograph_id", referencedColumnName = "id")
    @ManyToOne(optional = false)
    private GalleryPhotograph galleryphotographId;

    public Comment()
    {
    }

    public Comment(Long id)
    {
        this.id = id;
    }

    public Comment(Long id, Date submitted)
    {
        this.id = id;
        this.submitted = submitted;
    }

    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public String getAuthor()
    {
        return author;
    }

    public void setAuthor(String author)
    {
        this.author = author;
    }

    public Date getSubmitted()
    {
        return submitted;
    }

    public void setSubmitted(Date submitted)
    {
        this.submitted = submitted;
    }

    public String getComment()
    {
        return comment;
    }

    public void setComment(String comment)
    {
        this.comment = comment;
    }

    @JsonIgnore
    @XmlTransient
    public GalleryPhotograph getGalleryphotographId()
    {
        return galleryphotographId;
    }

    public void setGalleryphotographId(GalleryPhotograph galleryphotographId)
    {
        this.galleryphotographId = galleryphotographId;
    }
}
And, voilà, no more LazyInitializationExceptions, no more retrieving EJBs through the InitialContext, no more EARs containing WARs and EJB JARs.

Infinite Recursion


One of the problems that occur, when you do NOT have any LazyInitializationExceptions, is Infinite Recursion. This happens when your Hibernate entities refer to each other, and in a REST service, Jersey tries to flatten the structure into JSON or XML for transmission.

This could be the case, in the example above, if there was a collection of comments in galleryphotograph, and a reference to the respective galleryphotograph in the comments.

In order to solve this, make sure to use XmlTransient and JsonIgnore at appropriate places.

Conclusion


The last paragraph "Can't this be done easier" in the Open Session In View is awesome. It provides the answer that the framework should handle all the transaction management, instead of yourself having to provide it.

And now this time has come! The new EJB 3.1 version allows you to put EJBs right there in your WAR! Either as a separate JAR file, or as class files. The same classloader will pick them up and you can use them in your classes via Dependency Injection as much as you like!

It does mean there is no modularization, but in my experience modularization is only a requirement for the exceptionally high-end big projects.

References

Open Session In View
https://community.jboss.org/wiki/OpenSessionInView
Data Transfer Objects
http://martinfowler.com/eaaCatalog/dataTransferObject.html
Wikipedia : Data Transfer Object
http://en.wikipedia.org/wiki/Data_transfer_object
Java Persistence With Hibernate
Christian Bauer, Gavin King
Is Java EE 6 War The New EAR? The Pragmatic Modularization And Packaging
http://www.adam-bien.com/roller/abien/entry/is_java_ee_6_war

Sunday, 25 July 2010

REST Webservice URI setup

Thank heavens I found the blog topic http://marxsoftware.blogspot.com/2010/02/jax-rs-with-jersey-introduction.html.

So, here's the setup.

http://hostname/<context root of web application>/<url pattern of the servlet mapping>/<path defined in java class>

http://
hypertext transfer protocol
hostname
the hostname where the web server is lurking
context root of web application
the context root is defined by the proprietary xml file sun-web.xml
url pattern of the servlet mapping
the url pattern defined in the web.xml for a particular servlet, to indicate for which urls the servlet needs to be called
path defined in java class
the path is defined in the java class that is going to function as the REST webservice. It's defined by means of the @Path annotation on the Class itself.

Friday, 9 July 2010

How to Transmit New Objects To REST Service

One of the reasons for adding this, is because there was a huge lack of POST/PUT/DELETE/HEAD examples out there, and I thought I should do my part. Although the principles are the same as with GET.

I've been at it for some time now, and for some reason there always seem to be one or two things that go wrong when creating a new REST Service, even though I've created a working REST Service not two days ago. That in itself is kind of frustrating.

Check out Japod's Blog for starters. In order to use more complicated Data Structures in REST, these need to be defined in a derivative of the JAXBContext class.

Personally, I really don't understand why that same cannot be done using simple Annotations, but that's just me.

Then there's the security issue. How to see who the person is that is accessing the webservice. Luckily, I found me some help here.

There seems to be some confusion regarding the mapping of the HTTP calls3, which I've tried to put in the picture above.

Updated 14/09/2014.

References

[1] Why PUT and DELETE?
http://www.artima.com/lejava/articles/why_put_and_delete.html
[2] rfc2616
http://www.ietf.org/rfc/rfc2616.txt
[3] Wikipedia - Representational state transfer
http://en.wikipedia.org/wiki/Representational_state_transfer#Architectural_constraints

Wednesday, 23 June 2010

JSON and the single-value array

The one you really need to read can be found here : https://blogs.oracle.com/japod/entry/configuring_json_for_restful_web

Jersey NATURAL JSON notation is awesome.

28-05-2012: Updated with new links to more up to date content.