Monday, August 18, 2014

Deploying JavaEE apps with TomEE and Docker

What will you see in this post? How to use CoreOS and Docker to deploy Apache TomEE behind a Nginx proxy with multiple connected Docker containers.

Source code: https://github.com/tveronezi/chatdocker

A brand new Apache TomEE version was released this week. We will commemorate this milestone (details in the official announcement) with a new way to deploy software. Do you remember the chat applications that we created in the last post? We will deploy them again. They will use the same computer but now we will have one application per container. Our solution will also include a third container that will work as proxy for our jchat and springchat applications.

This is an overview of our solution:
  • The "Container 1" contains an Apache TomEE instance with ActiveMQ activated and the jchat application installed. 
  • The "Container 2" contains another Apache TomEE instance and the springchat application. 
  • The "Container 3" contains the proxy server [nginx] that will serve as facade to our applications via port 80.
  • The springchat application will connect to the ActiveMQ broker in the "Container 1". 
  • The "Container 3" exposes two links: http://jchat.ddns.net/ and http://springchat.ddns.net/.
The hardest part of the demo is to create a CoreOS instance. Once we have it ready, the deployment of our apps is trivial. It requires a simple "run.sh" script execution.

Our CoreOS machine will host the containers. It can be bare-metal or VM. In this post, we are going to use a VirtualBox machine.

Installation process

