Monday, 26 December 2011

Accessing Parameters from a Spring AOP 2 Pointcut

I recently had a question from one of our customers, asking how you can access and modify the parameters in Spring AOP 2 - we didn't refer to this on the course as we concentrated on the most common uses of AOP - so here's a quick blog post showing how to do this.

If you haven't used our Spring Fundamentals training course, the full chapter covering AOP is available as a preview below (you can play this at full screen to see the full detail):


Modifying parameters in advice is a very powerful thing thing to do (be careful - powerful means dangerous!), but it can be achieved easily in Spring AOP 2, using the AspectJ syntax.

On the course, we write a performance timing advice class, using Around advice. I've taken the annotation based version from the course, and I've modified it to take one of the incoming parameters (the customerId) and to change it's value before passing it on to the target method.
@Advice
public class ModifyIncomingParameterAdvice
{
 @Pointcut("execution(* com.virtualpairprogrammers.calls.CallHandlingService.recordCall(..)) && args (customerid, call, actions)")
 public void trapRecordCall(String customerid, Call call, Collection actions) {}
 
 @Around("trapRecordCall(customerid, call, actions)")
 public Object changeTheIncomingCustomerId(ProceedingJoinPoint method, String customerid, Call call, Collection actions) throws Throwable
 {
  System.out.println("Asked to record a call for customer id " + customerid);
    
  // run the target code - but with a different customer id!
  String newCustomerId = customerid + "NEW";
  
  // we can pass parameters as an object array - you must get the correct number of 
  // parameters as the target is expecting, or you get a runtime exception.
  Object returnValue = method.proceed(new Object[] {newCustomerId, call, actions});
    
  return returnValue;
 }
}

Notice the use of the args() in the pointcut. This is the important part of this technique. It is applying the pointcut only to invocations of methods called recordCall that have exactly three incoming parameters. And these three parameters are given names which we can use as parameters to the Around advice.

If you want to use the XML form of AOP (I prefer XML for AOP in Spring), then you would just change the pointcut in your Spring XML - a rough example follows:
 
 
 
 
 
  
   
  
 
Notice that I had to escape the ampersands (&) in the pointcut, as you will get an XML error otherwise.

Now, this is a made up and probably useless example, but I hope you can see the power of this. I guess that most projects will very rarely want to use this technique, but I'd be very interested if you've used this on your real world projects - do tell me if you have some examples.

Tuesday, 20 December 2011

Eclipse WTP Tools - Free Module Available to All

We have a new short module for download, at VirtualPairProgrammers.com

When we write our training courses at VirtualPairProgrammers, we are careful to make as much of the course as possible "IDE Neutral". In other words, we want the courses to be useful whether you're using Eclpse, or NetBeans, or IntelliJ, or some other environment (and some still use command line compilers).

We manage this by using a simple Ant script to build and deploy our code to an application server (Glassfish on the JavaEE course, Tomcat on the other courses) - and we've made it so you don't even need to understand Ant to make it work (although I'd recommend any Java developer get to know Ant - it's old and clunky but it still has a lot of value).

In avoiding using particular development environments, it does mean that the courses miss out on showing you how plugins can help. As a kind of appendix to our courses, we've produced a short module (2 sessions of 30 minutes each) showing how the WTP plugins for Eclipse work. There's nothing very complicated in the module, but it does show you how easy it can be to run a Tomcat instance inside Eclipse, whilst automatically deploying your code each time you make a change.

The modules are designed with existing customers in mind, but if you haven't used a VirtualPairProgrammers.com course before, and you're curious, you can download the entire module for free at www.virtualpairprogrammers.com. Just add the product to your cart, go to the checkout and then you'll get access to the course for free.

Do let me know if you find this short module useful - if there's enough interest I'll create a module for NetBeans and maybe IntelliJ.

Friday, 14 October 2011

Glassfish and Tomcat Problems with Java 7

Now that Java 7 is released (finally!), we've had a few reports of problems with our training courses that are using Tomcat or Glassfish.

Both Tomcat and Glassfish are running on top of the Java Runtime (the JVM) which is pointed to by your system's environment variables. When you install Java 7, your system should be updated to be using the version 7 JVM, which Tomcat and Glassfish should run on without problems.

However, some people are finding that after installing Java 7, the compiler is working just fine in their IDE, but at runtime their Tomcat is reporting errors such as the following (You may have to check carefully in the logs for these errors):

