Insprise Blogs

August 1, 2008

Quick AS Note: Date

Filed under: Software Development — jack @ 12:45 pm

Date Parsing

var text:String = t1.text; // “Sat Jul 19 21:21:26 GMT-0400 2008″;
var date:Date = new Date(Date.parse(text));
if(isNaN(date.getTime())) {
throw new Error(”Invalid date: ” + text);
}else{
trace(”Date parsed: ” + date);
}

Note: if a string fails to be parsed to a Date, no error will be thrown. However, you can validate a Date by the value returned by getTime().

July 9, 2008

Dirty ArrayCollection

Filed under: Software Development — jack @ 11:25 pm

I spent quite some time on debugging an issue on Flex-Java serialization. Below is the lesson learnt.

The problem: the order of the elements in an ArrayCollection changes when it is sent to the server (Java side).

On the client side, the ArrayCollection has EditField:2C as element 0 and EditField:1C as element 1.

However, the server side has EditField:1C as element 0 and EditField:2C as element 1.

First thoughts: there is something wrong with the serialization.

The code snippet:

// in method public function writeExternal(output:IDataOutput):void

output.writeObject(_targetObjects == null ? null : new ArrayCollection(_targetObjects.source)); // writeExternal of Array -> java.util.List.

_targetObjects is of a class extending ArrayCollection. In order to use default ArrayCollection -> Java List serialization, a new ArrayCollection is created based on the same source array. On the client side, _targetObjects contains the following:

[Element 0] - EditField:2C
[Element 1] - EditField:1C

On the server side, a List is created with the following:

[Element 0] - EditField:1C
[Element 1] - EditField:2C

Obviously, the order changes. So the following lines are inserted to the writeExternal method on the client side for debuggin purpose:

trace(”**** 0: ” + _targetObjects.getItemAt(0));
trace(”**** 1: ” + _targetObjects.getItemAt(1));
trace(EOUtils.traceEO(new ArrayCollection(_targetObjects.source)));

The log shows that the order problem arises on the client side even before the array is sent to the server:

**** 0: EditField:2C#ODE
**** 1: EditField:1C#FP5
ArrayCollection #0
[0] EditField:1C#FP5 #1
[1] EditField:2C#ODE #3

The real cause:

_targetObjects has sort property set. The sort function affects the order of the elements returned by getItemAt, although the underlying source array does not change.

Some thoughts:

  • When using ArrayCollection, *always* consider the side effects or sort and filter. sort may change the order of the elements of an array; while filter may hide certain elements in the array.
  • ArrayCollection != Java’s List
    • ArrayCollection can have sort and filter, which affects element order and visibility;
    • ArrayCollection.getItemIndex uses reference comparison to find non-primitive objects; while most of Java classes implementing the List interface use equals for object equality comparison. If you need an object reference comparison based List, use com.insprise.common.collection.ArrayListComparisonByReference.
  • IMHO, the design of ArrayCollection is dirty. It supposes to be M part of the MVC pattern, but it plays both the M and C (sort/filter) roles. ArrayCollection is widely used in any Flex application, and every Flex developer must take great care when using ArrayCollection with sorting and filtering capibilities. It’s recommmended to document clearly whether an ArrayCollection may have sort/filter; if so, who does it, and where.

Dirty ArrayCollection

Filed under: Software Development — jack @ 11:22 pm

I spent quite some time on debugging an issue on Flex-Java serialization. Below is the lesson learnt.

The problem: the order of the elements in an ArrayCollection changes when it is sent to the server (Java side).

On the client side, the ArrayCollection has EditField:2C as element 0 and EditField:1C as element 1.

However, the server side has EditField:1C as element 0 and EditField:2C as element 1.

First thoughts: there is something wrong with the serialization.

The code snippet:

// in method public function writeExternal(output:IDataOutput):void

output.writeObject(_targetObjects == null ? null : new ArrayCollection(_targetObjects.source)); // writeExternal of Array -> java.util.List.

_targetObjects is of a class extending ArrayCollection. In order to use default ArrayCollection -> Java List serialization, a new ArrayCollection is created based on the same source array. On the client side, _targetObjects contains the following:

