Pages

Wednesday, February 22, 2012

JEE example - part 1: remote EJB invocation using JBoss AS7


JBoss AS 7 7.1.0.Final (codename “Thunder”) the well-known JEE application server was released last week and it can be downloaded here.
 This version is certified JEE 6 full profile, while the previous 7.0 was certified JEE Web profile only. Therefore, this blog entry will present in how to create, deploy and test a JEE 6 application using remote EJBs.

First off all download the JBoss archive (zip or tar.gz) and decompress it on your disk. Optionally, you may set up the JBOSS_HOME environment variable. All you need now to do is to launch the server using scripts in /bin folder. It is to remark one of the new features of JBoss AS7: the possibility to manage multiple instances (a collection of such instances are referred as members of “domain”) from a single control point. In order to have such coordinated production multi server management you may use domain.sh or domain.bat scripts. In our examples, we will use a single server instance and launch standalone.bat or standalone.sh scripts

============
21:47:35,369 INFO  [org.jboss.modules] JBoss Modules version 1.1.1.GA
21:47:35,509 INFO  [org.jboss.msc] JBoss MSC version 1.0.2.GA
21:47:35,556 INFO  [org.jboss.as] JBAS015899: JBoss AS 7.1.0.Final "Thunder" starting
21:47:36,320 INFO  [org.jboss.as.server] JBAS015888: Creating http management service using socket-binding (management-http)
21:47:36,320 INFO  [org.xnio] XNIO Version 3.0.3.GA
21:47:36,336 INFO  [org.xnio.nio] XNIO NIO Implementation Version 3.0.3.GA
21:47:36,351 INFO  [org.jboss.remoting] JBoss Remoting version 3.2.2.GA
21:47:36,351 INFO  [org.jboss.as.logging] JBAS011502: Removing bootstrap log handlers
21:47:36,351 INFO  [org.jboss.as.configadmin] (ServerService Thread Pool -- 32) JBAS016200: Activating ConfigAdmin Subsystem
21:47:36,367 INFO  [org.jboss.as.jacorb] (ServerService Thread Pool -- 38) JBAS016300: Activating JacORB Subsystem
21:47:36,367 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 37) JBAS010280: Activating Infinispan subsystem.
21:47:36,367 INFO  [org.jboss.as.osgi] (ServerService Thread Pool -- 49) JBAS011940: Activating OSGi Subsystem
21:47:36,383 INFO  [org.jboss.as.webservices] (ServerService Thread Pool -- 58) JBAS015537: Activating WebServices Extension
21:47:36,398 INFO  [org.jboss.as.connector] (MSC service thread 1-3) JBAS010408: Starting JCA Subsystem (JBoss IronJacamar 1.0.7.Final)
21:47:36,414 INFO  [org.jboss.as.security] (ServerService Thread Pool -- 54) JBAS013101: Activating Security Subsystem
21:47:36,414 INFO  [org.jboss.as.naming] (ServerService Thread Pool -- 48) JBAS011800: Activating Naming Subsystem
21:47:36,539 INFO  [org.jboss.as.naming] (MSC service thread 1-6) JBAS011802: Starting Naming Service
21:47:36,539 INFO  [org.jboss.as.security] (MSC service thread 1-6) JBAS013100: Current PicketBox version=4.0.6.final
21:47:36,570 INFO  [org.jboss.as.jaxr] (MSC service thread 1-6) Binding JAXR ConnectionFactory: java:jboss/jaxr/ConnectionFactory
21:47:36,570 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 33) JBAS010403: Deploying JDBC-compliant driver class org.h2.Driver (version 1.3)
21:47:36,601 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 33) JBAS010404: Deploying non-JDBC-compliant driver class org.postgresql.Driver (version 8.4)
21:47:36,617 INFO  [org.jboss.as.mail.extension] (MSC service thread 1-6) JBAS015400: Bound mail session [java:jboss/mail/Default]
21:47:36,663 INFO  [org.jboss.ws.common.management.AbstractServerConfig] (MSC service thread 1-2) JBoss Web Services - Stack CXF Server 4.0.1.GA
21:47:36,913 WARN  [org.jboss.as.messaging] (MSC service thread 1-1) JBAS011600: AIO wasn't located on this platform, it will fall back to using pure Java NIO. If your platform is Linux, install LibAIO
21:47:36,913 INFO  [org.jboss.as.server.deployment.scanner] (MSC service thread 1-3) JBAS015012: Started FileSystemDeploymentService for directory D:\servers\jboss-as-7.1.0.Final\standalone\deployments
21:47:36,929 INFO  [org.apache.coyote.http11.Http11Protocol] (MSC service thread 1-2) DÚmarrage de Coyote HTTP/1.1 sur http-127.0.0.1-127.0.0.1-8080
21:47:36,929 INFO  [org.jboss.as.remoting] (MSC service thread 1-7) JBAS017100: Listening on 127.0.0.1/127.0.0.1:4447
21:47:36,944 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) live server is starting with configuration HornetQ Configuration (clustered=false,backup=false,sharedStore=tr
21:47:37,116 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) Waiting to obtain live lock
21:47:37,131 INFO  [org.hornetq.core.persistence.impl.journal.JournalStorageManager] (MSC service thread 1-1) Using NIO Journal
21:47:37,131 INFO  [org.jboss.as.remoting] (MSC service thread 1-2) JBAS017100: Listening on /127.0.0.1:9999
21:47:37,194 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-6) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS]
21:47:37,194 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-5) JBAS010400: Bound data source [java:/PersonDS]
21:47:37,194 INFO  [org.hornetq.core.server.impl.FileLockNodeManager] (MSC service thread 1-1) Waiting to obtain live lock
21:47:37,194 INFO  [org.hornetq.core.server.impl.FileLockNodeManager] (MSC service thread 1-1) Live Server Obtained live lock
21:47:37,272 WARN  [jacorb.codeset] (MSC service thread 1-5) Warning - unknown codeset (Cp1252) - defaulting to ISO-8859-1
21:47:37,412 INFO  [org.jboss.as.jacorb] (MSC service thread 1-5) JBAS016330: CORBA ORB Service started
21:47:37,490 INFO  [org.jboss.as.jacorb] (MSC service thread 1-4) JBAS016328: CORBA Naming Service started
21:47:37,771 INFO  [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-1) Started Netty Acceptor version 3.2.5.Final-a96d88c 127.0.0.1:5445 for CORE protocol
21:47:37,787 INFO  [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-1) Started Netty Acceptor version 3.2.5.Final-a96d88c 127.0.0.1:5455 for CORE protocol
21:47:37,787 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) Server is now live
21:47:37,787 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) HornetQ Server version 2.2.11.Final (HQ_2_2_11_FINAL_AS7, 122) [cda4651d-5c69-11e1-ad91-30a420524153]) starte
21:47:37,787 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-5) trying to deploy queue jms.topic.testTopic
21:47:37,802 INFO  [org.jboss.as.messaging] (MSC service thread 1-5) JBAS011601: Bound messaging object to jndi name java:/topic/test
21:47:37,802 INFO  [org.jboss.as.messaging] (MSC service thread 1-5) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/topic/test
21:47:37,818 INFO  [org.jboss.as.messaging] (MSC service thread 1-7) JBAS011601: Bound messaging object to jndi name java:/ConnectionFactory
21:47:37,818 INFO  [org.jboss.as.messaging] (MSC service thread 1-8) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/RemoteConnectionFactory
21:47:37,833 INFO  [org.jboss.as.messaging] (MSC service thread 1-8) JBAS011601: Bound messaging object to jndi name java:/RemoteConnectionFactory
21:47:37,833 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-3) trying to deploy queue jms.queue.testQueue
21:47:37,833 INFO  [org.jboss.as.messaging] (MSC service thread 1-3) JBAS011601: Bound messaging object to jndi name java:/queue/test
21:47:37,833 INFO  [org.jboss.as.messaging] (MSC service thread 1-3) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/queue/test
21:47:37,833 INFO  [org.jboss.as.deployment.connector] (MSC service thread 1-6) JBAS010406: Registered connection factory java:/JmsXA
21:47:37,849 INFO  [org.hornetq.ra.HornetQResourceAdapter] (MSC service thread 1-6) HornetQ resource adaptor started
21:47:37,849 INFO  [org.jboss.as.connector.services.ResourceAdapterActivatorService$ResourceAdapterActivator] (MSC service thread 1-6) IJ020002: Deployed: file://RaActivatorhornetq-ra
21:47:37,849 INFO  [org.jboss.as.deployment.connector] (MSC service thread 1-6) JBAS010401: Bound JCA ConnectionFactory [java:/JmsXA]
21:47:37,865 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.1.0.Final "Thunder" started in 2715ms - Started 172 of 249 services (75 services are passive or on-demand)



