Getting Started With Defne Web Framework and Apache OpenWebBeans
Defne is a service oriented web application framework. The main motivation behind Defne is ease of use. Defne allows developers to concentrate on their business logic while it provides all other application requirements such as transaction and security. With Defne, you can implement powerful enterprise web applications on time and with a service oriented fashion.
Required Runtime
Defne requires Java runtime less than or equal to 1.5. Moreover, it requires OpenWebBeans and JPA runtimes for dependency injection and database operations, respectively.
SIwpas simple web application server, http://code.google.com/p/siwpas , provides necessary runtimes to use Defne framework.
Writing a First Service
In this getting started guide, we will implement a registery form using Defne. We will use JSF 2.0 to implement our web application's GUI. Complete source code of this web application can be downloaded from svn.
Defne Concepts
- Defne Service: POJO class annotated with @Service
- Defne Operation: POJO class static method annotated with @Operation and obeys the following method signature, (serviceName is any application Java method name)
public static Message <serviceName>(Message input) throws DefneException
- Defne Transaction: Transactions are provided while calling service operation. TransactionPolicy enum contains the following entries:
NO_TRANSACTION, Do not use any JPA transaction
WITH_TRANSACTION, Run within JPA transaction
NEW_TRANSACTION, Not supported currently without using EJB executors(defne-ejb).
- Defne Security: Defne provides annotated based security configuration. It provides @Roles annotation to configure security roles on service operations. Defne framework provides Service Provider Interface(SPI) org.defne.security.spi.IPrincipal for implementing by the Defne runtimes. It allows Defne to get currently logined user roles from an application server.
Currently only SIwpas based implementation is provided, org.defne.security.impl.SiwpasProvidedPrincipal. To use this security implementation in our applications, we have to add the following entry to web application beans.xml file.(This is the same for the Apache Tomcat 7)
<beans>
<alternatives>
<class>org.defne.security.impl.SiwpasProvidedPrincipal</class>
</alternatives>
</beans>
Ok, let's start to write some service code.
Request Flow
When a service request is issued from a web browser, the following actions are occured on the server side,
OpenWebBeans Managed Bean calls OwbServiceExecutor Proxy calls OwbServiceExecutor calls Actual Service
OwbServiceExecutor Proxy and OwbServiceExecutor are provided by the Defne Framework. Therefore, your responsibility is to implement Managed Bean and Service.
OpenWebBeans managed bean is a managed bean that injects OwbServiceExecutor Proxy instance using @Inject @PojoExecutorProxy IServiceExecutorProxy pojoExecutor. Proxy handles all of the transaction, security, JPA stuff etc. If everthing is successful on proxy side, proxy calls service executor that calls the actual service. Funny haaa!!!
JPA Entity Class
@Entity
public class Person
{
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@Column
private String name;
@Column
private String surname;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getSurname()
{
return surname;
}
public void setSurname(String surname)
{
this.surname = surname;
}
}
OpenWebBeans Managed Bean
@Named
@RequestScoped
public class RegisterBean {
//Injection of service executor proxy
private @Inject @PojoExecutorProxy IServiceExecutorProxy pojoExecutor;
private String message;
private String name;
private String surname;
public RegisterBean()
{
}
public String register()
{
//Creating a message
Message input = MessageFactory.newMessage(IRegisterService.SERVICE_NAME,IRegisterService.RegisterOperation.OPERATION_NAME);
//Calling with JPA transaction
input.putMessageParameter(IMessageConstants.SERVICE_CALLER_TRANSACTION_POLICY, TransactionPolicy.WITH_TRANSACTION);
//Adding service parameters
input.putMessageParameter(IRegisterService.RegisterOperation.INPUT.NAME, this.name);
input.putMessageParameter(IRegisterService.RegisterOperation.INPUT.SURNAME, this.surname);
//Execute servcie
input = this.pojoExecutor.execute(input);
//Any message
this.message = input.getMessageParameter(String.class, IRegisterService.RegisterOperation.OUTPUT.MESSAGE);
return null;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getSurname()
{
return surname;
}
public void setSurname(String surname)
{
this.surname = surname;
}
}
Our Service Code
Service is composed of 2 components, service descriptor interface and service class,
Service descriptor interface,
public interface IRegisterService
{
String SERVICE_NAME = "RegisterService";
public interface RegisterOperation{
String OPERATION_NAME = "register";
public interface INPUT{
String NAME = "NAME";
String SURNAME = "SURNAME";
}
public interface OUTPUT{
String MESSAGE = "MESSAGE";
}
}
}
Service code,
@Service
public class RegisterService
{
@Operation
public static Message register(Message inBag) throws DefneException
{
String name = inBag.getMessageParameter(String.class, IRegisterService.RegisterOperation.INPUT.NAME);
String surname = inBag.getMessageParameter(String.class, IRegisterService.RegisterOperation.INPUT.SURNAME);
EntityManager entityManager = EntityManagerUtil.getEntityManagerFromBag(inBag);
Person person = new Person();
person.setName(name);
person.setSurname(surname);
entityManager.persist(person);
inBag.putMessageParameter(IRegisterService.RegisterOperation.OUTPUT.MESSAGE, "Registered user, " + name + surname );
return inBag;
}
}
Writing our JSF Page
Register page, register.xhtml
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Defne :: Owb Register Page</title>
</h:head>
<h:body>
<h:form id="form">
<div>
<h:outputText value="Your Name : " />
<br/>
<h:inputText value="#{registerBean.name}"></h:inputText>
<br/>
<h:outputText value="Your SurName : " />
<br/>
<h:inputText value="#{registerBean.surname}"></h:inputText>
<br/>
<h:commandButton action="#{registerBean.register}" value="Register" />
</div>
<div>
<h:outputText value="#{registerBean.message}"></h:outputText>
</div>
</h:form>
</h:body>
</html>
Update Configuration Files
WEB-INF/beans.xml,
<beans>
<alternatives>
<class>org.defne.security.impl.SiwpasProvidedPrincipal</class>
</alternatives>
</beans>
WEB-INF/web.xml
<web-app id="WebApp_ID" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<listener>
<listener-class>org.defne.service.scanner.ScannerListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
</web-app>
Deploy it into the SIwpas
That is it, deploy it int the container. If you wish to use core Apache Tomcat, you have to add all of Defne dependencies to Tomtcat lib folder or bundle with application WEB-INF/lib.
Hit browser URL
http://localhost:8080/owb-register/register.jsf
Calling Services From Pure AJAX Client
Defne also provides hooking points for calling services from JavaScript. Defne provides JSON Servlet for executing the AJAX requests that are targeted for server side services.
For example, below is the jQuery AJAX request that calls Defne service residing on the server side;
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
function postjson(){
$.ajax({type:"POST",url:"/json-example/DefneJson",data:"{'adaptorClass':'org.samples.jsonexample.HelloAdaptor','service':'HelloService','method':'sayHello','args':{'NAME':'Gurkan','SALARY':'1000'}}",
dataType:"json"});
}
$(document).ready(function() {
$("#myb").click(function(event){
postjson();
});
});
In JSON case, developer is required to implement IJsonAdaptor interface to change Map<String,String> to Message and vice versa. For example ,
public class HelloAdaptor implements IJsonAdaptor
{
@Override
public Map<String, String> fromOutputMessage(Message message)
{
Map<String, String> out = new HashMap<String, String>();
out.put("MESSAGE", message.getMessageParameter(String.class, "MESSAGE"));
return out;
}
@Override
public Message toInputMessage(String service, String method, Map<String, String> args)
{
Message message = MessageFactory.newMessage(service, method);
//GEt name
message.putMessageParameter(IHelloService.SayHelloOperation.INPUT.NAME, args.get(IHelloService.SayHelloOperation.INPUT.NAME));
//Get salary
Integer integer = new Integer(args.get(IHelloService.SayHelloOperation.INPUT.SALARY));
//Put args
message.putMessageParameter(IHelloService.SayHelloOperation.INPUT.SALARY, integer);
//No transaction
message.setTransactionPolicy(TransactionPolicy.NO_TRANSACTION);
//No JPA, default use JPA
message.putMessageParameter(IMessageConstants.SERVICE_CALLER_USES_ENTITY_MANAGER_KEY, false);
return message;
}
}
You can look at the json-example from SVN , http://code.google.com/p/defne/source/browse/#svn/trunk/defne-samples/json-example
Enjoy!!!!
Web Site : http://code.google.com/p/defne/
SVN Site : http://code.google.com/p/defne/source/browse/
Maven Snapshot : https://oss.sonatype.org/content/repositories/snapshots/org/defne/
Defne Discussion : http://groups.google.com/group/defnedev
- Login or register to post comments
- 3218 reads
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)




Comments
Jacek Furmankiewicz replied on Thu, 2010/07/15 - 9:08am
Oh God, not another me-too Java web framework.
I fail to see a single feature here that has not been done to death in X number of different Java web frameworks.
Really, if your web framework cannot beat Python Django admin interface in terms of productivity, you shouldn't be releasing it. That's the level of abstraction and productivity today's Java web frameworks should be trying to beat.