2012/08/31

The Application of TWaver to the NMS of FTTX Devices

In recent years, with the increasingly high requirements on the bandwidth, optic network equipment has gradually replaced those old transmission mediums and become the mainstream one. Now we will give an introduction on how to apply TWaver to the NMS(Network Management System) of FTTX devices through a demo.

This demo is divided into 3 layers:

  1. The layer MAP
  2. What way this layer applies is the combination of Map and elements, which can present an overview of the current system on the whole.
    The map, in fact, is formed by splicing together a large number of elements, each of which can be managed and selected to operate. In addition, the color of the elements can also be changed to show different states.
    In this demo, we can double-click the blocks (regions) or the elements on them to enter their inner layers. (Here interactions can be customized according to the detailed requirements.)
  3. The layer GIS
  4. What way this method applies is TWaver’s GIS component whose map-accessed function can help you access the maps from outer net quickly and conveniently and the server of the map of self-driving tour from intranet. We use Map World in this example. With the help of it, your device can be exactly positioned on the map with only the longitude and latitude of the device. Surely, detailed information on the device can also be shown on the map through ways like Attachment.
  5. The layer Test
  6. Broken lines are used in most FTTX systems to show the linking relationship. These requirements can be well met by TWaver’s varieties of LinkType. In order to create a good effect, we need to make a little adjustment to the position of the Label of the Link.

2012/08/30

To Make Your Own Title Bar of Flex AIR

Recently, some people have made some requirements on how to use codes to make unable the max and min buttons on the title bar in Flex AIR program. Though the two buttons can be both enabled or made unable in app.xml files, they cannot be switched dynamically because WindowedApplication.maximizable and WindowedApplication.minimizable are read-only. Next we will introduce how to customize our own title bar of AIR program. Let’s first see the final effects:
  1. First hide the original title bar: edit xxx-app.xml, then find the row systemChrome, cancel the explanation, and set the value as none:
  2. <!-- The type of system chrome to use (either "standard" or "none"). Optional. Default standard. -->
    <systemChrome>none</systemChrome>
  3. Construct the title bar: first fill the background with gradient color; then add “close”, ”minimize”, ”maximize” and the title bar respectively. Fortunately, the method “exit”,”minimize”,”maximize” and “restore” have been provided in WindowedApplication of Flex, hence the simplicity to close, minimize, maximize and restore the window.
  4.   <s:Group width="100%" height="20">
        <s:Rect id="background" left="0" top="0" right="0" bottom="0">
            <s:fill>
                <s:LinearGradient rotation="90">
                    <s:entries>
                        <s:GradientEntry color="0xCCCCCC" ratio="0" alpha="1"/>
                        <s:GradientEntry color="0x999999" ratio=".66" alpha="1"/>
                    </s:entries>
                </s:LinearGradient>
            </s:fill>
        </s:Rect>
        <s:Image source="close.png" click="exit()" width="20" y="2"/>
        <s:Image source="min.png" click="minimize()" width="20" x="20" y="2"/>
        <s:Image source="max.png" click="handleMax()" width="20" x="40" y="2"/>
        <s:Label id="_titlebar" text="TestAir" left="60" top="0" right="0" bottom="0" textAlign="center" verticalAlign="middle"/>
    </s:Group>
  5. Add listener to the title so as to move the window when dragging the title. Here we have taken a roundabout course. (The listener is used to listen to the mouse-move events to calculate the distance that the mouse has moved to change x and y position. The window is kept shaking when the mouse is moving.) Since there is a method startMove in nativeWindow of WindowedApplication, the window can be moved as long as this method is called in mouse-down event.
this.addEventListener(Event.ADDED_TO_STAGE, function(e:*):void {
    _titlebar.addEventListener(MouseEvent.MOUSE_DOWN, function (e:MouseEvent):void {
        nativeWindow.startMove();
    });
});
 
 

2012/08/24

The Application of Modularized TWaver Flex Application

The more widely-used Flex is; the more problems will thus rise:
  1. The size of SWF files will become larger;
  2. It will cost longer time to download SWF files;
  3. If there are several Flex applications, then how to multiplex the same codes (including Flex Framework, customized component library and third-party packages, such as TWaver Flex );
  4. Users need to download the new SWF file again after every update;
  5. How to add the new functions without revising and editing the old SWF files.
How to solve these problems?
Firstly, Runtime Shared Libraries can be used. The Flex Framework, the customized component libraries and the third-party packages are all separate swf files. The codes for them will not be included in Flex application programs, so:
  1. Just update the codes for new users’ programs, instead of updating Flex Framework, customized component libraries and third-party packages after the program is revised;
  2. RSL is buffered by the browser: it is not necessary to download RSLagain after updating the user program;
  3. There is no need to download repeatedly since a RSL can be shared by several Flex applications.
Secondly,modularity can be used.Function modules are divided into different SWF files, so:
  1. Able to update a specified function module separately;
  2. Able to dynamically add modules.
