Wednesday, December 10, 2008

Java Utility Methods

1. Conversion
  a) Array => String

String modeStr = StringUtils.join(modes, '/')

  b) String => Array
String[] modes = StringUtils.split(protocolStr, '/')

2. Bit Ops
  a) Check bit
int RADIO_PROTOCOL_A = 0x1;
if (radioMode & RADIO_PROTOCOL_A) == RADIO_PROTOCOL_A

   b) Set/Unset bit
radioMode = radioMode | RADIO_PROTOCOL_A
radioMode = radioMode & ~RADIO_PROTOCOL_A


 

Thursday, November 20, 2008

GWT

A few important differences between GWT and Swing. First, the components that ship with GWT don’t follow the Model View Controller (MVC) pattern: No model object can be shared by multiple components to keep them in sync. Second, GWT doesn’t use layout managers to control the layout.

Monday, November 10, 2008

RESTful Web Services

- Goal: to reunite the programmable web (RSS, XML-RPC, SOAP) with the human web.
- HTTP is a document-based protocol

• The scoping information (“why should the server send this data instead of that data?”) is kept in the URI. This is the principle of addressability.
• The method information (“why should the server send this data instead of deleting it?”) is kept in the HTTP method. There are only a few HTTP methods, and everyone knows ahead of time what they do. This is the principle of the uniform interface
Statelessness means that every HTTP request happens in complete isolation.
• Connectedness

The difference between PUT and POST is this: the client uses PUT when it’s in charge of deciding which URI the new resource should have. The client uses POST when the server is in charge of deciding which URI the new resource should have.

Thursday, October 9, 2008

NIO server framework



- It follows one dispatcher, multiple worker threads model. The HandlerAdapter (worker thread) need to disable the channel's interest ops before the processing, to avoid selector fire more events and spawn other worker thread; it resumes channel's interest ops after the processing. However, selector is not thread-safe. So the approach is to only allow dispatcher thread updates channel's interest ops. Worker threads only queue the status change requests to dispatcher thread.

- HandlerAdapter present a Facade through which the InputHandler may interact with the framework. It encapsulates event state, channels, input and output queues. Client code registers an InputHandler for a channel, dispatcher wraps handler in an internal adapter class. The client InputHandler is decoupled from NIO and dispatcher implementation details. **Good practice **

- Client handler is passed a ChannelFacade interface through which it may interact with the channel and/or queues. **Elegant encapsulation, hide channel **

- When client code want to write data, i.e., send request, it acquires the handler, and then output byte data to the outputQueue of the channelFacade, modifies the interest ops to OP_WRITE, then next time selector will fire writable event and drain out the output queue to channel.

See: NIO Server Framework

Sunday, September 28, 2008

Java NIO [reading note]




- NIO is primarily block oriented, java.io uses streams
page-oriented nature of system I/O (disk, file)
stream I/O, OS provides non-blocking, readiness selection support

- Channels are conduits to OS I/O service, not stream. They do bulk data transfer to and from buffer, channel.write(buffer) ~= buffer.get(byteArray), channel.read(buffer)~= buffer.put(byteArray). Data is logically transferred in blocks, not char/byte at a time.

- Channels are gateways through which the native I/O services of the operating system can be accessed with a minimum of overhead, and buffers are the internal endpoints used by channels to send and receive data. Channel implementations often use native code. The channel interfaces allow you to gain access to low-level I/O services in a controlled and portable way.

- The new socket channels can operate in nonblocking mode and are selectable. These two capabilities enable multiplexed I/O.

- Readiness selection effectively prevents you from separating the code that checks for readiness from the code that processes the data, at least without significant complexity.

- A SelectionKey encapsulates the registration relationship between a specific channel and a specific selector. SelectionKey objects contain two bit sets (encoded as integers) interest set and ready set indicating which channel operations the registrant has an interest in and which operations the channel is ready to perform.

- Building Highly Scalable Servers with Java NIO has a good discussion on thread model:

  • M dispatchers/no workers
Several event-dispatch threads doing all the work (dispatching events, reading, processing requests, and writing).
  • 1 dispatcher/N workers
A single event-dispatch thread and multiple worker threads.
  • M dispatchers/N workers
Multiple event dispatch threads and multiple worker threads.

- More thread != More efficient. More thread means more context switching overhead. Actual concurrency is limited by the number of CPUs available.

See: Introducing Nonblocking Sockets

Monday, September 22, 2008

Form.target

Use Case: Sometimes you may want a form to be processed and the result displayed in a different window (popup->main, main->popup).

target is a read/write string property of the Form object. It specifies the name of the frame or window in which the results of the submission of form should be displayed. Four special target names are supported: _blank, _parent, _self and _top.


<script>
function openwin() {
  window.open("about:blank", "winDocPrint", "..size,etc");
}
</script>


<form action="printdoc.php?sa=<?php echo session_id(); ?>" target="winDocPrint" onsubmit="openwin">
...
</form>

** sa=<?php echo session_id(); ?> is URL rewriting used to keep the same session in the new window. And session_start() must be invoked on new window to resume the current one based on the current session id that's being passed via a request.

