Feeds:
Posts
Comments

Archive for January, 2015

Use case:
For an SPA application, a user is on a http page and clicks on a login link, a login dialog pops up.  The user credential needs to be sent over SSL via an AJAX call, which is not possible by default since it violates same origin policy. To make this work, CORS needs to be enabled on the server.

I am showing a simple example below.
web.xml
This file restricts the content under /resources to be transfered over SSL

<?xml version=”1.0″ encoding=”UTF-8″?>
<web-app version=”2.5″ xmlns=”http://java.sun.com/xml/ns/javaee&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd”&gt;
<display-name>Project Management</display-name>

<security-constraint>
<display-name>Main</display-name>
<web-resource-collection>
<web-resource-name>restful</web-resource-name>
<url-pattern>/resources/*</url-pattern>
<http-method>POST</http-method>
<http-method>GET</http-method>
</web-resource-collection>

<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>

</security-constraint>

</web-app>

Comments.java
This is the data model.

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.SequenceGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = “id”)
@SequenceGenerator(name = “id”, sequenceName = “id”)
private Long id;
private Long postId;
@Lob
@Column(length=40960)
private String content;
private String userId;

@Column(columnDefinition=”DATETIME”)
@Temporal(TemporalType.TIMESTAMP)
private Date commentTime;

public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getPostId() {
return postId;
}
public void setPostId(Long postId) {
this.postId = postId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Date getCommentTime() {
return commentTime;
}
public void setCommentTime(Date commentTime) {
this.commentTime = commentTime;
}
}

CommentResource.java
This file provides REST Service to display data in the Angularjs UI.

import com.cortez.samples.javaee7angular.data.Comment;
import com.cortez.samples.javaee7angular.pagination.CommentListWrapper;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.ws.rs.*;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import java.util.List;

/**
* REST Service to display data in the Angularjs UI.
*
* @Zhengqiu Cai
*/
@Stateless
@ApplicationPath(“/resources”)
@Path(“comments”)
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class CommentResource extends Application {
@PersistenceContext
private EntityManager entityManager;

private Integer countComments() {
Query query = entityManager.createQuery(“SELECT COUNT(c.id) FROM Comment c”);
return ((Long) query.getSingleResult()).intValue();
}

@SuppressWarnings(“unchecked”)
private List<Comment> findComments(Long postId) {
Query query = entityManager.createQuery(“SELECT c FROM Comment c where c.postId = ” + postId);

return query.getResultList();
}

private CommentListWrapper findComments(CommentListWrapper wrapper, Long postId) {
wrapper.setTotalResults(countComments());
wrapper.setList(findComments(postId));
return wrapper;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public CommentListWrapper listComments(@QueryParam(“postId”) Long postId) {
CommentListWrapper commentListWrapper = new CommentListWrapper();
return findComments(commentListWrapper, postId);
}

@GET
@Path(“{id}”)
public Comment getComment(@PathParam(“id”) Long id) {
return entityManager.find(Comment.class, id);
}

@POST
public Comment saveComment(Comment comment) {
if (comment.getId() == null) {
Comment commentToSave = new Comment();
commentToSave.setPostId(comment.getPostId());
commentToSave.setContent(comment.getContent());
commentToSave.setUserId(comment.getUserId());
commentToSave.setCommentTime(new java.util.Date());
entityManager.persist(commentToSave);
comment = commentToSave;

} else {
Comment commentToUpdate = getComment(comment.getId());
commentToUpdate.setPostId(comment.getPostId());
commentToUpdate.setContent(comment.getContent());
commentToUpdate.setUserId(comment.getUserId());
comment = entityManager.merge(commentToUpdate);
}
return comment;
}

@DELETE
@Path(“{id}”)
public void deleteComment(@PathParam(“id”) Long id) {
entityManager.remove(getComment(id));
}
}

CORSRequestFilter.java
This is a RESTful request filter

import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

@Provider
public class CORSRequestFilter implements ContainerRequestFilter {
@Override
public void filter( ContainerRequestContext requestCtx ) throws IOException {
System.out.println( “Executing REST request filter” );

if ( requestCtx.getRequest().getMethod().equals(“OPTIONS”) ) {
requestCtx.abortWith( Response.status( Response.Status.OK ).build() );

}
}
}

CORSResponseFilter.java
This is a RESTful response filter. It adds response header to each RESTful request to enable CORS on the server side.

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.ext.Provider;

@Provider
public class CORSResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestc,
ContainerResponseContext responsec) throws IOException {
System.out.println( “Executing REST response filter” );

responsec.getHeaders().add(“Access-Control-Allow-Origin”, “http://localhost:8080&#8221;);
responsec.getHeaders().add(“Access-Control-Allow-Methods”, “OPTIONS, GET, POST, DELETE, PUT, HEAD”);
responsec.getHeaders().add(“Access-Control-Allow-Headers”, “Content-Type, Accept, X-Requested-With, Accept-Encoding, Accept-Language, Cache-Control, Connection, Host, Origin, Referer, User-Agent”); }

}
database access is configured in Angularjs module file view.js
app.factory(‘commentService’, function ($resource) {
return $resource(‘resources/comments/:id’);
});

Test results:
GET request has no problem, as shown in Firebug screen shot below. http GET requests were successfully redirected to https and CORS calls were successful using the get method of commentService.
firebug1

but POST, PUT or DELETE calls failed using the corresponding method of commentService, for example:
firebug2

The POST method failed to redirect to https. Many people reported this problem on internet and I have not found a working solution yet. Here is the workaround which works for me:
Instead of using commentService.save():
commentService.save($scope.comment).$promise.then(
function () {
// Broadcast the event to refresh the data.
$rootScope.$broadcast(‘refreshData’);

},
function () {
// Broadcast the event for a server error.
$rootScope.$broadcast(‘error’);
});
I am using:
$http({
method: ‘POST’,
url: “https://localhost:8443/javaee-angular/resources/comments&#8221;,
data: $scope.comment,
headers: {‘Content-Type’: ‘application/json’}
}).success(
function () {
// Broadcast the event to refresh the data.
$rootScope.$broadcast(‘refreshData’);
},
function () {
// Broadcast the event for a server error.
$rootScope.$broadcast(‘error’);
}
);

Read Full Post »

compile dtd using xjc

C:\Users\rezca\Downloads\jaxb-ri\bin\opinio>..\xjc -dtd test.dtd
parsing a schema…
[ERROR] External parameter entity “%(null);” has characters after markup
line 1 of file:/C:/Users/rezca/Downloads/jaxb-ri/bin/opinio/test.dtd

Failed to parse a schema.

dtdxjc

Solution:
remove the first line  “<!DOCTYPE TVSCHEDULE[” and the last line “]>” from the the file test.dtd

Read Full Post »