[Element 0] - EditField:2C
[Element 1] - EditField:1C

On the server side, a List is created with the following:

[Element 0] - EditField:1C
[Element 1] - EditField:2C

Obviously, the order changes. So the following lines are inserted to the writeExternal method on the client side for debuggin purpose:

trace(”**** 0: ” + _targetObjects.getItemAt(0));
trace(”**** 1: ” + _targetObjects.getItemAt(1));
trace(EOUtils.traceEO(new ArrayCollection(_targetObjects.source)));

The log shows that the order problem arises on the client side even before the array is sent to the server:

**** 0: EditField:2C#ODE
**** 1: EditField:1C#FP5
ArrayCollection #0
[0] EditField:1C#FP5 #1
[1] EditField:2C#ODE #3

The real cause:

_targetObjects has sort property set. The sort function affects the order of the elements returned by getItemAt, although the underlying source array does not change.

Some thoughts:

  • When using ArrayCollection, *always* consider the side effects or sort and filter. sort may change the order of the elements of an array; while filter may hide certain elements in the array.
  • ArrayCollection != Java’s List
    • ArrayCollection can have sort and filter, which affects element order and visibility;
    • ArrayCollection.getItemIndex uses reference comparison to find non-primitive objects; while most of Java classes implementing the List interface use equals for object equality comparison. If you need an object reference comparison based List, use com.insprise.common.collection.ArrayListComparisonByReference.
  • IMHO, the design of ArrayCollection is dirty. It supposes to be M part of the MVC pattern, but it plays both the M and C (sort/filter) roles. ArrayCollection is widely used in any Flex application, and every Flex developer must take great care when using ArrayCollection with sorting and filtering capibilities. It’s recommmended to document clearly whether an ArrayCollection may have sort/filter; if so, who does it, and where.

July 5, 2008

Caution: ObjectUtil.toString triggers every relationship property!

Filed under: Software Development — jack @ 4:51 pm

I spent quite some time to fix a problem on huge object net. When I looked at the log, I found that every relationship property of every object is triggered for resolution. This results thousands of relationship resolution request to the server and huge object net sent to the server.

The root cause of this problem is ObjectUtil.toString(). In the code, I inserted the following line for debugging purpose:

log.info(”onRelEditPanelsResolvedSuccess: ” + (event == null ? “editForm” : event.relationshipObject) + “.panels”);

If the relationship is of to-many type, the class for realtionshipObject will be a subclass of ArrayCollection (which in turn is a subclass of ListCollectionView). ListCollectionView.toString uses ObjectUtil.toString to perform recursive object introspection and prints out every property. The object introspection process triggers every relationship property of every related object.

This behavior is very undesirable. After all, toString() is supposed to be read-only method. To fix this problem, simply provides an overriding toString method in the class for relationshipObject.

May 27, 2008

Select the Right containers and Layout Managers

Filed under: Uncategorized — jack @ 1:30 pm

Flex offers quite a number of containers. Often developers may have trouble to pick the right containers for their UI. Pick the most appropriate containers by using this reference table for all the Flex containers with information on properties, comparisons, best usages and their Java/HTML counterparts:

Type Properties/behaviors Best used for HTML counterpart Java counterpart
Layout Managers
Canvas Absolute (x=10, y=10) or constraint-based (left=20, top=20) layout for children Creating complex UI combining both absolute and constraint-based layouts. - - Absolute: null (layout)
- Constrainted base: GridBagConstraints
Box (HBox/VBox) Lays out its children in a row or column. The sizes of the children laid out vary. Laying out a group of size varying components, e.g., a group of control buttons. Normal HTML rendering FlowLayout
DividedBox (HDividedBox/VDividedBox) HDividedBox: Lays out its children in a row separated by draggable deviders. The height of all the children is set to the same as the divided box. VDividedBox: similar. Creating split panes - JSplitPane
Form [FormHeading, FormItem] A single column form like a HTML form. Data input form HTML form (table) -
Grid HTML table like; The height of all cells in a row is the same, however, each row may have a different height; the width of all cells in a column is the same, however, each column may have a different width. Each cell may contain zero or one child, and a child may multiple cols/rows. Organizing a large number of components in a tabular form HTML table GridBagLayout
Tile Similar to Grid, but the size of all the cells is the same. Tiling a number of children - GridLayout
ViewStack Displays only one of its children at any time; need to work with a LinkBar, TabBar, ButtonBar or ToggleButtonBar to select the child to be displayed. Stacking multiple children and showing only one selected by the user - CardLayout
TabNavigator A ViewStack with a TabBar as its stack selection control Creating tabbed panes JTabbedPane
Accordion Behaves similarly to a ViewStack, but Accordion displays the title (label) for each child when the title (label) of a child is selected, it will be displayed and all other children will be hidden. Creating multi-section data input forms - -
Windows
Panel A window with title bar, content pane and status message area. Three types of layouts: horizontal, vertical and absolute. Wrapping self contained application modules - JFrame (the closest thing)
TitleWindow A special Panel with a close button in the title bar that can be used for creating pop up windows. Creating pop up windows - JDialog
Special components
ApplicationControlBar Lays out its children like a tool bar. Creating a tool bar on the main application window. JToolBar
ControlBar Summary/control bar for a Panel or TitleWindow at the bottom Creating a summary/control bar at the bottom of a Panel or TitleWindow -

Issues in Relationship Resolution

Filed under: Software Development — jack @ 1:48 am

On-demand Relationship Resolution

When you load an object to the client side, you probably do not want to load all of its related objects. Related objects should be resolved on request. For example, when you access a relationship, e.g., employee.addresses and it is unresolved, the client library should return a placeholder ArrayCollection and automatically pend a request to the server for resolution. When the relationship is resolved and received by the client side, it will be merged into the UOW as a result, the ArrayCollection and any UI components using it as a data provider will get updated accordingly.

Issue 1 - ObjectUtil.toString(obj) triggers all relationships of the obj being resolved

For example, if you set the log level for mx.rpc.*/mx.messaging.*/mx.data.* to DEBUG, Flex will log the object being sent to the server through ObjectUtil.toString. The ObjectUtil.toString will try to print all the properties (including related objects) of the object, thus all relationships are triggered for resolution. This is undesirable. The solution is to set the log level for mx.rpc to INFO. If you still want to use ObjectUtil.toString to print detailed information about an object, consider to implement your own toString(verbose:Boolean) function.

Issue 2 - Selective relationship loading

Problem description: for normal objects selected from the database, all their resolved relationships should be sent to the client side. However, for application scope (in contrast to request/session scope) metadata objects, you might want to control whether relationships should be sent along with the objects to the client. For example, relationships should not be sent during initial loading; while later, they should be sent when relationship resolution requests are received.

Solution: When a request is received, classify it by whether metadata objects should send relationships. If so, set a ThreadLocal variable to true to force output all relationships; otherwise set it to false.

May 26, 2008

ActionScript Casting Gotcha - is/as

Filed under: Uncategorized — jack @ 12:58 am

is, as

Java counterpart for is: instanceof; Java counterpart for as: (TYPE)object. However, casting behaviors of AS3 and Java are quite different when handling invalid casting.

Testing code:

LogUtils.defaultLog.info(”(null is ArrayCollection): ” + (null is ArrayCollection));
LogUtils.defaultLog.info(”(undefined is ArrayCollection): ” + (undefined is ArrayCollection));
LogUtils.defaultLog.info(”(new ArrayCollection() as ArrayCollection): ” + (new ArrayCollection() as ArrayCollection));
LogUtils.defaultLog.info(”(new ArrayCollection() as ListCollectionView): ” + (new ArrayCollection() as ListCollectionView));
LogUtils.defaultLog.info(”(new ArrayCollection() as Object): ” + (new ArrayCollection() as Object));
LogUtils.defaultLog.info(”(new ArrayCollection() as EOObject): ” + (new ArrayCollection() as EOObject));
LogUtils.defaultLog.info(”(null as ArrayCollection): ” + (null as ArrayCollection));

Output:

[INFO] com.insprise.Log (null is ArrayCollection): false
[INFO] com.insprise.Log (undefined is ArrayCollection): false
[INFO] com.insprise.Log (new ArrayCollection() as ArrayCollection): [not null]
[INFO] com.insprise.Log (new ArrayCollection() as ListCollectionView): [not null]
[INFO] com.insprise.Log (new ArrayCollection() as Object): [not null]
[INFO] com.insprise.Log (new ArrayCollection() as EOObject): null
[INFO] com.insprise.Log (null as ArrayCollection): null

Findings:

  • null/undefined can not be casted into any object type [same as Java null instanceof Object is false.]
  • null/undefined as TYPE always results null [same as Java Map(null) is null.]
  • casting an object into a different class tree from the one is belongs will always results null, unlike Java no error will be thrown. [different from Java (Map)(new Object()) throws ClassCastException.]

May 24, 2008

Handling Errors in Web App

Filed under: Software Development — jack @ 10:11 pm

When i was surfing on the Facebook site, the following dialog popped up as a result of an error:

Whatever technology you are using on the client, transport error always occurs. The error dialog shown above is not user friendly. From my own experiences, there are three key points on handling such errors on the client side:

1. An error occurs during a read operation: try to read from server again before displaying an error message to the user;

2. An error occurs during a create/update/delete operation: the client side should try to query the server side again for the result of the last operation and refresh the UI accordingly;

3. A fatal error with all re-tries failed: display an error message to the user. The error message should explain what happened in plain English and suggest the user the next step to take. Optionally, a detailed technical message could be made available at the user’s request.

May 23, 2008

Java @SuppressWarnings

Filed under: Uncategorized — jack @ 2:19 pm

Introduction

While developing the software, the programmer should always give notice to warnings. Whenever a warned code practice is desired, @SuppressWarnings should be used. For example, sometimes, you do need a collection without specifying its parameterized type, e.g., object marshalling:

public void writeExternal(ObjectOutput out) throws IOException {
// construct a proper ArrayList, to be deserialized as ArrayCollection in the client side.
ArrayList list = new ArrayList(cachedObjects);
out.writeObject(list); // -> ArrayCollection.
}

The Eclipse IDE throws this warning on above code:

ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized

There are two ways to remove the warning. 1) Refactor the code, change ArrayList to ArrayList<Object>; 2) use @SuppressWarnings to disable the warning:

@SuppressWarnings({”unchecked”})
public void writeExternal(ObjectOutput out) throws IOException …

Usage

You can use @SuppressWarnings to annotate TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE. The set of warnings suppressed in a given element is a superset of the warnings suppressed in all containing elements.

- suppress all: @SuppressWarnings({”all”}) // use this with care

- suppress multiple warnings: @SuppressWarnings({”unchecked”,”fallthrough”})

List of Warning Types - Sun’s JDK 6.0

Use javac -X to print the list of warning types as below:

-Xlint:{all,deprecation,unchecked,fallthrough,path,serial,finally

Explanation:

  • all - all kinds of warning below
  • deprecation - a deprecated element (class/method/field) is used;
  • unchecked - collection is used without generic parameterized type;
  • fallthrough - falls-through to the next case without a break in a switch block;
  • path - non-existent path in classpath, sourcepath
  • serial - missing a serialVersionUID definitions on serializable classes
  • finally - finally clause that fails complete normally

List of Warning Types - Eclipse JDT v3.3

As described in JDT Plug-in Developer Guide [LINK]:

The list of tokens that can be used inside an SuppressWarning annotation is:

  • all to suppress all warnings
  • boxing to suppress warnings relative to boxing/unboxing operations
  • cast to suppress warnings relative to cast operations
  • dep-ann to suppress warnings relative to deprecated annotation
  • deprecation to suppress warnings relative to deprecation
  • fallthrough to suppress warnings relative to missing breaks in switch statements
  • finally to suppress warnings relative to finally block that don’t return
  • hiding to suppress warnings relative to locals that hide variable
  • incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case)
  • nls to suppress warnings relative to non-nls string literals
  • null to suppress warnings relative to null analysis
  • restriction to suppress warnings relative to usage of discouraged or forbidden references
  • serial to suppress warnings relative to missing serialVersionUID field for a serializable class
  • static-access to suppress warnings relative to incorrect static access
  • synthetic-access to suppress warnings relative to unoptimized access from inner classes
  • unchecked to suppress warnings relative to unchecked operations
  • unqualified-field-access to suppress warnings relative to field access unqualified
  • unused to suppress warnings relative to unused code