One of most impressive features of you can rapidly observe JBoss AS7 is the startup time, less than 3s. This is achieved among others by a modular architecture and a lazy loading mechanism.

Let’s create now our simple application. In the first time create an interface with one method

package org.example.jee.service;

import java.util.concurrent.Future;

/**
 * Service Interface
 * 
 * @author fracaru
 * 
 */
public interface IService {

 /**
  * Greetings 
  * @return greetings
  */
 String sayHello();
}

Now, we will create a stateless bean that implements the previous interface. In order to invoke this service remotely, you have to declare the expose the view of bean using @Remote annotation.

package org.example.jee.service.impl;

import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;

import org.example.jee.service.IService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @author fracaru
 * 
 */
@Remote(IService.class)
@Stateless
public class HelloServiceBean implements IService {

 /* the context used to illustrate asynchronous calls */
 @Resource
 SessionContext ctx;

 /* the logger */
 private final Logger logger = LoggerFactory
   .getLogger(HelloServiceBean.class);

 /*
  * (non-Javadoc)
  * 
  * @see org.example.jee.service.IService#sayHello()
  */
 @Override
 public String sayHello() {
  return "Hello World";
 }
}

I used maven to package the interface in a jar called project-common-service-1.0-SNAPSHOT.jar and the bean in a jar called project-server-ejb-1.0-SNAPSHOT.jar and created an ear archive project-jee-example.ear. In order to deploy the ear on the server we have several options:

  • Use maven plug-ins
  •  Use a CLI interface
  • Copy the ear to the deployment folder
  • Use the new improved web administration interface. Note that for this version the security is activated by default for the server so you need to create an admin user (using add-user scripts in the bin folder) in order to use the web interface.