Download the ISO file [https://coreos.com/docs/running-coreos/platforms/iso/] and create your VM.




Change your network adapter type to Bridged, so you can bypass the Host firewall.


Start your server with the CoreOS ISO file.


Create the cloud-config file that will be used by the installer. Save this file in a public place (your Dropbox, for example).
 #cloud-config  
 users:  
  - name: myusr  
   passwd: $6$rounds=4096$I950HqPomw$IVTXdX38Xvlkgp7K1vZqejhiYJXoztMZAuvRZPK.UCY2csQuwPt/tjz6JYtInOS1HTlA/TwkD.AvFtJmz3Nxf0  
   groups:  
    - sudo  
    - docker  

Did you notice how crazy complex is the password above? It's a password hash. Check here how to create your own.

Download your config file and execute "coreos-install" to start the installation process.

 wget https://dl.dropboxusercontent.com/u/1459144/cloud-config.txt   
 coreos-install -d /dev/sda -C stable -c cloud-config.txt  

Remove the virtual DVD from the virtual DVD driver and reboot your VM.


Please note that your cloud-config file can configure much more than just passwords. Please check the documentation for a complete reference [https://coreos.com/docs/cluster-management/setup/cloudinit-cloud-config/].

Once your VM is back online, use PUTTY to access it...



You are ready to deploy your applications. Execute the following lines in order to deploy them...

 wget https://github.com/tveronezi/chatdocker/archive/master.zip  
 unzip master.zip  
 cd chatdocker-master/   
 ./run.sh  

Now sit back and relax (approximately 20 minutes). Docker is preparing the containers...



Assuming that 192.168.1.120 is the IP address of your Docker host machine, you now have two new links:

You can also map them with your own DNS values. Open /chatdocker-master/chat/proxy/jchat.conf and /chatdocker-master/chat/proxy/springchat.conf and replace jchat.ddns.net and springchat.ddns.net by your own domains. Tip: I'm using "ddns.net" from http://www.noip.com/. They provide free subdomains.

After updating your files, execute the main "run.sh" command again. Don't worry. It will be much faster now...



What did just happen? 

Docker:
  • downloaded an image of the CentOS distribution [http://www.centos.org/].
  • installed Java, Maven, Git, Tar, Supervisor and TomEE in this image.
  • cleaned up the TomEE installation directory.
  • downloaded and built the jchat and the springchat projects.
  • installed jchat and springchat WAR files.
  • started and linked the TomEE instances
  • downloaded and installed a nginx proxy in a third container.
  • started and linked the nginx to the two TomEE instances.

Dockerfile

This is the recipe used by docker to create our Linux images. Reference here: https://docs.docker.com/reference/builder/

nginx

It's our proxy server. It maps our applications with our own domains. Reference here: http://blog.martinfjordvald.com/2010/07/nginx-primer/

supervisord

In order to run a container, you need to specify what image to use and what process to start. Note that Docker containers are able to track the execution of only one process at a time. Once that one process terminates, the whole container stops. If the user decides to manually stop a container, docker will try to gracefully stop its internal running process.

What if you wanted to execute more than one process at the same time? The solution is simple and elegant. You can use a process manager. Docker will manage the process manager process, and the process manager will manage the extra processes.

Reference here: http://docs.docker.com/articles/using_supervisord/

TomEE with ActiveMQ

These are our Apache friends. The first one is our application server. The second one is our message broker.

Linking containers

Docker containers share the same internal network. They use dynamic IPs, so how would you link these guys? Docker has a great solution: it will map the container names and IPs for you. It will update the "hosts" file of the containers with the provided information.

In the lines below we create three containers...

 docker run -d -p 8080:8080 --name=jchat jchat  
 docker run -d -p 8081:8080 --link=jchat:mybroker --name=springchat springchat  
 docker run -d -p 80:80 --link=jchat:jchat --link=springchat:springchat --name=proxy proxy  
  • The first one is the jchat container. It makes the port 8080 available from the host interface. 
  • The second one is the springchat. The springchat one maps its port 8080 to the port 8081 in the host machine. It also adds a link to the jchar container. "--link-jchat:mybroker" means that the springchat container can ping jchat with "ping mybroker". See how we use this information in the tomee.xml.
  • The third one creates the proxy and links jchat and springchat with the same approach.

Reference here: https://docs.docker.com/userguide/dockerlinks/

More resources

Tuesday, February 4, 2014

Two implementations of the same websocket application powered by TomEE (Java EE and Spring Framework)

Among the different ways to implement JVM based Enterprise Applications at our disposal today, two stand out in the crowd: Java EE and Spring Framework. We will implement the same chat application with both of them. This blog post won’t try point out which one you should use. It will simply show how to implement the same thing in two different ways.

We don't care about the infrastructure either. We will use the default values of what TomEE offers out of the box:
  • Embedded database server
  • Embedded messaging server
  • TransactionManager
  • EntityManagerFactory

These points define the common ground of the implementations:

The Java EE based application (jchat) will use only the standards. The Spring based application (springchat) will use the following modules:
  • org.springframework:spring-jms:4.0.1.RELEASE
  • org.springframework.data:spring-data-jpa:1.4.1.RELEASE
  • org.springframework:spring-webmvc:4.0.1.RELEASE
  • org.springframework:spring-websocket:4.0.1.RELEASE
  • org.springframework.security:spring-security-web:3.2.0.RELEASE

How does it look like?

It's the "Hello World" version of a "Websockets" application. There is a lot more to see under the hood, but the user interface is pretty standard.

jchatspringchat
The applications run in different VMs. ActiveMQ plays the link between them. One of the applications should run as node.

 mvn clean install tomee:run -P node  
 mvn clean install tomee:run  

When you use -P node, TomEE will use an external ActiveMQ broker instead of using its own. "-P node" is not part of the tomee-maven-plugin. It's just another maven profile defined by our applications.

Source code


Resource injection with Java EE

   @Inject  
   private ConnectionsService connections;  

Resource injection with Spring Framework

   @Autowired  
   private ConnectionsService connections;  

If an implementation of JSR-330 is detected, Spring is capable of using @Inject instead of @Autowired. Check [http://docs.spring.io/spring/docs/4.0.1.RELEASE/spring-framework-reference/htmlsingle/#beans-standard-annotations].

JMS MessageListener with Java EE

MessagesService.java
 @MessageDriven(messageListenerInterface = MessageListener.class, activationConfig = {  
     @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),  
     @ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/Messages"),  
     @ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),  
     @ActivationConfigProperty(propertyName = "clientId", propertyValue = "jchat")  
 })  

 @RunAs("chat-system")  
 public class NewTextMessage implements MessageListener {  
   @Inject  
   private ConnectionsService connections;  

   @Inject  
   private MessagesService messagesService;  

   @Override  
   public void onMessage(Message jms) {  
     MessageDto dto = new MessageDto();  
     try {  
       dto.setContent(jms.getStringProperty("message"));  
       dto.setFrom(jms.getStringProperty("user"));  
       dto.setTimestamp(jms.getLongProperty("date"));  
     } catch (JMSException e) {  
       throw new UnmanagedException(e);  
     }  
     MessageEntity bean = messagesService.save(dto.getTimestamp(), dto.getFrom(), dto.getContent());  
     dto.setId(bean.getUid());  
     connections.sendToAll("text", dto);  
   }  
 }  

JMS MessageListener with Spring Framework

MessagesService.java
 public class NewTextMessage implements MessageListener {  
   @Autowired  
   private ConnectionsService connections;  

   @Autowired  
   private MessagesService messagesService;  

   @Override  
   public void onMessage(Message jms) {  
     MessageDto dto = new MessageDto();  
     try {  
       dto.setContent(jms.getStringProperty("message"));  
       dto.setFrom(jms.getStringProperty("user"));  
       dto.setTimestamp(jms.getLongProperty("date"));  
     } catch (JMSException e) {  
       throw new UnmanagedException(e);  
     }  
     MessageEntity bean = messagesService.save(dto.getTimestamp(), dto.getFrom(), dto.getContent());  
     dto.setId(bean.getUid());  
     connections.sendToAll("text", dto);  
   }  
 }  

application-context.xml
  <jee:jndi-lookup id="jmsConnectionFactory" jndi-name="java:comp/env/myJmsConnectionFactory"/>  
  <bean id="jmsDestResolver" class=" org.springframework.jms.support.destination.JndiDestinationResolver"/>  
  <bean id="messageListener" class="springchat.jms.NewTextMessage"/>  
  <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">  
   <property name="connectionFactory" ref="jmsConnectionFactory"/>  
   <property name="destinationName" value="java:comp/env/NewTextMessageChannel"/>  
   <property name="destinationResolver" ref="jmsDestResolver"/>  
   <property name="messageListener" ref="messageListener"/>  
   <property name="pubSubDomain" value="true"/>  
   <property name="subscriptionDurable" value="true"/>  
   <property name="clientId" value="springchat"/>  
  </bean>  

Please note java:comp/env/myJmsConnectionFactory and java:comp/env/NewTextMessageChannel. These resources are created by the application server.

RESTful WebServices with Java EE

Extend the javax.ws.rs.core.Application class and list the classes with restful endpoints.

ApplicationRestConfig.java
 @ApplicationPath("/rest")  
 public class ApplicationRestConfig extends Application {  
   @Override  
   public Set<Class<?>> getClasses() {  
     final Set<Class<?>> classes = new HashSet<Class<?>>();  
     classes.add(AuthenticationRest.class);  
     classes.add(MessagesRest.class);  
     return classes;  
   }  
 }  

MessagesRest .java
 @Path("/messages")  
 public class MessagesRest {  
   @Inject  
   private MessagesService messages;  

   @POST  
   public Response postMessage(@FormParam("message") String message) {  
     messages.postMessage(message);  
     return Response.ok().build();  
   }  
.
.
.
 }  

RESTful WebServices with Spring Framework

application-context.xml
 <mvc:annotation-driven/>  

MessagesRest .java
 @Controller  
 public class MessagesRest {  
   @Autowired  
   private MessagesService messages;  

   @RequestMapping(value = "/rest/messages", method = RequestMethod.POST)  
   @ResponseStatus(HttpStatus.OK)  
   public void postMessage(@RequestParam("message") String message) {  
     messages.postMessage(message);  
   }  
.
.
.
 }  

Services with Java EE

MessagesService.java
 @Stateless  
 public class MessagesService {  
.
.
.
 }  

Services with Spring Framework

MessagesService.java
 @Service  
 public class MessagesServiceImpl implements MessagesService {  
.
.
.  
 }  

Please note that the Java EE version does not implement an interface. It's not mandatory in both cases, but an interface makes it easier to mock dependencies during unit tests. Our Java EE application is tested with a real server (via Arquillian), so no mocking is required.

Manual user authentication with Java EE

We use the standard JAAS to validate the user name and password. TomEE provides many ways to implement it. We use the ScriptLoginModule, which allows the use of a script in order to validate user credentials. According to the wikipedia, the main goal of JAAS is to separate the concerns of user authentication so that they may be managed independently. Therefore, some server side configuration is required. We hard code this configuration via tomee-maven-plugin. For more information about JAAS, check [http://tomee.apache.org/tomee-jaas.html].

login.config
 ScriptLogin {  
   org.apache.openejb.core.security.jaas.ScriptLoginModule required  
        engineName="js"  
        scriptURI="loginScript.js";  
 };  

loginScript.js
 function localAuthentication() {  
   var result = new java.util.ArrayList();  
   result.add('chat-user');  
   if (!user || user.trim() === '') {  
     throw 'Bad user or password. Test.';  
   }  
   return result;  
 }  
 localAuthentication();  

context.xml
 <Context antiJARLocking="true" path="/jchat">  
  <Realm className="org.apache.catalina.realm.JAASRealm" appName="ScriptLogin"  
      userClassNames="org.apache.openejb.core.security.jaas.UserPrincipal"  
      roleClassNames="org.apache.openejb.core.security.jaas.GroupPrincipal">  
  </Realm>  
 </Context>  

AuthenticationRest.java
 @Path("/auth")  
 public class AuthenticationRest {  
   @POST  
   @Produces("application/json")  
   public AuthenticationResultDto postUser(@FormParam("user") String user, @Context HttpServletRequest request) {  
     AuthenticationResultDto dto = new AuthenticationResultDto();  
     dto.setSessionId(request.getSession().getId());  
     try {  
       request.login(user, "");  
       request.getSession().setAttribute("authenticated", Boolean.TRUE);  
       dto.setSuccess(true);  
     } catch (ServletException e) {  
       dto.setSuccess(false);  
       dto.setInfo("bad.username.or.password");  
       request.getSession().setAttribute("authenticated", Boolean.FALSE);  
     }  
     return dto;  
   }  
.
.
. 
 }  

The request.login(user, "") call triggers our ScriptLoginModule.

Manual user authentication with Spring Framework

We use the Spring Security framework.

web.xml
  <filter>  
   <filter-name>springSecurityFilterChain</filter-name>  
   <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  </filter>  
  <filter-mapping>  
   <filter-name>springSecurityFilterChain</filter-name>  
   <url-pattern>/*</url-pattern>  
  </filter-mapping>  

UserDetailsServiceImpl.java
 import org.springframework.security.core.authority.AuthorityUtils;  
 import org.springframework.security.core.userdetails.User;  
 import org.springframework.security.core.userdetails.UserDetails;  
 import org.springframework.security.core.userdetails.UserDetailsService;  
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
  
 public class UserDetailsServiceImpl implements UserDetailsService {  
   @Override  
   public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {  
     return new User(name, "", AuthorityUtils.createAuthorityList("ROLE_CHATUSER"));  
   }  
 }  

application-context.xml
  <security:http auto-config="true">  
   <security:intercept-url pattern="/fakepath/*" access="ROLE_USER"/>  
  </security:http>  
  <security:authentication-manager alias="authenticationManager">  
   <security:authentication-provider user-service-ref="userDetailsService"/>  
  </security:authentication-manager>  
  <security:global-method-security secured-annotations="enabled"/>  

Note that we need to declare at least one security:intercept-url, otherwise the system fails to load the controllers. Also note the ROLE_ prefix. It is required by the RoleVoter class.

AuthenticationRest.java
 import org.springframework.security.authentication.AbstractAuthenticationToken;  
 import org.springframework.security.authentication.AuthenticationManager;  
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;  
 import org.springframework.security.core.Authentication;  
 import org.springframework.security.core.context.SecurityContextHolder;  
 import org.springframework.security.web.authentication.WebAuthenticationDetails;  
 
 @Controller  
 public class AuthenticationRest {  
   @Autowired  
   @Qualifier("authenticationManager")  
   protected AuthenticationManager authenticationManager;  

   @RequestMapping(value = "/rest/auth", method = RequestMethod.POST, produces = {"application/json"})  
   @ResponseBody  
   public AuthenticationResultDto postUser(@RequestParam("user") String user, HttpServletRequest request) {  
     AuthenticationResultDto dto = new AuthenticationResultDto();  
     dto.setSessionId(request.getSession().getId());  
     try {  
       // Must be called from request filtered by Spring Security, otherwise SecurityContextHolder is not updated  
       AbstractAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, "");  
       token.setDetails(new WebAuthenticationDetails(request));  
       Authentication authentication = authenticationManager.authenticate(token);  
       SecurityContextHolder.getContext().setAuthentication(authentication);  
       dto.setSuccess(Boolean.TRUE);  
       request.getSession().setAttribute("authenticated", Boolean.TRUE);  
     } catch (Exception e) {  
       SecurityContextHolder.getContext().setAuthentication(null);  
       dto.setSuccess(Boolean.FALSE);  
       request.getSession().setAttribute("authenticated", Boolean.FALSE);  
     }  
     return dto;  
   }  
.
.
.
 }  

Websockets with Java EE

ChatSocketConnection.java
 import javax.websocket.*;  
 import javax.websocket.server.ServerEndpoint;  
   
 @ServerEndpoint(value = "/ws/connection")  
 public class ChatSocketConnection {  
   
   @Inject  
   private ConnectionsService service;  
   
   @OnOpen  
   public void open(Session session, EndpointConfig conf) {  
     service.addSession(session);  
   }  
   
   @OnClose  
   public void close(Session session) {  
     service.removeSession(session);  
   }  
   
   @OnError  
   public void error(Session session, Throwable cause) {  
     service.removeSession(session);  
   }  
   
 }  

Websockets with Spring Framework

ConnectionHandler.java
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.web.socket.CloseStatus;  
 import org.springframework.web.socket.WebSocketSession;  
 import org.springframework.web.socket.handler.TextWebSocketHandler;  
 import springchat.service.ConnectionsService;  
   
 public class ConnectionHandler extends TextWebSocketHandler {  
   
   @Autowired  
   private ConnectionsService service;  
   
   @Override  
   public void afterConnectionEstablished(WebSocketSession session) throws Exception {  
     service.addSession(session);  
   }  
   
   @Override  
   public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {  
     service.removeSession(session);  
   }  
   
   @Override  
   public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {  
     service.removeSession(session);  
   }  
 }  

application-context.xml
  <bean id="connectionHandler" class="springchat.sockets.ConnectionHandler"/>  
  <websocket:handlers>  
   <websocket:mapping path="/ws/connection" handler="connectionHandler"/>  
  </websocket:handlers>  

Testing (Arquillian and EasyMock)

The jchat project uses the Arquillian mantra: "No more mocks. No more container lifecycle and deployment hassles. Just real tests!" [http://arquillian.org/] You may call it integration tests, but the modern Application Servers (Hint hint... TomEE) make it possible to run such tests almost as fast as the old mock objects. You don't need to create glue code to mock your beans, simply start your server and test the real thing.

The springchat project uses EasyMock [http://easymock.org/], following what's proposed by the reference documentation. You can also use Arquillian with your Spring code. Check [http://arquillian.org/blog/tags/spring/] for more information.

Conclusion

At the end of the day, we just want to code and have fun with it. Whether you choose Java EE, Spring or a combination of them is entirely up to you - in a perfect world. ;) The last thing we need in our jobs is to worry about how to setup our external dependencies and servers. Just let TomEE do it for you.

Tuesday, November 12, 2013

Running your applications with TomEE plugin for Maven and Maven Profiles

This post shows:
  • an use case for TomEE Maven Plugin;
  • an use case for Maven Profiles;
  • how to start up multiple instances of TomEE with TomEE Maven Plugin;
  • a new sample application [Launcher].

Do you want to see your programmers happy? You don’t need parties, free coffee, snacks and beer. Just give your developers an easy way to build, test and run their code. I have good news: this is possible with Maven, TomEE and TomEE plugin for Maven. Everyone will be happy! Ok, beer also helps. ;)

Let's go straight to our sample of the day. Do you remember our three main projects?
Msglnk [Scala with YUI]
FaceID [Groovy with ExtJS]
PhotoDB [Java with BackboneJS]

PhotoDB, FaceID and MsgLnk are designed to work together as a solution. PhotoDB handles our pictures; FaceID handles our users; MsgLnk handles our communication (email and JMS). Despite being part of a solution, they can also run as standalone applications. In fact, they don't even know about the existence of each other. The app-to-app communication is via JMS.

  • Download PhotoDB here;
  • Download FaceID here;
  • Download MsgLnk here.

In order to run these applications on stand-alone mode, download and extract the source code in a directory of your choice and execute the following command in the project root directory:

 mvn clean install tomee:run  

The command above builds, installs and deploy your project. Once TomEE is online, you should be able to access your application at one of these links:


Note that the previous command starts an application on stand-alone mode. If you start all three applications like that, they won't talk to each other because we would have three instances of the ActiveMQ server. It's very easy to start the applications on "solution" mode though. Just use the "solution" maven profile...

 mvn clean install tomee:run -P solution  

Pictures! Note that we use Java, so these steps are multi-platform.







Repeat the steps above for each application. It will seem like you are downloading the entire Internet. Well, someone else is doing it for you. Maven downloads approximately 250MB of binaries the first time you execute the command. It's a good thing you don't need to worry about that! :)


It looks good, but you may be wondering what the heck does that command mean? It's a combination of three commands with extra parameters. You can do the same thing with...

 mvn clean  
 mvn install 
 mvn tomee:run -P solution  

  • The first command cleans up the target directory of your application.
  • The second one builds and installs the application binaries in your local maven repository.
  • The third one executes the run goal of the tomee plugin with the solution profile.

What does "solution" profile mean? Maven Profiles is a big topic. I advise you to go take a look at this documentation. For short, in our case, this is a way to set variables according to what we want to do.

Our applications have only one real profile: solution. The only way to activate this profile is by passing it along with the -P flag.

Every time we run mvn tomee:run, the plugin starts a new TomEE+ instance. Every TomEE+ server starts its own ActiveMQ server by default. On solution mode, we want to have only one ActiveMQ instance. All our applications should use that single instance as JMS broker. When running on solution mode, PhotoDB and FaceID do not start their instances of the ActiveMQ server. All the applications will use the one started by the MsgLnk.

It's easy to disable the ActiveMQ of a TomEE server...

  <Resource id="MyJmsResourceAdapter" type="ActiveMQResourceAdapter">  
   # Do not start the embedded ActiveMQ broker  
   BrokerXmlConfig =  
   ServerUrl = tcp://localhost:61616  
  </Resource>  
  <Resource id="MyJmsConnectionFactory" type="javax.jms.ConnectionFactory">  
   ResourceAdapter = MyJmsResourceAdapter  
  </Resource>  
  <Container id="MyJmsMdbContainer" ctype="MESSAGE">  
   ResourceAdapter = MyJmsResourceAdapter  
  </Container>  

The TomEE maven plugin is super flexible. Among its many options, there is the config one. It defines the directory that contains TomEE configuration files. Anything you put in this directory will be copied to or will override the files in apache-tomee/conf. Here we see how the Maven profiles can be useful. We can override config values by using it.

  <profiles>  
   <profile>  
    <id>solution</id>  
    <properties>  
     <tomee.config.dir>${project.basedir}/src/main/tomee/network/conf</tomee.config.dir>  
     <tomee.args>-Xmx512m -XX:PermSize=256m -Djava.security.auth.login.config=${project.basedir}/src/main/tomee/network/conf/login.config</tomee.args>  
    </properties>  
   </profile>  
  </profiles>  

See how the plugin configuration would look like.

    <plugin>  
     <groupId>org.apache.openejb.maven</groupId>  
     <artifactId>tomee-maven-plugin</artifactId>  
     <version>${tomee.version}</version>  
     <configuration>  
      <context>photodb</context>  
      <config>${tomee.config.dir}</config>  
      <args>${tomee.args}</args>  
      <tomeeClassifier>plus</tomeeClassifier>  
      <debugPort>5005</debugPort>  
      <tomeeAjpPort>8009</tomeeAjpPort>  
      <tomeeHttpPort>8080</tomeeHttpPort>  
      <tomeeShutdownPort>8005</tomeeShutdownPort>  
      <debug>false</debug>  
     </configuration>  
    </plugin>  

Note that the plugin configuration uses variables set by the profile (tomee.config.dir and tomee.args).

Resources

Wait! There is a third way to start up all three applications: https://github.com/tveronezi/launcher. The Launcher is just a wrapper application. It uses the TomEE plugin to retrieve and start PhotoDB, FaceID and MsgLnk in a single TomEE instance.

Download the source-code here, unzip it, and execute...

 mvn clean install tomee:run  

Once you see...
... you should be able to access http://localhost:8080/.


That's it! Have fun!

Friday, October 11, 2013

Bookmarkable ExtJS application with BackboneJS


The JavaScript world has a lot of good frameworks. BackboneJS and ExtJS are examples of it. They are well known players in this field. Both are elegant and fun to work with, but only BackboneJS is open source and free. ExtJS gives nice widgets that developers can use as simple components out of the box. Both have their own pros and cons. This post isn't about which one is the ultimate JavaScript framework. This post only tries to explain how to use features of both in the same project. It shows how these two guys can play nicely together. As gift, it also shows another example of JavaEE application with groovy powered by Apache TomEE.

Browser bookmarks are useful. Users expect to save the state of a web application by simply copying the application URL. Unfortunately, this feature is not easy to implement on Single Page Applications. In this kind of application, we don't have real page transitions. Due to the fact that the HTML is built by the JavaScript framework directly on the browser, the framework needs to access the browser address bar and figure out how to represent that URL in HTML code. It needs to match what is defined in the address bar and the actual state of the application.

ExtJS provides the Ext.History object. It gives the ability of using hash based history. It means that the address bar will have a hash value (everything after the “#” character) that is not handled by the server. BackboneJS also supports hash fragments, but it can use the Html5 history if available. It means that BackboneJS can use cleaner URL addresses. Our application will be an ExtJS MVC application that uses BackboneJS to handle the URL in the address bar.

Lets take a look in our application. It's based on the Feed Viewer example available on the official ExtJS examples page. The welcome page shows an empty page with two buttons: add and remove.


Click on "Add Feed" and add a new RSS feed. There are some feed links available at the yahoo developer page (http://developer.yahoo.com/rss/).



Now select the new feed. 


Did you notice that the URL is updated as soon as you select the feed? Now double-click one of the RSS items.  


The URL was again updated. Copy the address of this page and paste it in another browser, or simply hit F5.


What did just happen?

Our server returns the "index.jsp" as result to any request. It means that if you try to access something like http://localhost:8080/rssreader/i-dont-know-what-to-do the server will return the "index.jsp" page on its initial state.


After the initial page load, the framework takes over and checks what is in the URL string and executes the function mapped to that particular URL. This is the definition of our current Router:

 var Router = Backbone.Router.extend({  
         routes: {  
           '': 'showChannel',  
           '/': 'showChannel',  
           'channel/:channel/': 'showChannel',  
           'channel/:channel': 'showChannel',  
           'channel/:channel/:item': 'showChannel',  
           'channel/:channel/:item/': 'showChannel'  
         },  
         showChannel: function (channel, item) {  
           var param = {  
             channel: channel,  
             channelItem: item  
           };  
           me.fireEvent('show-channel', param);  
         }  
 });  

Yeah. It is ridiculously simple. The router maps URLs to functions. In the case above, all the URLs point to the same "showChannel" function. ":channel" and ":item" are path parameters. In case we have an URL like http://192.168.1.126:8080/rssreader/channel/365/647, the selected channel ID is "365" and the selected item ID is "647".

How to map all the requests to "index.jsp"? We need to change the "web.xml". We want the server to properly map our JavaScript, Images and CSS resources; but everything else should return "index.jsp".

First map "/*" to "index.jsp"...

  <servlet>  
   <servlet-name>index</servlet-name>  
   <jsp-file>/index.jsp</jsp-file>  
  </servlet>  
  <servlet-mapping>  
   <servlet-name>index</servlet-name>  
   <url-pattern>/*</url-pattern>  
  </servlet-mapping>  

Now every request points to "index.jsp". It is time to map your static resources to the "default" servlet...

  <servlet-mapping>  
   <servlet-name>default</servlet-name>  
   <url-pattern>/app/*</url-pattern>  
  </servlet-mapping>  

Note that our static resources are all in "/app/". When the server sees the rule above, it will return a resource instead of  the "index.jsp" file. For example, http://192.168.1.126:8080/rssreader/app/js/app.js gives the source code of the "app.js" file.


As usual, this sample implements a JavaEE application that runs on Apache TomEE. The source code is available on github.

ExtJS Histoty object -> http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.util.History
BackboneJS Router -> http://backbonejs.org/#Router (-> Read it. It shows more examples of route strings.)
Sample source code -> https://github.com/tveronezi/rssreader
Apache TomEE -> http://tomee.apache.org/

Please mind the ExtJS licensing rules. For short:

Sunday, August 18, 2013

Creating and extending JavaScript classes with ExtJS

JavaScript is not a class-based language. It uses the prototyping approach instead. If your background is based on classical languages, this may discourage you for a moment. But wait! Don’t go away just yet! JavaScript is also a dynamic and very flexible language. Therefore, it’s pretty easy to build frameworks that simulate the classical approach on top of it.

Before checking what ExtJS has to offer, we should understand how we would create classes without the help of any framework.

 var MyNameSpace = MyNameSpace || {};  
 MyNameSpace.Person = function(config) {  
   this.name = config.name;  
 };  
 MyNameSpace.Person.prototype.sayHi = function(dude) {  
   return 'Hi ' + dude + '! My name is ' + this.name + '.';  
 };  
 var person = new MyNameSpace.Person({  
   name: 'Foo'  
 });  
 window.console.log(person.sayHi('Bar'));  

First we need to create the namespace where our class will live. Then, we create a function that works as the constructor of our class. If we wanted to create a public function, we would add it to a mysterious “prototype” property of the constructor. It seems a bit strange, doesn’t it? How would we do the same thing with ExtJS?

 Ext.define('MyNameSpace.Person', {  
   config: {  
     name: null  
   },  
   sayHi: function(dude) {  
     return Ext.String.format('Hi {0}! My name is {1}.', dude, this.name);  
   },  
   constructor: function(config) {  
     this.initConfig(config);  
   }    
 });  
 var person = Ext.create('MyNameSpace.Person', {  
   name: 'Foo'  
 });  
 window.console.log(person.sayHi('Bar'));  

That looks better. We no longer need to create the namespace because the framework takes care of it; We can easily locate our constructor; The “sayHi” function and the “name” property are part of what represents the body of our class. The recipe is simple:

 Ext.define('<name of your class>', classDefnObject, createdcallBack);  

The “classDefnObject” is a map with the definitions of our new class. The optional “createdCallback” will be executed once the class is created and is ready to be used.

Notice that we don’t use the “new” keyword. Instead, we use the “Ext.create” function. We still can use “new MyNameSpace.Person({name: ‘Foo’})”, but the create function allows the framework to dynamically load the JavaScript file that contains the “MyNameSpace.Person” source code the first time the “Person” class is needed.

You can also create anonymous classes just like you would do with Java.

 function wrapper() {  
   var Class = Ext.define(null, {  
     config: {  
       name: null  
     },  
     sayHi: function(dude) {  
       return Ext.String.format('Hi {0}! My name is {1}.', dude, this.name);  
     },  
     constructor: function(config) {  
       this.initConfig(config);  
     }    
   });  
   var person = new Class({  
     name: 'Foo'  
   });  
   window.console.log(person.sayHi('Bar'));  
 }  
 wrapper();  

In this case, you wouldn’t be able to use the “Ext.create” function. It is already loaded anyway. This feature makes possible to create classes inside functions.

Due to the dynamic nature of the JavaScript language, ExtJS is able to generate code on-the-fly. Out of the box, we have getters and a setters for all the keys defined in the “config” property.

 person.setName('Baz');  
 window.console.log(person.sayHi('Bar'));  
 window.console.log(person.getName());  

What about some validation?

 Ext.define('MyNameSpace.Person', {  
   config: {  
     name: null  
   },  
   applyName: function(name) {  
     if (Ext.isEmpty(name)) {  
       throw 'Invalid "name"';  
     }  
     return name;  
   },  
   sayHi: function(dude) {  
     return Ext.String.format('Hi {0}! My name is {1}.', dude, this.name);  
   },  
   constructor: function(config) {  
     this.initConfig(config);  
     this.setName(config.name);  
   }    
 });  
 var person = Ext.create('MyNameSpace.Person', {  
   name: 'Foo'  
 });  
 person.setName(null); // throws the validation exception  

The getter and the setter methods are not supposed to be overridden. You may want to create an “apply” method instead.

 .  
 .  
 .  
 apply<Name of the property>: function(setterParameter) {  
   // your logic here  
   return setterParameter;  
 },  
 .  
 .  
 .  

You can create class extensions by adding a “extend” property.

 Ext.define('MyNameSpace.Programmer', {  
   extend: 'MyNameSpace.Person'  
 });  
 var person = Ext.create('MyNameSpace.Programmer', {  
   name: 'Geek'  
 });  
 window.console.log(person.sayHi('Bar'));  

A programmer is a different kind of person. We say “hi” differently. We log the “date”!

 Ext.define('MyNameSpace.Programmer', {  
   extend: 'MyNameSpace.Person',  
   sayHi: function(dude) {  
     var greetings = this.callParent(arguments);  
     return Ext.String.format(  
       '{0} [Message sent at {1}]',   
       greetings, new Date()  
     );  
   }  
 });  

We call the “sayHi” function of the parent class, and then we “enhance” the resulting text. Be careful about using the “callParent” function. If you use it and the “'use strict';” statement at the same time, it will throw an exception.


The ExtJS developers needed to choose a nasty solution to make this "callParent" magic to work. A workaround for this issue is to call...

   sayHi: function(dude) {  
     var greetings = MyNameSpace.Programmer.superclass.sayHi.apply(this, arguments);  
     var greetings = this.callParent(arguments);  
     return Ext.String.format(  
       '{0} [Message sent at {1}]',   
       greetings, new Date()  
     );  
   }  

It gives you the same effect, and you can still use the strict mode.

Mixins are another way to enhance your classes. Imagine we have these classes:

 Ext.define('MyNameSpace.EnglishSpeaker', {  
   enSayHi: function(dude) {  
     return Ext.String.format('Hi {0}!', dude);  
   }  
 });  
   
 Ext.define('MyNameSpace.FrenchSpeaker', {  
   frSayHi: function(dude) {  
     return Ext.String.format('Salut {0}!', dude);  
   }  
 });  
   
 Ext.define('MyNameSpace.PortugueseSpeaker', {  
   ptSayHi: function(dude) {  
     return Ext.String.format('Oi {0}!', dude);  
   }  
 });  

They would define some linguistic abilities. You can use them by setting the "mixins" property.

 Ext.define('MyNameSpace.Person', {  
   mixins: {  
     'en': 'MyNameSpace.EnglishSpeaker',  
     'fr': 'MyNameSpace.FrenchSpeaker',  
     'pt': 'MyNameSpace.PortugueseSpeaker'  
   }  
 });  
   
 var person = Ext.create('MyNameSpace.Person', {});  
 window.console.log(person.enSayHi('Bar'));  
 window.console.log(person.frSayHi('Bar'));  
 window.console.log(person.ptSayHi('Bar'));  

Would you like to enhance one of the mixins functions? Just create a function with the same name of the one defined in the mixin.

 Ext.define('MyNameSpace.Person', {  
   mixins: {  
     'en': 'MyNameSpace.EnglishSpeaker',  
     'fr': 'MyNameSpace.FrenchSpeaker',  
     'pt': 'MyNameSpace.PortugueseSpeaker'  
   },  
   enSayHi: function() {  
     var greetings = this.mixins.en.enSayHi.apply(this, arguments);  
     return Ext.String.format('{0} [Message sent at {1}]', greetings, new Date());  
   }  
 });  

The mixins object holds the mixins prototypes. In the case above, en points to the EnglishSpeaker prototype.

Ext.define
Ext.create
What does "use strict" do in JavaScript, and what is the reasoning behind it?
ECMAScript 5 Strict Mode, JSON, and More
Mixins
callParent
Function.prototype.apply
arguments object