Sunday, October 21, 2012

Array, ArrayList, ListCollectionView and ArrayCollection

Few days back I got stuck with one minor but pretty confusing problem. I was getting an ArrayList from java as a remote call and I assigned that event.result to the ArrayCollection in Flex. And I was using the same arraycollection at three different places. At one place I was showing all the items in the arraycollection and at other places I was applying some filter function. It all seemed ok, but there was some logic which was performing search at one place and at some other places it was trying to perform some addition/deletion/update work on the items in the collection. But some times I observed weird behavior: after doing the search at one place I was getting the index and trying to remove the element at that index at second place from the same collection and it resulted into range error exception. That was surprising!!


Then after some debugging I realized that the filter function applied at second place, actually changes the elements of the arraycollection but the underlying source (array) remains intact. But I want to have a solution which will allow me to use the same collection at multiple times, along with the option that I can apply filter at one place without disturbing the list of items at other place. Also if I do insertion/deletion at any one place, the other should be updated as well. So I came with the idea of exploring all of them. One very useful post I found here.and here. Let's proceed.

Array: Similar to array in any other language. It stores a list of references to other objects. It is zero-based (like java) and is unbounded (means automatically grow when items are added). Unfortunately we cannot peek into the source class for this. More

 // create an empty array then add elements
   var array1:Array = new Array();
   array1[0] = "A";
   array1[1] = "B";
   array1[2] = "C";
   trace( "Array has " + array1.length + " elements" ); // returns 3

To loop over an array in action script we can find an example here

ArrayList: An ArrayList wraps an array with the name source (note that it does not extend Array but wraps it) and adds event listeners to all of its items. It extends EventDispatcher class so, when the items are added/deleted/updated it dispatches proper event so that the component (List, DataGroup etc) can update itself.

public class ArrayList extends EventDispatcher  implements IList,IExternalizable, IPropertyChangeNotifier
{
           private var _source:Array;

           public function get source():Array
           {
              return _source;
           }
    
           public function set source(s:Array):void
           {
              var i:int;
              var len:int;
              if (_source && _source.length)
              {
                 len = _source.length;
                 for (i = 0; i < len; i++)
                 {
                    stopTrackUpdates(_source[i]);
                 }
              }
             _source  = s ? s : [];
             len = _source.length;
             for (i = 0; i < len; i++)
             {
                   startTrackUpdates(_source[i]);
             }
        
             if (_dispatchEvents == 0)
             {
                   var event:CollectionEvent =
                   new  CollectionEvent(CollectionEvent. 
                     COLLECTION_CHANGE);
                   event.kind = CollectionEventKind.RESET;
                   dispatchEvent(event);
             }
         }

}
If the item in the ArrayList is IEventDispatcher the startTrackUpdates and stopTrackUpdates methods will start or stop tracking the updates for the item.




ListCollectionView: It wraps (and not extends) the ArrayList (which implements IList interface, explained later on) and provides filtering, sorting and cursor functionality.

public class ListCollectionView extends Proxy implements ICollectionView, IList, IMXMLObject
{
   private var _list:IList;
   public function get list():IList
    {
        return _list;
    }
    public function set list(value:IList):void
    {
        if (_list != value)
        {
            var oldHasItems:Boolean;
            var newHasItems:Boolean;
            if (_list)
            {
               _list.removeEventListener(CollectionEvent.
               COLLECTION_CHANGE,listChangeHandler);
                oldHasItems = _list.length > 0;
            }

            _list = value;

            if (_list)
            {
               // weak listeners to collections and dataproviders
        _list.addEventListener(CollectionEvent.
            COLLECTION_CHANGE,listChangeHandler, false, 0, true);
                newHasItems = _list.length > 0;
            }

            if (oldHasItems || newHasItems)
                reset();
            dispatchEvent(new Event("listChanged"));
        }
    }
}

When a filter is applied, all the items internally remained untouched, but it is just the outer code cannot see them (hence the name collection View).It means if a component is using ListCollectionView as data provider only the items passing the filtering will be shown by the component.

ArrayCollection: ArrayCollection extends ListCollectionView and inherits all the attributes and introduces a n array with name source. Internally it will wrap this array to arraylist and from there on wards its all in hands of ListCollectionView.

public class ArrayCollection extends ListCollectionView implements IExternalizable
{
       .........
       .........
       public function set source(s:Array):void
      {
            list = new ArrayList(s);
       }

}

That's all. I hope it was useful.




Wednesday, October 3, 2012

Implementing Singleton in Java

A singleton class will always have at most one instance and so it will be instantiated only once.

There are two primary ways to implement it:
  • using public static method and 
  • using public factory method. 