Once our application installed, you can check the server log (or the interface notification) to verify that the ear was correctly deployed:

22:04:50,551 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-6) JBAS015876: Starting deployment of "project-server-ejb-1.0-SNAPSHOT.jar"
22:04:50,941 INFO  [org.jboss.weld.deployer] (MSC service thread 1-2) JBAS016002: Processing weld deployment project-jee-example.ear
22:04:50,988 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016002: Processing weld deployment project-server-ejb-1.0-SNAPSHOT.jar
22:04:50,988 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named HelloServiceBean in deployment unit subdeployment "project-server-ejb-1.0-SNAPSHOT.jar" of deployment "project-jee-exampl

        java:global/project-jee-example/project-server-ejb-1.0-SNAPSHOT/HelloServiceBean!org.example.jee.service.IService
        java:app/project-server-ejb-1.0-SNAPSHOT/HelloServiceBean!org.example.jee.service.IService
        java:module/HelloServiceBean!org.example.jee.service.IService
        java:jboss/exported/project-jee-example/project-server-ejb-1.0-SNAPSHOT/HelloServiceBean!org.example.jee.service.IService
        java:global/project-jee-example/project-server-ejb-1.0-SNAPSHOT/HelloServiceBean
        java:app/project-server-ejb-1.0-SNAPSHOT/HelloServiceBean
        java:module/HelloServiceBean


Now that the application is deployed we will create a remote client that accesses the exposed service. In order to work the client need on the one hand the project-common-service-1.0-SNAPSHOT.jar and the JBoss client dependencies. For the 7.1.0 version, JBoss provided a jboss-client-7.1.0.Final.jar in the bin/client directory which contains a minimal set of jars required for remote JMS and EJB usage. This jar is to be used for non-maven clients; for maven users JBoss recommends to not use this jar, but use the following BOM dependencies instead:

        
            org.jboss.as
            jboss-as-ejb-client-bom
            pom
        
        
            org.jboss.as
            jboss-as-jms-client-bom
            pom
        
    

Here is my client code, inspired from the JBoss documentation:

private static IService service;

 @BeforeClass
 public static void setUpTests() throws NamingException {
  System.out.println("Init tests...");
  Hashtable envs = new Hashtable();
        envs.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        InitialContext context = new InitialContext(envs);

  // The app name is the application name of the deployed EJBs. This is
  // typically the ear name
  // without the .ear suffix. However, the application name could be
  // overridden in the application.xml of the
  // EJB deployment on the server.
  final String appName = "project-jee-example";
  // This is the module name of the deployed EJBs on the server. This is
  // typically the jar name of the
  // EJB deployment, without the .jar suffix, but can be overridden via
  // the ejb-jar.xml
  // In this example, we have deployed the EJBs in a
  // jboss-as-ejb-remote-app.jar, so the module name is
  // jboss-as-ejb-remote-app
  final String moduleName = "project-server-ejb-1.0-SNAPSHOT";
  // AS7 allows each deployment to have an (optional) distinct name. We
  // haven't specified a distinct name for
  // our EJB deployment, so this is an empty string
  final String distinctName = "";
  // The EJB name which by default is the simple class name of the bean
  // implementation class
  final String beanName = "HelloServiceBean";
  // the remote view fully qualified class name
  final String viewClassName = "org.example.jee.service.IService";
  // let's do the lookup
  String lookUpJNDI = "ejb:" + appName + "/" + moduleName + "/"
    + distinctName + "/" + beanName + "!" + viewClassName;

  service = (IService) context.lookup(lookUpJNDI);

 }

@Test
 public void testService() {
  String message = service.sayHello();
  System.out.println("Message = " + message);
  Assert.assertEquals("Hello World", message);
 }

Several things are to be discussed before testing the client. First off all,  the JNDI name used (the comments in code are self explanatory):
"ejb:project-jee-example/project-server-ejb-1.0-SNAPSHOT//HelloServiceBean!org.example.jee.service.IService"

Personally, I would prefer to have here the global portable JNDI name for EJB3.1, ie java:global/[<application-name>]/<module-name>/<bean-name>!<fully-qualified-bean-interface-name>.instead of ejb:// and JBoss specific name.

The second thing is the necessity to provide in the client classpath a file called jboss-ejb-client.properties containing EJB client context properties. A different file may be indicated using the command
-Djboss.ejb.client.properties.file.path=/home/fracaru/jbossas7/client/custom-jboss-ejb-client.properties



####################################################################
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false

remote.connections=default

remote.connection.default.host=localhost
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=true

remote.connection.default.username=user
remote.connection.default.password=userpassword
####################################################################


Note in this file the server host address and port number (by default JBoss AS7 is using the 4447 for remote EJB invocation). It also to remark user / password properties provided in the properties file which must be set because the security-realm is enabled for the subsystem remoting. They must be set by using the command bin/add-user.sh (or.bat). If you do not need the security, just remove the attribute security-realm in the configuration (standalone.xml).


And when launching the client, you should see the next output log.

févr. 21, 2012 10:51:09 PM org.jboss.ejb.client.EJBClient <clinit>
INFO: JBoss EJB Client version 1.0.2.Final
Lookup OK ! Proxy for remote EJB StatelessEJBLocator{appName='project-jee-example', moduleName='project-server-ejb-1.0-SNAPSHOT', distinctName='', beanName='HelloServiceBean', view='interface org.example.jee.service.IService'}
févr. 21, 2012 10:51:09 PM org.xnio.Xnio <clinit>
INFO: XNIO Version 3.0.3.GA
févr. 21, 2012 10:51:09 PM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.0.3.GA
févr. 21, 2012 10:51:09 PM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 3.2.2.GA
févr. 21, 2012 10:51:10 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
INFO: Received server version 1 and marshalling strategies [river]
févr. 21, 2012 10:51:10 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
INFO: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@15a64e6, receiver=Remoting connection EJB receiver [connection=Remoting connection <1f17060>,channel=jboss.ejb,nodename=ak8820]} on channel Channel ID c063cdac (outbound) of Remoting connection 00e2b745 to localhost/127.0.0.1:4447
févr. 21, 2012 10:51:10 PM org.jboss.ejb.client.remoting.ChannelAssociation$ResponseReceiver handleMessage
WARN: Unsupported message received with header 0xffffffff
Message = Hello World



I was very delighted to discover this JBoss AS7 7.1.0 release certified JEE 6 full profile.  A new and improved architecture, fast boot time and new features are in the menu. It’s time to use them …
Thanks. In a second blog entry, I will enhance this example with stateful EJB, asynchronous ejb call, JPA and REST features. …

Wednesday, February 15, 2012

