XEO – EboContext when to create and how to use

Hi everyone,

Today I’ll talk about an important concept in the XEO Framework. The EboContext. Specifically how you should use it, and how you shouldn’t use it.

If you’ve been using the framework, by now you know that whenever you need to load a model instance or create a list of model instances, you need to pass an instance of EboContext to the respective methods, like the following:

boObjectList.list(ctx, “select Model where something=otherthing”);

Most of the times, you can just do the following to get your hands on an instance of EboContext:

EboContext ctx = boApplication.currentContext().getEboContext();

But depending on the things you’ve been doing, you might find that the EboContext instance is null, why is that?
When a request is issued to the XWC Servlet (the Servlet that configured in your web.xml to process any request for files with a .xvw extension), that servlet is responsible for creating an EboContext and associating it to the current thread context and by the end of the request closing it. So each request has the following structure:

  • Browser makes request
  • XWC Servlet creates EboContext instance and associates it to the current context
  • Request is processed
  • XWC Servlet disposes of the EboContext instance

The step that created and associated the EboContext instance is the one responsible for you being able to issue a statement like boApplication.currentContext().getEboContext().

But what if you’re not using the XWC servlet and have some JSP page where you need to deal with XEO Objects? Well in that case you’re responsible for dealing with the EboContext instances. So what do you need to do to create an EboContext instance? See the example:

What’s really important to know about creating EboContext instances?

You MUST ABSOLUTELY CLOSE every instance you EXPLICITLY create

If you create instances of EboContext and don’t close them, pretty soon you’ll run out of database connections 🙂 Talk about resource leakage heh?

Summary

  • In you’re in the context of a .xvw file, no need to create EboContext instances
  • If you’re out of that context, you’re responsible for creating the EboContext instance (and for closing it)
  • If you explicitly create an EboContext instance, you must explicitly close it in a finally statement
  • If you need the EboContext you created, to be accessible via boApplication.currentContext().getEboContext() you need to associated the instance via boApplication.currentContext.addEboContext(ctx).

Hope it helps when dealing with EboContexts!

 

 

Introducing XALPI – Alternative API for XEO Applications

XALPI

Hi everyone,

I’ve been working on an application, using the XEO Framework, for a while now and there were two situations that I wanted to improve. First it was my inability to write unit tests for my application’s logic (using JUnit, for example) and the other was I had trouble finding which attributes were being used where and overall can’t rely on the compiler to help me out. XEO’s API is very flexible and all but I thought that in order to address these two issues I would have to come up with something on my own.

Notice: This work is not associated with the XEO Framework, although I do work at ITDS (which creates the framework), XALPI does not reflect anything but my own opinion and effort on the subject.

Meet XALPI! (beta)

XALPI stands for XEO ALternative API and is a personal attempt to create a more convenient (for me) API and allow the creation of unit tests. It’s an open source project that you can find on Bitbucket, licensed under the BSD license (rev3), meaning you can do just about anything with it.

You can download it here (see the instructions at the wiki page).

So, what makes XALPI different from XEO’s original API?

  • Provides an interface representing each XEOModel with getters and setters for each attribute (see example bellow)
  • Set iFile values using java.io.File instances
  • Get/Set Lov Values using a class instance (good for searching references) instead of the value itself
  • The description of each attribute/model is placed as javadoc in the generated interfaces / classes
  • Provides an easy API to create lists of objects and iterate a list
  • Provides a new Logger abstraction to allow creating application logic to be tested without needing the XEO Logger (which throws a bunch of errors to the error console when the server is not up and running)
  • Reduces the number of boRuntimeExceptions thrown by the API (only update/destroy throw exceptions)

Each of these situations is (I hope) well explained at the wiki. Although some information may still be missing ( it’s beta after all ) I will, to the best of my abilities, complete it as fast as I can.

An example? Compare the following code (current API) :