Both the approaches make use of private constructor. As the constructor is private we will generally not be able to construct an instance of this calls using new operator. But a privileged  client can invoke the private constructor reflectively with the aid of the AccessibleObject.setAccessible method. So we can create an exception if it's asked to create a second instance.


Using public static field:

// Singleton with public final field
public class God{
   public static final God INSTANCE = new God();
   private God() { ... }
   public void worshipHIM() { ... }
}


Using public static factory method:

// Singleton with static factory
public class God{
   private static final God INSTANCE = new God();
   private God() { ... }
   public static God getInstance() { return INSTANCE; }
   public void worshipHIM() { ... }
}

One advantage of the latter approach is: we can remove the singleton constraint easily without changing the API, if we want. As of Java 1.5 there is one more approach as pointed by Joshua Bloch(Effective Java, Item 3) here.

// Enum singleton - the preferred approach
public enum God{
   INSTANCE;
   public void worshipHIM() { ... }
}

Implementing singleton using first two approaches may need some extra work if we also want the class to be serializable. We need to make all the fields transient and also need to provide readResolve method. If we don't do so we will get new instance each time we de-serialize a serialized instance. So we need to add the following method to GOD class:

// readResolve method to preserve singleton property
private Object readResolve() {
   // Return the one true God and let the garbage collector
   // take care of the God impersonator.
   return INSTANCE;
}

There is one third approach as well by using enum:

public enum God {
   INSTANCE;
  public void makeAMiracle() { ..... }
}

And this is the best approach.

More can be found here:









Friday, September 14, 2012

BlazeDS, LCDS and Flex-Java Interaction (Part 2)

Question: What do we mean by serialization/deserialization and Marshalling/UnMarshalling?
Answer: We can use remoting in blazeDS/LCDS to make use of server-side logic and  get the result back in Flex Client. Whenever we call any function on server side we generally pass some value-objects/primitives to server and there this marshalling (or serialization) comes into picture.

The conversion between data types in actionscipt to corresponding data types to Java (or any other supported server side laguage) is main idea of marshalling or serialization. While we receive data back from server side it is referred to as deserialization or un-marshalling. We can also use instances of our own custom (value objects) and then provide complete path of the corresponding value-object (in remote object tag)on server side to help blazeDS and FVM (Flash Virtual Machine) to cooperate in serialization/de-serialization.
BlazeDS uses the AMF binary protocol to serialize and deserialize Java classes, and the Flash Player does the same for the Flex classes on the client side.The use of a AMF binary data transfer format increases performance, allowing applications to load data up to 10 times faster than with text-based formats such as XML or SOAP.

Question: What is AMF protocol and where is it used?
Answer: AMF stands for Action Message Format. It is binary data prorocol supported by Flash Virtual Machine. It can be best described as SOAP-RPC hybrid, in which data is transferred via Remote Procedure Calls. This protocol is open source now.
Advantages of AMF include: rapid data transfer, automatic marshalling and unmarshalling of data objects by the FVM, support across the entire spectrum of server side languages including .NET, PHP, Java, Ruby, and Python.
Disadvantages of AMF include: proprietary protocol that is not compatible with other client-side RIA development platforms such as DOJO, Scriptaculous, and SilverLight.  However, JavaScript communication via AMF with a server language is made possible through the Adobe AIR platform.


Question: Can we achieve custom serialization/de-serialization?
Answer: Yes. The solution is to use flash.utils.IExternalizable interface in ActionScript which is compatible with java.io.IExternalizable API. We need to implement these interfaces on the client side and server side value objects respectively to take control of their serialization The API requires two methods readExternal() writeExternal() which take flash.utils.IDataInput and flash.utils.IDataOutput streams respectively. The implementations of these methods mirror the server Java class, which implements java.io.Externalizable – also with two methods readExternal() and writeExternal() taking java.io.ObjectInput and java.io.ObjectOutput streams respectively.


 public void writeExternal(ObjectOutput out) throws IOException 

 {    

    out.writeObject(id);    

    out.writeObject(name);   

    out.writeObject(description);   

    out.writeInt(price);  

 }  

 …mirrors the client readExternal method in ActionScript:  

 public function readExternal(input:IDataInput):void{  

    _id = input.readObject() as String;    

   name = input.readObject() as String;    

   description = input.readObject() as String;    

   price = input.readInt();  

 }  
A similar relationship exists for the reverse situation for sending instances back from the client to the server.


Question: Now we know that we can write custom serialization/de-serialization routines, but sometimes these are invoked for Flex->Server (BlazeDS) direction and not for Server->Flex Direction. What can be done to solve this problem?
Answer:If we encounter any such problem then the solution is to write own AMFEndpoint class and relevant serialization class.