Exception in thread "main" java.lang.UnsupportedClassVersionError
or:
java.lang.VerifyError: Expecting a stackmap frame (followed by something scary looking).
Both errors point to that although your code was compiled using version 7, the runtime of your Tomcat or Glassfish is still on version 6 (or older), and eventually this will lead to a crash.

As a check, fire up a command prompt window (I'm assuming you're on Windows, these are the only reports we've had so far), and type the command:

java -version
This will give the runtime version (note that 1.7 means Java 7 and 1.6 means Java 6 - confusing huh?)

If you're seeing the wrong version, I cannot explain why this is happening because I've tried to replicate the situation myself but for me everything installed just fine.

A quick fix is to copy the file called "java.exe" from the directory in which you installed Java 7 (this is often c:\program files\java\jdk1.7.x\bin), across to the c:\windows\system32 directory (you will need to overwrite what is already there). It is probably also wise to copy across the javac and javaw exe files to the same directory.

Now try java -version again, you should now see version 1.7.

A Further Step for Glassfish 3.0 Users

I've discovered that a further step is needed if you're running on Glassfish 3.0. The startup script invokes a script in the glassfishv3/glassfish/config directory, called "asenv.bat". Bizarrely, in Glassfish 3, this script hardcodes the location of the JVM in the final line of the script.

Find the following instruction:

set AS_JAVA=C:\Program Files\Java\jdk1.6.0_25
You can safely delete this line. If the AS_JAVA variable isn't set, the startup script falls back to using just plain "java" to run the JVM (which will now be version 7).

(If you're interested, the reason the copy to system32 works is that your system PATH always includes the /windows/system32 directory. The Java installation program actually drops the JVM and Compiler into this directory, so they will always be found on the command line and by any tools wanting to run a JVM, such as Tomcat. I suspect that for some reason, some installations fail to make the copy and so you're left with the old version.)

Tuesday, 13 September 2011

PrimeFaces DataTable on Glassfish 3.1

Further to my earlier post about Glassfish 3.1 and re-deploy errors, another (minor) problem has also been found with the JavaEE course, this time with JSF pages.

After using the <p:dataTable> from the excellent PrimeFaces library, you will probably find that the boring plain Data Table is still being displayed.

This can fixed by adding a <h:head> and </h:head> before the <h:body> table. You can leave the head tag empty for now, but you would add in all of the usual HTML elements that are needed on any web page's head tag, such as <title> and any meta tags.

Monday, 12 September 2011

Glassfish 3.1 Problems - "operation on a closed EntityManagerFactory"

The JavaEE course ships with a copy of Glassfish 3.0, so you can get started with your training right away. However, as we say on the course, if you'd rather use a more recent version of Glassfish, you should be ok.

Glassfish 3.1 was recently released, and whilst it should be fine, we've had a couple of reports of problems with re-deploying on this version.

When re-deploying you application, you may see the following symptoms:

  • No "JPA" engine is listed on the engines list. This can be ignored, it seems to be a bug on the admin console and JPA will work as usual.
  • However, after a redeploy (NOT an initial deploy), you may get an error, with the following reported in the log:

    java.lang.IllegalStateException: Attempting to execute an operation on a closed EntityManagerFactory.
As far as I can tell, this is a Glassfish admin console bug also. The deployment process should be responsible for opening and closing the EntityManagerFactory, and it looks like it isn't been properly re-opened on re-deployment.

If this happens to you, I can suggest one of the following:

a) Uninstall Glassfish 3.1 and use the version supplied with the course instead. You won't lose any functionality that is important to the course (all I can think of that is missing would be clustering, which isn't needed for the course).

OR

b) Instead of re-deploying, perform a clean deploy by undeploying and then deploying again (remembering to re-enter the Application Name). This is, however, a little tedious to do each time.

We will raise a bug report with Glassfish, in the meantime do let us know if you discover some steps that prevent the problem entirely.

Wednesday, 27 July 2011

Separating Webservice Classes from EJBs

In our JavaEE Video Training Course, we write both a RESTful and a traditional SOAP webservice.

One of the seductive features of JavaEE is that for many situations, it is a trivial job to convert an existing EJB in to a SOAP Webservice with a single annotation. On the JavaEE course, we end up with a class that looks something like this:

@Stateless
@WebService(name="employeeManagementWebService")
public class EmployeeManagementImplementation 
    implements EmployeeManagementServiceRemote, EmployeeManagementServiceLocal {

 @EJB
 private EmployeeDataAccess dao;

 @EJB
 private ExternalPayrollSystem payrollSystem;

 public void registerEmployee(Employee newEmployee) throws SystemUnavailableException 
 {
    dao.insert(newEmployee);
    payrollSystem.enrollEmployee(newEmployee);
 }

 // further code omitted

Line 2 is the line of interest, and with this single line, on deployment you get a WSDL and a Webservice Endpoint for free.

On the course, I do take care to explain that real life situations may not be as simple as this: you may have requirements to change the interface to your clients (perhaps the operation names in the WSDL are different to the method names in the Java), or you may want to handle some complex XML mappings and so on, but the point remains: adding a SOAP layer to an EJB is wonderfully easy, at least at first.

However, a few users have reported that adding the @WebService annotation to an EJB isn't working in Glassfish 3.1. (We supply Glassfish 3.0 as part of the course downloads, but many of our users prefer to use the latest version, which is fine).

This is definitely a bug in Glassfish, but there is a workaround. The workaround sounds like a real pain. But actually it turns out to be a much better way of implementing a webservice, and I would recommend you follow this approach anyway.

The Workaround: Separate the Webservice Class from the EJB Class.


That's right: we're going to turn our back on the seductive feature and go for a longhand - but ultimately better - way.

Step 1: Write a Webservice Class.


This is a brand new class. It is annotated with the @WebService interface. It isn't an EJB as it doesn't have a @Stateless annotation. But each method in the class delegates to an EJB, in this case the EmployeeManagementService.

@WebService(name="employeeManagementWebService")
public class EmployeeManagementWebService implements EmployeeManagementServiceRemote
{
 @EJB
 private EmployeeManagementServiceLocal employeeManagementService;

 public void registerEmployee(Employee newEmployee) throws SystemUnavailableException 
 {
  employeeManagementService.registerEmployee(newEmployee);
 }
  
 // other methods would follow here
}

(Note that I've implemented the Remote interface on my webservice: in fact you don't have to do this, implementing an interface is optional on a JavaEE webservice).

The line of most interest here is line 5, where we are injecting the EmployeeManagementService EJB as a dependency. Notice that I'm using the Local interface - as both the Webservice class and the EJB class are deployed to the same server, I need to ensure that I don't get the performance hit of making remote calls. (This technique is described in detail on the full JavaEE course).

Step 2: Restore the EJB


And now the EJB can have anything related to WebServices removed. I won't show the code here, it will be very similar to our original EJB, just with the @WebService annotation removed.

At first, this may seem ridiculous. It is much more work, you need a whole second class (with a lot of apparent repetition), and yet the end result is the same.

What have we gained?


Put simply, it is better engineering. We have two completely separate concerns here:

1) The interface that we want to expose to our Remote clients
2) The implementation of the management of the business logic

And both of these will need to vary independently. For example, it is more than possible that over time, the webservice interface needs to change. Remember that SOAP webservices are closely related to XML, and there are lot of XML concerns that need to be addressed by our webservice class (a random example - namespace changes).

Although on the training course, our Webservice class is very simple, as your requirements get more serious you are likely to need more and more Webservice related annotations on your class. Without the separation, this would eventually begin to obscure the really important employee management code inside the class.

So, although it is seductive to just drop a "@WebService" annotation on any EJB, think carefully before doing so. Separating the two concerns is easy enough to do, and could save you a lot of pain in the future.

Usually on our courses, we aim to show the professional way of doing things rather than the simple way. This was one area where I really should have thought more carefully.

(Ps - in the REST chapter, I do separate the REST class from the EJB class, but it would be very difficult to combine those two classes anyway, due to the nature of REST).

Tuesday, 17 May 2011

Importing a Project into Eclipse

Several viewers of our Spring MVC course have reported problems in importing the project code that is supplied with the course.

I should really have shown the steps on the videos as it can be quite awkward in Eclipse. There are several different ways of achieving this, but these steps work best for me:

1) Your "Practicals and Code" download contains a "Starting Workspace" folder. Open this as a workspace in Eclipse.

2) Once Eclipse is opened, you will notice that the left hand panel (Package Explorer) is blank.