Friday, September 12, 2008

Non-blocking Socket

The problem

Importance of Java as a language and runtime platform for server application grows with every day. A fundamental trait of a server application is that it services multiple clients concurrently. The only way to achieve concurrency before JDK 1.4 was to allocate a separate thread of execution for servicing every connection. While this model is quite easy to implement, it contains inherent scalability problems. First, a server that maps one connection to one thread can not serve more concurrent connections than it can allocate threads. Second, while threads - from the developer's standpoint - provide a convenient virtualization of available CPU resources, they are costly both in terms of space (each thread requires a separate call stack) and time (context switching a CPU between threads consumes time). All these factors impose limits on both the number of connections the server can process at any given time, as well as on the effective throughput. Last, but not least the threads will potentially spend a significant part of their processing time blocked in I/O operations. This makes the server vulnerable to a particular kind of denial-of-service attacks, where a malicious client can bog down the server by opening many connections to it (therefore allocating all available threads), and then send it a completely valid request extremely slowly (say, one byte per minute). This effect can be caused even with otherwise benevolent clients sitting behind narrow bandwidth connections.

The solution

If you are concerned with any of these problems (support for extremely large number of connections, throughput maximization, and protection from service degradation due to slow clients), you should write your servers in a non-blocking fashion. This means a radical paradigm shift - instead of allocating a dedicated thread to serve a connection, a single thread (or eventually several threads) service a large number of connections using an event-driven mechanism. In the event-driven architecture, one thread watches multiple network sockets, and when one or more sockets are ready to be read from or written to, the thread recieves an event and gets the chance to service those connections that became ready. However, this architecture assumes the availability of a non-blocking I/O library, since a crucial requirement is that the thread must never block on an I/O operation.

Also, the way network protocol is implemented in a non-blocking world is drastically different than in the blocking world. With the blocking, one-thread-per connection paradigm, you encapsulate a network protocol in a procedural way, that is you write a code that is executed on a thread that is dedicated to executing the code for its single connection. You can store much of the processing state on the stack: local variables, call arguments, and the code execution path itself. On the contrary, in the non-blocking world, your code is invoked to process one or two packets of data at a time and then it returns control. Therefore, you can't contain any state on the stack, as you would Essentially, you must write a finite-state machine where events (incoming packet and empty outgoing network buffer) drive state transitions.

Thursday, September 11, 2008

Message Bus



A message bus specializes in transporting messages between applications. A message bus contains three key elements:

    * A set of agreed-upon message schemas
    * A set of common command messages [Hohpe04]
    * A shared infrastructure for sending bus messages to recipients

When you use a message bus, an application that sends a message no longer has individual connections to all the applications that must receive the message. Instead, the application merely passes the message to the message bus, and the message bus transports the message to all the other applications that are listening for bus messages through a shared infrastructure. Likewise, an application that receives a message no longer obtains it directly from the sender. Instead, it takes the message from the message bus. In effect, the message bus reduces the fan-out of each application from many to one.

Usually, the bus does not preserve message ordering. Internal optimizations, routing, buffering, or even the underlying transport mechanism might affect how the messages travel to the receiving applications. Therefore, the order in which messages reach each receiver is nondeterministic.

See: Prescriptive Architecture Message Bus

Wednesday, September 10, 2008

Concurrent Programming in Java [reading note]

- Overriding run() in Thread vs. Using Runnable as an argument in Thread constructor
   Default strategy is to define Runnable as a separate class and supply it in a Thread constructor. Isolating code within a distinct class relieves you of worrying about any potential interactions of synchronized methods or blocks used in the Runnable with any that may be used by methods of class Thread.
   A small proof for Composition over Inheritance.

- Method Adapter patterns
   Besides adapter, sub-classing, template method, the most flexible approach to before/after control is to define a class whose entire purpose is to invoke a particular method on a particular object. In the command object pattern and its many variants, instances of such classes can then be passed around, manipulated, and ultimately executed. In some other languages, function pointers and closures are defined and used to achieve some of these effects.


interface Callable {
   Object call(Object arg) throws Exception;
}

- Collection Traveral
   Lock the whole collection and operate on each item may be time consuming. JDK's Iterator is a fast-fail iterator that throw a ConcurrentModificationException if the collection is modified in the midst of a traversal using the version approach.

Friday, August 15, 2008

relative containing block

Elements with position:relative are positioned relative to themselves. If we just set position:relative on an element, without specifying any of the edge properties, the element ends up exactly where it would have been if we had set position:static, or if we hadn't set position at all.

But there is one important usage. If we set relative positioning on div-1, any elements within div-1 will be positioned relative to div-1, not matter they are static/absolute/relative/float(width). Thus, it serves as a container (or containing block).

By definition, the containing block of an absolutely positioned element is its nearest positioned ancestor with position property is absolute, fixed or relative. So if we don't define div-1 as relative positioned, it won't be its containing block.

Note that this is a special definition for absolutely positioned element **only**. The containing block of other elements is any block box (div) surrounding it.