Eclipse RCP P2 self-update


I have been working last time in order to add update mechanism to Eclipse RCP application we have developed in my team. I must confess I struggled for some time with the P2 mechanism and finally I succeeded to obtain the expected result: an RCP based application with an automatic self-update mechanism, using headless build and testable with Jenkins.


Adding self-update to an application is not a ordinary or easy task. There are few examples here, here, or here
I tried different solution and there were always some scenarios that didn’t work properly (headless build did not work as expected,  problems with dependencies in eclipse.equinox.p2.user.ui, plug-in org.eclipse.equinox.ds not started and the most frustrating the updates were not detected). Therefore, my colleagues agreed all that P2 mechanism is "unnecessary complicated".  


Here are steps that I followed in order to have the provisioning mechanism working.
  • Create a feature-based product (a simple RCP Application to which we will add features)
  •  Export the product
  •  Export features to be included in the application
  • Install features to the result application. You may add them manually using the Install New Software menu or use a command line or script. For instance you may use:

%eclipse_home%/eclipsec.exe -application org.eclipse.equinox.p2.director -repository <list_of_comma_separated_repositories>  -installIU <your_feature_group> -destination <location_of_targeted_product>  -profile <profile>
  • Modify your bundles and features version number
  • Export again the features and deploy them optionally on a web server
  • Start your application and check for updates (update sites may be added at he runtime, in the code or using p2.inf file to have pre-defined locations): it should detect the updated features. Additionally, I added headless update at startup as described here

I hope this will help you to have your P2 working. I will publish soon the source code and scripts for this application.

Thursday, December 29, 2011

Exceptions: Best Practices


Last days I had a discussion with few colleagues about best practices on handling exception in the code (more precisely in the JEE application server). As we exposed each one his point of view, we arrived to point the performance issue that may arrive. At that moment, I remembered an older entry on Xebia French blog that illustrated such performance issue related to exception management.

First off all, the author explains that it was not obvious to find the source of its performance problem. Fortunately, he was using an open source framework and he was able to isolate the code causing the problem. In fact there was a method that threw a NoClassDefFoundError at each call. This method body was looking something like that:
try {
 variable = new SomeClass();
} catch (Throwable t) {
    try {
        variable = new SomeNewClass();
    } catch (Throwable t2) {
        variable = new SomeOtherClass();
    }
}
 
I must confess I spent a whole day to find a bug in one of our projects, caused by a similar code in an external jar file that for some reason threw an exception:
try {
 // doing something
} catch (Throwable t) {
};

Another subject that the author illustrates (and the one of the users argued and proved) is that comparing two method calls, one with nominal execution and the other one throwing an exception, there were significant differences on the execution time between the two cases. This is caused, on the one hand by the object creation and on the other hand by the synchronized fillInStackTrace method in Throwable class.

In conclusion, what we have learn from these examples when using exceptions:
  • exceptions must be used in order to handle errors, an exceptional event that disrupts the normal execution of the program; do not use exceptions in order to transfer values, return parameters from methods etc; 
  • if you catch an exception, log an appropriate message or do something that help the debugging
  • do not catch Throwable, Error or RuntimeException (well there may be some exceptions here  :p)

Wednesday, November 16, 2011

To Agile or not to Agile, that is the challenge


Last week I read one of Nicole Bellios articles on true Agile stories. I found this article and the comments very interesting and confirmed me the idea that I have on Agile.

Indeed, Agile has obvious advantages: ability to respond to changing requirements, collaboration with the stakeholder, team interaction. In my company, agile has also brought us more white boards in the rooms and work area :p. Agile is a MUST in some projects, and it proved the added value for the client and for us. Consequently, we have several agile success stories.

On the other hand, we also have a lot of successful projects that followed a classical process. Agile is not always the right answer. Agile does not fit well in all environments (and this is a postulate from Agile defenders). There are many ways to do agile. Or better, we can successfully apply Agile concepts to projects that are not conducted in a pure agile way: continuous integration, intensive tests, stand-up (even if we were sited) meetings etc.

Moreover, there are people thinking that Agile is focusing on team and result forgetting the main actors, the individuals. Not fully sticking with Agile is OK. Agile or not Agile, there are advantages and disadvantages, constraints and benefits, best practices and individuals beats processes and tools, the success of a project is made by motivated people.

