Just got a new MacBook Pro with Retina display and had a heart attack when 3 days in the display started flashing blue and yellow, almost like a refresh problem. After resetting the NVRAM (which had no effect on my issue), clearing out bad color profiles, deleting caches, etc, I was ready to head to the Mac store. Luckily, I tried one last thing which was to disable Automatic Graphics Switching under the Energy Saver system preference.
Once this was disabled I haven't seen the problem since. Hope this helps someone else! I imagine this happened after an update was applied, but I have no proof of that.
Tuesday, September 29, 2015
Wednesday, July 15, 2015
Reminder of Wirebox Dependency Injection Lifecycle
I remember reading it in the Wirebox Ref Card, but I actually ran into an issue with Wirebox dependency injection and a race condition today. I wanted to blog about it just in case you started with Wirebox without reading the documentation end-to-end ;)
When you are using Wirebox mixin injection to autowire properties, dependencies are not injected until after your pseudo-constructor is called. Here is an example that will fail:
This will cause an error since myDAO has not been injected into the component before init() is called. The solution is pretty simple:
Adding the onDiComplete annotation to the postInit() method tells Wirebox to run the method after it has instantiated the object and injected any dependencies. I did notice that the method must be public which is unfortunate, but it makes sense. This simple example is pretty useless, but in my case I needed to store a query into a singleton on instantiation so this was just the ticket.
When you are using Wirebox mixin injection to autowire properties, dependencies are not injected until after your pseudo-constructor is called. Here is an example that will fail:
component accessors="true" {
property name="myDAO" inject="";
public function init() {
getMyDAO().myMethod();
}
}
This will cause an error since myDAO has not been injected into the component before init() is called. The solution is pretty simple:
component accessors="true" {
property name="myDAO" inject="";
public function init () {
}
public function postInit() onDiComplete {
getMyDAO().myMethod();
}
}
Adding the onDiComplete annotation to the postInit() method tells Wirebox to run the method after it has instantiated the object and injected any dependencies. I did notice that the method must be public which is unfortunate, but it makes sense. This simple example is pretty useless, but in my case I needed to store a query into a singleton on instantiation so this was just the ticket.
Thursday, June 25, 2015
Wirebox: Creating a Transient Object in a Service
Today I had the need to create a transient object outside of the normal places Wirebox lives in a Coldbox application (handlers, interceptors, etc). I come from a ColdSpring background, so I never used CS to handle any of my transients, but I wanted to see how Wirebox handled this so I could keep my object creation centralized.
There are several ways to handle creating a transient object in a ColdFusion service. The easiest is to use createObject() or create a new object using the new keyword right where you need it like this:
var myObj = createObject("component", "path.to.my.Object");
-or-
var myObj - new Object();
Another option is to have your service hand you a new object by defining a load() method:
public myObjectType function load () {
return createObject("component", "path.to.my.Object");
}
The above method works best when using something like CF ORM, where you would specify an optional id parameter and use entityLoadByPK() and return a persistent object. Overkill for what I need here (no persistence in this application).
What I ended up doing to keep my objects coming from a single source (Wirebox) was to inject Wirebox into my service and use the getInstance() method to hand me a transient instance of my object:
Wirebox.cfc
...
map("myObject").to("path.to.my.Object");
...
Service.cfc
component accessors="true" {
property name="wb" inject="wirebox";
...
function myFunc () {
var myObj = getWB().getInstance("myObject");
}
}
I figure doing it this way makes it much easier as I am presently moving around packages, so defining them once in Wirebox means I don't have to perform a search and replace once the packages settle - I just fix the path in the Wirebox configuration and all objects are updated when the application is reloaded.
Note that this works well for transient objects, but remember for singletons you would just inject them into a property in your service tier.
There are several ways to handle creating a transient object in a ColdFusion service. The easiest is to use createObject() or create a new object using the new keyword right where you need it like this:
var myObj = createObject("component", "path.to.my.Object");
-or-
var myObj - new Object();
Another option is to have your service hand you a new object by defining a load() method:
public myObjectType function load () {
return createObject("component", "path.to.my.Object");
}
The above method works best when using something like CF ORM, where you would specify an optional id parameter and use entityLoadByPK() and return a persistent object. Overkill for what I need here (no persistence in this application).
What I ended up doing to keep my objects coming from a single source (Wirebox) was to inject Wirebox into my service and use the getInstance() method to hand me a transient instance of my object:
Wirebox.cfc
...
map("myObject").to("path.to.my.Object");
...
Service.cfc
component accessors="true" {
property name="wb" inject="wirebox";
...
function myFunc () {
var myObj = getWB().getInstance("myObject");
}
}
I figure doing it this way makes it much easier as I am presently moving around packages, so defining them once in Wirebox means I don't have to perform a search and replace once the packages settle - I just fix the path in the Wirebox configuration and all objects are updated when the application is reloaded.
Note that this works well for transient objects, but remember for singletons you would just inject them into a property in your service tier.
Tuesday, June 23, 2015
Maildev for Local Development
Recently at work I was tasked with finding a fake SMTP server that would capture emails for review for environments preceding Production. This is especially useful when you are importing production data for testing across environments and ensuring that your customers don't get test emails. It's something we have all coded around with complex environment configurations in the past, and it offers a much simpler solution.
I looked around at quite a few solutions and most ended up being Windows service based. Being on a Mac they were less than useful, and given that my requirements included the need to move the configuration across multiple environments which are shared by a team of developers, those fell short as none included a web interface for reviewing emails. They all seemed to favor a desktop GUI which could not be viewed without logging in to each server for viewing.
Enter Maildev. Maildev is actively maintained and looks like it has been around for almost year now (probably longer, I'm just going by github commits).
There are a few ways to install, but I installed via npm. It couldn't be simpler:
I looked around at quite a few solutions and most ended up being Windows service based. Being on a Mac they were less than useful, and given that my requirements included the need to move the configuration across multiple environments which are shared by a team of developers, those fell short as none included a web interface for reviewing emails. They all seemed to favor a desktop GUI which could not be viewed without logging in to each server for viewing.
Enter Maildev. Maildev is actively maintained and looks like it has been around for almost year now (probably longer, I'm just going by github commits).
There are a few ways to install, but I installed via npm. It couldn't be simpler:
- Download and install NodeJS/NPM, unless you already have them (as you should!)
- Install Maildev using npm (npm install -g maildev). You'll need to sudo for Mac/Linux.
- Start maildev by typing maildev
Pretty straightforward stuff. Maildev starts on port 1025 by default. The web interface is available at port 1080. Maildev will listen on all IPs by default (0.0.0.0). These are easy to configure using the command line options -s, -w, and --ip.
Installing this across environments permits you to capture emails on each specific environment, and binding Maildev instances to various IPs allows you to isolate email on a per application basis. If you are on windows you can always install Maildev as a service using nssm. On Linux you'd use a combination of forever (maybe) and upstart or chkconfig or whatever your flavor permits. Let's face it, you're on Linux. You'll figure it out.
Maildev also has some nice features like testing your emails in various viewports and viewing headers and attachments.
For my purposes using ACF or Railo, the mail config was moved to the app configuration and switches across environments using Ant filter tasks triggered by Jenkins. I'm sure whatever language you are using has a similar simple configuration option to simplify the task.
Kudos to Dan Farrelly for creating such a useful development tool.
Friday, May 9, 2014
Quick ColdFusion WebSockets Gotcha
I've been playing around with CF WebSockets for a few days now and have just started to work on message filtering. Through the use of a selector I can target messages to a single client (or range of clients). This is great, as there was a bug in the implementation of Flash Remoting and ColdFusion that broke filtering. This meant that I had to send messages to all connected clients and filter on the client side, which as you can imagine is noisy.
Here is the Javascript I am using to subscribe and publish where ws is the ColdFusion WebSocket object created with the cfwebsocket tag:
When I tested filtering I found that all of my messages were being delivered regardless of filtering criteria. I had read previously that if your channel listener CFC implemented the canSendMessage() method, that this would occur. I had removed the offending function but all of my messages continued to arrive regardless of selector criteria.
After much frustration I restarted ColdFusion and everything started working. What seems to have happened is that when CF the Java creates classes from your CFC it picks up on changes within a method, but does not pick up that a method has been removed until the server is restarted (or if the application ends would be my guess). Hope this saves someone some time.
Here is the Javascript I am using to subscribe and publish where ws is the ColdFusion WebSocket object created with the cfwebsocket tag:
ws.subscribe("messaging.friends", {userid: $('#userid').val(), selector: "targetuser eq '"+userselector+"'"}, friendsCallback);
...
ws.publish("messaging.friends", $("#message").val(), {targetuser: $('#userid').val()});
The simple code above subscribes to the messaging.friends subchannel using a selector that jQuery grabs from a web form. The second line of code published a message to that channel with the same targetuser to match the selection criteria.When I tested filtering I found that all of my messages were being delivered regardless of filtering criteria. I had read previously that if your channel listener CFC implemented the canSendMessage() method, that this would occur. I had removed the offending function but all of my messages continued to arrive regardless of selector criteria.
After much frustration I restarted ColdFusion and everything started working. What seems to have happened is that when CF the Java creates classes from your CFC it picks up on changes within a method, but does not pick up that a method has been removed until the server is restarted (or if the application ends would be my guess). Hope this saves someone some time.
Friday, January 4, 2013
BlazeDS Error with an Illogical Fix
I've been having nothing but problems with BlazeDS lately, and I wanted to share an oddity I came across.
Configuration errors are the bane of my existence. I don't want to know how BlazeDS works under the covers, it always just works. That's why I use it, plus it's integration with Adobe ColdFusion and Grails (if you use the BlazeDS plugin).
For the past few days I have been receiving the error:
The message in question occurs when a new person joins a group chat. I send a DTO to CF via the sameRemoteObject, and then the CF sends a message to all clients that care about this specific group chat. This fails with the above error when the client polls for its messages. I am however, able to send the message from a browser test file through the same gateway and Flex receives the message and everyone is happy.
If I make the same call from Flex and disregard the DTO sent from Flex, creating my own DTO on the server side, I also get the error above.
What is weird is the first case works, and the second case does not. The fix was to go into the config file that ColdFusion uses in its gateway config {cfroot}/WEB-INF/cfusion/gateway/config/flex-messaging-gateway.cfg and comment out the line "host=localhost".
The config file states:
While I can't explain what is going on here, I can at least provide the above solution so that someone else can save the 4 days it took me to figure this out. Enjoy!
Configuration errors are the bane of my existence. I don't want to know how BlazeDS works under the covers, it always just works. That's why I use it, plus it's integration with Adobe ColdFusion and Grails (if you use the BlazeDS plugin).
For the past few days I have been receiving the error:
[BlazeDS]Exception occurred during serialization: java.lang.NullPointerExceptionNPE errors are always so helpful. The basic setup is that CF sends an Apache Flex client messages. Message1 occurs when a user signs in. I notify the CF server via a RemoteObject call, and it then pushes a message out to all connected clients using BlazeDS the ColdFusionGateway channel. This is working great and the Flex client receives the message via a consumer subscribed to an AMF polling channel.
The message in question occurs when a new person joins a group chat. I send a DTO to CF via the sameRemoteObject, and then the CF sends a message to all clients that care about this specific group chat. This fails with the above error when the client polls for its messages. I am however, able to send the message from a browser test file through the same gateway and Flex receives the message and everyone is happy.
If I make the same call from Flex and disregard the DTO sent from Flex, creating my own DTO on the server side, I also get the error above.
What is weird is the first case works, and the second case does not. The fix was to go into the config file that ColdFusion uses in its gateway config {cfroot}/WEB-INF/cfusion/gateway/config/flex-messaging-gateway.cfg and comment out the line "host=localhost".
The config file states:
# [Optional] The hostname or IP address of the Flex server.I don't know what it means to install Flex as "part of ColdFusion" but the Flex client is running from the debugger, so it is definitely not part of ColdFusion. I don;t think there has been a Flex Server component since version 1.5. If they mean BlazeDS or Flash Remoting, then, maybe? Either way, the configuration help needs improved upon.
# If omitted, the Flex server is expected to be installed as part
# of ColdFusion. Specify 'localhost' if Flex is on this machine but
# not installed as part of ColdFusion.
While I can't explain what is going on here, I can at least provide the above solution so that someone else can save the 4 days it took me to figure this out. Enjoy!
Thursday, January 3, 2013
ColdFusion 9 and ColdFusion 10 Together - Behind Apache HTTP Server
I have several projects using Adobe ColdFusion 9 and a new one starting on CF 10, so I needed to get CF 10 (running on Apache Tomcat of course) behind an Apache HTTP server. I was having some issues finding anything via Google, but hidden behind a dead page that I could view only in text-mode via the cache was this gem from one of Adobe's ColdFusion engineers, Kavya: Co-existence of ColdFusion9 and ColdFusion10 using Apache web server
I was running a beta version of ColdFusion 10 so I had some issues initially, where the CF 10 instance ignoring the DocumentRoot directive and pushing me into the {cfwebroot}/cfusion/wwwroot directory. One I reinstalled the latest release all was fine.
Two notes from Kavya's post:
I was running a beta version of ColdFusion 10 so I had some issues initially, where the CF 10 instance ignoring the DocumentRoot directive and pushing me into the {cfwebroot}/cfusion/wwwroot directory. One I reinstalled the latest release all was fine.
Two notes from Kavya's post:
- If you are not familiar with Apache HTTP server and are setting it up on multiple ports, you'll need to add Listen directives inside your httpd.conf file (e.g. Listen 81), one port per line.
- I set mine up all listening on port 80 and it worked beautifully. Not sure if anyone still needs the workaround with multiple ports.
Monday, December 31, 2012
BlazeDS Error Solved
I have been working on a fun project that requires a streaming gateway between Adobe ColdFusion and Apache Flex. I had a vanilla installation of CF 9.0.2 (after numerous attempts to configure my current setup) and was consistently getting the error:
Googling brought up the same few posts which were not related to my situation, so I wanted to post the solution here quickly in case I can save someone else 3 days of hair-pulling.
In the end I had to change the definition for the ColdFusionGateway destination in messaging-config.xml. I had to uncomment and set the gatewayhost property to localhost as shown below:
I also don't recall ever having to do this prior to ColdFusion 9.0.2. It is also worth noting that I am on Mac OS X Mountain Lion (10.8) and also reproduced this in 9.0.2 on OS X 10.7.
Regardless, I am back up and running, and if you are reading this I hope this helps you as well.
Unable to find the Flex adapter for destination ColdFusionGateway in the RMI registry on localhost:1099I haven't done much Java in some time and BlazeDS installed with CF 9 is generally pretty simple, so I correctly assumed the problem was configuration related instead of going down a rabbit hole. The problem was that this code was working on another of my machines just fine, and this is a fresh install and the config files matched.
Googling brought up the same few posts which were not related to my situation, so I wanted to post the solution here quickly in case I can save someone else 3 days of hair-pulling.
In the end I had to change the definition for the ColdFusionGateway destination in messaging-config.xml. I had to uncomment and set the gatewayhost property to localhost as shown below:
The help text states:<gatewayhost>localhost</gatewayhost>
If ColdFusion is running on a different host, enter that here. Default is to expect ColdFusion and Flex to share the same web application. You must enter 'localhost' if CF and Flex are not in the same web app.This doesn't make sense since I am calling the messaging component from within ColdFusion (BlazeDS installs with CF 9+). This is why I couldn't figure out what setting needed flipped. I would understand if I was getting this message in my Flex application, as in my current test environment the Flex application I am working on I am running out of Flash Builder in debug mode. The Flex project does not live anywhere within the context of ColdFusion so this setting would make sense.
I also don't recall ever having to do this prior to ColdFusion 9.0.2. It is also worth noting that I am on Mac OS X Mountain Lion (10.8) and also reproduced this in 9.0.2 on OS X 10.7.
Regardless, I am back up and running, and if you are reading this I hope this helps you as well.
Tuesday, July 17, 2012
Quick IntelliJ Tip - Disable Unlimited Whitespace
It drives me nuts when my code has trailing spaces at the end of a line when programming. Why anyone would want this is beyond me. I'm a Mac and running IntelliJ 11.1 Ultimate. To disable this wonky feature I had to do some digging.
What you need to do is go to your IntelliJ IDEA menu and click 'Preferences'. Select 'Editor' from the preferences panel (under IDE Settings) and in the upper right you will see a heading for 'Virtual Space'. Uncheck 'Allow placement of caret after end of line'. Not sure why it is named caret instead of cursor, but who cares. I can now cmd-arrow to the front and back of the line as with Eclipse.
What you need to do is go to your IntelliJ IDEA menu and click 'Preferences'. Select 'Editor' from the preferences panel (under IDE Settings) and in the upper right you will see a heading for 'Virtual Space'. Uncheck 'Allow placement of caret after end of line'. Not sure why it is named caret instead of cursor, but who cares. I can now cmd-arrow to the front and back of the line as with Eclipse.
Wednesday, May 16, 2012
Need ColdFusion 9 with Verity? Go Get it NOW!
Rakshith, the dashingly handsome newlywed ColdFusion Product Manager just posted this on the ColdFusion Blog:
"Our contract with Verity will soon end and we will no longer be able to allow downloads that have Verity in it (CF9/CF8 installers have Verity) post 31st of May."This means, and I can't stress it enough, that if you rely on Verity you need to go grab the 9.0.1 installer right now. The ColdFusion Team will be releasing ColdFusion 9.0.2 on June 1 and purging all pages of 9.0.1 downloads. 9.0.2 will not contain the Verity engine, and only Solr will be an option for searching.
Saturday, March 10, 2012
Some Nifty Adobe ColdFusion 10 Language Changes
I am reviewing the Adobe ColdFusion 10 beta documentation and wanted to point out a few small things I was happy to see. These might not be earth shattering to you, but these will affect the way I write code so I felt it was worth sharing.
Thing 1: for - in syntax for looping queries
ColdFusion 10 (codenamed Zeus) allows us to loop over queries in cfscript using for - in syntax. This syntax was previously used for looping keys in a structure. I had previously mentioned this in my post Dear ColdFusion Team: Please fix this stuff in Zeus as number 4. Maybe someone read my blog, or maybe it just made that much sense ;)
The new syntax looks like this:
How does this affect my code?
It makes life so much easier and code so much more elegant (as ColdFusion is meant to be), especially when you consider the code we write in ColdFusion 9:
It also feels more like the tag based alternative, which I generally think is a good thing.
Thing 2: Retrieve Application Metadata
ColdFusion 10 adds a new function called getApplicationMetadata(). This is pretty cool as when you dump out the application scope you generally only see application variables, with the exception of the application name. The new getApplicationMetadata() function provides insight into the application settings themselves.
How does this affect my code?
I can see several uses for this, but the first one that immediately jumps to mind is that I can sync us my JavaScript timeouts with my session timeouts. That alone is pretty big to me, since I write HTML/Ajax apps. This helps with pingback and timeout redirection. Some of this I can also see being really helpful for framework and 3rd party app developers.
Thing 3: onAbort Application method
Although I now have to change my ColdFusion Application.cfc presentations to stop saying 7 application events ;), I'm happy that this function has been added. What it does is allows you to process the results when you use <cfabort> or abort;. The new application event handler is placed in your Application.cfc file. Here is the syntax, directly from the documentation:
How will this affect my code?
To be honest, I haven't decided yet. I imagine I will be able to start using <cfabort> for more than just debugging, but it hasn't quite solidified in my mind yet.
Thing 4: Ability to slice arrays
I don't need to go too in depth on this one. It's something that I can do in other languages and is an important part of array handling. Here is the syntax, right from the docs:
How will this affect my code?
Easy, I won't have to finagle my arrays. We now have a language construct to slice.
Thing 5: Method chaining in CFCs
Since ColdFusion 6 we have been able to method chain to a certain degree. This worked across multiple CFCs (following the object's composition):
This should not be confused with the new method chaining within beans, which specifically affects mutator methods in our objects (if we have accessors explicitly defined of accessors="true" in our CFC definition). Check this out:
How will this affect my code?
The jury is still out on this one for me. I use method chaining like this in jQuery often. I personally think it makes my code more legible. It is certainly shorter code, but is it really better? Not sure.
Thing 6: Structures now support colon notation
#1 on my Dear ColdFusion Team: Please fix this stuff in Zeus list, I am certainly happy to see this. Railo already did this, as did other ECMAScript based languages such as JavaScript and ActionScript.
Again CF team, thanks for listening!
How will this affect my code?
Easy. I won't have to troubleshoot stupid errors when I move from language to language any more. I can always use the same accepted syntax!
Other stuff
There are plenty of other language changes in ColdFusion 10. Just because I don't use them doesn't mean they aren't great. I encourage you to comment on some that will change the way you code. I bet the directoryCopy() function and <cffile> improvements alone have people thinking in new ways. Oh, and closures.
Thing 1: for - in syntax for looping queries
ColdFusion 10 (codenamed Zeus) allows us to loop over queries in cfscript using for - in syntax. This syntax was previously used for looping keys in a structure. I had previously mentioned this in my post Dear ColdFusion Team: Please fix this stuff in Zeus as number 4. Maybe someone read my blog, or maybe it just made that much sense ;)
The new syntax looks like this:
for ( row in myQuery ) {
fullname = row.fName & row.lName;
}
How does this affect my code?
It makes life so much easier and code so much more elegant (as ColdFusion is meant to be), especially when you consider the code we write in ColdFusion 9:
for ( var x=1;x<=myQuery.recordCount;x=x+1 ) {
fullname = myQuery.fName[x] & myQuery.lName[x];
}
It also feels more like the tag based alternative, which I generally think is a good thing.
Thing 2: Retrieve Application Metadata
ColdFusion 10 adds a new function called getApplicationMetadata(). This is pretty cool as when you dump out the application scope you generally only see application variables, with the exception of the application name. The new getApplicationMetadata() function provides insight into the application settings themselves.
![]() |
| getApplicationMetadata() output |
How does this affect my code?
I can see several uses for this, but the first one that immediately jumps to mind is that I can sync us my JavaScript timeouts with my session timeouts. That alone is pretty big to me, since I write HTML/Ajax apps. This helps with pingback and timeout redirection. Some of this I can also see being really helpful for framework and 3rd party app developers.
Thing 3: onAbort Application method
Although I now have to change my ColdFusion Application.cfc presentations to stop saying 7 application events ;), I'm happy that this function has been added. What it does is allows you to process the results when you use <cfabort> or abort;. The new application event handler is placed in your Application.cfc file. Here is the syntax, directly from the documentation:
<cffunction name="onAbort"
access="public"
returntype="void"
hint="Hanldes Aborted request">
<cfargument type="String"
name="targetPage"
required=true/>
<cfoutput> Target Page: #targetPage#</cfoutput>
<!--- do stuff --->
</cffunction>
}
How will this affect my code?
To be honest, I haven't decided yet. I imagine I will be able to start using <cfabort> for more than just debugging, but it hasn't quite solidified in my mind yet.
Thing 4: Ability to slice arrays
I don't need to go too in depth on this one. It's something that I can do in other languages and is an important part of array handling. Here is the syntax, right from the docs:
<cfscript>
array = [1, 2, 3, 4, 5, 6, 7, 8];
newArray = arraySlice(array, 2, 3);//returns 2,3,4
newArray = arraySlice(array, 4);//returns 4,5,6, 7, 8
newArray = arraySlice(array, -5, 3);//returns 4,5,6
</cfscript>
How will this affect my code?
Easy, I won't have to finagle my arrays. We now have a language construct to slice.
Thing 5: Method chaining in CFCs
Since ColdFusion 6 we have been able to method chain to a certain degree. This worked across multiple CFCs (following the object's composition):
employeeName = company.getEmployee().getFullname();
This should not be confused with the new method chaining within beans, which specifically affects mutator methods in our objects (if we have accessors explicitly defined of accessors="true" in our CFC definition). Check this out:
employee.setName('Bob').setDepartment('Accounting').setFavoriteColor('Green');
How will this affect my code?
The jury is still out on this one for me. I use method chaining like this in jQuery often. I personally think it makes my code more legible. It is certainly shorter code, but is it really better? Not sure.
Thing 6: Structures now support colon notation
#1 on my Dear ColdFusion Team: Please fix this stuff in Zeus list, I am certainly happy to see this. Railo already did this, as did other ECMAScript based languages such as JavaScript and ActionScript.
st = {
name: 'Richard',
age: 44,
favoriteColor: 'Purple'
}
Again CF team, thanks for listening!
How will this affect my code?
Easy. I won't have to troubleshoot stupid errors when I move from language to language any more. I can always use the same accepted syntax!
Other stuff
There are plenty of other language changes in ColdFusion 10. Just because I don't use them doesn't mean they aren't great. I encourage you to comment on some that will change the way you code. I bet the directoryCopy() function and <cffile> improvements alone have people thinking in new ways. Oh, and closures.
Friday, March 9, 2012
Railo, Tomcat and Apache on Amazon EC2 Ubuntu AMI
About this guide
This guide is long because I wanted to give some background info so you can not only install Railo on an Amazon Ubuntu AMI, but so that you understand why you are doing what you are doing. If you want to see how easy this is, just skip from gray block to gray block below. There are 13 actual commands to install Apache, Railo and Tomcat. There are 7 lines of configuration to paste into two config files. It doesn't get much easier.
Background on why I tried Railo in the cloud
So I've been very fortunate in my life to have been a ColdFusion developer, Ajax developer, Adobe trainer, digital media developer, Flex developer, product manager, project manager, task lead, agile trainer and Director in my short life, which has put me in the unique position to be contacted by start ups for advice on how to get going quickly using an Agile methodology. The exciting part about this skill set is I get to help them plan their technology stack, development and deployment methods including Scrum, continuous integration, continuous builds, etc.
Now, one thing I am always sure to say is that ColdFusion should be a part of that technology stack. See, I use ColdFusion differently than many of you. I use it almost exclusively as a service tier. I use Flex or HTML/Ajax for my interaction tier and ColdFusion only exists to proxy information and handle my business logic. ColdFusion does an awesome job of this and with most start ups needing to get to minimum viable product quickly with low overhead, ColdFusion just makes sense.
Over the past 5 years I've had the luxury of working with one start up where money was no problem. They had the best of everything from a custom data center to 5 rows of racks filled with servers and all the software and processing power we could ever need. That has happened exactly ONE time. Most of the start ups I have worked with are cash poor, but idea rich. The idea that I can take ColdFusion and deploy it to the cloud with virtually no long term commitment is just plain awesome for them. They can shut down the next day if they had to, or they could add another 10 servers in minutes. With Amazon I helped take one company from $80k per month in data center costs down to $3k a month. With savings like that a few Adobe ColdFusion Enterprise licenses were easy to sell.
Recently I have wanted to test Railo in the cloud as an alternative to Adobe ColdFusion for start ups, for no particular reason. This guide is a result of that test.
Why Amazon
So I chose Amazon as my virtual host for 3 reasons:
Amazon EC2
I've found that Adobe ColdFusion runs great even on Amazon micro instances, depending on load and what sort of application you are running. I usually will go with a small or large instance though for a service tier. Amazon recently released medium instances, but I have not been able to test them yet. For Railo I also deployed to a micro instance, mainly since this was a test.
I'm not going to go through the process of creating a new Amazon EC2 instance, but I will say that I deployed to Ubuntu 11.04 Natty Narwhal. I am using the 64-bit version. Your mileage may vary with other versions.
Deploying an instance takes about 5 minutes. When done you can assign a security group or edit the default. If this is for a public site you'll probably also want to add an elastic IP (which acts as a static IP for DNS).
Get Ubuntu Up To Date
The first thing to do is to update Ubuntu
Apache Installation
Next, we need to get Apache HTTP Server set up. You technically don't need to use Apache HTTP as Apache Tomcat can serve the pages for you just fine. I am using Apache HTTP server for familiarity and extensibility.
Get Railo
To install Railo I used the Tomcat/Railo installation from getrailo.org. You may want to have more control over it than I wanted. I did also deploy Tomcat6 on Ubuntu the one time and downloaded Railo and deployed it manually. It wasn't hard, but the pre-rolled installer worked just great. The commands below are for the current version of Railo (3.3.1) at the time of this writing. I am also using the 64-bit version. Just go to getrailo.org to grab the latest correct version for your OS.
The installer works great on Ubuntu. All of the defaults should be fine. The only things I changed were the user Railo was running under (I called it 'railo', the default is 'root' so I suggest you change it) and the default Tomcat port. The text below is a snapshot of those settings:
Test Railo
Well, you now have Railo installed on Tomcat. Go test Railo by going to http://localhost:8080 and you will see the welcome page. If you want to test remotely, be sure to add 8080 as an incoming TCP rule in your Amazon security group for the Railo instance.
Connect Railo to Apache
The hardest part for me was getting Railo to work with Apache. There are lots of guides around, but none simple enough for me. I'll paste the steps below in one place as that's what I had problems finding. During installation Apache was configured for the Tomcat connection. There are a few things we need to do yet.
First, you'll need a few mods to help proxy requests from Apache HTTP to Apache Tomcat. It is my understanding that this does the same job as the Adobe ColdFusion connector does. Some of these might already be enabled, but it won't hurt to try adding them. In older versions of Apache HTTP these would be in your httpd.conf file as includes. Now, the a2enmod command will symlink the modules from mods-enabled to mods-available.
If you are familiar with older versions of Apache HTTP, you'll understand we need to create a virtual site. This virtual site will allow us to define a server name and link it to a host in our Tomcat configuration. Your virtual host might be more complex than the one below, specifying directory Aliases and custom logs, but what you see below is the minimum. In older versions of Apache you would be putting these entries into extra/httpd-vhosts.conf which are included in httpd.conf. That would work as well, but in the current version you create a file in the /etc/apache2/sites-available directory with the name of your site. The file below, for nictunney.com, is found at /etc/apache2/sites-available/www.nictunney.com.
Next, you'll need to enable that site (creating a symlink from sites-enabled to sites-available). In older versions of Apache you just include the httpd-vhosts file in the main httpd.conf. In the newer version you use a2ensite.
Configuring Tomcat
The next thing we have to do is tell Tomcat about the site. This is done in the server.xml file. If you are following my instructions this is located at /opt/railo/tomcat/conf/server.xml. To configure Tomcat you need to add a Host entry. This needs to be done inside the AJP connector definition (search for '8009' in server.xml). Make sure to put this inside the Engine definition for Catalina. I put mine directly under the Host definition for 'localhost'. Note that the docBase directory matches the directory I defined in my Apache site configuration. Put yours wherever, but make sure they match.
Finishing up
All that is left to do is restart Apache HTTP server and Apache Tomcat.
Caveat
I had fits at this point and was getting 500 errors. Luckily I have Mark Drew on IM and he found my issue quickly. Permissions were wacky on my webroot (/var/www) by default. I had to change them to 766, changed the owner to the railo user and set the group to staff. You might have differing opinions on how to secure your own web directory.
Initially I had some issues getting Railo up and running as Tomcat was new to me (I deployed to Tomcat), but I figured it was worth learning since Adobe ColdFusion is also coming on a version of Tomcat starting in ColdFusion 10. The cool thing about deploying to the cloud is I was able to terminate my existing instance and reload from scratch in about 15 minutes. I did this 4 times. I love cloud deployment!
I had help
Much thanks goes to Mark Drew for taking them time to sort out my error, letting me see his config files and helping me determine what mods I needed in Apache HTTP server, and to the following folks on Twitter who helped me at various points along the way, being very patient with my Tomcat n00b-ness. Several of them have tutorials and installation scripts as well, so please give them the proper nod and thanks, in order of appearance:
@talltroym
@azawaza
@gert_railo
@kwispel
@webRat
@bluewebtech
@mikehenke
@mpwoodward
@markdrew
This guide is long because I wanted to give some background info so you can not only install Railo on an Amazon Ubuntu AMI, but so that you understand why you are doing what you are doing. If you want to see how easy this is, just skip from gray block to gray block below. There are 13 actual commands to install Apache, Railo and Tomcat. There are 7 lines of configuration to paste into two config files. It doesn't get much easier.
Background on why I tried Railo in the cloud
So I've been very fortunate in my life to have been a ColdFusion developer, Ajax developer, Adobe trainer, digital media developer, Flex developer, product manager, project manager, task lead, agile trainer and Director in my short life, which has put me in the unique position to be contacted by start ups for advice on how to get going quickly using an Agile methodology. The exciting part about this skill set is I get to help them plan their technology stack, development and deployment methods including Scrum, continuous integration, continuous builds, etc.
Now, one thing I am always sure to say is that ColdFusion should be a part of that technology stack. See, I use ColdFusion differently than many of you. I use it almost exclusively as a service tier. I use Flex or HTML/Ajax for my interaction tier and ColdFusion only exists to proxy information and handle my business logic. ColdFusion does an awesome job of this and with most start ups needing to get to minimum viable product quickly with low overhead, ColdFusion just makes sense.
Over the past 5 years I've had the luxury of working with one start up where money was no problem. They had the best of everything from a custom data center to 5 rows of racks filled with servers and all the software and processing power we could ever need. That has happened exactly ONE time. Most of the start ups I have worked with are cash poor, but idea rich. The idea that I can take ColdFusion and deploy it to the cloud with virtually no long term commitment is just plain awesome for them. They can shut down the next day if they had to, or they could add another 10 servers in minutes. With Amazon I helped take one company from $80k per month in data center costs down to $3k a month. With savings like that a few Adobe ColdFusion Enterprise licenses were easy to sell.
Recently I have wanted to test Railo in the cloud as an alternative to Adobe ColdFusion for start ups, for no particular reason. This guide is a result of that test.
Why Amazon
So I chose Amazon as my virtual host for 3 reasons:
- Price - can't be beat on processor time cost, and from what I remember, all incoming bandwidth is free. This is especially important when you are working with digital media.
- Familiarity - I've always used Amazon. The Amazon Management Console makes sense to me and I understand the pricing structure.
- Reach - They have data centers all over the place, and Amazon has always been very reliable.
Amazon EC2
I've found that Adobe ColdFusion runs great even on Amazon micro instances, depending on load and what sort of application you are running. I usually will go with a small or large instance though for a service tier. Amazon recently released medium instances, but I have not been able to test them yet. For Railo I also deployed to a micro instance, mainly since this was a test.
I'm not going to go through the process of creating a new Amazon EC2 instance, but I will say that I deployed to Ubuntu 11.04 Natty Narwhal. I am using the 64-bit version. Your mileage may vary with other versions.
Deploying an instance takes about 5 minutes. When done you can assign a security group or edit the default. If this is for a public site you'll probably also want to add an elastic IP (which acts as a static IP for DNS).
Get Ubuntu Up To Date
The first thing to do is to update Ubuntu
$ sudo apt-get update
$ sudo apt-get upgrade
Apache Installation
Next, we need to get Apache HTTP Server set up. You technically don't need to use Apache HTTP as Apache Tomcat can serve the pages for you just fine. I am using Apache HTTP server for familiarity and extensibility.
$ sudo apt-get install apache2
Get Railo
To install Railo I used the Tomcat/Railo installation from getrailo.org. You may want to have more control over it than I wanted. I did also deploy Tomcat6 on Ubuntu the one time and downloaded Railo and deployed it manually. It wasn't hard, but the pre-rolled installer worked just great. The commands below are for the current version of Railo (3.3.1) at the time of this writing. I am also using the 64-bit version. Just go to getrailo.org to grab the latest correct version for your OS.
# get the railo tomcat installer
$ wget http://www.getrailo.org/down.cfm?item=/railo/remote/download/3.3.1.000/tomcat/linux/railo-3.3.1.000-pl1-linux-x64-installer.run -O railo-3.3.1.000-pl1-linux-x64-installer.run
# make it executable
$ sudo chmod +x railo-3.3.1.000-pl1-linux-x64-installer.run
#run the installer
$ sudo ./railo-3.3.1.000-pl1-linux-x64-installer.run
The installer works great on Ubuntu. All of the defaults should be fine. The only things I changed were the user Railo was running under (I called it 'railo', the default is 'root' so I suggest you change it) and the default Tomcat port. The text below is a snapshot of those settings:
Installation Directory [/opt/railo]:
Tomcat Administrator Username [admin]:
Tomcat Administrator Password []: ##########
Tomcat Port [8888]: ####
Tomcat System User [root]: railo
Yes, Start Railo at Boot Time [Y/n]:
Install Apache Connector? [Y/n]:
Please choose an option [1] : (Apache 2.2)
Please choose an option [2] : (64-bit)
Apache Control Script Location [/etc/init.d/apache2]:
Apache Modules Directory [/usr/lib/apache2/modules]:
Apache Configuration File [/etc/apache2/apache2.conf]:
Apache Logs Directory [/var/log/apache2]:
Test Railo
Well, you now have Railo installed on Tomcat. Go test Railo by going to http://localhost:8080 and you will see the welcome page. If you want to test remotely, be sure to add 8080 as an incoming TCP rule in your Amazon security group for the Railo instance.
Connect Railo to Apache
The hardest part for me was getting Railo to work with Apache. There are lots of guides around, but none simple enough for me. I'll paste the steps below in one place as that's what I had problems finding. During installation Apache was configured for the Tomcat connection. There are a few things we need to do yet.
First, you'll need a few mods to help proxy requests from Apache HTTP to Apache Tomcat. It is my understanding that this does the same job as the Adobe ColdFusion connector does. Some of these might already be enabled, but it won't hurt to try adding them. In older versions of Apache HTTP these would be in your httpd.conf file as includes. Now, the a2enmod command will symlink the modules from mods-enabled to mods-available.
# add the necessary mods for Apache HTTP Server
$ sudo a2enmod proxy
$ sudo a2enmod proxy_http
$ sudo a2enmod proxy_scgi
$ sudo a2enmod proxy_balancer
If you are familiar with older versions of Apache HTTP, you'll understand we need to create a virtual site. This virtual site will allow us to define a server name and link it to a host in our Tomcat configuration. Your virtual host might be more complex than the one below, specifying directory Aliases and custom logs, but what you see below is the minimum. In older versions of Apache you would be putting these entries into extra/httpd-vhosts.conf which are included in httpd.conf. That would work as well, but in the current version you create a file in the /etc/apache2/sites-available directory with the name of your site. The file below, for nictunney.com, is found at /etc/apache2/sites-available/www.nictunney.com.
<VirtualHost *:80>
ServerAdmin admin@nictunney.com
DocumentRoot "/var/www"
ServerName www.nictunney.com
</VirtualHost>
Next, you'll need to enable that site (creating a symlink from sites-enabled to sites-available). In older versions of Apache you just include the httpd-vhosts file in the main httpd.conf. In the newer version you use a2ensite.
$ sudo a2ensite www.nictunney.com
Configuring Tomcat
The next thing we have to do is tell Tomcat about the site. This is done in the server.xml file. If you are following my instructions this is located at /opt/railo/tomcat/conf/server.xml. To configure Tomcat you need to add a Host entry. This needs to be done inside the AJP connector definition (search for '8009' in server.xml). Make sure to put this inside the Engine definition for Catalina. I put mine directly under the Host definition for 'localhost'. Note that the docBase directory matches the directory I defined in my Apache site configuration. Put yours wherever, but make sure they match.
<Host name="www.nictunney.com" appBase="webapps">
<Context path="" docBase="/var/www" />
</Host>
Finishing up
All that is left to do is restart Apache HTTP server and Apache Tomcat.
$ sudo service apache2 restart
$ sudo /opt/railo/railo_ctl restart
Caveat
I had fits at this point and was getting 500 errors. Luckily I have Mark Drew on IM and he found my issue quickly. Permissions were wacky on my webroot (/var/www) by default. I had to change them to 766, changed the owner to the railo user and set the group to staff. You might have differing opinions on how to secure your own web directory.
Initially I had some issues getting Railo up and running as Tomcat was new to me (I deployed to Tomcat), but I figured it was worth learning since Adobe ColdFusion is also coming on a version of Tomcat starting in ColdFusion 10. The cool thing about deploying to the cloud is I was able to terminate my existing instance and reload from scratch in about 15 minutes. I did this 4 times. I love cloud deployment!
I had help
Much thanks goes to Mark Drew for taking them time to sort out my error, letting me see his config files and helping me determine what mods I needed in Apache HTTP server, and to the following folks on Twitter who helped me at various points along the way, being very patient with my Tomcat n00b-ness. Several of them have tutorials and installation scripts as well, so please give them the proper nod and thanks, in order of appearance:
@talltroym
@azawaza
@gert_railo
@kwispel
@webRat
@bluewebtech
@mikehenke
@mpwoodward
@markdrew
Wednesday, March 7, 2012
Cryptic ColdFusion ORM Hibernate Error
Troubleshooting an old Adobe ColdFusion 9 application of mine today and was getting this error message:
Here is the snippet of code that checks to see if the domain already exists, and creates the object if it does not:
The moral is that the error can be thrown when we are trying to save a disconnected object with ColdFusion ORM's entitySave() that already exists in our persistence layer. Hopefully this helps someone else make some sense of their issue!
HIBERNATE ERROR - Exception executing batch:Now I also saw an error about a foreign key at one point, but who knows why. The issue was being caused during a value update. The goal is to allow the user to create a new object of type Domain inline. It's simple really, they just enter the Domain text and on the back end I make sure the Domain doesn't already exist before creating the domain and adding it to its parent entity (which they are editing at the time).
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
Here is the snippet of code that checks to see if the domain already exists, and creates the object if it does not:
// try to load the domain by the passed name
var domain = entityLoad("Domain", {name=arguments.value, project = o.getProject()}, true);
// if it doesn't exist, we need to create a new domain for this project
if ( NOT structKeyExists(local, 'domain') ) {
domain = entityNew('Domain');
domain.setName(arguments.value);
domain.setProject(o.getProject());
entitySave(domain);
}
o.setDomain(domain);
So what is happening above is we try to load the Domain, if it doesn't exist we create it, set the bi-di relationship to the project and then save it. The Domain is then added to the parent object. When the error is thrown no line number is given (cryptic, remember).
So the most curious thing was I had another object type that was working fine. I compared them, and saw the error in my ways. Here is the offending object:
<cfcomponent persistent="true" table="sel_domain" output="false" entityName='Domain'>
<!---- properties ---->
<cfproperty name="id" column="id" type="numeric" ormtype="int" fieldtype="id" generator="increment" />
<cfproperty name="name" column="domain" type="string" ormtype="string" />
<cfproperty name="color" column="color" type="string" ormtype="string" default="" />
<cfproperty name="project" cfc="com.Project" fkcolumn="projectID" fieldtype="many-to-one" />
<cfproperty name="entities" singularname="entity" fieldtype="one-to-many" cfc="com.Entity" fkcolumn="domainid"/>
<cffunction name="init" returntype="Domain" access="public" output="false" hint="Constructor">
<cfscript>
setID(-1);
</cfscript>
<cfreturn this />
</cffunction>
</cfcomponent>
Can anyone guess what the issue is? If not, don't feel bad. Took me about 20 minutes to figure it out with the stack trace in front of me. I forgot to add the unsavedvalue="-1" to the id field. This can be fixed by adding that attribute, or in the case of the working object, simply removing the init() function.The moral is that the error can be thrown when we are trying to save a disconnected object with ColdFusion ORM's entitySave() that already exists in our persistence layer. Hopefully this helps someone else make some sense of their issue!
Tuesday, February 28, 2012
Adobe Flash Roadmap
I've been reading the Adobe Flash Roadmap published last week and wanted to post a few thoughts. If you haven't read it yet, it isn't a long read so perhaps hop on over there and read it for yourself before you read my opinions.
So, no doom and gloom here. Really this is the way it seems Flash has been moving for a few months now so there are no huge surprises. The first point I'd like to make is based on this text:
Looking forward, Adobe believes that Flash is particularly suited for addressing the gaming and premium video markets, and will focus its development efforts in those areas. At the same time, Adobe will make architectural and language changes to the runtimes in order to ensure that the Flash runtimes are well placed to enable the richest experiences on the web and across mobile devices for another decade.So this is no huge surprise if you look at the effort Adobe has been putting into 3D rendering and graphics acceleration. I actually think this could be an awesome thing and would argue that the next big thing on the web will be multiplayer and social Flash based games. Not Farmville, but immersive experiences with lots of video and realism. I like the idea of architectural and language changes to speed things up. My first worry though is how the Apache Flex project will adapt to these changes. It will be imperative for the Adobe operatives in the Apache project to voice their opinions loudly, but it might become a debacle like the CFML steering committee. More on this later. The next point I'd like to make deals with:
With the growth of competition in the browser market, browser vendors are increasingly innovating and providing functionality that makes it possible to deploy rich motion graphics directly via browser technologies, a role once served primarily by Flash Player. Increasingly, rich motion graphics will be deployed directly via the browser using HTML5, CSS3, JavaScript and other modern web technologies. While the primary role of Flash Player as an engine for innovation on the web remains the same, what it is used for will change.Well, here I take issue. I feel that HTML5 is about 2 years away from being a solution we can use for "rich motion graphics". With all of the hype around HTML5, people forget that not only does it have serious cross-browser support issues, but it also doesn't even contain many features that are considered standard and must-have in the Flash environment. Have you actually tried to deploy a video player across browsers and devices in HTML5? Phew. While I'm excited for the future of HTML5, and while everyone else is trying to find the next Javascript framework, I'll keep pushing out high quality apps for my clients using Flex and Flash today. For those of you who know me, you know that I love to tinker with video encoding, transcoding and delivery so this next one is important:
Adobe believes that Flash Player will continue to stay at the forefront of online video by innovating in key areas. These include the following:Nothing here isn't exciting, and it all makes sense. I'm excited to see how they continue to innovate with DRM and analytics. Even more importantly, and so I don't geek out on the video stuff, is this line:Adobe believes that Flash has a number of fundamental and unique advantages for video:
- Bringing Adobe's video streaming and content protection technology to more platforms in native formats
- Supporting the needs of premium content owners
- Closer collaboration with hardware vendors to provide high-performance quality experiences
- Single and consistent player and codec support across browsers, platforms, and operating systems
- Support for content protection (single DRM), which enables premium video content to be licensed for online distribution
- Mature, full-featured, proven solution that provides a "mission critical" video platform for premium content owners, including support for ad insertion and analytics
Single and consistent player and codec support across browsers, platforms, and operating systemsWhat I want to point out is that this closely mirrors my thoughts on why Flash and Flex are awesome. Why does Adobe embrace this with video, but they seem to forget that this is why Flex and Flash are awesome: penetration, cross-browser support, cross-OS support. I understand that Adobe is a tools company, but lets just see what Flash Next does to Flex. A few Flash Player roadmap nuggets to point out. These should be pretty exciting for game developers:
Now, here is an "are you freaking kidding me?" moment. I wish we could've done this with Flex applications for years:
- Support for more hardware accelerated video cards (from January 2008) in order to expand availability of hardware-accelerated content.
- New Throttle event API (dispatches event when Flash Player throttles, pauses, or resumes content)
- Multithreaded video decoding pipeline on PCs, which improves overall performance of video on all desktop platforms
Keyboard input support in full-screen modeThe possibilities for video delivery in full-screen mode with keyboard input are immense. It closes the gap between set top based AIR apps and their sister applications on the web. I am not sure how they decided to handle security, but I'd be interested in seeing how this plays out. Here is a language enhancement that will have a far reaching effect. Sit and chew on this one for awhile and you will understand:
ActionScript workers (enables concurrent ActionScript execution on separate threads)And now the meat:
Below are a few items being explored for the next generation of the ActionScript language and virtual machine:So it is no secret that I love ActionScript. I'm all about improvements and the improvements above are exciting (well except for the last bullet unless it is implemented passively as they promise). Here is the problem... we now have a language spec handled by a commercial organization, and a framework (Apache Flex) that is run by an open source group. What are the chances that these stay in line, especially given the fact that Adobe has stated ActionScript Next will not be 100% backwards compatible with AS3, which is what Flex is built on (anyone remember AS2 > AS3?). Here is my worry. As Apache starts considering their options and develops the Flex roadmap, how long until they say "We aren't going to compile to AS3 anymore, lets compile to Python or SmallTalk or ...". I'd be willing to bet you'll see a port in the near future, which means that innovation in Flex will need to take a backseat while the compiler is rewritten. I'd love to hear your thoughts!
- Stringent static typing as default, with optional dynamic typing: Most stretches of most programs are expected to benefit from static typing. However, ActionScript 3 tends to lapse into dynamic typing all too easily in places where absolutely stringent static typing would be preferable. This will be corrected. Dynamic typing will still be available when needed, but it will no longer be the default for ActionScript, and it will need to be enabled explicitly.
- Type inference: Type declarations will only be necessary in certain strategic places. Everywhere else the compiler will automatically infer suitable type declarations and treat the whole program as statically typed, even though the programmer does not have to state any types. Thus the convenience of untyped programming can be approximated quite well, while providing the performance advantages of typed programming.
- Hardware-oriented numeric types: For example, int, uint, float, float4, byte, short, long, etc. (the exact set of types is still under discussion). Currently in ActionScript 3 integer values can overflow into floating point values. This will be changed so that numeric operations will never change the underlying representation of the numeric. We foresee this addition greatly reducing implementation complexity and improving runtime performance.
Tuesday, November 15, 2011
More news from Adobe on Flex
The Adobe Flex team has finally come out from hiding long enough to post an edit to their original blog post that sent the community screaming. While this does not address all of my concerns, it makes me feel a bit better about the direction of Flex, as long as Adobe is still committing resources. Some key pieces of information are quoted below.
This is about all I needed to hear, although I do think it might turn into the CFML Advisory board debacle. This would just mean that Adobe brings it back in-house I guess:
FINALLY, the statement that they don't hate Flex right now, just that it is a stopgap until HTML5 gets cool:
Ok, I think this could work, but again, inklings of the last committee stuff they tried before:
Awesome:
I don't buy this one. The first time there is a divergence in the committee, this will spell trouble for this initiative:
Well, while I still continue to learn HTML5 (the not-even-a-spec-or-supported-by-my-browser language), I will still happily create Flex applications for mobile. The complete post can be seen here, just scroll down past the stuff you read last time.
This is about all I needed to hear, although I do think it might turn into the CFML Advisory board debacle. This would just mean that Adobe brings it back in-house I guess:
Adobe will also have a team of Flex SDK engineers contributing to those new Apache projects as their full-time responsibility.
FINALLY, the statement that they don't hate Flex right now, just that it is a stopgap until HTML5 gets cool:
[W]e are incredibly proud of what we’ve achieved with Flex and know that it will continue to provide significant value for many years to come. We expect active and on-going contributions from the Apache community. To be clear, Adobe plans on steadily contributing to the projects and we are working with the Flex community to make them contributors as well.
Ok, I think this could work, but again, inklings of the last committee stuff they tried before:
We expect project management to include both Adobe engineers as well as key community leaders.
Awesome:
Adobe will continue to support applications built with Flex, as well as all future versions of the SDK
I don't buy this one. The first time there is a divergence in the committee, this will spell trouble for this initiative:
Adobe will undertake the required work to ensure Flash Builder is compatible with future releases of Flex SDK.
Well, while I still continue to learn HTML5 (the not-even-a-spec-or-supported-by-my-browser language), I will still happily create Flex applications for mobile. The complete post can be seen here, just scroll down past the stuff you read last time.
Monday, November 14, 2011
Making Sense of the Madness (Adobe)
So, I'm trying to write a quick and non FUD post about the recent Adobe news on Flex and Flash. I'm going to say a few things here, and everyone knows I'm an Adobe fanboy, but this stuff hit pretty hard and Adobe is not taking steps behind the scenes to clear up the confusion so the rumor mill is flying. Many peers and friends are now stuck in the lurch trying to figure out what is happening to their careers and the platform they spent years building. Primarily, what do we tell our clients that we worked hard selling these technologies as recently as last week. Here is what Adobe needs to address:
- Adobe did a terrible job working with and through the community that serves them well. They have abandoned the roadmap and have made us look inept. This needs to be addressed. A new roadmap needs to be released ASAP. Let everyone know you have a plan for the next few years and GET THE COMMUNITY BEHIND IT.
- Adobe needs to address our concerns with HTML5. They abandoned a great technology (Flex) for a technology that doesn't even have a spec defined yet. They may not have abandoned Flex at all, but man are they doing a shitty job saying that. Just let us know the plan for transition and what timeframe it happens in.
- What is happening with ColdFusion? We need to hear that the budget and plan has not been changed. SHOW THE ROADMAP!
- What's going on with AIR and mobile? Flex was the 'go to' for us to build cross platform apps. HTML5 makes great web sites. How about native apps. Don't tell me I HAVE to use PhoneGap. My hope is that I will still be using ActionScript to write AIR apps, but who knows! Adobe needs to let us know.
- Spoon takes care of Flex, and it doesn't turn into the mess that was the CFML Advisory Board debacle.
- Clients embrace Flex post Adobe, just like they embrace jQuery, Drupal and other OSS projects.
- Adobe continues to support AIR mobile apps written in ActionScript.
- Adobe continues to support Flash Builder with Flex, or opensources what exists.
- ColdFusion doesn't disappear into the darkness next week ;)
- LiveCycle goes through a 4th retooling and minimizes it reach and focus to core concepts. Adobe also retools the pricing structure to reflect this change.
- DRM and DAM becomes a focus with easy tools (outside of LiveCycle) that allow us to work them right into our production workflow.
Thursday, September 1, 2011
Accessing the Twitter Streaming API from Adobe Flex/AIR
Over the weekend I discovered an interesting new hobby, so being the geek that I am I wrote a mobile application to support it. I found that I really like watching the pictures people post on Twitter in real-time. This was based around hurricane #irene so seeing the incoming photos was awesome, although I suppose it could also be applied to even more interesting endeavors like #friskyfriday (NSFW) ;) In the application I wrote I wanted to connect to the Twitter live stream instead of using search. Although it doesn't send you the full firehose of tweets, I wanted everything in real-time for geek-ability.
I won't post all the gory details of getting this application up and running, but there were two things that anyone developing for this API will need to do, and here they are:
I had tried to do this in the past and had much more luck using curl or Java to coax the tweets out of the Streaming API, but this time I wanted to do it all in ActionScript as I didn't want to keep track of anything in a database. I wanted real-time streaming of data as it came in, and nothing historical. To do this I used the URLStream class. URLStream opens a HTTP request and then downloads the received data as it comes. URLStream is especially suited to this type of request as the download does not have to finish before you can access the downloaded bytes. This means two things: 1) You can read the bytes as they come and maintain the connection to keep receiving bytes, and 2) you must be super careful, as the Streaming API sends chunks of data. This means that the last chunk you received from Twitter might not be a complete object. You can imagine what this does to the parser (more on this later).
The Streaming API current supports both basic and OAuth authentication. Twitter says that basic authentication is deprecated, so use at your own risk. This article will use basic auth as OAuth and Twitter has been done to death on other blogs.
While setting up the stream controller, we will create a property that will hold our URLStream. This must exist in the scope of the controller as all of the events will interact with this stream as the URLRequest is processed.
The handler for this event takes the JSON response and adds it to any other text left over in the buffer from prior requests. We then need to parse the JSON text to look for complete objects to deserialize. Twitter made this easy. They send along a newline character at the end of each JSON object. Simply split() the JSON text on newline and you'll have an array of objects. By trying to deserialize any of these objects using the JSON class (available from the as3corelib package) we can create tweet objects. Any text that can't be deserialized will be put back into the String variable that is holding the JSON data to be parsed with the next data stream response.
I won't post all the gory details of getting this application up and running, but there were two things that anyone developing for this API will need to do, and here they are:
1. Connect to the Streaming API
I had tried to do this in the past and had much more luck using curl or Java to coax the tweets out of the Streaming API, but this time I wanted to do it all in ActionScript as I didn't want to keep track of anything in a database. I wanted real-time streaming of data as it came in, and nothing historical. To do this I used the URLStream class. URLStream opens a HTTP request and then downloads the received data as it comes. URLStream is especially suited to this type of request as the download does not have to finish before you can access the downloaded bytes. This means two things: 1) You can read the bytes as they come and maintain the connection to keep receiving bytes, and 2) you must be super careful, as the Streaming API sends chunks of data. This means that the last chunk you received from Twitter might not be a complete object. You can imagine what this does to the parser (more on this later).
The Streaming API current supports both basic and OAuth authentication. Twitter says that basic authentication is deprecated, so use at your own risk. This article will use basic auth as OAuth and Twitter has been done to death on other blogs.
While setting up the stream controller, we will create a property that will hold our URLStream. This must exist in the scope of the controller as all of the events will interact with this stream as the URLRequest is processed.
private var stream:URLStream;
After instantiating the class we need to set up our URLStream. This is accomplished by defining a new request, setting the URI we want to hit, setting the basic auth parameters and finally adding event handlers to react to the data streaming in or any errors that might occur.public function startStream():void {
stream = new URLStream();
var request:URLRequest;
request = new URLRequest("http://stream.twitter.com/1/statuses/filter.json?track=&include_entities=1");
// set up basic auth
var encoder:Base64Encoder = new Base64Encoder();
encoder.encode(appController.username + ":" + appController.password);
var credentials:String = encoder.toString();
var authHeader:URLRequestHeader = new URLRequestHeader("Authorization","Basic " + credentials);
//add the header to request
request.requestHeaders.push(authHeader);
request.method = URLRequestMethod.POST;
// in a real app I would also recommend handlers for SecurityErrorEvent.SECURITY_ERROR, IOErrorEvent.IO_ERROR at a minimum
stream.addEventListener(ProgressEvent.PROGRESS, progressHandler);
try {
stream.load(request);
} catch (error:Error) {
trace("Bad URL.");
}
}
A few notes about the code above... First, there is a track parameter being passed but it is currently empty. This allows you to filter your request. For my example I let the user enter this in on a prior view and passed it in via an application controller. Second, we are only listening for a single event, ProgressEvent.PROGRESS. In the real application I suggest you listen for at least security errors and input errors. You can also listen for HTTP status codes. This is important and Twitter would like for you to watch those codes and throttle your requests accordingly. Please make sure to do this or they will terminate your stream. Lastly, please note that we are requesting the response to be JSON. The streaming API only allows you to request JSON.
Next, we need to define our handler. The one I am concerned with for this tutorial is the progress handler (it handles the ProgressEvent.PROGRESS event). When a progress event is received you can check the Stream object to see if enough bytes have been loaded to process the stream's data. In this application I didn't care how much data had been sent as I was more concerned with if the data available had any complete tweets (JSON objects) in it. To do this I fire off an event to another controller which processes the data.private function progressHandler(event:ProgressEvent):void {
// read the bytes
var x:ByteArray = new ByteArray();
stream.readBytes(x, 0, stream.bytesAvailable);
// create an event to create the picTweets from the JSON
var te:TweetEvent = new TweetEvent( TweetEvent.NEW_TWEET_RECEIVED );
te.json = x.toString();
// I'm using Swiz to dispatch my events - perhaps you should be also ;)
dispatcher.dispatchEvent(te);
trace("Progress Event Handled.");
}
We read the bytes from the stream as a ByteArray. The ByteArray data is then sent across to the other controller as a string using a custom event. The custom event looks like this:
package events
{
import flash.events.Event;
public class TweetEvent extends Event
{
public static const NEW_TWEET_RECEIVED:String = "events.TweetEvent.NEW_TWEET_RECEIVED";
public var json:String;
public function TweetEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
2. Parse the resulting data
The handler for this event takes the JSON response and adds it to any other text left over in the buffer from prior requests. We then need to parse the JSON text to look for complete objects to deserialize. Twitter made this easy. They send along a newline character at the end of each JSON object. Simply split() the JSON text on newline and you'll have an array of objects. By trying to deserialize any of these objects using the JSON class (available from the as3corelib package) we can create tweet objects. Any text that can't be deserialized will be put back into the String variable that is holding the JSON data to be parsed with the next data stream response.
public function handleNewTweet(json:String):void {
// add the new json to the text storage - this is a private var for this controller
jsonText += json;
// now parse through the text for newline chars, which denote the end of a JSON object
var aJSON:Array = jsonText.split(/\n/);
if ( aJSON.length ) {
// clear the jsonText for appending any partial objects
jsonText = '';
for ( var i:String in aJSON ) {
// try to deserialize, if we error, we dont have a complete object in that array, add it back to the queue (it will always be the last item in the array that fails, if any)
// deserialize the JSON
if ( aJSON[i].length ) {
try {
var tweet:Object = JSON.decode(aJSON[i]);
var j:String;
// HERE IS WHERE YOU CAN ACTUALLY PROCESS THE TWEET
} catch ( e:Error ) {
// here is where we add the partial object back into the jsonText variable - will be appended to the next response
if ( aJSON[i].length && aJSON[i].indexOf('\r') != 0 ) { jsonText += aJSON[i]; }
}
}
}
}
}
For my purposes I just parsed the entities for media and displayed it within my application. You have the full status object to play with for your application. Have fun, and if you use this drop me a comment so I can check it out!
Wednesday, August 31, 2011
ColdSpring Setter Injection versus Constructor Arguments Snafu
I was troubleshooting an issue a colleague of mine was having the other day, where to his credit he was following best practices but it shot him in the foot. Wanted to mention it here quickly.
Most times when you are injecting a bean into another bean in ColdSpring you will use setter injections. They look like:
Bean2 defines a mutator (setter) method, setBean1(). ColdSpring will inject the Bean1 into Bean2 when Bean2 is created by explicitly calling Bean2.setBean1(bean1). This is a best practice when performing dependency injection to prevent circular dependencies.
So the problem we were encountering in code was that the Bean2 constructor was calling a method that relied on the Bean1 property, which was of course undefined during the instantiation. It took a little while to track this down as this was a Model-Glue subapplication with lots of other stuff that could have been creating the error.
So, the lesson learned is to remember how ColdSpring and DI works. ColdSpring is going to create an instance of a bean, call the bean's constructor and then perform any necessary setter injections. It all makes perfect sense, except when you least expect it ;)
The answer in this case was to determine if a circular dependency would occur, which in our case it wouldn't, and instead inject the dependent bean via a constructor argument like this:
In the constructor call setBean1(arguments.bean1).
Most times when you are injecting a bean into another bean in ColdSpring you will use setter injections. They look like:
<bean id="bean1" class="com.nictunney.Bean1"/>
<bean id="bean2" class="com.nictunney.Bean2">
<property name="Bean1">
<ref bean="Bean1"/>
</property>
</bean>
Bean2 defines a mutator (setter) method, setBean1(). ColdSpring will inject the Bean1 into Bean2 when Bean2 is created by explicitly calling Bean2.setBean1(bean1). This is a best practice when performing dependency injection to prevent circular dependencies.
So the problem we were encountering in code was that the Bean2 constructor was calling a method that relied on the Bean1 property, which was of course undefined during the instantiation. It took a little while to track this down as this was a Model-Glue subapplication with lots of other stuff that could have been creating the error.
So, the lesson learned is to remember how ColdSpring and DI works. ColdSpring is going to create an instance of a bean, call the bean's constructor and then perform any necessary setter injections. It all makes perfect sense, except when you least expect it ;)
The answer in this case was to determine if a circular dependency would occur, which in our case it wouldn't, and instead inject the dependent bean via a constructor argument like this:
<bean id="bean1" class="com.nictunney.Bean1"/>
<bean id="bean2" class="com.nictunney.Bean2">
<constructor-arg name="bean1">
<ref bean="Bean1" />
</constructor-arg>
</bean>
In the constructor call setBean1(arguments.bean1).
Wednesday, August 24, 2011
Are you ColdFusion Curious?
There is always lots of buzz about Adobe ColdFusion across social networking channels from developers. Most of it is positive, but ColdFusion also takes some abuse from programmers who have not used it. This criticism then gets met with some pushback from well-meaning CF developers, which in turn makes the bulk of us look like rabid loyalists.
Unfortunately for those scouring for information on language pros or cons, many of the negative statements are misinformed, heresy, and some of it is just good-natured ribbing (which I encourage as I do the same). I'd like to challenge all of you who use a web development language like Ruby, PHP, C# and ASP to take a single hour and attend one of the Adobe ColdFusion Developer Week sessions and challenge yourself to check out CF and see just how productive it can be. Don't worry, I won't tell any of your friends you were there ;)
Unfortunately for those scouring for information on language pros or cons, many of the negative statements are misinformed, heresy, and some of it is just good-natured ribbing (which I encourage as I do the same). I'd like to challenge all of you who use a web development language like Ruby, PHP, C# and ASP to take a single hour and attend one of the Adobe ColdFusion Developer Week sessions and challenge yourself to check out CF and see just how productive it can be. Don't worry, I won't tell any of your friends you were there ;)
Sunday, August 14, 2011
Android Mobile Application Connection Issues with Flash Remoting and ColdFusion
I was debugging an application tonight that uses Flex to connect an Android mobile application to ColdFusion via Flash Remoting. Every time I tried to call the remote method via the RemoteObject I got the message:
Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Failed
So I checked my LAN settings and then played around with my Mac firewall control panel. It was disabled so I was baffled. I then came across this post that hinted that it could be my usage of the CheckPoint VPN-1 SecureClient. Disabling and closing the client had no effect, so eventually I figured out I had to just disable the security policy (Tools > Disable security policy). I hope this helps someone out there from ruining an otherwise perfectly good evening of coding!
Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Failed
So I checked my LAN settings and then played around with my Mac firewall control panel. It was disabled so I was baffled. I then came across this post that hinted that it could be my usage of the CheckPoint VPN-1 SecureClient. Disabling and closing the client had no effect, so eventually I figured out I had to just disable the security policy (Tools > Disable security policy). I hope this helps someone out there from ruining an otherwise perfectly good evening of coding!
Subscribe to:
Posts (Atom)


