Tuesday, November 27, 2007

Java To AS3 on AIR


Found this great project that enables me to convert Java code to ActionScript3 code, or at least get me close enough that I can do minor manual tweaks to get code to compile (granted that compiled code does not mean that it runs :-). However, in its current format, it was a laborious process as I can only process one file at the time, and had to copy and paste the generated code from the text area into a file. There must be a better way ! And yes there is a better way using Adobe AIR. AIR enables me to read from and write to the local file system. So, I took the core Converter class and wrapped it with the AIR File api.
A user can now select the output folder and upon the selection of the input folder, all the java files will be read, converted and written to the output folder. In addition, you can drag and drop onto the output or input button the output or input folder.
Download the AIR file from here. BTW - this is using the latest beta3 version :-)

Granite Data Services

I love Life Cycle Data Services. As a developer, IMHO, I think it is worth its weight in gold. However, I do get customers that want to do remoting with it :-( So...since HTTPService and WebService are first class citizens in Flex, I recommend that they SOAP enable their server side services, or come up with some kind of XML representation and XML over HTTP since XML is a native type in AS3. But the serialization/deserializtion is costly, and it would be great if we can use the flash native binary format (AMF) to transfer objects around. Thus enters Granite. Quoting from the introduction "Granite Data Services (GDS) is a free, open source (LGPL'd), alternative to Adobe® LiveCycle® (Flex™ 2) Data Services for J2EE application servers. It is not, however, a drop-in replacement: you won't be able to simply deploy a Flex 2 Data Services application into a Granite Data Services server without modifications. The main goal of this project is to provide a framework for Flex 2/EJB3/Spring/Pojo application development with full AMF3/RemoteObject benefits."
So, if you are a java server side programmer, try it out. In addition, if you use Spring to manage your POJOs, then client side RemoteObjects can have a destination that is bound to a spring bean.

Friday, November 23, 2007

GeoRSS Support

AWX has GeoRSS support. So given for example the following feed (on my local machine I can access it as http://ccccmac/~mansour/geofeed.xml):

<?xml version="1.0"?>
<rss xmlns:georss="http://www.georss.org/georss" version="2.0">
 <channel>
  <title>GeoRSS-Simple Example</title>
  <description>Example GeoRSS-Simple Feed</description>
  <georss:box>38.373576,-122.854022,38.423121,-122.804327</georss:box>
  <item>
   <title>GeoRSS-Simple Polygon</title>
   <description>A polygon describes an arbitrary geographic shape. The 
  format is a series of ordered latitude, longitude pairs. The last pair 
  must be the same as the first pair, closing the polygon.</description>
   <guid>urn:uuid:d496f4e3-7fd8-4169-ac6208e36dffa7f0</guid>
   <link>http://georss.org/simple</link>
   <author>georss supporter</author>
   <pubDate>Mon, 09 Jul 2007 10:49:00 PDT</pubDate>
   <georss:polygon>
  45.256 -110.45 46.46 -109.48 43.84 -109.86 45.256 -110.45
  </georss:polygon>
  </item>
 </channel>
</rss>

You can create a GeoRSS layer as follows:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
 xmlns:mx="http://www.adobe.com/2006/mxml"
 xmlns:awx="http://www.arcwebservices.com/2007/awx"
 layout="absolute"
 xmlns:layers="com.esri.aws.awx.map.layers.*">
 <mx:Script>
  <![CDATA[
   import flash.net.navigateToURL;
   import mx.events.ChildExistenceChangedEvent;
   import com.esri.aws.awx.map.layers.overlays.OverlayObject;
   
   private function onChildAdd( event : ChildExistenceChangedEvent ) : void
   {
    var overlayObject : OverlayObject = event.relatedObject as OverlayObject;
    overlayObject.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, false, 0.0, true);
   }
   
   private function onMouseDown( event : MouseEvent ) : void
   {
    var overlayObject : OverlayObject = event.target as OverlayObject;
    navigateToURL( new URLRequest( overlayObject.link), "_blank");
   }
   
   private function onFeedLoad() : void
   {
    map.extent = geoRSSLayer.extent.createBuffer(0.2);
   }
  ]]>
 </mx:Script>
 <awx:Framework/>
 <awx:Map id="map" createDefaultLayers="false">
  <layers:GeoRSSLayer
   id="geoRSSLayer"
   feedUrl="http://ccccmac/~mansour/geofeed.xml"   
   feedLoad="onFeedLoad()"
   childAdd="onChildAdd(event)"
   >
   <layers:polygonStyle>
    <awx:PolygonStyle color="0xFFFF00" outlineColor="0x000000" outlineThickness="2"/>    
   </layers:polygonStyle>
  </layers:GeoRSSLayer>  
 </awx:Map>
</mx:Application>

In this example, I'm setting the GeoRSSLayer feed URL, and I have the option to set the style of the polygon, in this case a yellow filling with a 2 pixel wide black outline. On each added overlay, I'm adding a mouse down event listener, such that when I click on the overlay, I navigate to the associated URL. When the feed is fully loaded, I'm setting the map extent to the layer extent plus a 2 percent buffer.


Remember, if you want to access a remote GeoRSS feed, make sure that it has a crossdomain.xml file or you can always use a proxy server.

Thursday, November 22, 2007

10000 Markers

Been wanting to blog about this for a while. Users been asking me "how to I plot thousands of markers without the overhead of a Marker (which is a subclass of UIComponent) but still get the benefits of Marker mostly for mouse over/out/click events ?". Back in the days when I was RAT (Rent-a-Tech), my friend Leo came up with a concept of TurboLayer for SDE, where you group in one feature all the geometries of a feature class. It was fast, but you could not get to an individual feature because it was all "blob'ed" together (SDE folks out there, you know what I mean :-) So I took the same concept and implemented it in AWX, but with an extra twist where you can get to an individual feature indirectly using an RTree class. An RTree enables you to efficiently index features spatially on the client side. cool, eh ? You can download this zip file that contains an application that loads 1000 random points and when you mouse over a point, a tooltip shows up with the id of the point. If there are more that one point at that mouse location, then the tooltip text is a list of ids separated by '/'. I've tried this on 10000 point and did not notice a performance issue - this is due to the efficient implementation of the RTree (thanks Kerry :-). So...download the file and try it out and tell me what you think. Happy Thanksgiving.

Wednesday, November 21, 2007

DefaultProperty metadata

Looking back at the last post, yea... it is nice to MXML, but it is a bit ugly and verbose till I remembered the [DefaultProperty("xxxx")] metadata.   Adjusted my local copy and what you will get is this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:awx="http://www.arcwebservices.com/v2007/awx"
  layout="absolute"
  >
  <awx:Framework/>
  <awx:Map createDefaultLayers="false">
    <awx:PolygonLayer>
      <awx:Polygon>
        <awx:PolygonShape>
          <awx:GeoPoint x="45" y="45"/>
          <awx:GeoPoint x="45" y="-45"/>
          <awx:GeoPoint x="-45" y="0"/>           
        </awx:PolygonShape>
      </awx:Polygon>
    </awx:PolygonLayer>
  </awx:Map>
</mx:Application>

WDYT ? oh and BTW, hoping to put this for the next release :-)

