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!

Dealing with JSF ids in CSS and Javascript (JQuery)

Hi everyone,

If you ever had the opportunity to work with JSF applications (or JSF’ish applications like XEO Applications) you may have noticed that most elements in the page have these weird ids like form:input

Imagine the following example in a XEO Application:

<xvw:form id='form'>
   <xvw:attribueText id='name' objectAttribute='username'>
</xvw:form>

The resulting HTML would create a div for the input like the following:

<div id='form:name'>
 ...
</div>

Now, if you want to use Jquery to do something to this element, you would probably do it like this:

$("#form:name")

The problem is that you can’t do this, because in Jquery selectors the colon “:” is a special character and cannot be used like this to select an id. In order for the jquery selector to work you have to escape the colon with a double backslash, like the following:

$("#form\\:name")

But that is one ugly piece of code… you can do the following to ease the pain:

$(document.getElementById('form:name'))

Document.getElementById does not interpret selector, as such there’s no problem having the colon, and since the jQuery selector accepts a DOM element, all is well. If you’re using the XEO Framework, you can do the following as well:

$(XVW.get('form:name'))

And what about CSS? 

Well with CSS the problem is the same, you cannot have the colon in identifiers, so you have to escape it, like the following:

/* Wrong */
#form:name{
 color : red;
}

/* Correct */
#form\:name{
 color : red;
}

There’s just one little problem… this doesn’t work in IE6/7 (shocking, I know). In order to have a compatible solution you need the following:

/* Correct! Compatible with IE 6/7 */
#form\3A name{
  color : red;
}

And I think this pretty much nails it 🙂 Hope it helps someone!
Happy coding!