andrewzuercher.com – personal blog site migrated
Greetings,
Greetings,
Zuercher Technologies is making a comeback. As many of you probably already know the Appcelerator Atlanta Office closed down. Some have asked me what is on the horizon and I’ve held back a little to make a formal announcement. Over the next couple of weeks I’ll be putting up a new web front for zuerchtech, but the premise is that I will be starting a services delivery company aimed at helping companies create RIA based web solutions as an Appcelerator partner. I’d like to thank all those who have offered their support over the past couple of weeks and am very excited with the opportunities to come in the near future!
Just implementing resource bundles to localize your application doesn’t quite cut it. You need to do things like work with localized dates in the browser (including formatting), numbers, currencies, and who knows what else to munge your data. It sure would be nice if there were a way to transparently make this happen in a message oriented way that does not require server side awareness for services, can you help me with this problem? sure.
Globalization (G11N) and Localization (L10N) both get lumped into Internationalization (I18N) – how to deal with languages, time, data formats and everything else that goes on making it so that people in different places in the world can use your glorious application. Appcelerator localization helps you out with this on some really simple levels with the langid attribute:
<span langid="account.number.title"></span>:<input type="text"></input>
This should arm you successfully with an ability to deal with things like simple messages and labeling in your application. Now if you want to blend in your data payload to render localized text, you can make use of appcelerator javascript functions Appcelerator.Localization.get and the more powerful but less documented Appcelerator.Localization.getWithFormat.
<script>
var en_lang_bundle = {
"invalidlogin.message": "Dear sir/madame, the username you provided '#{username}' does not exist:"
}
Appcelerator.Localization.addLanguageBundle("en",English",$H(en_lang_bundle));
</script>
<span on="l:invalidlogin.response then value[text]"></span>
<app:script on="r:invalidlogin.response then execute">
var text = Appcelerator.Localization.getWithFormat('invalidlogin.message',null,null,{username:'azuercher'});
$MQ('l:invalidlogin.response',{text:text});
</app:script>This is a nice way to use message indirection for munging messages, but really is quite messy and anything but transparent. There must be a better way!
A lesser known feature of Appcelerator is the concept of interceptors – client side behavior that you can have play in-between the delivery of queued messages to their recipients. In the case for client-2-server orchestration all server requests and their corresponding response messages are enqueued and subject to perversion by interceptors. You just have to know how to implement them. Lets say that whenever I send a CRUD request to the server called ‘r:createorder.request’ I want to add a new attribute called last_modified_utc which is a numerical representation of a utc date as a long. I can add that to the payload to the back end service completely transparently with the Appcelerator.Util.ServiceBroker.addInterceptor method – the method takes a callback to the following:
In the example below I
<app:script> var interceptor = { interceptQueue: function(msg, callback, messageType, scope) { if (messageType=='remote:createorder.request') { msg.data.last_modified_utc = new Date().getTime(); } return true; }, interceptDispatch: function (requestid, type, data, datatype) { return true; }, interceptSendToListener: function (listener, messageType, data, datatype) { if (messageType=='createorder.response') { date = new Date(data.last_modified_utc); data.last_modified = date.toString(); } return true; } }; Appcelerator.Util.ServiceBroker.addInterceptor(interceptor); $MQ('r:createorder.request',{hi:'there'}); </app:script>
Obviously, you can take this a step further and then add interceptors that munge your data conditionally based on the current locale defined in Appcelerator.Localization. The benefit here is that this data transformation happens at a layer outside of my normal pub/sub for messages in Appceleator – the normal pattern is to either replace or add attributes in the payload.
Although not a shrink wrapped solution for I18N in all its glory, its not hard to implement interceptors to do so. Beyond I18N, a lot of other aspects for your messages can be mutated in the browser non-intrusively. Although the key demonstration here is data transformation, you would potentially add other horizontal services into your application.
this article cross posted at http://www.appcelerant.com/using-appcelerator-interceptors-for-i18n-l10n-g11n.html
zuerchtech.com has moved to use the wordpress engine, to view the earlier version and previous posts you can do so at http://oldblog.zuerchtech.com. more will be updated soon
A few weeks ago i started a thread on the Appcelerator development network about remote routes. The thread got a bit of attention and ultimately meant different things to different people.
When I get in front of customers today that have an existing web solution in place, they tend to ask some simple questions:
Primary focus: cost to implement seems to be the main chasm for them to hurdle.
A bunch of the developers out there are jazzed about building RESTfull services to remotely expose an endpoint for integration. Re-using these endpoints is a natural fit for them and paramount to their needs.
Primary focus: A clean single place to define their services.
Then there are the framework guys that are out there that have the need to add Appcelerator to extend their portfolio. Recently I helped out with implementing an Appcelerator service for grails. To facilitate the framework integration I write a similar service broker in grails much akin to what we have done for the other platforms. The controller would discover the Appcelerator services written in grails and then invoke them directly. The downside is that:
Primary focus: not duplicating existing framework functionality in a way that is consistent with their architecture
In the past I’ve prescribed a 4-tiered strategy for those that are out there that are interested in integrating their existing application using Appcelerator;
Instead of writing remote services that are Appcelerator specific and restrictive, an implicit contract is adhered to. This means that back end services can be written in any language or platform so long as they are able to consume and render in an approved format (for example ‘application/json’).
Here is a simple example for a traditional service.
class MyService < Appcelerator::Service Service 'order.create.request', :create_order, 'order.create.response' def create_order order = Order.new(params["amount"]) order.save {'success'=>true, 'id'=>order.id} end end
And now we make use of controllers as well as remote routes. Here is the controller
class OrderController < ApplicationController def create order = Order.new(params["amount"]) order.save respond_to do |format| format.json { render :json => {:success => true, :id => order.id} } end end end
And now in the client we include the following in our javascript (there are a ton of ways to implement this, but here is an example for now)
$MQR('r:create.order.request','/order/create','post', 'r:create.order.response');
| Item | Remote Routes | Appcelerator Service | app:http |
|---|---|---|---|
| Web controllers | Yes | No, must be appcelerator services. | Yes |
| Message Mapping | Yes, client side as javascript to define routes. Concise and not too terribly tedious and can be done in exactly one place. | Server side using annotations to map methods to message types. | Yes, client side widget declarations per message type. |
| Message Multiplexing | One-2-One: a given request message is associated with a single response message and are processed one at a time. | Many-2-Many: this is a big upside for the existing service brokers is that groups of messages can be delivered to the back end at a given time and different types of messages can respond to them | One-2-One: a given request message is associated with a single response message and are processed one at a time. |
| Service Endpoints | Multiple can be supported, the target url is an aspect of the message mapping | Fixed, all requests go through specifically one exposed endpoint (service broker) | Multiple can be supported, the target url is an aspect of the message mapping |
| External Services | Yes | No | Yes |
| Serialization | Up to back end service to implementor | Appcelerator remote service takes care of it for you | Up to back end service to implementor |
Understanding the trade-offs for the different service routing opportunities should be considered when you architect your solution. At the core of it, Appcelerator provides you with options and leaves that decision up to you, empowering you to make that choice for yourself.
this blog has beeen cross-posted at http://www.appcelerant.com/appcelerator-remote-routes-for-service-integration.html
Problem Definition
Are you considering integrating a bunch of web services together but may not feel too comfortable with the vulnerabilities of a mash-up approach, the overhead of setting up and using an ESB, or writing a bunch of mind numbing spilling crushing service transformation code? If thats what you want then, yeah sure that would work for a problem definition.
How does it do it?
The java:axis2 plugin (an appcelerator plugin) installs an appcelerator command that can be run either silently or prompt for input to generate and build axis2 stubs from your WSDL url. Once the stubs have been built, the command then creates a java appceleator-based class with services for each corresponding soap endpoint. The solution makes use of code generation so that you may enhace the services should you so desire. Serialization is also taken care of by transforming to/from the JSON model to the Axis2 model so that making the changes to the service mapping is clean and simple.
How would 1 set it up?
Before you can use the plugin, you need to download axis2 and setup your path appropriately. Its pretty easy, just extract axis2 and set your AXIS2_HOME environment variable. Now you can add the plugin to your java project (named $PROJECT):
app install:plugin java:axis2 cd $PROJECT app add:plugin java:axis2
How do I use it?
Now that you’ve added the plugin, you can now implement the service orchestration for invoking a SOAP endpoint. Lets assume that your wsdl is at http://localhost:8080/axis/services/QueryPort?wsdl. This is how it would flow for you in prompted mode
app gen:axis2 Whats the url for your wsdl? http://LODVM1044:8080/axis/services/QueryPort?wsdl What directory do you want to use for storing the axis stubs? [src/axissource] src/axissource/queryport What package name do you want to use for your axis stubs? [my.axis] queryport.axis What directory do you want to generate the services to? [app/services] app/services What package name do you want to use for your appcelerator services? [my.service] queryport
Alternatively you could run this silently:
app gen:axis2 --axisdir=src/axissource/queryport --axispackage=queryport.axis \ --wsdl=http://localhost:8080/axis/services/QueryPort?wsdl --silent=true --appcpackage=queryport
Here is a sample snippet of the code that will be generated to map your appcelerator services to a web service call:
package cmdb.service; import org.appcelerator.annotation.Service; import org.appcelerator.messaging.Message; public class QueryService { @Service(request = "graphQuery.request", response = "graphQuery.response") public void graphQuery(Message request, Message response) throws Exception { uery param = (axis.query.QueryServiceStub$Query) AxisUtil.toAxisObject(request, axis.query.QueryServiceStub$Query.class, "param"); axis.query.QueryServiceStub$QueryResult result = new axis.query.QueryServiceStub().graphQuery(param); response.getData().put("result",AxisUtil.toMessageDataObject(result)); } }
Note that for this to work you will have to upgrade your Appcelerator installer to 1.1.20+ (next release to be out shortly), I’ve updated mine off of the svn trunk. To check your installer:
app --versionSome more details on how to test
Now the question is, how do i know how to construct my request parameters? You can use the AxisUtil class to help you out, here is a sample snippet for my parameter into the web service, the model class Query:
Query param = createQuery(); //however you want to create your model object System.out.println(AxisUtil.toJSONObject(param).toString());
the request body will directly reflect that ex:
{"query":{"itemTemplate":[{"contentSelector":null,"id":{"value":"ALL_CI1s"}, "instanceIdConstraint":null,"recordConstraint":[],"suppressFromResult":false, "xpathExpression":[]},{"contentSelector":null,"id":{"value":"ALL_CI2s"},"instanceIdConstraint":null, "recordConstraint":[],"suppressFromResult":false,"xpathExpression":[]}], "relationshipTemplate":[{"contentSelector":null,"depthLimit":null, "id":{"value":"ALL_Relations"},"instanceIdConstraint":null,"recordConstraint":[], "sourceTemplate":{"maximum":22,"minimum":0,"ref":{"value":"ALL_CI1s"}}, "suppressFromResult":false,"targetTemplate":{"maximum":0,"minimum":0,"ref":{"value":"ALL_CI2s"}}, "xpathExpression":[]}]}}
This utility will help you to see how the data is structured. For a more detailed example unit test check out SerializationTest.java
Wrap Up
In this post we demonstrated:
this blog cross-posted at http://www.appcelerant.com/java_axis2.html
The Appcelerator framework allows for the extension of the build and deployment process so that you can add components and modify the behavior of your service implementations. It is quite powerful and not only restricted to services, plugins for example could span across to the modification of applications and the entire build and deployment process for that matter. For simplicity, this article will identify how to create a new component added to our java service for monitoring performance.
I’ve assumed that you’ve successfully downloaded and installed Appcelerator from http://www.appcelerator.org/products. Once you’ve gone through the installer you can get the java service
1 | app install:service java |
You may want to get an existing plugin (I needed the java:spring plugin to implement my plugin):
1 | app install:plugin java:spring |
Lets assume that our plugin is going to be called java:perf, to create the plugin project:
1 2 | cd $HOME/workspace app create:plugin . java:perf |
This will create a sub directory named java_perf, now you will want to create a proper license entry in your build.yml for example check out build.yml. You now have the opportunity to modify the entry points in your java_perf.rb. I personally wanted to setup my install script so that:
All of this is in before_add_plugin(event) callback. If you want to see where this is called, check out add_plugin.rb. Once my coding is complete (added my source files to java_perf/src), I created the plugin distribution:
1 | rake zip |
As you noticed, I haven’t covered debugging the plugin just yet, this is because I want to first set up the plugin for installation and then work with it in my install directory. Lets install it to the local machine:
1 | app install:plugin java_perf.zip |
I thought that I’d create a blank java project real quick
1 2 | cd workspace app create:project . myproject java |
now we can add the spring plugin and our new java:perf plugin to our project
1 2 3 | cd myproject app add:plugin java:spring app add:plugin java:perf |
You can now directly modify the java_perf.rb file in your install directory
I suggest that you continue to modify the java_perf.rb this way to debug it and then finalize by copying back over to $HOME/workspace/java_perf
As a final parting you can release your new plugin so that others may be able to leverage it
1 2 | cd $HOME/workspace/java_perf app release java_perf.zip |
-andrew
this article is cross posted at:
http://zuerchtech.com/2008/3/4/implementing-an-appcelerator-plugin
If you are venturing to implement a Rich Internet Application (RIA) with Appcelerator, then there are features about the framework that I’m really geared up about that help you implement your solution effectively. When used together these items enable the agile creation of solutions in a shorter time that integrate nicely with services in an existing architecture and provide a richer user experience for clients.
There are a bunch of ways to do this, personally I leverage app:content files judiciously. You can provide args in the definition of your content files so that you can use the same content file over again. Some things to keep in mind:
here is an example app:content reference
1 2 3 | <app:content lazy="false" on="mainstate[person] then show else hide" args="{'prefix':'person'}"> </app:content> |
here is the content.html file
1 2 | <div id="#{prefix}header" ... </div> |
I know that this may be abstract, but the point is that you can use the arg “prefix” to reuse the file and provide alternative behavior based on it.
You can mock out server side services extremely easily with the framework. This is extremely useful whether your goal is:
Once you have this in place, you have a well defined contract in place which makes knocking out the service implementation a snap.
If you are just working on your application (no service work), you can directly make changes to your application without requiring rebuilding and redeploying your application. In java I typically work directly in my tomcat deploy directory and have an ant task to pull the web files into my workspace. With our next version of the framework coming out, this will be even easier with our support for Jetty coming and the Ruby based command line tool. In the meantime, the following is useful in your java project:
1 | ant pullweb |
Make sure that you have your deploy.dir setup in your $HOME/.ant.properties for example:
1 | deploy.dir=/Applications/apache-tomcat-6.0.14/webapps |
With our Ruby implementation for example, this is even easier (running webbrick directly in your workspace).
I’ve touched a bit on this in a previous post on JSON serialization with Appcelerator java services. To summarize the framework enables
In case you haven’t looked, you dont need to include a form tag anywhere in the application: simply add a fieldset attribute to your input elements and put something like this
1 2 3 4 | <input name="age" fieldset="save_person" type="text"/> <input name="name" fieldset="save_person" type="text"/> <input value="Create Person" fieldset="save_person"/> on="click then r:create.person.request" type="button"/> |
This will create a message of type r:create.person.request with the payload being all your input elements with fieldset of “save_person” ex:
1 | {'name':'jim','age':'35'} |
To me, this is very eloquent solution to leveraging form input elements with a messaging architecture.
I love some of the widgets that are at your fingertips. Some of the ones that i use the most
All these widgets have a very terse usage that is very intuitive. For example, using this set, I was able to knock out a realtime dashboard application in 3 evenings.
Pitching the right framework is something that varies from project to project. For example, possibly your client wants to leverage an existing java infrastructure and is sold on its robustness for scaling enterprise applications, while on the other side possibly you want to take advantage of using a Rails controller and ORM/Active Record implementation for rapid development. On the same level you also have the option for implementing services to customers that deliver in a .Net solution architecture. Many other platforms also exist (python, PHP) enabling the opportunity to plug into those services as well.
The app:get non-visual widget also makes pre-existing services accessible as well and since Messaging is at the heart of the implementation, plugging into an ESB or pure MOM framework is perfectly setup as well.
In this article 7 key tips have been covered
Although there are more items that have not been covered here, these are the ones that appeal personally to me and have noticed a huge gain in doing much more with less effort.
The ability to debug applications is critical when things go sideways on you. I understand that for some of the developers out there learning a new framework can be challenging. Appcelerator provides developers with the tool-set to drastically reduce the amount of javascript code that they need to write and to be honest I think that the more you use the framework, the less you will need to debug applications as you familiarize yourself with the syntax.
Prior to logging, alerts were the best way to display state during execution (showing you how old school I’ve been). Nonetheless, sometimes this is just easier since it blocks execution until you confirm. When you do this, you may want want to display objects. Lets take for example the following
1 | alert(myobject); |
You make get an alert that shows:
Well that isn’t very useful. If you want a nice string representation, use the following
1 | alert(Object.toJSON(myobject)); |
Now you’ll get a nice JSON representation.
Safari and Firefox both provide you with the ability to view logging in the console. For firefox, you need to install firebug. If you are a safari user, you can use webkit (from the Debug menu, click “Show Javascript Console”). Both of which make available a console that displays log statements.
In firefox you can do the following in javascript
1 | console.log("wassup"); |
I suggest however that you dont do that! Instead make use of the abstracted Logger
1 | Logger.info("wassup"); |
This will not only show up in Firefox, but also in Safari’s console.
On another note, you can use the debug=1 parameter in your URL and you will see a ton of appcelerator messages (ex: http:localhos:8080/myapp?debug=1). I will caution you that it will almost look like spam given the amount of detail that is logged, but nonetheless its there if you want it.
You can also expand the Get and Post statements in firefox which will let you know what you have sent in your request and the JSON result that was returned from the server.
Lets say that you have an error in your app:script. Well in Firefox, you can take a look at the console and that will give you some pretty good feedback, however its going to be some cryptic text and you can’t step through it. You have 2 options that will enable you to step through the code:
Here is scenario 1:
1 2 3 | <app:script on="r:someevent.response then execute"> Myapp.dosomething(this.data); </app:script> |
and the corresponding javascript
1 2 3 4 5 | Myapp = Class.create();
Myapp.dosomething = function(data)
{
//code here
} |
For scenario 2: alternatively you could just define in your javascript file
1 2 3 4 | $MQL('r:someevent.response',function(type,msg,datatype,from)
{
//code here
}); |
The downside of this is that your implementation is not colocated in a single html file, but the upside is that you can debug it. Note that if you are not using content files, then you could alternatively define the above in a script element instead (a little cleaner), however if its a large app, then you really will want to decompose your app and use content files.
To be honest I’m not a huge IE fan, but it makes up an install base of 80% of the market. Chances are that pretty much everyone out there is using IE if you are building an application that appeals to the general public. To this end, Microsoft has made the .Net Developer Studio available for debugging your applications. The steps are pretty simple:
For understanding styling, I suggest downloading the Internet Explorer Developer Toolbar. This will allow you to inspect individual elements (using the hover) and then setting styling attributes on your elements. This is much better than changing your html and reloading your page, especially for large applications.
As with IE, you can use the firefox plugin to step through your code.
As with IE, using the Inspect module in firebug is very useful for styling your application.
In this article we covered a bunch of ways that you can get down to the details in your application
For many this may be an obvious repeat of the mechanisms that they currently use as web developers, but hopefully it will uncover some of the tactics that are used.
-andrew
this blog is cross posted at:
http://zuerchtech.com/2008/2/21/debugging-appcelerator-applications
Once you have developed a functional application and are priming for a roll-out, it will be in your interest to tune your application and identify those touch-points which are candidates for tuning. I’ve preferred taking a quantitative approach to performance tuning so that you can compare metrics before and afterwards to identify improvement from a measurable perspective. To this end, it is possible to record statistics both client and server side (currently only for java services). Sometimes the culprit may be server side or client side and determining the area where performance bottlenecks exist is important which is why taking on a triangulation approach is important.
Currently in the client, you can invoke the Appcelerator.Util.Performance component. To enable it, simply include logStats=1 in your url, for example: http://localhost:8080/myapp?logStats=1. The performance component by design will have no impact on your application unless you include this parameter. By default, the servicebroker will calculate the statistics for handling all message types both local and remote. The statistics will include the following:
These statistics will be logged to the console (available in Firefox with Firebug and in Safari with Webkit).
However, you do not need to have logging available to inspect the statistics (please see the section “Viewing Client Side statistics” below). In addition the component also allows for resetting all statistics to restart your recording.
If for some reason you want to capture statistics at a finer level, you can easily to this in javascript:
1 2 3 | var stat = Appcelerator.Util.Performance.createStat(); //do some work Appcelerator.Util.Performance.endStat(stat,"mystat","mycategory"); |
In this example we create a statistic called “mystat” that will be included in a category of “mycategory”. This is useful for filtering through your stats as well as being able to compare statistics side by side. For example, the service broker will automatically record the following categories:
You may want to include the following content file in your application and make it visible when the logStats=1 parameter is included.
Here is the content source itself
clientperformance.html
As you develop larger applications, it may be useful to consider the following tips:
We covered in this article
In a later article we will identify how you can take this a step further to capture statistics on the server side as well with java services.This article has been cross posted on