A floated box is laid out according to the normal flow, then taken out of the flow and shifted to the left or right as far as possible in its containing block.
(float:right doesn't work in IE? ->the element must have width defined)

1. Learn CSS Positioning in Ten Steps
2. Relatively absolute
3. Atlantic CSS ZenGarden

Tuesday, August 12, 2008

radio button


<form name="orderform">
Which one is your favorite?
  <input type="radio" name="music" value="Rock" checked="checked"> Rock
  <input type="radio" name="music" value="Reggae"> Reggae
  <input type="radio" name="music" value="Pop"> Pop
  <input type="radio" name="music" value="Metal"> Metal
  <input type="submit" onclick="get_radio_value()">
</form>

Accessing the value for a set of radio buttons is not that straight forward. document.form_name.radio_name.value does not work.
To get the associated value -

function get_radio_value() {
  for (var i=0; i < document.orderform.music.length; i++) {
     if (document.orderform.music[i].checked) {
       var rad_val = document.orderform.music[i].value;
     }
    }
}

In DOM object, the radio "music" is an array of elements. But when the form is submitted, there is only one attribute 'music' with the checked radio value.

Also, note that there are two different way to access DOM element. document.getElementById or document.<form-name>.<input-element-name>

For select drop-down, we can set the selection either by select_element.value or iterate its options array, and set selectedIndex value. Note that onchange event won't be triggered automatically.

Tuesday, July 29, 2008

Regular Expression


/^.+[^\.].*\.[a-z]{2,}$/i

It is used to check FQHN (fully qualified host name). It is understood as -

^ begin with
.+ one or more characters
[^\.] one character not '.' dot (that is why a.ca wrong, and ab.ca correct)

.* zero or more characters (to ignore all dots in the middle and focus on last one only)
\. dot (actually last dot)
[a-z]{2,} two or more letters in the alphabet
$ end of the string

For instance, a.ca (NO), ab.ca (YES), ab.a.ca (YES)

Parsing Regexp is recursive for best match, not just parsed once


String str = "serial 5555555555555555 roger test5 AP3610";
Pattern pattern = Pattern.compile("serial[ ](\\S+)[ ](.*)[ ](\\S+)");
Matcher matcher = pattern.matcher(str);

if (matcher.find()) {
for (int i = 0; i <= matcher.groupCount(); i++) {
System.out.println("Group" + i + ":" + matcher.group(i));
}
}

// The result is:
// Group0:serial 5555555555555555 roger test5 AP3610
// Group1:5555555555555555
// Group2:roger test5
// Group3:AP3610

\S A non-whitespace character
Note that group2 can contains whitespace.

Wednesday, July 23, 2008

assigned by value?


$myArray = array('key1'=>array('1', '2'), 'key2'=>array('3', '4'));
$subArray = $myArray['key1'];
array_push($subArray, '5');

The trick is that new value '5' is ONLY added to $subArray, but not to $myArray['key']. PHP's assignment operator '=' assigns value by copy. So $subArray is not really a sub-array of $myArray, it is a separate array. Assignment by reference is also supported, using the $var = &$othervar; syntax.

The same for the 'foreach' loop

foreach($myArray as $subArray)

As of PHP 5, foreach ($arr as &$value) is supported. This will assign reference instead of copying the value.

Monday, July 21, 2008

Utility Functions

1. Sorting with user defined comparator

In PHP -


usort($bp_radios, create_function('$a, $b',
'return $a["radio_index"] - $b["radio_index"];'));


In JS -

tabRF_apList[i]['radios'].sort(function(a,b) {
return a['radio_index'] - b['radio_index']});

2. Array <=> String with delimiter

In PHP -

$radio = implode('/', $radioNameArray); // {'a', 'b'} => 'a/b'
$radioNameArray = explode('/', $radio);

In JS -

var radio = radioNameArray.join('/');
var radioNameArray = radio.split("/");

Tuesday, July 15, 2008

"" == 0

An empty string is a length 1 array containing '\0' (which is equal to zero). Javascript automatically casts single length strings to characters and vice versa. '\0' == 0 therefore "" == 0.

To strictly compare, use === operator.

PHP:


if (strpos($S_COMPANY_NAME,"Extreme") === false)

strpos return false if not found, but may also return a non-Boolean value which evaluates to FALSE, such as 0 or "". So we have to use === to test it.

Wednesday, July 9, 2008

Overloading

In Javascript. As for differing amounts of arguments, Javascript really doesn't care about that either.

function bla(a, b, c)
is pretty much the same as
function bla()
except that in the former, a = arguments[0], b = arguments[1], c = arguments[2] in the namespace of the function.

PHP function support variable-length argument list too. And we can set default argument value.


function getFormatedRadioMode($radioMode, $showoff = true) {
   global $ap_radioModeTable;
   ...
}

Tuesday, July 8, 2008

dynamic variable

This article talks about different ways to compose dynamic Javascript variable -


eval('name' + i + ' = "Marco"'); // compose a string with variable as eval's argument
window['name' + i] = 'Marco';

And the PHP counterpart is:

${'name'.$i} = 'Marco';
echo 'ap_bVNSRadio_${vname}';

Monday, June 30, 2008

Pass data structure from PHP to JS

In JS:


var ap_radioMode = unserialize('<?php echo serialize ($ap_radioMode) ?>');

i.e. Use PHP's serialze() and echo out the value, then apply JS's counterpart unserialize() to get the data structure.

Sunday, June 15, 2008

Cookie

Cookie is sent from web server to the browser as a header, and it is stored in the browser. On all the subsequent requests, the browser would send the cookie data transparently to the server, So it advised to keep the size minimal.

Http Session data is stored in the server, but its session identifier is sent in cookie. In this way, the session reference is passed instead of the actual data to save network traffic. When the user disable the cookie in the browser, URL rewrite (response.encodeUrl) will be used to append jsessionid on url parameters.

When a GET hits the server with no session cookie or id, Tomcat creates a new session and sets the cookie:
Set-Cookie: JSESSIONID=2978A7FABFF3DB35BE622290E1294CDE; Path=/
It then also encodes all URLs on a page with jsessionid. At this point, does not know if the browser supports cookies. So the next GET (with both cookie and URL parameter) is required to decide if cookies are OK or not.

Thursday, June 5, 2008

Is RMIRegistry a JNDI service provider?


The JNDI architecture consists of an API and a service provider interface (SPI). Java applications use the JNDI API to access a variety of naming and directory services. The SPI enables a variety of naming and directory services to be plugged in transparently.RMIRegistry is also one type of JNDI provider besides Ldap, File System.


envs.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory");
envs.put(Context.PROVIDER_URL, "rmi://localhost:1099");

RegistryContextFactory implements getInitialContext() method.JNDI provides a naming context, which is a a set of name-to-object bindings. All naming operations are relative to a context.A name that is bound within a context is the JNDI name of the object. A Context object provides the methods for binding names to objects, unbinding names from objects, renaming objects, and listing the bindings.

File System: file name -> file (accessed via file handler)
DNS: machine name -> IP
LDAP: Ldap name -> Ldap entry

The Initial Context
In the JNDI, all naming and directory operations are performed relative to a context. There are no absolute roots. Therefore the JNDI defines an initial context, InitialContext(in the API reference documentation), which provides a starting point for naming and directory operations. Once you have an initial context, you can use it to look up other contexts and objects.When the initial context is constructed, its environment is initialized with properties defined in the environment parameter passed to the constructor, and in any application resource files.

JNDI determines each property's value by merging the values from the following two sources, in order:

1. The first occurrence of the property from the constructor's environment parameter and (for appropriate properties) the applet parameters and system properties.
2. The application resource files (jndi.properties).

Wednesday, May 28, 2008

YUI study notes - Event

The window.onload event is synchronous with images and external dependencies, so it doesn't fire until they've all resolved (or timed out), also in some browser (IE), the target elements that do not yet exist when onload event fired. What we really want is an event that fires when the DOM ready, YUI's onDOMReady(), onAvailable() and onContentReady () help to avoid this problem.

Event object is accessed differently in different browser. In IE the event object is accessed through the window object, whereas in Firefox, it is automatically passed to your event handler as an argument.

[1] has a good explanation on the callback function signature.

Callback for Native Browser Events


var callback = function(e, o) {
alert(o.msg);
};

YAHOO.util.Event.addListener(elemId, "click", callback, {msg: "hi"});

Callback for Custom Events
If the custom event is fired with parameter signature YAHOO.util.CustomEvent.LIST, which is by default

var callback = function(e, a, o) {
//a is an array contains arguments fire method: arg1, arg2, ...
//o is the object passed from the subscribe method
alert(o.msg);
};

//to fire this event
eventObj.fire(arg1, arg2, ...);

//to listen to this event
eventObj.subscribe(callback, {msg: "hi"});

where
e - Name of this custom event.
a - Arguments that passed to the fire method of this event.
o - Object that passed as a parameter to this callback function.

If the custom event is fired with parameter signature YAHOO.util.CustomEvent.FLAT

var callback = function(a, o) {
//a is the first argument that passed to fire method of this event
//o is the object passed from the subscribe method
alert(o.msg);
};

//to fire this event
eventObj.fire(arg);

//to listen to this event
eventObj.subscribe(callback, {msg: "hi"});

Monday, May 26, 2008

Redirect-after-Post pattern and Session bound ActionMessages

To deal with double submit problem, the Redirect after Post pattern is purposed in [1] and [2].
- Never show pages in response to POST
- Always load pages using GET
- Navigate from POST to GET using REDIRECT

To facilitate this, the errors/messages need to be stored in session scope, o/w they would get lost after redirect. From Struts 1.2.4, Action.saveMessages(HttpSession, ActionMessages) is added [3]. Upon the first access to the messages they are effectively removed from the session. This allows messages to be retained when using the redirect after post pattern.

ActionRedirect inherits from ActionForward, with support for adding parameters at runtime.

Wednesday, May 21, 2008

MySql straight join and index hint


SELECT STRAIGHT_JOIN p.NAME AS NAME,
    ROUND(AVG(r.VAL)) AS AVGVAL,
    MIN(r.MINVALUE) AS MINVAL,MAX(r.MAXVALUE) AS MAXVAL
FROM reports_hourly AS r force index (PRIMARY), polleddata AS p,wirelessaccesspoint ap
WHERE p.OID = ? AND p.ID=r.POLLID
  AND r.ttime >= ? AND p.name=ap.name AND ap.aprole=0
GROUP BY p.NAME
ORDER BY AVGVAL DESC
LIMIT 0,5

* Table reports_hourly is the biggest table, contains millions records. Its primary key index is on (ttime, pollid). If move it to the last table to join, the query would run much slower.

Tuesday, May 20, 2008

MySql innodb transaction/logs



- MySql's innodb follows Oracle's multi-version read consistency model. It's multi version is based on undo log. In Innodb, each table has two hidden columns, a transaction number and a pointer to the previous version of that row in the undo log. With the rollback pointer, READ COMMITTED can go back one step to the past, whereas REPEATABLE READ can go back multiple steps until it reaches the newest version after its transaction starts. Based on the transaction number, we know particular row in data buffer is associated with committed or uncommitted transaction.

- Write-Ahead logging (WAL) principal: all modifications are written to a log before they are applied to the database. It is to guarantee the Atomicity and Durability of ACID. WAL significantly reduces the number of disk writes, since only the log file needs to be flushed to disk at the time of transaction commit. In multi-user environments, commits of many transactions may be accomplished with a single fsync() of the log file. The log file is written sequentially, so the cost of syncing the log is much less than the cost of flushing the data pages. Writing back change to table space involves slow disk seek rather than liner write. Another benefit of WAL is consistency of the data pages.

- Two buffers: log buffer and data buffer in InnoDb. Log buffer is for insert/update, whereas data buffer is for all operations, it used to cache data and indexes of the tables. Also there are some other memory buffer such as sort buffer and query cache buffer. When a transaction commit, the rows in log buffer are flushed to disk, whereas the rows in data buffer are marked as dirty but not flushed. When innodb_flush_log_at_trx_time set to 0, even the log buffer is not flushed (not recommended). There are several threads monitoring buffer activity, and three situations -- overflow, checkpoint, and commit -- that result in disk writes.

- InnoDB uses both row level locking and multi-versioning concurrency control (MVCC). Multi-version Consistent read is the default mode in which InnoDB processes SELECT statements in READ COMMITTED and REPEATABLE READ isolation levels. FOR UPDATE or IN SHARE MODE apply exclusive (X) lock and shared (S) lock.

- Checkpoint: InnoDB takes some pro-active measures against overflows, and the most important of these measures is checkpointing. There is a separate thread, or a combination of threads that are separate from the thread that changes the buffers. At fixed intervals the checkpointer will wake, look for buffer changes, and ensure that writes happen.

See:
Transactions - An InnoDB tutorial
How Logs work on MySQL with InnoDB tables

Thursday, May 15, 2008

HttpSessionBindingListener vs. HttpSessionAttributeListener

HttpSessionBindingListener:
If an object implements HttpSessionBindingListener, it is notified when it is bound to or unbound from a session. For example,


MyObject implements HttpSessionBindingListener
{
// class definition
}

If I call

session.setAttribute ("Object", MyObject)

or

session.removeAttribute ("Object", MyObject)

and so on, methods valueBound and/or valueUnbound (defined in HttpSessionBindingListener, implemented in MyObject are called)

When any class implements HttpSessionAttributeListener interface it is notified when any change in the attribute list of session occurs. For example

MyClass implements HttpSessionAttributeListener
{
// implementations of methods
}


session.setAttribute ("anything", AnyObjectNotOnlyMyClass);

or

session.removeAttribute ("anything", AnyObjectNotOnlyMyClass);


indicates change in the list of attributes and hence appropriate method is called

Differences:
Implementing HttpSessionBindingListener works only for the object that implements it whereas implementing HttpSessionAttributeListener listens to any attribute added, removed or replaced.

See:Difference between HttpSessionBindingListener and HttpSessionAttributeListener.

Friday, May 9, 2008

JMX service URL




A Remote JMX Client is just like a Local JMX Client except that it must instantiate a Connector client and connect it up to a Connector server to get a MBeanServerConnection. It then uses the MBeanServerConnection in the same way as a Local JMX Client. Remote JMX applications can not work with an MBeanServer object, only an MBeanServerConnection.

The Agent must run a Connector Server using the same tranport protocol that you will use on the client side. If your server serves tranport "rmi", then your client(s) need to use protocol "rmi". Other protocols are jmxmp, http, snmp. RMI is the default transport protocol. So we have JMX Connector client and JMX connector server for different protocols.

On connector server side:


// Instantiate the MBean server
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
// Create an RMI connector server
JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi://srv:20000/jndi/rmi://srv:30000/server");
JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url,null, mbs);
cs.start();