public void createHistory(EboContext ctx, BigDecimal patientBoui) throws boRuntimeException {
		Timestamp time = DateUtils.getTodayDateAsTimeStamp();
		long boui = patientBoui.longValue();
        boObjectListBuilder builder = new boObjectListBuilder(ctx, "select FileHistory where user = CTX_PERFORMER_BOUI and file = ? and dateOpen = ?").argsList(boui,time).cache(false);
		boObjectList list = builder.build();
		if (list.getRecordCount() == 0){

			if (logger.isFineEnabled()){
				logger.fine("Created fileHistory for " + patientBoui.longValue());
			}

			boObject historyEntry = boApplication.getDefaultApplication().getObjectManager().createObject(ctx, FileHistory.MODEL_NAME);
			historyEntry.getAttribute(FileHistory.USER).setValueLong(ctx.getBoSession().getPerformerBoui());
			historyEntry.getAttribute(FileHistory.FILE).setValueLong(boui);
			historyEntry.getAttribute(FileHistory.DATE_OPEN).setValueDate(DateUtils.getTodayDate());
			historyEntry.update();
	    } 
	}

With this (XALPI) :

public void createHistory(Patient fileOpened, BaseModel user) throws boRuntimeException{

		Timestamp time = DateUtils.getTodayDateAsTimeStamp();
		FileHistoryList history = Select.FileHistory().where("user = CTX_PERFORMER_BOUI and file = ? and dateOpen = ?").args(fileOpened,time).build();

		if (history.isEmpty()){

			logger.fine("Created fileHitroy for %s",user.getBoui());

			FileHistory history = FileHistoryManager.create();

			history.setDateOpen(DateUtils.getTodayDate());
			history.setFile(fileOpened);
			history.setUser(user);
			history.update();
		}

	}

Check out the rest at the wiki page and tell me if you like it. I’m open to suggestions and improvements

Happy coding!

XEO API – Loading, Listing and Iterating

Hi

Today I’d like to showcase a bit of XEO’s API to load, list and iterate instances of XEOModels, which are really basic activities while using the API, so let’s get started:

Loading an instance

You have the following choices when loading an instance

EboContext ctx = boApplication.currentContext().getEboContext();

//Load a specific BOUI, bypasses securities
boObject.getBoManager().loadObject(ctx, "1234"); 
//Load a specific BOUI, respect securities
boObject.getBoSecurityManager().loadObject(ctx,"1234");
//Load using a BOQL Query (query must return a single result)
boObject.getBoManager().loadObject(ctx, "select Example where name = ?",new Objct[]{"name"});
//Load using the BOUI with the ObjectManager
boApplication.getDefaultApplication().getObjectManager().loadObject(ctx, boui);
//Instantiate the ManagerBean and load the object
new boManagerBean().loadObject(ctx, boui);

Be aware that usually there are two paths when loading a boObject. Using the SecurityManager (which respects security policies) and the normal Manager (which bypasses security)

For listing you can do the following:

EboContext ctx = boApplication.currentContext().getEboContext();

//Select without arguments
boObjectList.list(ctx, "select Example");
//Select with arguments
boObjectList.list(ctx, "select Example where name = ?", new Object[]{"name"});
//Select with multiple options
boObjectList.list(ctx, boql, args, page, pageSize, orderBy, fullText, letter_filter, userQuery, useSecurity, useCache);
//Select using a Builder
new boObjectListBuilder(ctx, "select Example where name = ? and other = ?").argsList("arg1","arg2").cache(false).pageSize(3).build();
//Use the builder without the new
boObjectList.builder("select Example where name = ?").arg("name").build();

Listing functions also have a parameter to apply security policies or not.

In case you want to iterate a list you do the following.

boObjectList list = boObjectList.list(ctx, "select Example");
list.beforeFirst();
while (list.next()){
	boObject current = list.getObject();
}

In case you want to iterate a collection attribute, do one of the following

bridgeHandler bridge = obj.getBridge("collection"); 
//Using a bridge handler directly
bridge.beforeFirst();
while (bridge.next()){
	boObject current = bridge.getObject();
}

//Using an "iterator"		
boBridgeIterator it = bridge.iterator();
while (it.next()){
	boObject current = it.currentRow().getObject();
}

That will be all, happy coding!