3) Select "File -> New Java Project".

4) The workspace contains a folder called "MVC Project". This is the project folder. On the New Project wizard, type in exactly the same name - "MVC Project". On typing the final character, you will see that several options are grayed out, and a message is displayed indicating the a new project based on the existing source is going to be created.


5) Click finish, and a full project should now appear in the left hand pane.

Thursday, 7 April 2011

JavaEE 6 Course is Now Released

The great news today is that the JavaEE 6 course is now live at https://www.virtualpairprogrammers.com/courses/JavaEE.html.

This is easily our biggest course yet. I started work on this in November and save a week at Christmas, I've done nothing else so I'm really glad to get it out there!

Here's a quick preview of the course with a run down of all the topics covered.

Saturday, 26 March 2011

Autodeploying in Glassfish

When recording the JavaEE Course, I faced a dilemma: do I use Glassfish's Autodeployment feature or not?

I decided "not". You'll see this if you follow the course: each time a change is made to any of the server side code, we have to run a build and then redeploy to Glassfish manually. It's only a few mouse clicks, but given that we re-deploy hundreds of times, it does get tedious.

So why did I opt not to use Glassfish's perfectly good Autodeployment feature?

It comes from my experience on live courses, where the autodeploy would fail for some minor reason (eg file locking problems, failing to delete a previous installation of a bean, etc). As you're busy learning lots of complex technologies, you tend to assume that you've done something wrong in the code.

Then, you lose hours trying to debug code that is actually working!

So, for simplicity, I use manual deployment through the course. But at some point, you will want autodeployment ON, so I've produced a short video to accompany the course.

It's only 15 minutes, and after following these steps your workflow should be much faster.



But please: as soon as you hit a problem where you've made a change to your code and yet nothing seems to have changed, do check your autodeploy folder for details of any failure.

Note: if you are using autodeployment in the later stages of the course when we are building a web application, it is your WAR file that needs to be autodeployed, not the JAR file.

Tuesday, 1 March 2011

Using Sessions in Spring-MVC (including "scoped-proxies")

On the Spring-MVC video training course, I described three different approaches to handling sessions in Spring.

On the video, I mention that there is also a fourth way, but since the course was getting a bit long I said that I would cover this in a blog post, and here it is.

Thankyou to Bob Casazza for reminding me to do this.

First, a recap of the three approaches described on the video:

1: Use HttpSession directly.

With this approach, you declare HttpSession as a parameter to your controller method. The example on the course looks like this:

public ModelAndView addToCart(@RequestParam("id") int id, HttpSession session)
{
   ShoppingCart cart = (ShoppingCart)session.getAttribute("cart");
   // etc, continue with the cart
}
Pros: it's simple, very much like you would do it in older Spring-MVC and other less capable frameworks.

Cons: it's messy, exposes your clean controller to the Servlet API and needs null checking after you've called getAttribute. Unit testing of your controller is now much harder to do (you need to Mock the HttpSession object).

I don't like this approach, I would avoid it unless necessary (later in the post, I'll explain when I would use it).

2: Scope the Controller

Make your controller session scoped. You can then simply instantiate the object you want to store in session scope as a member variable of the controller...

@Controller
@Scope("session")
public class CartManagementController
{
   private ShoppingCart cart = new ShoppingCart();

   @RequestMapping("/addToCart")
   public ModelAndView addToCart(@RequestParam("id") int id)
   {
      // now just use the cart
   }
}
Pros: A very clean controller, very unit testable.

Cons: A new controller is created for each session, the controller object must be stored in HttpSession. This could bloat the session and in particular could mean replication problems on a large scale system. (Replication: where your web application is hosted on multiple servers. Then the session has to be copied from one server to another. Whilst this is automatic, big sessions cause serious performance problems)

3: Scope the Objects in the Session

This is a narrowing of the session scope, and we session scope just the object we want to store in the session.

@Component
@Scope("session")
public class ShoppingCart
{
   // just a plain java class - member variables and methods as usual
}
Note that the class is now a Spring Bean.

Then, we inject instances of the class into the controller:

@Controller
@Scope("request")
public class CartManagementController
{
   @Autowired
   private ShoppingCart cart;

   @RequestMapping("/addToCart")
   public ModelAndView addToCart(@RequestParam("id") int id)
   {
      // now just use the cart
   }  
}
So, for each request, Spring creates an instance of the controller and then finds the shopping cart from the session.