However, the problems will not be solved if just use RSL or Modularity:
  1. The function modules cannot be divided and they also cannot be loaded dynamically if only RSL is used.
  2. The shared Flex Framework, customized component libraries and the third-party package used in all modules are not able to be deleted if only using Modularity, hence the oversize of the sub-modular files.
In this article we will introduce the combination of RSL and Modularity in detail and help you to make modularized, extensible and powerful TWaver Flex application.
To begin with,in order to avoid the high coupling between the main program and the sub-module, we need to create a Flex Library project which has defined all public classes used in sub-modules and the interface of the communication between the sub-modules and the main program.
  1. IModule interface: the sub-module’s realization of this interface is used to show the name of it in the main program (get title), and call back it after the loading of it is finished (ready).
  2. package demo {
        public interface IModule {
            function get title():String;
            function ready(app:IApplication):void;
        }
    }
     
  3. IApplication interface is realized by the main program, used in the interaction between the sub-module and the main program. Now there is no method in this interface. You can add your own methods according to your requirement.
  4. package demo {
        public interface IApplication {

        }
    }
     
In addition, Library project has also customized the Network components and Node to the use of sub-module. But you need to pay attention to the fact that the link type of framework linkage and twaver.swc must be changed to external in the project selections in order to reduce the size of the sec files generated by Library project.
Next, create the main program--Flex project which uses the Library project above and twaver.swc. Its function is to show Tree on the left side and after clicking the tree node, the corresponding sub-module will be loaded on the right side.
  1. Add the component’s label and initialize the interface. First is HDivededBox component. Left: FastTree, right: VBox. (In VBox) up: Label, showing the name of the sub-module, bottom: sub-module container.
  2. <mx:HDividedBox width="100%" height="100%">
        <tw:FastTree id="tree" width="300" height="100%"/>
        <mx:VBox width="100%" height="100%">
            <mx:Label id="title" width="100%" textAlign="center"/>
            <mx:Canvas id="content" width="100%" height="100%"/>
        </mx:VBox>
    </mx:HDividedBox>
     
  3. Initialize the tree node: in order to succeed to dynamically add modules, here we read the information on modules from xml files. If you need to add new modules, you can change xml files directly instead of changing the main program.
  4. Xml file includes the name and the url of the module: 
      <modules>
          <module name="PSTN" url="ModulePSTN.swf"/>
          <module name="Alarm" url="ModuleAlarm.swf"/>
      </modules>
    Load codes for xml files as follows to save url information into the “client” property and to use this url to load the sub-module when clicking this node. 
    private function initTreeBox():void {
        var httpService:HTTPService = new HTTPService();
        httpService.resultFormat = "e4x";
        httpService.addEventListener(ResultEvent.RESULT, this.addModules);
        httpService.url = "modules.xml";
        httpService.send();
    }

    private function addModules(e:ResultEvent):void {
        for each(var module:XML in e.result.module){
            this.addModule(module.@name, module.@url);
        }
    }

    private function addModule(name:String, url:String):void {
        var data:Data = new Data();
        data.name = name;
        data.setClient("url", url);
        this.tree.dataBox.add(data);
    }

  5. Add the listener which listens to the selection of the nodes in Tree: When a node in Tree is selected, we first judge whether the corresponding sub-module has been loaded or not. If not, it will be dynamically loaded, and then saved into the “client” property; if it has already been loaded, the sub-module previously saved in the “client” property will be directly added into the container at the right side:
  6. this.tree.selectionModel.addSelectionChangeListener(this.handleSelectionChangeEvent);

    private function handleSelectionChangeEvent(e:SelectionChangeEvent):void {
        var selectedData:IData = this.tree.selectionModel.lastData;
        if(selectedData){
            var moduleLoader:ModuleLoader = selectedData.getClient("module");
            if(moduleLoader){
                this.content.removeAllChildren();
                this.content.addChild(moduleLoader);
                this.title.text = (moduleLoader.child as IModule).title;
            }else{
                moduleLoader = new ModuleLoader();
                moduleLoader.percentWidth = 100;
                moduleLoader.percentHeight = 100;
                moduleLoader.addEventListener(ModuleEvent.READY, this.moduleReady);
                moduleLoader.loadModule(selectedData.getClient("url"));
                selectedData.setClient("module", moduleLoader);
            }
        }
    }

    private function moduleReady(event:ModuleEvent):void {
        var moduleLoader:ModuleLoader = event.target as ModuleLoader;
        var module:IModule = moduleLoader.child as IModule;
        content.removeAllChildren();
        content.addChild(moduleLoader);
        this.title.text = module.title;
        module.ready(this);
    }
     
Notice that when importing twaver.swc and Library project, twaver.swc must be above the Library project, or it will complains: couldn’t find the class twaver.network::Network. In addition, the link type of framework linkage, twaver.swc and the Library project just mentioned above must be Runtime Shared Library(RSL). Please see the third step in the following for how to set in detail:

At last, please notice that when importing twaver.swc and Library project, twaver.swc must be above the Library project, or it will complains: couldn’t find the class twaver.network::Network. In addition, the link type of framework linkage, twaver.swc and the Library project just mentioned above must be Runtime Shared Library(RSL). Please see the third step in the following for how to set in detail:
Moreover, the compiling path of the sub-module can be changed to the catalogue of bin-debug of the main-program project. In this way, you don’t need to replicate the sub-module swf to the bin-debut of the main program after changing the sub-module every time.

Furthermore, it is unnecessary to generate HTML Wrapper, for the sub-module cannot be run independently. It can only be loaded from the main program. So there is no need to generate the html file which wraps sub-modules:
Finally, please notice that when changing link type to RSL, the OK button cannot be clicked only after you add RSL path, or you can just click “Add” button.
The codes for the sub-module is quite simple, but you need to pay attention that the root tab of mxml files must be changed to Module and the IModule interface must be realized.
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:demo="http://www.demo.com/demo" implements="demo.IModule"
    xmlns:tw="http://www.servasoftware.com/2009/twaver/flex"
    creationComplete="init()" width="100%" height="100%">
<mx:Script>
<![CDATA[
    import demo.*;

    private var _app:IApplication = null;

    public function get title():String {
        return "Alarm Demo";
    }

    public function ready(app:IApplication):void {
        this._app = app;
    }
]]>
</mx:Script>
</mx:Module>
We can last test the program after the procedures above:
Now let’s see the size of the package including the sub-modules, Library project and the main program. (It is really small-sized for the sub-module only is only less than 50K.)
Please refer to the official document of Adobe for more information on Module and RSL:
Creating Modular Applications
Using Runtime Shared Libraries

2012/08/23

To Draw Lines on the Nodes of Tree in Twaver

Recently, someone has asked how to add the guide lines to the nodes of Tree in TWaver on TWaver’s forum. This will be added into the new edition of TWaver Flex. Let’s first see the effects:
The properties in the following have been added in the new FastTree:
  1. lineStyle. Default: Consts.TREE_LINE_STYLE_NONE. Options: Consts.TREE_LINE_STYLE_NONE, Consts.TREE_LINE_STYLE_DOTTED and Consts.TREE_LINE_STYLE_SOLID.
  2. lineThickness. Default: 1
  3. lineColor. Default: 0×808080
  4. lineAlpha. Default: 1.
The following example can adjust these properties:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:tw="http://www.servasoftware.com/2009/twaver/flex"
                applicationComplete="init()" backgroundColor="#FFFFFF">
    <mx:Script>
        <![CDATA[
            import twaver.*;

            private var box:DataBox = new DataBox();

            private function init():void {
                // Init data
                addDatas(null, 2, 2);

                // Set icon function
                tree.iconFunction = function(data:IData):String{
                    if (showIcon.selected == true){
                        return data.icon;
                    }
                    return null;
                };
                tree.dataBox = box;
                tree.expandAll();
            }

            // Init data
            private function addDatas(parent:IData, level:int, count:int):void {
                for(var i:int = 0; i < count; i++) {
                    var data:IData = new Data();
                    data.name = "Data" + level + "-" + count;
                    data.parent = parent;
                    box.add(data);
                    if(level > 0) {
                        addDatas(data, level-1, count);
                    }
                }
            }

            // Change line style
            private function handleLineStyleChanged():void {
                tree.lineStyle = String(lineStyle.selectedItem);
            }

            // Change line thickness
            private function handleLineThicknessChanged():void {
                tree.lineThickness = lineThickness.value;
            }

            // Change line color
            private function handleLineColorChanged():void {
                tree.lineColor = lineColor.selectedColor;
            }

            // Change line alpha
            private function handleLineAlphaChanged():void {
                tree.lineAlpha = lineAlpha.value;
            }

            // Change check mode
            private function handleCheckModeChanged():void {
                tree.checkMode = showCheckbox.selected ?
                    Consts.CHECK_DESCENDANT_ANCESTOR : null;
            }
        ]]>
    </mx:Script>
    <mx:HBox width="100%" height="100%">
        <tw:FastTree id="tree" width="200" height="100%"
                     lineStyle="{Consts.TREE_LINE_STYLE_DOTTED}"/>
        <mx:Form width="100%" height="100%">
            <mx:FormItem label="Line Style">
                <mx:ComboBox id="lineStyle" selectedIndex="1"
                             change="handleLineStyleChanged()">
                    <mx:dataProvider>
                        <mx:String>{Consts.TREE_LINE_STYLE_NONE}</mx:String>
                        <mx:String>{Consts.TREE_LINE_STYLE_DOTTED}</mx:String>
                        <mx:String>{Consts.TREE_LINE_STYLE_SOLID}</mx:String>
                    </mx:dataProvider>
                </mx:ComboBox>
            </mx:FormItem>
            <mx:FormItem label="Line Thickness">
                <mx:NumericStepper id="lineThickness"
                                   minimum="0" maximum="5" stepSize="1" value="1"
                                   change="handleLineThicknessChanged()"/>
            </mx:FormItem>
            <mx:FormItem label="Line Color">
                <mx:ColorPicker id="lineColor" selectedColor="#808080"
                                change="handleLineColorChanged()"/>
            </mx:FormItem>
            <mx:FormItem label="Line Alpha">
                <mx:NumericStepper id="lineAlpha" minimum="0"
                                   maximum="1" stepSize="0.1" value="1"
                                   change="handleLineAlphaChanged()"/>
            </mx:FormItem>
            <mx:FormItem label="Show Checkbox">
                <mx:CheckBox id="showCheckbox"
                             label="Show Checkbox" selected="false"
                             change="handleCheckModeChanged()"/>
            </mx:FormItem>
            <mx:FormItem label="Show Icon">
                <mx:CheckBox id="showIcon" label="Show Icon" selected="true"
                             change="tree.invalidateModel()"/>
            </mx:FormItem>
        </mx:Form>
    </mx:HBox>
