I ran into this very strange bug in the flash player while working on a project. The problem appeared when using flex 4's TLF (text layout framework) with embedded fonts (using cff).
In other projects I added the unicode ranges to the css file like lots other blogs describe (like: http://blog.flexexamples.com/2007/08/07/specifying-certain-unicode-ranges-for-embedded-fonts/), you do want to set the unicode ranges you need on the fonts you embed to save lots of otherwise wasted memory space.
In our other projects this worked without any problems, but in combination of TLF suddenly weird stuff was happening. When having a sentence with lots of spaces, like "a a a a a a a a a a a a a a a a a a a a a a a a", words start to disappear in the beginning of the sentence. The more words and spaces your add, the more words start disappearing :-/
I created a bug back in November on Adobe's bugtracker (https://bugs.adobe.com/jira/browse/FP-3082) but didn't get any response from Adobe about this.
A couple of days ago I decided to take another shot on this issue and thanks to a colleague with a couple of good idea's I came to the following conclusion.
The problem occurs with this unicode range:
unicodeRange:
U+0040-U+007E;
}
The problem is solved with this unicode range:
unicodeRange:
U+0009-U+0009,
U+0040-U+007E;
}
The unicode U+0009 is the 'horizontal tabular character'. I really don't know how the internals of the flash player are creating tab's over my characters or something, but at least the solution works.
Wednesday, January 06, 2010
Tuesday, December 01, 2009
Java, ImageMagick and Runtime.getRuntime().exec(command)
Today I needed a to show a 50MB EPS file in the flash player on the client. I chose ImageMagick (a c++ image manipulation library) to convert the image to a jpeg because there really aren't any good java libraries who can do this kind of stuff without draining all of your resources on the server.
ImageMagick wasn't hard to install at all, the guide on http://www.imagemagick.org is pretty clear and self explanatory.
There are only 2 ImageMagick wrappers for java: JMagick and Im4Java. Both are poorly documented and hardly used at all. JMagick uses a JNI connection through some dll you have to install, Im4Java uses the java Runtime.getRuntime().exec command to get it to work, on the downside; the library does not work on Windows without modification of the source code.
Anyway, both didn't seem mature enough (or working at all) to use in a production environment, so I decided to do it myself.
Getting it to work was fairly easy using the exec command. I omitted the try-catch clauses for clarity in the code following. The command variable is a String[] of parameters including imagemagick's convert command. ie as a string:
"/usr/bin/convert -geometry 100x100 -quality 75 in.gif out.jpg"
This worked fine untill I tried my 50MB EPS file. The result was that the convert.exe command on my machine never exited and the java application just waited at proc.waitFor() forever.
After searching through the internet and javadocs I discovered this:
"Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock."
There is a pretty good blog on this subject on javaworld: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1
The solution is to continuously read the output streams, you could do this using a while loop or u can use StreamGobbler:
"A stream gobbler pipes ("gobbles") an input stream to an output stream."
API: http://www.is.informatik.uni-duisburg.de/projects/jayspirit/javadoc/hyspirit/util/StreamGobbler.html
JAR: http://www.findjar.com/jar/ch.ethz.ganymed/jars/ganymed-ssh2-build209.jar.html
This fixed my problem, no more deadlocks :-) Here is the complete code used:
ImageMagick wasn't hard to install at all, the guide on http://www.imagemagick.org is pretty clear and self explanatory.
There are only 2 ImageMagick wrappers for java: JMagick and Im4Java. Both are poorly documented and hardly used at all. JMagick uses a JNI connection through some dll you have to install, Im4Java uses the java Runtime.getRuntime().exec command to get it to work, on the downside; the library does not work on Windows without modification of the source code.
Anyway, both didn't seem mature enough (or working at all) to use in a production environment, so I decided to do it myself.
Getting it to work was fairly easy using the exec command. I omitted the try-catch clauses for clarity in the code following. The command variable is a String[] of parameters including imagemagick's convert command. ie as a string:
"/usr/bin/convert -geometry 100x100 -quality 75 in.gif out.jpg"
proc = Runtime.getRuntime().exec(command);
exitStatus = proc.waitFor();
This worked fine untill I tried my 50MB EPS file. The result was that the convert.exe command on my machine never exited and the java application just waited at proc.waitFor() forever.
After searching through the internet and javadocs I discovered this:
"Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock."
There is a pretty good blog on this subject on javaworld: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1
The solution is to continuously read the output streams, you could do this using a while loop or u can use StreamGobbler:
"A stream gobbler pipes ("gobbles") an input stream to an output stream."
API: http://www.is.informatik.uni-duisburg.de/projects/jayspirit/javadoc/hyspirit/util/StreamGobbler.html
JAR: http://www.findjar.com/jar/ch.ethz.ganymed/jars/ganymed-ssh2-build209.jar.html
This fixed my problem, no more deadlocks :-) Here is the complete code used:
private boolean convert(File in, File out, int width, int height) {
LOGGER.info("convert(" + in.getPath() + ", " + out.getPath() + ", " + width + "x" + height);
ArrayListcommand = new ArrayList (10);
command.add(imageMagickConvertCommand);
command.add("-geometry");
command.add(width + "x" + height);
command.add("-quality");
command.add("" + JPGQUALITY);
command.add(in.getAbsolutePath());
command.add(out.getAbsolutePath());
return exec((String[]) command.toArray(new String[1]));
}
private boolean exec(String[] command) {
Process proc;
try {
proc = Runtime.getRuntime().exec(command);
} catch (IOException e) {
System.out.println("IOException while trying to execute " + command);
return false;
}
//streamgobbler consumes any error or input streams to prevent the process from hanging.
new StreamGobbler(proc.getErrorStream());
new StreamGobbler(proc.getInputStream());
int exitStatus = -1;
try {
exitStatus = proc.waitFor();
} catch (InterruptedException e) {
LOGGER.error(e.getMessage(), e);
}
if (exitStatus != 0) {
LOGGER.error("Error executing command: " + exitStatus);
}
return exitStatus == 0;
}
Labels:
java imagemagick
Monday, November 16, 2009
Flex Accessibility Option
A couple of days ago I updated to the latest nightly build version of the flex sdk (4.0.0.11686) because of some bugs I encountered. After updating my code everything seemed to run smoothly and the bugs I previously had where fixed in the nightly build.
After a run through our build server and a deploy to the test environment, the application seemed to have stopped working. The only clou I got was from the debug player which rapported the following error:
My first guess was that something had changed in the RSLs which I forgot to update. Something weird is happing here, because the RSL-swfs in the SDK are named like framework_4.0.0.11686.swf, but after enabling the RSLs in flash-builder, flash-builder itself generates (copies) the swfs to the bin-debug dir but named like framework_4.0.0.0.swf and the default flex-config.xml also uses the 0.0.swf notation by default..
Anywayz, it turned out it had nothing to do with it anyway. The problems was a setting called 'accessible' in the flex-config.xml, normally this setting is false by default. Also flash-builder overrides this setting default to false. So it seems like the application was running fine from flash-builder, but when compiled with ant it used different settings. Also this setting was always false in the former releases of the SDK.
Flashbuilder screenshot of the accessible setting:

I don't know if Adobe made this change permanent or its just for development in the nightly builds or something.
About accessibility: http://www.yswfblog.com/blog/2008/07/22/accessible-trueflash-and-flex-accessibility-docs/
After a run through our build server and a deploy to the test environment, the application seemed to have stopped working. The only clou I got was from the debug player which rapported the following error:
TypeError: Error #1009: Cannot access a property or method of a null object reference. at spark.accessibility::PanelAccImpl$/http://www.adobe.com/2006/flex/mx/internal::createAccessibilityImplementation()[E:\dev\trunk\frameworks\projects\spark\src\spark\accessibility\PanelAccImpl.as:76] at spark.components::Panel/initializeAccessibility()[E:\dev\trunk\frameworks\projects\spark\src\spark\components\Panel.as:457]
My first guess was that something had changed in the RSLs which I forgot to update. Something weird is happing here, because the RSL-swfs in the SDK are named like framework_4.0.0.11686.swf, but after enabling the RSLs in flash-builder, flash-builder itself generates (copies) the swfs to the bin-debug dir but named like framework_4.0.0.0.swf and the default flex-config.xml also uses the 0.0.swf notation by default..
Anywayz, it turned out it had nothing to do with it anyway. The problems was a setting called 'accessible' in the flex-config.xml, normally this setting is false by default. Also flash-builder overrides this setting default to false. So it seems like the application was running fine from flash-builder, but when compiled with ant it used different settings. Also this setting was always false in the former releases of the SDK.
<!-- Turn on generation of accessible SWFs. -->
<accessible>false</accessible>
Flashbuilder screenshot of the accessible setting:
I don't know if Adobe made this change permanent or its just for development in the nightly builds or something.
About accessibility: http://www.yswfblog.com/blog/2008/07/22/accessible-trueflash-and-flex-accessibility-docs/
Saturday, May 16, 2009
10 steps to improve your Vista installation
Finally, I switched to Vista, I decided to give it a try. I never used Vista before, but I heard (a lot) of complaints from co-workers who had all sorts of problems with Vista, mostly performance troubles.
I did some research on the internet and tweaked my Vista install in a pretty simple way and greatly enhanced performance and the overall annoyance level of Vista, even without disabling the Aero theme.. While disabling Aero will boost your overall performance (like disabling fade effects and transparency and stuff) thats not the goal here. I assume you have a system which runs the basic Vista install just fine. The problem occurs when you are using Vista a lot and sometimes Vista just becomes increasingly slower over time or just hangs every now and then for small periods of time. The suddenly decrease of performance and hangs are all traced back to a couple of Vista 'features' which run at moments you need all the performance you can get. At worst, while you are trying to do you work, Vista will be defragmentating your hard drive, while it is indexing it, scanning it for virusses and installing updates. If you don't want that, here is a list of things you can do or disable to prevent this.
1. UAC (User Account Control).
First things first, _THE_ most annoying part of Vista is the UAC. In Vista with every simple action you'd like to perform you seem to need to click on some 'are you sure' button. While this can be very helpful for inexperienced computer users it certainly is not for us programmer geeks, it is simple absurd. There are a lot of blogs out there about how to disable it, but by disabling it you might run into some troubles (like with Windows Update), some programs simply require UAC to be turned on or they might decide your computer is not save enough to perform certain operations. The better, but more advanced option, is to auto-accept the 'are you sure' boxes. Here is an explanation how to accomplish this:
Click Start and Control Panel. Switch to Classic View (if you haven't already) and click on the Administration Tools icon. In the list that opens click on Local Security Policy, and in the next window, Local Policies (a tiny bit redundant, but all UIs can't be perfect -- If UAC is running you'll get a UAC pop-up somewhere in here). In the Local Policies list click Security Options, and scroll down to "User Account Control: Behavior" (the full title of the policy is "User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode" but the window barely opens that far). Double-click the title and in the dialog box change its setting from "Prompt for Consent" to "Elevate without prompting." Click OK and the urge to tear your hair and scream at your PC will be greatly diminished in the future.
Update: After reboot Vista will show an error icon at the bottom left, when you double click it you will go to the security center. Security Center will say you have disabled the UAC. To get rid of the annoying tray icon simple go to Control Panel -> Security -> Security Center -> Change the way security center alerts me and choose 'Don't notify me and don't display the icon'.
2. The indexing service
Alright, it is time to disable some performance-slurping Vista features, starting with the indexing service. I usually don't use windows search anyway, i know where to find my stuff. Also when searching IN files I tend to use other products. Disable it by Going to Control Panel -> System and Maintenance -> Indexing Options. Click Modify and click on Show all locations, notice you don't have the annoying 'are you sure' popup anymore!. Deselect all the locations that are currently being indexed.
3. Disk Defragmentation
Offcourse, defragmentation of your disks is a must. In XP you had to click the defragment button yourself to do it. In Vista they decided to do it automatically, which is a good thing. The only problem is when the process is scheduled; every Wednesday at 2pm, which is in working hours. And you don't want Windows to start defragmentating your drives when you are trying to build your code and run your unit-tests right? Go to Controler Panel -> System and Maintenance -> Defragment your hard drive (under Administrative Tools). Modify the schedule and schedule it weekends or disable it and manually run the process every now and then.
4. Windows Defender
Vista comes with extra security and extra security comes with a price. The extra security is needed and welcome by the majority, ordinary Windows users. However the more experienced users won't need this extra level of security. Windows Defender is a spyware detection program which adds an extra level of security, however what most people don't know is it runs a computer scan, searching for infected (malware) files, every day at 2PM, again when we are compiling code and running our j-unit tests. You can disable the daily scanning (or re-schedule it) at Control Panel -> Security -> Windows Defender -> Tools -> Options -> Automatic scanning. You can also disable the Windows Defender entirely (option at the bottom) when you don't want Defender to scan every file you open, or you have another spyware/virus scanner/firewall program running.
5. Power plan
This one is really easy, but sometimes overseen by the most expert of users. Vista comes with Power plans, which are really good to save battery power. Default on my laptop it was set to 'HP Optimized', which means it won't go full performance to save battery but it can adjust dynamically. Well this won't make sense when your power cable is plugged in, but Vista won't change it automatically to 'High Performance' mode. Manually set it to 'High Performance' to get, well .. a higher performance.
6. Physical Address Extension (PAE)
If you have a system with 4GB's of memory or more then you will see Vista only using and displaying 3GB's in the system dialog. This is only limited in 32bits operating systems, so this is not an issue if you have 64bit Vista installed.
There is something called Physical Address Extension (PAE) which makes it possible to crank up Vista to use the full 4GB or more, you can read about it here: http://www.daniweb.com/forums/thread180206.html. If you don't interest in reading it and just want to enable it, type: "BCDEdit /set pae ForceEnable" in an elevated command prompt (which means a command prompt opened with the 'Run as Administrator' option).
7. Side Bar
Vista comes with a widget holding side bar, this was actually the first thing I disabled when I started my machine. Maybe its just a personal question of style or something, but I don't see the added value of it. Right click on the Sidebar and choose Properties -> Uncheck the 'Start sidebar when Windows starts' checkbox. Then right-click the sidebar icon and exit the sidebar.
8. Windows Auto Update
Windows Auto Update is a feature you don't want to disable at all, you need the updates. However, again, Vista installs the updates at moments you probably do not want it to. The best way is to automatically download the updates, but let Vista ask you whether or when you want to install it. Go to Control Panel -> Security -> Security Center -> Automatic Updating -> Change Settings -> Let me choose -> select 'Download updates but let me choose whether to install them'.
9. Automatic Restore Points
Restore points are a neat feature, if you are afraid some virus that corrupts your Vista machine, it will make it possible to go back to a certain point in time and restore your Vista configuration back to that point. However it is not a full backup of you machine, if a virus hits your machine, multiple files are probably infected and Restore only helps to a certain point. Vista automatically creates restore points now and then, which again costs performance (and disk space) to create them. It is better to just fully backup your machine every now and then. When something goes wrong just restore the full backup or reinstall your machine. In that case, or when you are just not afraid to get any viruses, disable the Automatic Restore Points. Go to Control Panel -> System and Maintenance -> System -> System protection -> uncheck all checkboxes.
10. HP Security Tools
Last thing is not really a Vista thing, but more an issue that comes with HP machines/laptops, is the HP Security Tools. While some people absolutely love this feature and this is not performance related, it just annoyed the crap out of me. The Single sign on feature is clever, but doesn't work with the browser of my choice (which isn't IE). I don't like the annoying popups asking me to save passwords and when i disable it I can't remove the icon from the icon bar. It even still popups every now and then warning me. So I just totally uninstalled the software.
Although the above points greatly improves your Vista experience, it also makes your computer less save, so don't forget to install your virus scanner software!
I did some research on the internet and tweaked my Vista install in a pretty simple way and greatly enhanced performance and the overall annoyance level of Vista, even without disabling the Aero theme.. While disabling Aero will boost your overall performance (like disabling fade effects and transparency and stuff) thats not the goal here. I assume you have a system which runs the basic Vista install just fine. The problem occurs when you are using Vista a lot and sometimes Vista just becomes increasingly slower over time or just hangs every now and then for small periods of time. The suddenly decrease of performance and hangs are all traced back to a couple of Vista 'features' which run at moments you need all the performance you can get. At worst, while you are trying to do you work, Vista will be defragmentating your hard drive, while it is indexing it, scanning it for virusses and installing updates. If you don't want that, here is a list of things you can do or disable to prevent this.
1. UAC (User Account Control).
First things first, _THE_ most annoying part of Vista is the UAC. In Vista with every simple action you'd like to perform you seem to need to click on some 'are you sure' button. While this can be very helpful for inexperienced computer users it certainly is not for us programmer geeks, it is simple absurd. There are a lot of blogs out there about how to disable it, but by disabling it you might run into some troubles (like with Windows Update), some programs simply require UAC to be turned on or they might decide your computer is not save enough to perform certain operations. The better, but more advanced option, is to auto-accept the 'are you sure' boxes. Here is an explanation how to accomplish this:
Click Start and Control Panel. Switch to Classic View (if you haven't already) and click on the Administration Tools icon. In the list that opens click on Local Security Policy, and in the next window, Local Policies (a tiny bit redundant, but all UIs can't be perfect -- If UAC is running you'll get a UAC pop-up somewhere in here). In the Local Policies list click Security Options, and scroll down to "User Account Control: Behavior" (the full title of the policy is "User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode" but the window barely opens that far). Double-click the title and in the dialog box change its setting from "Prompt for Consent" to "Elevate without prompting." Click OK and the urge to tear your hair and scream at your PC will be greatly diminished in the future.
Update: After reboot Vista will show an error icon at the bottom left, when you double click it you will go to the security center. Security Center will say you have disabled the UAC. To get rid of the annoying tray icon simple go to Control Panel -> Security -> Security Center -> Change the way security center alerts me and choose 'Don't notify me and don't display the icon'.
2. The indexing service
Alright, it is time to disable some performance-slurping Vista features, starting with the indexing service. I usually don't use windows search anyway, i know where to find my stuff. Also when searching IN files I tend to use other products. Disable it by Going to Control Panel -> System and Maintenance -> Indexing Options. Click Modify and click on Show all locations, notice you don't have the annoying 'are you sure' popup anymore!. Deselect all the locations that are currently being indexed.
3. Disk Defragmentation
Offcourse, defragmentation of your disks is a must. In XP you had to click the defragment button yourself to do it. In Vista they decided to do it automatically, which is a good thing. The only problem is when the process is scheduled; every Wednesday at 2pm, which is in working hours. And you don't want Windows to start defragmentating your drives when you are trying to build your code and run your unit-tests right? Go to Controler Panel -> System and Maintenance -> Defragment your hard drive (under Administrative Tools). Modify the schedule and schedule it weekends or disable it and manually run the process every now and then.
4. Windows Defender
Vista comes with extra security and extra security comes with a price. The extra security is needed and welcome by the majority, ordinary Windows users. However the more experienced users won't need this extra level of security. Windows Defender is a spyware detection program which adds an extra level of security, however what most people don't know is it runs a computer scan, searching for infected (malware) files, every day at 2PM, again when we are compiling code and running our j-unit tests. You can disable the daily scanning (or re-schedule it) at Control Panel -> Security -> Windows Defender -> Tools -> Options -> Automatic scanning. You can also disable the Windows Defender entirely (option at the bottom) when you don't want Defender to scan every file you open, or you have another spyware/virus scanner/firewall program running.
5. Power plan
This one is really easy, but sometimes overseen by the most expert of users. Vista comes with Power plans, which are really good to save battery power. Default on my laptop it was set to 'HP Optimized', which means it won't go full performance to save battery but it can adjust dynamically. Well this won't make sense when your power cable is plugged in, but Vista won't change it automatically to 'High Performance' mode. Manually set it to 'High Performance' to get, well .. a higher performance.
6. Physical Address Extension (PAE)
If you have a system with 4GB's of memory or more then you will see Vista only using and displaying 3GB's in the system dialog. This is only limited in 32bits operating systems, so this is not an issue if you have 64bit Vista installed.
There is something called Physical Address Extension (PAE) which makes it possible to crank up Vista to use the full 4GB or more, you can read about it here: http://www.daniweb.com/forums/thread180206.html. If you don't interest in reading it and just want to enable it, type: "BCDEdit /set pae ForceEnable" in an elevated command prompt (which means a command prompt opened with the 'Run as Administrator' option).
7. Side Bar
Vista comes with a widget holding side bar, this was actually the first thing I disabled when I started my machine. Maybe its just a personal question of style or something, but I don't see the added value of it. Right click on the Sidebar and choose Properties -> Uncheck the 'Start sidebar when Windows starts' checkbox. Then right-click the sidebar icon and exit the sidebar.
8. Windows Auto Update
Windows Auto Update is a feature you don't want to disable at all, you need the updates. However, again, Vista installs the updates at moments you probably do not want it to. The best way is to automatically download the updates, but let Vista ask you whether or when you want to install it. Go to Control Panel -> Security -> Security Center -> Automatic Updating -> Change Settings -> Let me choose -> select 'Download updates but let me choose whether to install them'.
9. Automatic Restore Points
Restore points are a neat feature, if you are afraid some virus that corrupts your Vista machine, it will make it possible to go back to a certain point in time and restore your Vista configuration back to that point. However it is not a full backup of you machine, if a virus hits your machine, multiple files are probably infected and Restore only helps to a certain point. Vista automatically creates restore points now and then, which again costs performance (and disk space) to create them. It is better to just fully backup your machine every now and then. When something goes wrong just restore the full backup or reinstall your machine. In that case, or when you are just not afraid to get any viruses, disable the Automatic Restore Points. Go to Control Panel -> System and Maintenance -> System -> System protection -> uncheck all checkboxes.
10. HP Security Tools
Last thing is not really a Vista thing, but more an issue that comes with HP machines/laptops, is the HP Security Tools. While some people absolutely love this feature and this is not performance related, it just annoyed the crap out of me. The Single sign on feature is clever, but doesn't work with the browser of my choice (which isn't IE). I don't like the annoying popups asking me to save passwords and when i disable it I can't remove the icon from the icon bar. It even still popups every now and then warning me. So I just totally uninstalled the software.
Although the above points greatly improves your Vista experience, it also makes your computer less save, so don't forget to install your virus scanner software!
Monday, April 20, 2009
Oracle buys Sun!
http://www.sun.com/third-party/global/oracle/index.jsp#
Well is it good, or bad news?
Well is it good, or bad news?
Labels:
java
Thursday, April 16, 2009
Follow my blog!
Hey lets make this blog a little more communicative using the google friend connect features of blogger. Everyone reading this blog please click the FOLLOW button at the top right corner to join my blog as a 'follower'. This is a great new neat feature of google :-)
greetingz
greetingz
Tuesday, April 07, 2009
Remote object reference pooling in Flex
Ever tried to compare object by reference when using remote objects and failed? Or wondered why you have so many instances of the same object in memory.. This blogpost will describe why and when this happens, and offers a solution including source code.
The problem appears when building RIA applications based on the domain driven design principle. Typically you will have a domain layer in your backend, maybe a DTO layer in between, and about the same actionscript version of your domain layer in your client.
Imagine you have a model class in your client containing a loggedInUser:User object and a search view listing all users from the database. Both the loggedInUser and the search results are retrieved through a RemoteObject call with AMF from the backend server. You can select a row in your search view and open a details page of that particular selected user. So what if you want to check if the selected user is the same as the logged in user? Your first try could be something like model.loggedInUser == userForDetailPage and find out this will never work. The solution would be to check on a unique identifier like an id (model.loggedInUser.id == userForDetailPage.id). Just don't forget to also check for null reference (maybe loggedInUser is not set, etc..).
So why is the simple object compare not working? The problem is RemoteObject will give you a new Object() every time you request something from the server. So if you call the method getUserById(1) twice, you will get 2 different objects with the exact same data as a result.
Well that can't be optimal right? It will cost more memory because you have multiple instances of the same domain object and also it will be very confusing... For example if you have like 5 reference to the same domain object scattered across your application, and you change a property in an edit view, the property will be changed on only 1 instance of the 5 instances in your app. The other 4 instances will still contain the old (stale) data, so now you have to refresh the other objects, which again costs more time and memory and results in higher code complexity. The other option would be to reflect the adjusted state to the other 4 objects manually by setting the changed properties.
To fix this weird behavior i created an extension on RemoteObject, called PoolingRemoteObject. This new PoolingRemoteObject adds some extra code that simply checks what object(s) is returned from the server, looks it up in a map and returns the object in the map instead when its already there. This will eliminate the whole multiple reference to the same domain object problem. The original object returned from the server is disposed and the object from the pool is returned.
There is just one problem, if the object is already on the client in the pool, the client will never retrieve a newer updated version of the object. The solution is to just reflection to copy all the data from the new object (from the server) to the old already existing object in the pool. This way the object in the pool is fully updated with the new data from the server. All the 5 references to this object in the pool (as in the previous example) will all reflect the new changes immediately because they all reference to the same object. Changing any of the 5 will result in updating all because it is the same thing actually.
The PoolingRemoteObject also handles collections of objects returned from the server, and recursively handles objects containing references to other objects (or collections of objects for that matter), just to be sure a domain object will never have multiple instances on the client. Logic is added to detect and handle circular references.
This class is already successfully used in production on multiple large flex applications. The only thing you need to do is implement the UniqueDto interface, this interface needs 1 method to be implemented, the purpose of the method is to specify the unique property of your domain object, this usually just returns the id, but could be any other unique property. There also is a Dto interface which you can implement if you do want to scan the dto object for deeper nested UniqueDto objects. When using the Dto interface the object won't be stored in the pool; only scanned. This is handy when you use wrappers around dto objects, for like example a SearchResultDto containing paging info and a List of UniqueDto's. The SearchResultDto won't be stored in the pool (because it isn't uniquely identifiable), but the List inside it will be.
What we also managed to achieve in a very simple way is lazy loading from the client side, using this object reference pool technique. I'll cover more on this topic in a later post.
Here are a couple of code snippets to display how it works, download the zip file at the bottom for the complete source code.
Usage of the pooling remote object:
Credits also goes to my friend and colleague Daniel Rijkhof for helping developing this piece of software.
Update: Daniel discovered a bug in the mx.utils.ObjectUtil class. Apparently the cache inside the object util is not working properly. What they did is cast a Boolean object to a String using the 'as' operator (like: var stringVar = booleanVar is String). This cast always returns null because it isn't a String.
The following bug report is added to adobe's jira: https://bugs.adobe.com/jira/browse/SDK-20516
- Marcel Panse
The problem appears when building RIA applications based on the domain driven design principle. Typically you will have a domain layer in your backend, maybe a DTO layer in between, and about the same actionscript version of your domain layer in your client.
Imagine you have a model class in your client containing a loggedInUser:User object and a search view listing all users from the database. Both the loggedInUser and the search results are retrieved through a RemoteObject call with AMF from the backend server. You can select a row in your search view and open a details page of that particular selected user. So what if you want to check if the selected user is the same as the logged in user? Your first try could be something like model.loggedInUser == userForDetailPage and find out this will never work. The solution would be to check on a unique identifier like an id (model.loggedInUser.id == userForDetailPage.id). Just don't forget to also check for null reference (maybe loggedInUser is not set, etc..).
So why is the simple object compare not working? The problem is RemoteObject will give you a new Object() every time you request something from the server. So if you call the method getUserById(1) twice, you will get 2 different objects with the exact same data as a result.
Well that can't be optimal right? It will cost more memory because you have multiple instances of the same domain object and also it will be very confusing... For example if you have like 5 reference to the same domain object scattered across your application, and you change a property in an edit view, the property will be changed on only 1 instance of the 5 instances in your app. The other 4 instances will still contain the old (stale) data, so now you have to refresh the other objects, which again costs more time and memory and results in higher code complexity. The other option would be to reflect the adjusted state to the other 4 objects manually by setting the changed properties.
To fix this weird behavior i created an extension on RemoteObject, called PoolingRemoteObject. This new PoolingRemoteObject adds some extra code that simply checks what object(s) is returned from the server, looks it up in a map and returns the object in the map instead when its already there. This will eliminate the whole multiple reference to the same domain object problem. The original object returned from the server is disposed and the object from the pool is returned.
There is just one problem, if the object is already on the client in the pool, the client will never retrieve a newer updated version of the object. The solution is to just reflection to copy all the data from the new object (from the server) to the old already existing object in the pool. This way the object in the pool is fully updated with the new data from the server. All the 5 references to this object in the pool (as in the previous example) will all reflect the new changes immediately because they all reference to the same object. Changing any of the 5 will result in updating all because it is the same thing actually.
The PoolingRemoteObject also handles collections of objects returned from the server, and recursively handles objects containing references to other objects (or collections of objects for that matter), just to be sure a domain object will never have multiple instances on the client. Logic is added to detect and handle circular references.
This class is already successfully used in production on multiple large flex applications. The only thing you need to do is implement the UniqueDto interface, this interface needs 1 method to be implemented, the purpose of the method is to specify the unique property of your domain object, this usually just returns the id, but could be any other unique property. There also is a Dto interface which you can implement if you do want to scan the dto object for deeper nested UniqueDto objects. When using the Dto interface the object won't be stored in the pool; only scanned. This is handy when you use wrappers around dto objects, for like example a SearchResultDto containing paging info and a List of UniqueDto's. The SearchResultDto won't be stored in the pool (because it isn't uniquely identifiable), but the List inside it will be.
What we also managed to achieve in a very simple way is lazy loading from the client side, using this object reference pool technique. I'll cover more on this topic in a later post.
Here are a couple of code snippets to display how it works, download the zip file at the bottom for the complete source code.
Usage of the pooling remote object:
var service:RemoteObject = new PoolingRemoteObject(method);A typical dto in flex:
service.destination = destination;
service.endpoint = _endPoint;
service.addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void {
//enter your result handling code here as normal...
}
service.getOperation(method).send();
[Bindable]Download the zip file containing complete code: complete code
[RemoteClass(alias="nl.quintor.sampleproject.web.dto.UserDto")]
public class UserDto implements UniqueDto {
public var id:Number;
public var username:String;
public var email:String;
public function get uid():String {
return "UserDto@"+id);
}
}
Credits also goes to my friend and colleague Daniel Rijkhof for helping developing this piece of software.
Update: Daniel discovered a bug in the mx.utils.ObjectUtil class. Apparently the cache inside the object util is not working properly. What they did is cast a Boolean object to a String using the 'as' operator (like: var stringVar = booleanVar is String). This cast always returns null because it isn't a String.
The following bug report is added to adobe's jira: https://bugs.adobe.com/jira/browse/SDK-20516
- Marcel Panse
Thursday, February 05, 2009
Scroll behavior in flex
Most of the sites we build are using textarea's to display multiple lines of text. However all scroll functionality is handled internally by the TextArea component (or more exact the underlying TextField). Which means if you have a page that scrolls and you have a TextArea component somewhere, the scrollwheel won't work if you have your mouse directly above the text in the TextArea.
Fortunately you can disable this behavoir by extending the TextArea component and adding the following lines of code (i added a Boolean property to enable/disable this new behavior):
Ali Rantakari has created a good working fix for this issue using javascript to pass on the scroll properties: http://hasseg.org/blog/?p=138
Fortunately you can disable this behavoir by extending the TextArea component and adding the following lines of code (i added a Boolean property to enable/disable this new behavior):
Another issue we encountered was that scrolling on a mac simply doesn't work at all.
override protected function createChildren():void {
super.createChildren();
if( disableInternalScrolling ) {
removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
textField.mouseWheelEnabled = false;
}
}
Ali Rantakari has created a good working fix for this issue using javascript to pass on the scroll properties: http://hasseg.org/blog/?p=138
Saturday, December 20, 2008
A simple bamboo notifier tray icon
We build all our software using the continuous integration tool Bamboo. After searching the internet for a while I still couldn't find a simple tray icon notifier for bamboo, so I decided to create one myself.
You can find the project located at: http://bamboo-notifier.googlecode.com
Bamboo notifier is an Adobe AIR application that runs in the system tray on various platforms, it notifies you of you build statusses. It works by reading Bamboo's RSS feed. It shows green or red icons in the system tray and in the application per build plan. It is also possible to click on a build and read the commit message, author and committed file set. More features can be added on request.
Feel free to submit bugs and feature requests in the issues section.
You can download the application at the following url: http://bamboo-notifier.appspot.com/downloads/bamboo-notifier.air
You need the adobe AIR runtime to be able to install the application. If you OS doesn't know what to do with the .air file install Adobe AIR first: http://get.adobe.com/air/
The application is fully opensource, you can download the source code at: http://bamboo-notifier.googlecode.com. The application files are hosted at google's app engine :)
By the way, I haven't tested it yet on a Mac, so i don't know if it even works at all..
Comments are appreciated
You can find the project located at: http://bamboo-notifier.googlecode.com
Bamboo notifier is an Adobe AIR application that runs in the system tray on various platforms, it notifies you of you build statusses. It works by reading Bamboo's RSS feed. It shows green or red icons in the system tray and in the application per build plan. It is also possible to click on a build and read the commit message, author and committed file set. More features can be added on request.
Feel free to submit bugs and feature requests in the issues section.
You can download the application at the following url: http://bamboo-notifier.appspot.com/downloads/bamboo-notifier.air
You need the adobe AIR runtime to be able to install the application. If you OS doesn't know what to do with the .air file install Adobe AIR first: http://get.adobe.com/air/
The application is fully opensource, you can download the source code at: http://bamboo-notifier.googlecode.com. The application files are hosted at google's app engine :)
By the way, I haven't tested it yet on a Mac, so i don't know if it even works at all..
Comments are appreciated
Saturday, November 29, 2008
Using the flex framework RSL's in Flex 3 using Ant
Using RSLs will save you over 300kb of your swf filesize. Flexbuilder has build in features to compile your swf using the rsl libraries, but offcourse we are building on our build server using ant. Using the flex frameworks RSL's from ant is easier said then done. Appearantly this Ant mxmlc target does not implement this feature yet. This feature is shipped with the next flex version (Flex 4 Gumbo). The solution after the jump!
So simply adding the RSL to the mxmlc tag in ant does not work:
The framework RSL is default, but you can also specify to use the rpc and datavisualization RSLs in the same flex-config.xml.
When you are using a build server, change this setting in the sdk on your build server, be aware that all projects that are build by this build server are using the same settings!
You also need to include the compiled libraries next to your compiled swf file. You can find the files in frameworks/libs and frameworks/rsls folders of your sdk. These files are neccessary for people who didn't cache the frameworks libraries yet in their flex player. Don't be fooled if it works for you without the files, you probably have them cached already.
So simply adding the RSL to the mxmlc tag in ant does not work:
The easiest (probably not the prettiest) way to fix this is to specify the RSLs in the flex-config.xml file, located in your flex sdk. Simply change the following statement to false to use the RSL.
<runtime-shared-library-path path-element="${FLEX_HOME}/frameworks/libs/framework.swc">
<url rsl-url="${FLEX_HOME}/frameworks/rsls/framework_3.0.189825.swz"/>
</runtime-shared-library-path>
<static-link-runtime-shared-libraries>true</static-link-runtime-shared-libraries>
The framework RSL is default, but you can also specify to use the rpc and datavisualization RSLs in the same flex-config.xml.
When you are using a build server, change this setting in the sdk on your build server, be aware that all projects that are build by this build server are using the same settings!
You also need to include the compiled libraries next to your compiled swf file. You can find the files in frameworks/libs and frameworks/rsls folders of your sdk. These files are neccessary for people who didn't cache the frameworks libraries yet in their flex player. Don't be fooled if it works for you without the files, you probably have them cached already.
Labels:
flex ant
Subscribe to:
Posts (Atom)