The connector server cs is launched by calling the start() method of JMXConnectorServer, whereupon the instance of RMIConnectorServer that is created exports its underlying RMI server stub server to the RMI registry.

On connector client side:

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://srv:20000/jndi/rmi://srv:30000/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();

As you can see, the Client defines the same service URL url as that defined by Server. This allows the connector client to retrieve the RMI connector server stub named server from the RMI registry running on port 30000 of the srv host, and to connect to the RMI connector server.

In javax.management.remote.rmi doc, the service URL is explained in detail. A simplified URL is service:jmx:rmi:///jndi/rmi://srv:30000/server. The absent host means local host, and the absent port means the the exported remote object RMIServerImpl_Stub is not exported to a specified port. Remember when we export a remote object, The second argument in exportObject method, specifies which TCP port to use to listen for incoming remote invocation requests for the object. It is common to use the value zero, which specifies the use of an anonymous port. The actual port will then be chosen at runtime by RMI or the underlying operating system.

Compute engine = new ComputeEngine();
Compute stub =(Compute) UnicastRemoteObject.exportObject(engine, 0);Registry registry = LocateRegistry.getRegistry();
registry.rebind("computer", stub);

At last, the "jndi" in the middle of the url means we use JNDI to look up the remote object. RMIRegistry is just one of its service provider, others include file system, ldap, etc. So we may have jndi/ldap:localhost:839, jndi/c:/myphotos, etc.