</mx:Application>

2012/08/17

TWaver’s Application in Power-system

As a professional graphical interface component, TWaver can be used in all walks of life. In this article we are going to give an introduction on how to draw an interface of power system with the help of TWaver. Now let's first see several images on power system:
the 1st wiring layout of a specified substation:

the 2nd wiring layout of a specified substation:

Of course the images above are what I have found on the Net. Then is TWaver able to realize it? The answer is absolutely. Let’s first analyze it: in a power system these interfaces are composed of many electric elements, such as transformer, disconnecting link, switch, earthed switch, capacitor and generator, etc.

Then let’s see how to extend these electric elements: first comes a simple disconnecting link which has two statuses: open and closed. So we can define a class for it which inherits from ResizableNode and adding turnOn to control its switch-status.

public class Switch extends ResizableNode{
    private boolean turnOn = true;

    public Switch() {
        super();
        init();
    }

    public Switch(Object id){
        super(id);
        init();
    }

    private void init(){
        this.setSize(5,30);
        this.putBorderColor(Color.black);
        this.putBorderInsets(12);
    }

     public String getUIClassID() {
        return SwitchUI.class.getName();
    }

     public boolean isTurnOn() {
        return turnOn;
    }

     public void setTurnOn(boolean turnOn) {
        if(this.turnOn != turnOn){
            boolean oldValue = this.turnOn;
            this.turnOn = turnOn;
            this.firePropertyChange("turnOn", oldValue, this.turnOn);
        }
    }
}
Next, we need to draw the shape of the swich according to the property of turnOn on UI. Here is the major paint method:

public void paintBody(Graphics2D g) {
    g.setStroke(TWaverConst.DOUBLE_WIDTH_STROKE);

    Switch switzh = (Switch)this.getElement();

    //get position
    final Point location = switzh.getLocation();
    final Dimension size = switzh.getSize();
    boolean trunOn = switzh.isTurnOn();
    final int x = location.x;
    final int y = location.y;
    final int width = size.width;
    final int height = size.height;

    //draw color frame
    g.setColor(new Color(170,0,225));
    g.drawOval(x, y, width, width);
    g.drawOval(x, y+height-width, width, width);

    if(trunOn){
        g.drawLine(x+width/2, y+height-width, x+height/2,y+width);
    }else{
        g.drawLine(x+width/2, y+height-width, x+width/2, y+width);
    }
}
Let’s see the extended effect through main

This is a simple disconnecting-link element, so it is quite easy to extend it. The next one is a little more complicated- disconnecting link. Same as disconnecting link, it also has two statuses.
Since in the example above we have set several different directions to the earthed switches, we can also do the same to disconnecting link. Let’s see how to draw the earthed switch:

public void paintBody(Graphics2D g) {
    g.setStroke(TWaverConst.BASIC_STROKE);
    g.setColor(Color.black)

    EarthingSwitch earthingSwitch = (EarthingSwitch)this.getElement();
    final Point location = earthingSwitch.getLocation();

    boolean turnOn = earthingSwitch.isTurnOn();
    int position = earthingSwitch.getSwitchPosition();
    final int x = location.x;
    final int y = location.y;
    int width = earthingSwitch.getWidth();
    int height = earthingSwitch.getHeight();
    //draw body
    if(turnOn){
        if(position == Utils.SWITCH_POSITION_TOP){
            g.drawLine(x+width/4, y, x+width/4*3, y);
            g.drawLine(x+width/6, y+2, x+width/6*5, y+2);
            g.drawLine(x, y+4, x+width, y+4);
            g.drawLine(x+width/2, y+4, x+width/2, y+7);
            g.drawLine(x+width/2, y+7, x+width, y+height-10);
            g.drawLine(x+width/2, y+height-3, x+width/2, y+height);
        }else if(position == Utils.SWITCH_POSITION_LEFT){
            //transfer width and height
            int middle = width;
            width = height;
            height = middle;

            g.drawLine(x,y+height/4, x, y+height/4*3);
            g.drawLine(x+2, y+height/6, x+2, y+height/6*5);
            g.drawLine(x+4, y, x+4, y+height);
            g.drawLine(x+4, y+height/2, x+7, y+height/2);
            g.drawLine(x+7, y+height/2, x+width-10, y);
            g.drawLine(x+width-3, y+height/2, x+width, y+height/2);
        }else if(position == Utils.SWITCH_POSITION_BOTTOM){
            g.drawLine(x+width/4, y+height, x+width/4*3, y+height);
            g.drawLine(x+width/6, y+height-2, x+width/6*5, y+height-2);
            g.drawLine(x, y+height-4, x+width, y+height-4);
            g.drawLine(x+width/2, y+height-4, x+width/2, y+height-7);
            g.drawLine(x+width/2, y+height-7, x, y+10);
            g.drawLine(x+width/2, y+3, x+width/2, y);
        }else if(position == Utils.SWITCH_POSITION_RIGHT){
            //transfer width and height
            int middle = width;
            width = height;
            height = middle;

            g.drawLine(x+width,y+height/4, x+width, y+height/4*3);
            g.drawLine(x+width-2, y+height/6, x+width-2, y+height/6*5);
            g.drawLine(x+width-4, y, x+width-4, y+height);
            g.drawLine(x+width-4, y+height/2, x+width-7, y+height/2);
            g.drawLine(x+width-7, y+height/2, x+10, y);
            g.drawLine(x+3, y+height/2, x, y+height/2);
        }
    }else{
        if(position == Utils.SWITCH_POSITION_TOP){
            g.drawLine(x+width/4, y, x+width/4*3, y);
            g.drawLine(x+width/6, y+2, x+width/6*5, y+2);
            g.drawLine(x, y+4, x+width, y+4);
            g.drawLine(x+width/2, y+4, x+width/2, y+7);
            g.drawLine(x+width/2, y+7, x+width/2, y+height-3);
            g.drawLine(x+width/2, y+height-3, x+width/2, y+height);
        }else if(position == Utils.SWITCH_POSITION_LEFT){
            //transfer width and height
            int middle = width;
            width = height;
            height = middle;

            g.drawLine(x,y+height/4, x, y+height/4*3);
            g.drawLine(x+2, y+height/6, x+2, y+height/6*5);
            g.drawLine(x+4, y, x+4, y+height);
            g.drawLine(x+4, y+height/2, x+7, y+height/2);
            g.drawLine(x+7, y+height/2, x+width-3, y+height/2);
            g.drawLine(x+width-3, y+height/2, x+width, y+height/2);
        }else if(position == Utils.SWITCH_POSITION_BOTTOM){
            g.drawLine(x+width/4, y+height, x+width/4*3, y+height);
            g.drawLine(x+width/6, y+height-2, x+width/6*5, y+height-2);
            g.drawLine(x, y+height-4, x+width, y+height-4);
            g.drawLine(x+width/2, y+height-4, x+width/2, y+height-7);
            g.drawLine(x+width/2, y+height-7, x+width/2, y+3);
            g.drawLine(x+width/2, y+3, x+width/2, y);
        }else if(position == Utils.SWITCH_POSITION_RIGHT){
            //transfer width and height
            int middle = width;
            width = height;
            height = middle;

            g.drawLine(x+width,y+height/4, x+width, y+height/4*3);
            g.drawLine(x+width-2, y+height/6, x+width-2, y+height/6*5);
            g.drawLine(x+width-4, y, x+width-4, y+height);
            g.drawLine(x+width-4, y+height/2, x+width-7, y+height/2);
            g.drawLine(x+width-7, y+height/2, x+3, y+height/2);
            g.drawLine(x+3, y+height/2, x, y+height/2);
        }
    }
}
There are some other elements, such as switch, generator and transformer. These can be easily configured by customDraw provided by TWaver. These are very easy so here the codes are omitted. See the image directly:
With the basic elements, it seems not so complicated to draw a power-system interface. We have drawn a power-system image with tools in TWaver through the extended electric elements above.
At last, interactions can be added on the interface, for example: you can double-click to open or close the switch of disconnecting link and then add your own business. A simple power-system is thus finished.

network.addElementDoubleClickedActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
        Element ele = network.getSelectionModel().lastElement();
        if(ele instanceof Switch){
            boolean turnOn = ((Switch)ele).isTurnOn();
            ((Switch)ele).setTurnOn(!turnOn);
        }
    }
});
In this way, the first two images of a substation can also be easily made. The following is another power-interface image made by TWaver.