Crucually, the controller in this approach MUST be request scoped. The default is for Spring to create a global singleton instance of the controller, and this would not work as a singleton is shared by all requests (you can't injection session scoped objects into singleton scoped objects anyway).

Pros: Clean testable controller as in approach two, with the added benefit of the session now only holds the relevant session data.

Cons: A new instance of the controller is created for each request. This is fine if the controller is "small", but if it is expensive to create (ie the constructor is slow for some reason), scalability would be a problem. Also, this approach is harder to understand because of the request scoped controller.

Ok, so they're the three approaches on the course. The problem is they all have drawbacks. I personally almost always use approach 3 where possible, but if I have a "heavy weight" controller, I'd consider using approach 1.

But the fourth approach removes all of the downsides of the previous. The only "con" of this approach is that it is much more complicated. It relies on Spring's best friend: proxies...

4: Use a <aop:scoped-proxy/>

This is covered in full in the Spring Reference manual (at the time of writing, at http://static.springsource.org/spring/docs/3.1.0.M1/spring-framework-reference/html/beans.html#beans-factory-scopes-other-injection)

The general idea of this approach is that you declare your session data as a regular spring bean, with a special tag applied to it (<scoped-proxy>). Your controller will remain a regaular Spring bean, as singleton scope.

With the scoped-proxy tag, your controller looks like it is holding a reference to the session data, but it is actually holding a reference to a proxy which Spring has generated at run time. This proxy's responsibility is to find a session each time it is accessed.

If this is a bit complicated, you might need to check out our AOP session in the Spring Fundamentals video. Or, you can just copy what's here:

Sadly, they haven't created an annotation for scoped-proxy, so your session data (the shopping cart) has to be declared in old-school XML. You add this to your Spring wiring (eg Dispatcher-servlet.xml on the course):

<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

   <!-- an HTTP Session-scoped bean exposed as a proxy -->
   <bean id="shoppingCart" class="com.virtualpairprogrammers.ShoppingCart" scope="session">
      <!-- this next element effects the proxying of the surrounding bean -->
      <aop:scoped-proxy/>
   </bean>
</beans>

Now, your controller looks very simple:
@Controller
public class CartManagementController
{
   @Autowired
   private ShoppingCart cart;

   @RequestMapping("/addToCart")
   public ModelAndView addToCart(@RequestParam("id") int id)
   {
      // now just use the cart
   }  
}
Pros: unit testable and clean as before, only session data is stored in the HttpSession, and the controller is a single-instance global singleton, so no issues with performance of creating them.

Cons: it's much harder to understand (I've taken hours over this post!) and you have to fall back to old fashioned XML wiring.

Conclusion:

The "fourth approach" is probably the most elegant in that it solves all of the technical problems identified earlier. But really, in most situations, approach 3 will be just fine. I have never felt the need to use this fourth approach, it seems like a really heavy solution to the session "problem".

In real life, I've always been happy to use approach 3, and when I'm worried about performance (in the rare case where I'm doing heavy work in the constructor), I'll use approach 1 instead.

I hope no-one minds me omitting approach four from the course, I felt that we had more than enough information on sessions - but I'm glad I've been able to cover it here.

Monday, 28 February 2011

A Fix to Our Spring-MVC Course

Just a quick blog post to alert that there is an error in one of the config files in the Spring-MVC course. I'm uploading a fixed version now, so if you're a user of the course, please download the new "Practicals and Code" folder, or follow these instructions:

If you start your project from the "Starting Code" folder, our web.xml contains the following:

   <!--  we've already configured Spring-MVC for you - nothing to do here! -->         
    <servlet>
       <servlet-name>FrontController</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <load-on-startup>1</load-on-startup>
    </servlet>
  
    <servlet-mapping>
       <servlet-name>FrontController</servlet-name>
       <url-pattern>*.do</url-pattern>
    </servlet-mapping>

However, our Spring XML config file is called "Dispatcher-servlet.xml".

By default, Spring finds it's config file in a web app by taking the servlet name and appending "-servlet.xml" to the end - it then looks for a matching file in /WEB-INF.

If you downloaded the course before the date of this post, please rename the servlet name to Dispatcher (it appears twice in web.xml).

So, your web.xml file should be (in full):

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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"
         version="2.5">
         
    <!--  we've already configured Spring-MVC for you - nothing to do here! -->         
    <servlet>
       <servlet-name>Dispatcher</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <load-on-startup>1</load-on-startup>
    </servlet>
  
    <servlet-mapping>
       <servlet-name>Dispatcher</servlet-name>
       <url-pattern>*.do</url-pattern>
    </servlet-mapping>

</web-app>


Many apologies for the inconvenience this has caused - it was entirely my fault and happened because I changed my naming convention between chapters.

Thanks to David Wubshet and Benjamin Quarless amongst others for flagging up this problem.

Thursday, 17 February 2011

Integrating Spring MVC and a "Real" Database

On the Spring MVC and WebFlow video training course, we build a system from scratch based around a book store. To keep things focussed on the web tier, we use a mock implementation of a service class.

Therefore, we can run the system up without worrying about setting up a database, getting the tables set up etc.

However, I've had a few requests from people who are stuck on "upgrading" their Spring MVC project that uses the Mock. They want to talk to a back end database but for some reason it isn't working.

The best way to work is to start from your Spring-MVC project, and make sure that is working. As on the course, you'll probably have a Dispatcher-servlet.xml file with the web-tier beans, and a separate application.xml containing the "middle-tier" beans.

Now write a production version of your service class, in the same style as on the fundamentals course (for example, service class calls a dao which uses a Spring template to read/write to the db).

As all of the above is covered in both courses, it's just a case of integrating your knowledge.

There are a couple of steps you might need to follow however:

1: Add in missing Jar files

Add in any JAR files that you need for your data access strategy. I used Hibernate 3 (the old XML mapping style, not annotations), and I added:

antlr-2.7.6.jar
dom4j-1.6.1.jar
hibernate3.jar
hsqldb.jar
javassist.jar
jta.jar

If you're using Hibernate with Annotations, or MyBatis or whatever, your dependencies will be different. I simply borrowed these JARs from the project I created on the Spring Fundamentals course.

Step 2: Ensure your mapping files are copied across (Hibernate XML only)

Now for an annoying complication: I'm using the old fashioned but still usable XML mapping approach to Hibernate. I have a file called Book.hbm.xml in my package "com.virtualpairprogrammers.domain".

However, this file is not being picked up by the build script we used on the Spring MVC course. When Eclipse compiles, it copies any non-Java files from the /src folder structure, across to the corresponding folder under /bin.

The ant compile task does NOT do this, however. So I need to manually add this step into my build.xml.

<!-- ensure hibernate XML files are also moved in the compilation -->
<copy todir="${bin}">
   <fileset dir="${src}">
      <include name="**/*.hbm.xml"/>
   </fileset>
</copy>
Note: this is added inside the compile target.

I've uploaded a full sample project to http://vpp-misc-files.s3.amazonaws.com/MVC%20Project.zip. These sample files will only be available for a short period, so grab them while you can.

Tuesday, 15 February 2011

JavaEE 6 with Glassfish is Nearly There!

It's good to report that we're approaching the final stages of recording the JavaEE course. Just two more scripts to write and a few more recording sessions and we're there.

The running order right now looks like this (and it shouldn't change too much in post production):

1: Getting Started with Glassfish
2: Writing an EJB Session Bean
3: JNDI and Calling Remote Session Beans
4: More on Session Beans
5: The Java Persistence API: Mapping Classes
6: JPA2: Updates and Deletes
7: JPA: Relationships
8: JPA2: Queries using JPQL and The JPA2 Criteria API
9: JPA in a Managed Environment: the PersistenceContext
10: Declarative Transactions
11: JSF fundamentals
12: JSF Component Libraries (including Prime Faces)
13: Security in JavaEE
14: Webservices and REST
15: Messaging and Message Driven Beans

This is probably going to turn out to be our biggest course yet.

I decided to cover just one application server, Glassfish, as to cover more than that would confuse and overload the course. But everything on the course should work just fine on other app servers. We may release variants for other servers if there's a demand.

The estimated release time will be early March. The only block in the way is that writing the Webservices and REST chapter is proving very difficult as Webservices is a big topic that is orthogonal to Java. As always, I'll be aiming to make the material understandable to all, so I am having to do a lot of working covering the basics of SOAP, WSDLs, REST and the like.

But it will be worth it! My next post will probably be announcing the course release, so watch this space!