Blogged with Flock

Tuesday, November 20, 2007

Creating polygons in MXML


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
xmlns:geom="com.esri.aws.awx.geom.*"
xmlns:arcwebservices="http://www.arcwebservices.com/2007/awx"
>
<arcwebservices:Framework/>
<arcwebservices:Map>
<arcwebservices:basemaps>
<arcwebservices:PolygonLayer>
<arcwebservices:Polygon>
<arcwebservices:shape>
<geom:PolygonShape>
<geom:geoPoints>
<geom:GeoPoint x="45" y="45"/>
<geom:GeoPoint x="45" y="-45"/>
<geom:GeoPoint x="-45" y="45"/>
</geom:geoPoints>
</geom:PolygonShape>
</arcwebservices:shape>
</arcwebservices:Polygon>
</arcwebservices:PolygonLayer>
</arcwebservices:basemaps>
</arcwebservices:Map>
</mx:Application>

Sunday, November 18, 2007

AWX 4.0 Is Released !

Check out the latest version 4.0 - lots of bug fixes - great documentation.   And if you are wondering what happened to version 3.0, well...it was an internal release.   Have fun :-)

Blogged with Flock

Friday, November 16, 2007

IntelliJ 7 Rocks

I've been using IDEA since I do not remember when.   Just got a license to the latest version.  It has great Spring support, and now you can see your web.xml files in this wizard cool panes.  In addition, there is support of AS3, I mean with auto-completion and refactoring. Too cool !

Blogged with Flock

Cairngorm and the Framework

People have been asking me to show them how to use Cairngorm with the AWX Framework that is loosely based on OSGi. The interaction will most likely come in an ICommand implementation or a Delegate.  Here is an example that shows how to use the Find Service.
First, make sure that you have registered with the Framework the FindActivator.
<Framework apiKey="[your-api-key]">
  <FindActivator/>
</Framework>
Next, since a Command is always created and executed by the CairngormEventDispatcher,  you can always get a reference to the Framework through its static function getInstance() and then get a reference to systemBundleContext which is an IBundleContext implementation.

package com.esri.awx
{
    import com.adobe.cairngorm.commands.ICommand;
    import com.adobe.cairngorm.control.CairngormEvent;
    import com.esri.aws.osgi.framework.Framework;
    import com.esri.aws.osgi.framework.IBundleContext;
    import com.esri.aws.osgi.framework.IServiceReference;
    import com.esri.aws.services.IFind;
   
    import flash.utils.getQualifiedClassName;
   
    import mx.collections.ItemResponder;

    public class FindCommand implements ICommand
    {
        public function execute(event:CairngormEvent):void
        {
            var findEvent : FindEvent = event as FindEvent;
            var context : IBundleContext = Framework.getInstance().systemContext;
            var ref : IServiceReference = context.getServiceReference(getQualifiedClassName(IFind));
            if( ref )
            {
                var find : IFind = context.getService( ref ) as IFind;
                find.findLocation( findEvent.location, null, new ItemResponder(
                function( data : Object, token : Object = null) : void {
                    // do something with data
                },
                function( info : Object, token : Object = null) : void {
                    // do something with info
                }
                ));
            }
        }
    }
}

And here is the FindEvent class:

package com.esri.awx
{
    import com.adobe.cairngorm.control.CairngormEvent;

    public class FindEvent extends CairngormEvent
    {
        public static const FIND : String = "find";
        
        public var location : String;
        
        public function FindEvent(
            type:String,
            bubbles:Boolean=false,
            cancelable:Boolean=false
        )
        {
            super(type, bubbles, cancelable);
        }
        
    }
}

Blogged with Flock

Sunday, November 11, 2007