AIR Cairngorm 2.0
I have received quite a few emails since the release of AIR 1.0 and Flex 3.0 regarding the AIR Cairngorm API which I developed last year. In the time since I have been working primarily with a modified version of AIR Cairngorm which I used on a number of successful real world AIR applications, however I simply have not had the time to document and refactor for general use until recently.
In case you are not familiar with AIR Cairngorm it is an open source project built on top of Adobe Cairngorm which provides a framework for working with the Adobe AIR SQLite API while building an application with Cairngorm.
AIR Cairngorm is built around the SQLService class which essentially wraps the AIR SQL APIs to provide a uniform interface which can be utilized as a service, much in the same way one would work with RPC services in a typical Cairngorm application. SQLService provides an API for both synchronous and asynchronous implementations.
In the time since the initial development and release of AIR Cairngorm, which was during the early alpha releases of AIR, there has been many changes to the SQL APIs in AIR. In addition I have also developed some new best practices for working with Adobe AIR and Cairngorm, all of which I tried to roll into this latest release where possible.
The following is a brief description of the current AIR Cairngorm API:
AIRServiceLocator: The AIRServiceLocator is a sub class of Cairngorm ServiceLocator, therefore it inherits the same API as ServiceLocator while also adding additional support for working with local databases via the getSQLService and hasSQLService methods.
AIRServiceLocator
SQLService: The SQLService class essentially wraps the SQLStatement and SQLConnection classes. SQLService allows developers to create an mxml implementation defined on a Cairngorm ServiceLocator just as one would with typical RPC services (e.g. HTTPServices, WebService etc.)
SQLService
ISQLResponder: ISQLResponder provides a consistent API from which asynchronous SQLStatement execution results and faults can be handled. ISQLResponder is very similar to IResponder in that it defines both a result and fault handler however with a slightly different signature which is specific to a SQLStatement result / fault, (i.e. strongly typed parameters).
ISQLResponder
SQLStatementHelper: SQLStatementHelper is an all static utility class which facilitates substituting tokens in a SQL statement with arbitrary values.
SQLStatementHelper
I have also created a custom version of my Cairngen project specifically targeting AIR Cairngorm code generation. In addition I will be making some future updates to AIR Cairngorm which will include support for various other AIR APIs in Cairngorm, so stay tuned.
Below I have provided downloads to the source, binary, air.cairngen and asdocs as well as asynchronous and synchronous example projects:
source
binary
examples
asdoc
air cairngen
air cairngorm (all)
June 22nd, 2008 at 8:42 pm
Eric,
Nice Work buddy. You should have added all the cell phone minutes that have been eaten up by me for update requests. Yet again you come through for the community.
Nice work,
-Augie
June 30th, 2008 at 12:51 am
Thanks Eric,
All of your work effort for Flex / AIR community is amazing. Thanks for posting this one up.
Cheers,
W.
July 17th, 2008 at 1:07 pm
Really nice. Just in time as Í’m currently experimenting a little bit with both AIR and Cairngorm.
One question.
In your AIRCairngormSyncExample you have specified an userService.
The example seems to indicatie that a SQL service maps to a database file.
When you have multiple services (like an productService, orderService, customerService etc.) do they have to map to multiple database files. I currently have 1 database file containing all my tables. But I want multiple service to organise everything.
How should I do this? Is it just opening referencing to the same database filename? That would also mean multiple opened connections? Will this have some drawbacks?
How do you do this in your projects?
Cheers,
Marcel
July 22nd, 2008 at 5:53 am
Well I figured out myself. I’m just using 1 SQLService and for the rest some delegates.
I dived a little bit into the code and have some questions.
In SQLStatementHelper you are using StringUtil.substitute to create the sql statement. I don’t think this safe related to SQL injection. Shouldn’t you use ? or named parameters instead?
I also noticed that in the execute method the itemClass is only set when it provided (not null). In case statements are reused (and this is the case for the sych executed method!!) then it could happen that a previously set itemClass is used in the query. I don’t know if this could cause any problem, but why not set always the itemClass?
Cheers,
Marcel
July 22nd, 2008 at 7:23 pm
Hey Marcel,
Typically for Web Services (WSDL, REST, XML over HTTP, etc) I define a separate Service on the the ServiceLocator as well as a separate Business Delegate for each service.
For AIR applications utilizing local databases there are two ways to implement this:
A.) Define one Service (for connecting / accessing the database) on the ServiceLocator and then separate Business Delegates for each table.
- or -
B.) Define a separate Service and Business Delegate for each table.
Personally I suggest having one Service for each database as it simplifies debugging the connections as there will only be one connection to manage per database. As far as organizing is concerned this is best achieved by having separate Business Delegates for each table, these delegates would then define all of the operations which can be performed on the respective table.
If conceptually it makes more sense to you to define a separate SQLService object for each Service you could always just sub class SQLService and then define an instance of the sub class for each specific service, thus utilizing the same connection and database while separating the SQLService by function.
Hope that helps,
Eric
July 22nd, 2008 at 7:42 pm
Hey Marcel.
In regards to the SQLStatementHelper I have not had any injection issues because of this therefore I haven’t changed the implementation in this release. With that being said I do plan to make some changes to this implementation in a future update.
In regards to the item class it is a non-issue in the executeAsync method as the SQLStatement object is being re-instantiated in every call. However it is not being re-instantiated in the execute method so I will add an update to this soon.
- Eric
August 28th, 2008 at 12:21 pm
Hey Eric - I just upgraded from your initial blog post version which I had been tweaking. It was pretty smooth update and I’m happy to be back on the official version. My AbstractAIRDelegate is acting as an adapter, implements ISQLResponder and handles the result/fault events internally, converts them to regular mx.rpc Events and passed those back to the initial command/responder. I find this nice and clean so only the delegate communicates with AIRCairngorm and my command and responder classes only deal with VOs and rpc Events. If felt like the command/responder was tightly coupled with AIRCairngorm otherwise, but maybe it’s just me?!
Anyway I have one question regarding execute and executeAsync. Since this behavior is set when the connection is opened - do you think it would be a good idea to keep track of the connection type and throw an exception if execute is called when openAsync was specified, or vice versa? I don’t see in the code where this would be handled.
Thanks for providing this little API, it’s extremely handy.
August 29th, 2008 at 1:29 pm
I get the following error:
Unable to resolve resource bundle “queries” for locale “en_US”.
How to fix this.
Thanks
M
August 29th, 2008 at 7:10 pm
I have fixed the error.
I have many tables in the SQlite database , how to define all the table names.
Thanks
Mark
August 29th, 2008 at 7:23 pm
how to use “create table” to define fields type and fields in air caingorm?
Thanks
M