Monday, November 14, 2011

Using EMF in standalone Java application


During the last days I was working with Eclipse Modeling Framework (EMF) within the context of an R&D project. As our architecture became distributed, I had to use EMF outside an Eclipse-based application. Therefore, this article deals with us of EMF in a standalone Java application (standalone meaning here not running in en Eclipse framework like server-side components, Swing applications, etc). I will not present here how to use EMF to create models and generate the respective Java code (you may find a good tutorial on that at http://www.vogella.de/articles/EclipseEMF/article.html), but I will focus on using the generated code in a standalone Java application.

Let us remind that EMF project is a modeling framework and code generation facility for building tools and other applications based on a structured data model. Models can be specified using annotated Java, XML documents, or modeling tools and then can be used to produce a set of Java classes for the model, along with a set of adapter, factories and utility classes. You may find information and  documentation about the EMF project at http://www.eclipse.org/modeling/emf/docs/ .

Naturally, EMF (and its subprojects: EMF Core, CDO, Compare, Teneo, Model Query, etc) fits well in an Eclipse environment (Eclipse IDE or RCP). Nevertheless, EMF’s runtime features (use of generated code, notification, change recording, validation, persistence, etc) can be used in a standalone Java application. In order to benefits from EMF in such application, you must add all the needed jars to your classpath. In the book “EMF Eclipse Modelling Framework” you may find a table that clearly identifies the required jars based on the desired feature:

  • Core runtime, reflective API, validation: org.eclipse.emf.common_<version>.jar and org.eclipse.emf.ecore_<version>.jar
  • XML/XMI persistence: org.eclipse.emf.ecore.xmi_<version>.jar and the previous core runtime jars
  • EMF.Edit: org.eclipse.emf.edit_<version>.jar and the core runtime jars
  • Change model: org.eclipse.emf.change_<version>.jar and the core runtime jars
  • Ecore to XML persistence mapping: org.eclipse.emf.mapping.exore2xml_<version>.jar and the core runtime and XML/XMI jars
  • XML schema Infoset Model: org.eclipse.xsd_<version>.jar and the core runtime jars.


When using EMF under Eclipse, the plug-in extension mechanism is used to perform registration at runtime. In a standalone environment, default resource factories are not registered. Therefore, for each file extension or scheme the application wants to load or save, one needs to register the corresponding resource factory. For example, to load and save XML documents, it is necessary to add a similar line in your the application:
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("xml", new XMLResourceFactoryImpl());

In addition, one also needs to register one’s package, which happens as a side effect of accessing XyzPackage.eINSTANCE attribute. For example, to register the example model, it is necessary to add the following lines to the program:
MyEMFExamplePackage.eINSTANCE.eClass();
   ChangePackage.eINSTANCE.eClass(); // only if using EMF change feature

In my application I choose to code a class ResourceManager (which additionally is a Singleton) and put all these registrations in the initialization part of this object.
public class ResourceManager {

 /**
  * Create the resource manager.
  */
 private ResourceManager() {
  
  resourceSet = createResourceSet();

  // register factories
  Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("xml", new XMLResourceFactoryImpl());

  // register packages
  MyEMFExamplePackage.eINSTANCE.eClass();
  ChangePackage.eINSTANCE.eClass(); // only if using EMF change feature
 }

 /**
  * Create the resource set.
  */
 private ResourceSet createResourceSet() {
  ResourceSet rs = new ResourceSetImpl();
  // Register the default resource factory -- only needed for stand-alone
  rs.getResourceFactoryRegistry()
    .getExtensionToFactoryMap()
    .put(Resource.Factory.Registry.DEFAULT_EXTENSION,
      new XMIResourceFactoryImpl());
  rs.setURIConverter(new MapItURIConverter());

  return rs;
 }
 
 // Other methods ...
}

Now that we have registered all needed factories and packages, we can use the code generated by EMF in order to manipulate, save and load objects. In this example I instantiate a “dummy” model and, save it in an xml file. Subsequently,  I load the model and record the modification in order to apply it later.

In this entry, we have seen an example of using EMF outside Eclipse, i.e., in a standalone Java application which could be a server component, a Swing GUI etc. It is to note that in order to use EMF feature in such environment, it is necessary to perform two important steps:

  • Add required jars in the classpath
  • Register Factories and packages prior to model utilization.


/* */