High-performance Network of TWaver HTML5

TWaver HTML5 has already been released, in which the general components Tree and Table are highly efficient, for they are capable of loading more than tens of thousands of data. However, the network on which HTML elements are assembled are deficient in the amount of data, for it can only load about thousands of them. In order to meet the requirement of users on large amounts of data, we have added a high-performance network realization. You can just look at the following testing: the performance is as good as TWaver Java and the interfaces and the effects are almost the same as the original network. Besides, it is quite convenient for users to switchover. In addition, the high-performance network of TWaver Flex has also been released.




2012/08/10

Practice on Java Web Start: Dynamically Generating JNLP

Java has early released JWS technology (Java Web Start). Its original intention is quite good: wish to establish a seamless bridge between desktop apps and Web page. Although Applet technology has been in existence for more than ten years, it has declined and meantime JWS came into existence.
But JWS does not realize its original intention successfully. From several great revisions of Java we can see that JWS has many bugs and flaws, so Sun and Oracle have to frequently put patches to fix them. You can see that how many big or small upgrades in Java 5 and 6 are related to Java Web Start. No wonder so many people sighed: “I will not use Java Web Start any longer!”In fact, this is not always the case. With improvement in Java, we are able to eliminate some potential problems in JWS and to apply it successfully to enterprise applications as long as we have the knowledge of more skills.
Taking 2BizBox ERP project as an example, this article will introduce how to use the technology of dynamically generating JNLP file to realize rapid deployment in enterprise applications.

We all know that as a free-charged and quality ERP software, 2BizBox ERP has thousands of users. There are nearly one thousand servers our development team have the responsibility to maintain, not to mention the over a hundred client-sides each enterprises has. There is no doubt that it will be a huge workload if we apply the method to download client-sides to install the program and maintain all of these client-sides. In this way, neither the users nor us development team will feel relaxed and convenient. To solve it, the application of JWS is a must. In order to let the client-sides automatically download and install programs, we have deployed the following JNLP files on enterprises’ 2BizBox ERP servers.

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://**.**.**.**/webstart/">
        <information>
                <title>2BizBox</title>
                <vendor>Serva Software</vendor>
                <homepage href="http://www.2bizbox.com"/>
                <description>2BizBox ERP 3</description>
                <offline-allowed/>
        </information>
        <security>
                <all-permissions/>
        </security>
        <update check="always" policy="always"/>
        <resources>
                <j2se href="http://java.sun.com/products/autodl/j2se" version="1.6+" initial-heap-size="128m" max-heap-size="512m"/>
                <jar href="2bizbox.jar />
                <jar href="lib1.jar />
                <jar href="lib2.jar />
                <jar href="lib3.jar />
                <jar href="lib4.jar />
                <!-- more jar....   -->
        </resources>
        <application-desc main-class="com.serva.bb2.gui.Main">
                <argument>**.**.**.**</argument>
        </application-desc>
</jnlp>
The following JNLP file has defined the jar package needed for starting a 2BixBox ERP client-side and the download location and the jre edition.
It looks good in actual application. However, because of JNLP and the bugs in JWS itself, in some circumstances, users cannot obtain updates by starting JNLP after renewing and updating background jar programs. They have to clear up JWS cache by force, which, in general, users have not any idea. In another case, when changes have taken place in the jar package of ERP itself (such as addition or deletion of classes in it) which is equivalent to changes in the content in JNLP file, user-sides are asked to be aware of the changes in JNLP and to update JNLP first. In many java editions (for example, early jre6 editions and editions before ure6 update20), JNLP at user-sides cannot be updated successfully because of reasons like potential bugs, hence the failure in starting program.
How to solve this problem? An effective way is to apply the dynamic JNLP.
How to solve this problem? An effective way is to apply the dynamic JNLP.The way of dynamic JNLP: at the background of server, a JNLP file is dynamically generated by jsp or servlet instead of placing a static and unchanging JNLP file. Therefore, through the logic of background application we can dynamically generate or create the content of a JNLP file like what kind of jar archive and which jre edition is needed.
Take jsp as an example. In this jsp, the several key points you need to pay attention to are: first, set this page not to be buffered by the browser in order to avoid jnlp content’s not being able to be updated in time. Second, set mime class and let the browser consider it as a jnlp file in order to be downloaded instead of showing it directly in the browser. These can be realized by setting response.
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
response.setHeader("Content-Disposition", "filename=\"bb.jnlp\";");
response.setContentType("application/x-java-jnlp-file");
Meanwhile, the browser and webstart can be set as not allowed to cache content in jnlp by setting response.setHeader(“Pragma”, “no-cache”); and
response.setHeader(“Expires”, “0″);. You can also set the type of files and give a dynamic file name through response.setHeader(“Content-Disposition”, “filename=\”bb.jnlp\”;”);response.setContentType(“application/x-java-jnlp-file”);
You need to pay attention to a problem that when dynamically generating jnlp file you must be careful not to set the href tag in jnlp file. Why? You can see the words in jnlp format document:
http://lopica.sourceforge.net/ref.html#jnlp