[Reference]
Monitor Your Applications With JConsole
Remote JMX, RMI and JMXServiceURL
Implementing a remote interface
RMI Registry Service Provider for the Java Naming and Directory InterfaceTM (JNDI)

Wednesday, May 7, 2008

RMI stub, tomcat classloader, ..

RMI client look up RMI registry for remote object's stub instance.


LicServer licServer = (LicServer) Naming.lookup("//localhost:1099/LicServerAPI");

It return an instance of LicServerImpl_Stub. In run time, client need the Stub class to resolve it. It obtains it from local classpath or codeBase (remote classpath). The codeBase approach is to download the class bytecode via http, by setting -Djava.rmi.server.codebase=http://hostname/locationOfClasses

In our system, the RMI client resides on the same machine as a web app in an embedded Tomcat launched by webnms. Hence, it is able to get the stub files by classpath.

The Tomcat classloading has a hierarchy structure.
- Bootstrap: JVM classes
- System: based on system CLASSPATH, however, the default startup script catalia.bat ingore it and only pass in BootStrap.jar to start up.
- Common: shared by all web app and tomcat server's internal classes
- webapps: each web app has it own classloader. This web application classloader doesn't follow the common parent delegation model except those java.* classes according to servlet spec recommendation.

To add classpath to system classloader, we can modify the classpath in script, or when launching embeded tomcat, we can pass server's classpath to it by

Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
Class class1 = Class.forName("org.apache.catalina.startup.Bootstrap");
Method method = class1.getMethod("main", aclass);
method.invoke(null, aobj);