Channel-Definition


<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
        <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="ch.hedgesphere.core.blazeds.endpoint.AMFEndpoint"/>

         <properties>
            <serialization>
                <type-marshaller>ch.hedgesphere.core.blazeds.translator.HedgesphereASTranslatortype-marshaller>
            serialization>
        properties>

    channel-definition>

Custom AMF Endpoint
 
package ch.hedgesphere.core.blazeds.endpoint;


import ch.hedgesphere.core.blazeds.serialization.Serializer;

    public class AMFEndpoint extends flex.messaging.endpoints.AMFEndpoint {

    @Override
    protected String getSerializerClassName() {
        return Serializer.class.getName();
        }

    }

Custom Serializer

 package ch.hedgesphere.core.blazeds.serialization;

import java.io.OutputStream;
import flex.messaging.io.MessageIOConstants;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfMessageSerializer;
import flex.messaging.io.amf.AmfTrace;
public class Serializer extends AmfMessageSerializer {

    @Override
    public void initialize(SerializationContext context, OutputStream out, AmfTrace trace)
    {
        amfOut = new AMF0Output(context);
        amfOut.setOutputStream(out);
        amfOut.setAvmPlus(version >= MessageIOConstants.AMF3);

        debugTrace = trace;
        isDebug = trace != null;
        amfOut.setDebugTrace(debugTrace);
    }
}
Custom AMF0 Handling

 package ch.hedgesphere.core.blazeds.serialization;

import flex.messaging.io.SerializationContext;
public class AMF0Output extends flex.messaging.io.amf.Amf0Output {
public AMF0Output(SerializationContext context) {
    super(context);
}
@Override
    protected void createAMF3Output()
    {
        avmPlusOutput = new AMF3Output(context);
        avmPlusOutput.setOutputStream(out);
        avmPlusOutput.setDebugTrace(trace);
    }
}

Custom AMF3 Handling


package ch.hedgesphere.core.blazeds.serialization;
import java.io.IOException;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import flex.messaging.io.SerializationContext;
public class AMF3Output extends flex.messaging.io.amf.Amf3Output {
public AMF3Output(SerializationContext context) {
    super(context);
}
@Override
public void writeObject(Object value) throws IOException {
    if(value instanceof DateTime) {
        value = convertToDate((DateTime)value);
    }
    if(value instanceof LocalDate) {
        value = convertToDate((LocalDate)value);
    }
    if(value instanceof LocalTime) {
    value = convertToDate((LocalTime)value);
    }
    super.writeObject(value);
}
private Object convertToDate(LocalTime time) {
    return time.toDateTimeToday().toDate();
}
private Object convertToDate(LocalDate date) {
    return date.toDateMidnight().toDate();
}
private Object convertToDate(DateTime dateTime) {
    return dateTime.toDate();
}   }

Custom Marshaller from Flex->Java

@SuppressWarnings({"rawtypes"})

@Override
public Object convert(Object originalValue, Class type) {
    if( type.equals(DateTime.class)) {
        return convertToDateTime(originalValue);
    }
    if( type.equals(LocalDate.class)) {
    return convertToLocalDate(originalValue); 
    }
    if( type.equals(LocalTime.class)) {
        return convertToLocalTime(originalValue);
    }

    return super.convert(originalValue, type);
}
private Object convertToLocalTime(Object originalValue) {
    return originalValue == null ? null : new LocalTime(originalValue);
}
private Object convertToLocalDate(Object originalValue) {
    return originalValue == null ? null : new LocalDate(originalValue); }
private Object convertToDateTime(Object originalValue) {
    return originalValue == null ? null : new DateTime(originalValue);
}
@SuppressWarnings({"rawtypes"})
@Override
public Object createInstance(Object source, Class type) {
    return super.createInstance(source, type);
}
}


Question:The main problem in serialization/de-serialization occurs when we are using numeric types. Actually Flex does not have null data type and when a null value comes from java side it is converted to zero. Also no datatype in Flex can hold a value of long data type in Java. In case precision matters we need to write our own custom solution. What can be done?
Answer: BlazeDS uses a BeanProxy to read and write attributes into an object (using its getters and setters), and to convert it to the right type if needed. That is an ideal place to customize. When reading values i.e. sending them to Flex (from Java) it is fine but when values move from flex to java it is problem because it will handle setting the properties of object but not handle the conversion when the number is an argument to remote call. For that to work a custom NumberDecoder is needed. As there is no mechanism to write custom decoder, we also need to replace TypeMarshaller.

Above excerpt is taken from the following link:
http://labs.bsb.com/2010/11/serialization-of-numeric-types-with-blazeds/