Code Generation Consideration

All code generators should take care of the above mentioned warnings. If the generated Java code could contain warnings, let the user have the option to specify @SuppressWarnings.

Antlr:

Lexers and parsers generated by Antlr easily result hundreds of warnings. To fix it, copy Java.stg into a file name JavaSuppressWarnings.stg, and modify the new file as following:

<@imports>
import org.antlr.runtime.*;
<if(TREE_PARSER)>
import org.antlr.runtime.tree.*;
<endif>
import java.util.Stack;
import java.util.List;
import java.util.ArrayList;
<if(backtracking)>
import java.util.Map;
import java.util.HashMap;
<endif>
@SuppressWarnings({”unused”, “cast”})
<@end>

the set language=JavaSuppressWarnings in the options.

Still there could be some warnings about import, use Eclipse’s source -> organize imports.

May 21, 2008

Make Properties Bindable

Filed under: Software Development — jack @ 3:11 am

You use the [Bindable] metadata tag to indicate a property is bindable, e.g.:

[Bindable]
public var name:String;

I prefer accessors (getter/setter) instead of public variables to have more control. For a property with a pair of getter and setter functions, you should put the [Bindable] immediate above the getter function - no need to put it above the setter function. Another thing I noted that bindable can be used for a property with a getter function but no setter function. Additionally, use [Bindable(event=”theEventName”)] to explicitly dispatch event to notify about property value change. The class below illustrates how [Bindable] can be used:

public class Person extends EOObject {
static var log:ILogger = Log.getLogger(”com.insprise.test.Person”);

private var _name:String = “Jack”;
private var _title:String = “Mr.”;
private var _desc:String = “…”;

public function Person():void {
LogUtils.configLog();
}

[Bindable(event=”propertyChange”)]
public function get title():String {
log.info(”Get title: ” + _title);
return _title;
}

public function set title(title_:String):void {
log.info(”Setting title to: ” + title_);
if(_title == title_) {
return;
}
var old:String = this._title;
this._title = title_;
dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, “title”, old, title_));
}

[Bindable(event=”propertyChange”)]
public function get name():String {
log.info(”Get name: ” + _name);
return _name;
}

public function setTheName(name_:String):void { // no match setter.
log.info(”Setting name to: ” + name_);
if(_name == name_) {
return;
}
var old:String = this._name;
this._name = name_;
dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, “name”, old, name_));
}

[Bindable]
public function get desc():String {
log.info(”Get desc: ” + _desc);
return _desc;
}

public function set desc(desc_:String):void {
log.info(”Setting desc to: ” + desc_);
if(this._desc == desc_) {
return;
}
this._desc = desc_;
}
}

Testing:

var per:Person = new Person();
per.title = textTitle2.text;
// per.name = textName2.text;
per.setTheName(textName2.text);
per.desc = textDesc2.text;

Note:

  1. Property name does not have a setter name. However, when setTheName updates the value, a property change event will be dispatched and the UI components binding to the name property will get updated;
  2. We only put a [Bindable] without event name to property desc. In this case, ActionScript compiler will generate the code to track desc’s value change. From my basic testing, the performace of generated code and explict event handling is about the same.

Footnote: the generated code for [Bindable] desc (It’s very similar to our manual [Bindable(event=”propertyChange”)] setTheName):

class BindableProperty
{
/**
* generated bindable wrapper for property desc (public)
* - generated setter
* - original getter left as-is
* - original public setter ‘desc’ moved to ‘_3079825desc’
*/

[Bindable(event=”propertyChange”)]
public function set desc(value:String):void
{
var oldValue:Object = this.desc;
if (oldValue !== value)
{
this._3079825desc = value;
this.dispatchEvent(mx.events.PropertyChangeEvent.createUpdateEvent(this, “desc”, oldValue, value));
}
}
}

Newer Posts »

Powered by WordPress