Applications written in statically compiled programming languages, such as C and C++, are compiled into native, machine-specific instructions and saved as an executable file. The process of combining the code into an executable native code is called linking - the merging of separately compiled code with shared library code to create an executable application. This is different in dynamically compiled programming languages such as Java. In Java, the .class files generated by the Java compiler remain as-is until loaded into the Java Virtual Machine (JVM) -- in other words, the linking process is performed by the JVM at runtime. Classes are loaded into the JVM on an 'as needed' basis. And when a loaded class depends on another class, then that class is loaded as well.

It gives us the flexibility to control the class loading, e.g., apply security policy, loading from remote place, etc.

Friday, April 25, 2008

Return code

- In Java, invoke a sub-process


Process p = Runtime.getRuntime().exec(cmd);

Get the return code by p.waitFor() (not p.exitValue() which is not block-waiting and may get Exception). See this article for details.

- Return code in Java program
System.exit(n) where n is the status code, by convention, a nonzero status code indicates abnormal termination. It is different from the return value by method, which is returned to JVM. The exit code is returned from JVM to the machine.

- Check and return code in DOS batch
# invoke a java program ..
# check the program's exit code and abort with return code 2 (or we can log it), which will be digested
# by the caller of this batch file, e.g. C++ code in installer shield
if ERRORLEVEL 2 exit 2

The IF ERRORLEVEL n test succeeds if the error level is n or more.
See: ERRORLEVEL is not %ERRORLEVEL%

Tuesday, April 22, 2008

dynamic class reload

- Use different child classloader to reload the class and create new instance
- Apply proxy pattern to delegate the invocation to new instance, so that changes to the dynamic class become transparent to its caller.


// The dir contains the compiled classes.
File classesDir = new File("/temp/dynacode_classes/");

// The parent classloader
ClassLoader parentLoader = Postman.class.getClassLoader();


// Load class "sample.PostmanImpl" with our own classloader.
URLClassLoader loader1 = new URLClassLoader(
new URL[] { classesDir.toURL() }, parentLoader);
Class cls1 = loader1.loadClass("sample.PostmanImpl");
Postman postman1 = (Postman) cls1.newInstance();

/*
* Invoke on postman1 ...
* Then PostmanImpl.java is modified and recompiled.
*/

// Reload class "sample.PostmanImpl" with a new classloader.
URLClassLoader loader2 = new URLClassLoader(
new URL[] { classesDir.toURL() }, parentLoader);
Class cls2 = loader2.loadClass("sample.PostmanImpl");
Postman postman2 = (Postman) cls2.newInstance();