The jnlp file's one and only root.
Attributes
spec=version , optional
Specifies what versions of the jnlp spec a jnlp file works with. The default value is 1.0+. Thus, you can typically leave it out.
version=version , optional
Specifies the version of the application as well as the version of the jnlp file itself.
codebase=url , optional
Specifies the codebase for the application. Codebase is also used as base URL for all relative URLs in href attributes.
href=url , optional
Contains the location of the jnlp file as a URL. If you leave out the href attribute, Web Start will disable the update check on your JNLP file, and Web Start will not treat each new JNLP file as an application update - only updated jar files will. Leaving out href usually makes only sense if your jnlp file is created dynamically (that is, throug a cgi-script, for example) and if your jnlp file's arguments or properties change from request to request (user to user).
Note, that Java Web Start needs href to list your app in the Web Start Application Manager.

So, when dynamically generating JNLP, don’t set href. In this way the browser will download JNLP file anew at every turn.
Another point is that the jar archive in JNLP file can dynamically check the jar archive in the file and dynamically generate it. Therefore, if there is addition or deletion in the jar files in the program, there will be no need to modify jnlp files. The method is also quite simple: check the absolute path of the current web in the server and list all jar files, then output them when generating jnlp.

<%
String urlString=request.getRequestURL().toString();
URL url=new URL(urlString);
String host=url.getHost();
String path = request.getSession().getServletContext().getRealPath("/");
path=path.replace("\\.\\", "\\");
File file=new File(path);
String[] files = file.list();
ArrayList jarNames=new ArrayList();
for(int i=0;i<files.length;i++){
String fileName=files[i];
if(fileName.toLowerCase().endsWith(".jar")){
jarNames.add(fileName);
}
}
%>
Then list them as described in the following code in jar’s part:
        <resources>
                <j2se href="http://java.sun.com/products/autodl/j2se" version="1.6+" initial-heap-size="128m" max-heap-size="512m"/>
<%
for(int i=0;i<jarNames.size();i++){
out.write("\n");
out.write("<jar href=\""+jarNames.get(i).toString()+"\"/>");
}
%>
        </resources>
At last, if it is necessary to specify the ip address or the host address of the current server in jnlp, it can also be done by dynamic generation, such as the codebase in jnlp file. In addition, the ip address of the current server must also be given in the main function in 2BizBox ERP. However, it is out of our imagination, if every jnlp in over a thousand 2BizBox servers needs to be maintained manually. Now this problem can be perfectly solved by means of dynamic generation.
String urlString=request.getRequestURL().toString();
URL url=new URL(urlString);
String host=url.getHost();
 Then in jnlp:
<jnlp spec="1.0+" codebase="http://<%=host%>/webstart/">
...
        <application-desc main-class="com.serva.bb2.gui.Main">
                <argument><%=host%></argument>
        </application-desc>
The method to dynamically generate jnlp through jsp is thus completed. It goes well in 2BizBox ERP and let over a thousand 2BizBox ERP cloud-host users quickly get their programs updated and simplify the maintaining of programs.

2012/08/09

To Customize Alarm Coloration

In TWaver, there are varieties of ways to show alarms on the network, among which the most commonly-used one is to add the color of the corresponding alarm severity to the original image. It is supported in all TWaver’s product branches. Here is the effect:
In addition, there is another two ways which is to add the alarm color to the foreground or the background of elements. Here is the effect:

We mainly focus on the default way of coloration which is to overlay color on images, that is, we overlay the alarm color on the original image of the element. It goes perfect in most images. For example, we colorize two images randomly found on the Net.
The effect is good except for the colorizations on two images whose color is obviously different from that of alarm severity. We have made a test on an icon and found that:
In the image above, obviously, the three levels of alarm severity Major, Minor and custom’s color after alarm coloration are different from the color of their bubbles. How to deal with it? After reading API you will know that in TWaver you can customize alarm coloration. PIXEL_FILTER_FUNCTION in Defaults is applied as default. Let’s have a look at it:
function(sourceColor:uint, filterColor:uint):uint {
    var r:uint = (sourceColor >> 16 ) & 0xFF;
    var g:uint = (sourceColor >> 8 ) & 0xFF;
    var b:uint = sourceColor & 0xFF;
    sourceColor = (r * 77 + g * 151 + b * 28) >> 8;
    sourceColor = (sourceColor << 16) | (sourceColor << 8 ) | sourceColor;
    return sourceColor & filterColor;
}
Now we can customize it with this method. It will directly return the alarm color if we conduct special processing to the three colors.
function(sourceColor:uint, filterColor:uint):uint {
    if(sourceColor == s && (filterColor == AlarmSeverity.MAJOR.color ||
        filterColor == AlarmSeverity.MINOR.color)) {
        return filterColor;
    }
    var r:uint = (sourceColor >> 16 ) & 0xFF;
    var g:uint = (sourceColor >> 8 ) & 0xFF;
    var b:uint = sourceColor & 0xFF;
    sourceColor = (r * 77 + g * 151 + b * 28) >> 8;
    sourceColor = (sourceColor << 16) | (sourceColor << 8 ) | sourceColor;
    return sourceColor & filterColor;
};
Let’s see the effect after running the codes above:
The following is the complete codes for your reference:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:twaver="http://www.servasoftware.com/2009/twaver/flex"
                width="100%" height="100%"
                creationComplete="init()" backgroundColor="#FFFFFF" >
    <mx:Script>
        <![CDATA[
            import twaver.AlarmSeverity;
            import twaver.Defaults;
            import twaver.Node;
            import twaver.Utils;
            import twaver.Consts;
            import twaver.Styles;

            [Embed(source="/image/BTSGroup.png")]
            private static var bts:Class;

            [Embed(source="/image/network_server.png")]
            private static var wireless:Class;

            private static var customAlarmSeverity:AlarmSeverity = AlarmSeverity.register(3, 'custom', 'custom', 0xE4DC8A);

            private function init():void {
                var s:uint = (162 << 16 ) | (193 << 8 ) | 210;
                Utils.registerImageByClass('bts', bts);
                Utils.registerImageByClass('wireless', wireless);
                twaver.Defaults.PIXEL_FILTER_FUNCTION = function(sourceColor:uint, filterColor:uint):uint {
                    if(sourceColor == s && (filterColor == AlarmSeverity.MAJOR.color ||
                        filterColor == AlarmSeverity.MINOR.color
                        || filterColor == customAlarmSeverity.color)) {
                        return filterColor;
                    }
                    var r:uint = (sourceColor >> 16 ) & 0xFF;
                    var g:uint = (sourceColor >> 8 ) & 0xFF;
                    var b:uint = sourceColor & 0xFF;
                    sourceColor = (r * 77 + g * 151 + b * 28 ) >> 8;
                    sourceColor = (sourceColor << 16 ) | (sourceColor << 8 ) | sourceColor;
                    return sourceColor & filterColor;
                };

                addNode(AlarmSeverity.CRITICAL, 220, 100,'bts');
                addNode(AlarmSeverity.MAJOR, 340, 100,'bts');
                addNode(AlarmSeverity.MINOR, 460, 100,'bts');
                addNode(AlarmSeverity.WARNING, 580, 100,'bts');
                addNode(AlarmSeverity.INDETERMINATE, 700, 100,'bts');

                addNode(AlarmSeverity.CRITICAL, 220, 250,'wireless');
                addNode(AlarmSeverity.MAJOR, 340, 250,'wireless');
                addNode(AlarmSeverity.MINOR, 460, 250,'wireless');
                addNode(AlarmSeverity.WARNING, 580, 250,'wireless');
                addNode(AlarmSeverity.INDETERMINATE, 700, 250,'wireless');
            }

            private function addNode(alarmSeverity:AlarmSeverity, x:Number, y:Number,image):void {
                var node:Node = new Node();
                node.image = image;
                if(image == "bts"){
                    node.setStyle(Styles.INNER_STYLE, Consts.INNER_STYLE_SHAPE);
                    node.setStyle(Styles.INNER_SHAPE, Consts.SHAPE_CIRCLE);
                    node.setStyle(Styles.INNER_GRADIENT, Consts.GRADIENT_RADIAL_CENTER);
                    node.setStyle(Styles.INNER_GRADIENT_ALPHA, 0.5);
                    node.setStyle(Styles.INNER_ALPHA, 0.8);
                    node.setStyle(Styles.INNER_PADDING, -6);
                    node.setStyle(Styles.INNER_BACK, false);
                }else if(image == "wireless"){
                    node.setStyle(Styles.INNER_STYLE, Consts.INNER_STYLE_SHAPE);
                    node.setStyle(Styles.INNER_SHAPE, Consts.SHAPE_DIAMOND);
                    node.setStyle(Styles.INNER_GRADIENT, Consts.GRADIENT_RADIAL_SOUTHWEST);
                    node.setStyle(Styles.INNER_PADDING_TOP, 10);
                    node.setStyle(Styles.INNER_PADDING_BOTTOM, -5);
                    node.setStyle(Styles.INNER_PADDING_LEFT, -20);
                    node.setStyle(Styles.INNER_PADDING_RIGHT, -20);
                }

                node.name = alarmSeverity.name ;
                node.location = new Point(x, y);
                node.alarmState.setNewAlarmCount(alarmSeverity, 22);
                network.elementBox.add(node);
            }
        ]]>
    </mx:Script>
    <twaver:Network id="network" width="100%" height="100%" />
</mx:HBox>