/*
* Work with postman2 from now on ...
* Don't worry about loader1, cls1, and postman1
* they will be garbage collected automatically.
*/

The Java reflection API includes a handy utility for creating proxies. The class java.lang.reflect.Proxy provides static methods that let you create proxy instances for any Java interface.

InvocationHandler handler = new DynaCodeInvocationHandler(...);
Postman proxy = (Postman) Proxy.newProxyInstance(
Postman.class.getClassLoader(),
new Class[] { Postman.class },
handler);

public class DynaCodeInvocationHandler implements InvocationHandler {


public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// Get an instance of the up-to-date dynamic class
Object dynacode = getUpToDateInstance();

// Forward the invocation
return method.invoke(dynacode, args);
}
}

Reference link

Wednesday, April 16, 2008

MVC/MVP pattern

MVC


There are three components: the Model, View, and Controller The purpose of the MVC pattern is to decouple the user interface from the internal application state and the business logic that manages that state. To accomplish this, the MVC pattern relies heavily on events so that the interface between the three components are not tightly coupled. In fact, only one object, the Model, is usually physically shared between the View and the Controller. In order to maintain the highest degree of flexibility with the MVC pattern, there are some rules to follow:

1. The Model manages all state information
2. The Model notifies the View of state changes through events rather than direct calls
3. The View manages all user interface state and display information
4. The View only queries the Model for state information--it never changes the Model's state
5. The View responds to user gestures and informs the Controller of those gestures using events
6. The Controller responds to View events
7. The Controller queries the Model for state information
8. The Controller can change the Model state using methods exposed by the Model
9. The Controller often constructs the Model and the desired View
10. The Controller implements the business logic of the application with regards to responding to user gestures

Martin Flower's view:
* Make a strong separation between presentation (view & controller) and domain (model) - Separated Presentation.
* Divide GUI widgets into a controller (for reacting to user stimulus) and view (for displaying the state of the model). Controller and view should (mostly) not communicate directly but through the model.
* Have views (and controllers) observe the model to allow multiple widgets to update without needed to communicate directly - Observer Synchronization.

MVP

* View contains the Presenter instance (view "knows" presenter)
* Presenter is the only class knowing how to reach to model and retrieve the data needed for performing business logic
* Presenter talks to the View through the view interface (abstracted representation of the View without UI specific attributes)
* View doesn't know nothing about the Model

Advantage of MVP: dummy slave view (also called Passive View) make stub testing easier


MVC vs. MVP

A comparison is discussed here

MVP design pattern implementation has a view totally unaware of model. Presenter is the one exclusively communicating with the model and sending DTO (in case of Supervising controller) to model or performing direct manipulation with the view UI elements.

On the other hand, in MVC we have next two "read data" cases:

* a view reading data directly from model and perform "declarative data binding" of its controls or
* controller retrieving data from model, pass that context data to view while loading the appropriate view and view then binds to that sent context data

In most of the "update data" use cases we have a view sending updated context data to controller, where controller performs some validation and/or business logic and updates the model with that data.

Wednesday, April 2, 2008

Performance tuning

Whenever your application is connecting to a resource, such as a database, running in another process, you should optimize by focusing on the time spent connecting to the resource, the time spent sending or retrieving data, and the number of round-trips.

- HTTP: apply caching, HTTP compression
- Database: connection pooling, store procedure (save round trips)

To add cache control in Apache config httpd.conf


<Directory "C:/webnms/webclient">
   <Files ~ "\.(gif|jpe?g|png|css|js)$">
     Header set Cache-Control "public,max-age=3600"
   </Files>
</Directory>

Monday, March 24, 2008

Refresh double submit problem

After a HTTP post request, if the user click 'refresh', it may resubmit the form and cause problem.

Redirect the form submit action after complete is a good solution. It changes the 'history'. Ff the user tries to refresh the page, only the result view page is refreshed without form being resubmit.

Wednesday, March 5, 2008

A ridicious RMI issue

The stub files are stored in RMIRegistry. The object is bound when server side publish it via Naming.bind(name, remoteObject). The client side can look up it via Naming.lookup(name) to acquire the network aware stub file.

Basically the remote object is bound to localhost, and inside the stub files, it need the IP address to connect to. It maybe a problem for the host with multiple IPs. It appears that RMI will randomly set an interface IP to be used in stub files.

It causes a ridicious result in my testing. I have a MU (wireless network adapter) connected to the host. And it is miserably used as licence agent (remote object)'s IP in its stub file and crash the system.

Tuesday, March 4, 2008

concurrency general strategy


synchronized(this){
  Connection con = connectionMap.getByIp(ip);
  if (con == null) {
     con = new ConnectionFactory.createConn(..);
     connectionMap.put(con);
  }
  try {
    con.connect() // long-lasting job
  } catch (Exception e) {
     connectionMap.remove(con);
  }
}

Is there a strategy that we can apply to remove connect() out of the synchronized block for performance consideration?

The solution is to split one big lock into n + 1 small locks. n small locks on each Connection object and one lock on the ConnectionMap. Java 5's ReentrantLock (trylock())can be used to implement non-blocking mechanism.

Tuesday, February 12, 2008

Java Array Cast


wlcResp2.setBpList((BpTopo[])bpList.toArray(new BpTopo[bpList.size()]));

MySQL sql udpate - multiple table syntax


update polleddata pd set pd.absolutelastcountervalue=
( select lastcountervalue
from v2r2_temp_tbl1 vtt
where vtt.id=pd.id);

will run 15 minutes for 8000+ records. Change it to:

update polleddata pd, v2r2_temp_tbl1 vtt
set pd.absolutelastcountervalue=vtt.lastcountervalue
where pd.id=vtt.id;

has much better performance.

Tuesday, January 15, 2008

TreeSet Comparator

When using TreeSet(Comparator) for a sorted set, be cautious that the compare() or compareTo() must be consistent with equals. Set interface is defined in terms of the equals operation, but a TreeSet instance performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the set, equal.

E.g., unique id used in equals(), but name (could be duplicate) is used in compare() and cause problem. The item with same name actually couldn't be added to the set.


/** To sort by 2 attributes **/
public int compare(TreeElement e1, TreeElement e2) {
    // sort by tree name first
     int compareName =e1.getTreeName().compareTo(e2.getTreeName());
     if (compareName != 0) {
         return compareName;
     }
     // sort by databaseKey if tree names are the same
     return e1.getDatabaseKey().compareTo(e2.getDatabaseKey());
}

Monday, January 14, 2008

Graceful Shutdown

JVM has a shutdownHook Runtime.getRuntime.addShutdownHook(Thread) which allows us to register a shutdown hook. However, it doesn't work well with Windows. It responds to CTRL-C, but doesn't react when the process is killed (from task manager, or service console). In Linux/Unix it does work.

So an alternate is to add stop handling in JavaService, which run java class as NT service, and provides an adaptor layer .


licAgentService.exe -install "HiPath Wireless License Agent" %EMS_JAVA_HOME%\bin\client\jvm.dll
-Xms16m -Xmx64m
-Djava.class.path=bootstrap.jar;%EXTRA_CLASSPATH%
-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8100,suspend=n
-Djava.library.path=%EMS_HOME%\lib
-start com.siemens.bk.lic.bootstrap.Main
-stop com.siemens.bk.lic.bootstrap.Main -method systemExit
-out .\logs\stdout.log
-err .\logs\stderr.log
-current %LICAGENT_HOME%
-depends "License Agent","HiPath Wireless RMI"
-auto

With the debug option, we can debug a service too.
In Windows Registry \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\, we can review all the option settings of the service.

Friday, January 4, 2008

My 1st Stored Procedure

Create/run store procedure in MySQL SQL Browser
-script->create function/procedure
-click 'execute' button to compile and store in db (proc table)
-type "call sp_ginger()" to run it, without ';"
-database browser->sp_ginger right click to edit


// the task is to diff value between adjcent records in stat table which contains
// up to 14M records remember in sp, assign statement need to "set statement"
// one minor thing is in query "... ttime desc" doesn't work (i.e., ignored)
// in sp, has to be "..s.ttime desc" though it is OK in query, strange thing
// is that ttime is not ambiguous in the statement.
// note that in ginger_watchdog, the timestamp type column will be automatically
// populated with current timestamp during insertion.

DELIMITER $$

DROP PROCEDURE IF EXISTS `webnmsdb`.`sp_ginger` $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_ginger`()
BEGIN

declare done INT default 0;
declare firstItem int default 0;
declare pid, ttime, v bigint(20);
declare instance char(100);

declare pre_pid, pre_ttime, pre_v bigint(20) default -1;
declare pre_instance char(100) default null;
declare rate bigint(20);

declare cur cursor for select * from ginger_order_temp;
declare continue handler for not found set done = 1;

create table if not exists ginger_watchdog (desp char(100), cur_timestamp TIMESTAMP);
insert into ginger_watchdog(desp) values('started sp at');

drop table if exists ginger_result;
create table ginger_result(pollid bigint(20), instance char(100), ttime bigint(20), val bigint(20));

drop table if exists ginger_order_temp;
create table ginger_order_temp select s.pollid, s.instance, s.ttime, s.val from statsdata10_17_2007 s, ratesOidToConvert oid where s.pollid=oid.pollid and s.pollid=992 order by s.pollid, s.ttime desc;

open cur;

repeat
   fetch cur into pid, instance, ttime, v;
   if not done then
   if (firstItem = 0) then
     set pre_pid=pid, pre_instance=instance, pre_ttime=ttime, pre_v=v;
     set firstItem = 1;
   else
     if (pid = pre_pid) then
       set rate = abs(pre_v - v)/((pre_ttime - ttime)/1000);
       insert into ginger_result values(pre_pid, pre_instance, pre_ttime, rate);
     end if;
     set pre_pid=pid, pre_instance=instance, pre_ttime=ttime, pre_v=v;
   end if;

end if;
until done end repeat;
close cur;

insert into ginger_watchdog(desp) values('finished sp at');

END $$
DELIMITER ;