Discussions

J2EE patterns: ViewState Pattern

  1. ViewState Pattern (13 messages)

    If you want to implement a dynamic user interaction, you might find this pattern useful. It is inspired by the use of ViewState in ASP.NET application. I have not seem anything similar on the internet yet and therefore decided to share the idea.

    -- THE PROBLEM --
    The first idea of using this pattern came to me when i was implementing a webpage where there will be a checkbox for each item shown. The checkboxes may be initially check. When the user uncheck it and click submit, i wanted to know that it is uncheck. As the items are supposed to be dynamic and large, it is not practical to compare every items in the database. I wanted to make sure that the check and uncheck action is determine at the presentation layer before submiting the changes to the database layer. At the same time, for my application, it is not suitable to store the viewstate in the session objects as the user is allow to open more than one window of the same page at the same time. Using session objects will confuse the application making it not thread safe.

    -- The Pattern --
    Firstly, i create a ViewState Class that is use to store a HashMap of all objects i want to remember for that page. Make sure that the object is serializable.

    Then I convert the serializable object to a ByteArrayOutputStream object, then to a Byte[] Array before translating the byte[] Array to Hex value.

    The Hex value is then use as a hidden input in the html page named "viewState". The Hexvalue can be compressed before using it as viewstate to reduce the transmission data across the http.

    When the user submit the form, the viewState can be decompress and convert back to a java object again for comparasion.

    -- The code --
    (Example code shown does not include compression)

    public class ViewStateHelper
      {

    private void viewstate(){}

    public static final String[] hexLookupTable = {
    "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
    "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
    "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
    "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
    "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
    "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
    "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
    "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
    "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
    "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
    "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
    "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
    "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
    "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
    };


    public static String toViewState(Serializable obj) throws Exception
    {
    if(obj==null) return "";

    ObjectOutputStream oops;
    ByteArrayOutputStream baops;

    StringBuffer vs = new StringBuffer();
    try{
    baops = new ByteArrayOutputStream();
    oops = new ObjectOutputStream(baops);
    oops.writeObject(obj);
    oops.flush();
    byte[] objByteArray = baops.toByteArray();
    vs = createHexValue(objByteArray);
    oops.close();
    baops.close();
    }catch(IOException ex){
    ex.printStackTrace();
    throw new Exception(ex.toString());
    }catch(Exception ex){
    ex.printStackTrace();
    throw ex;
    }
    return new String(vs.toString());
    }

    public static Object toObject(String vs) throws Exception
    {
    if(vs==null || vs.length()==0) return null;

    ObjectInputStream oips;
    ByteArrayInputStream baips;

    Object obj;

    try{
    StringBuffer vsbuf = new StringBuffer(vs);
    byte[] objByte = createByteValue(vsbuf);
    baips = new ByteArrayInputStream(objByte);
    oips = new ObjectInputStream(baips);
    obj = oips.readObject();
    oips.close();
    baips.close();
    }catch(IOException ex){
    throw new Exception(ex.toString());
    }catch(Exception ex){
    throw ex;
    }
    return obj;
    }

      private static StringBuffer createHexValue(byte[] buffer) {
    try {
    int readBytes = buffer.length;
    StringBuffer strBuf = new StringBuffer();

    for (int i=0; i < readBytes; i++) {
    strBuf.append(hexLookupTable[0xff & buffer[i]]);
    }
    return strBuf;
    } catch (Exception ex) {
    ex.printStackTrace();
    return null;
    }
      }

      private static byte[] createByteValue(StringBuffer strBuf) throws IOException{

    int bufferLength=strBuf.length()/2;
    int digit=0;
    byte[] buffer = new byte[bufferLength];
    for (int i=0; i < bufferLength; i++) {
    digit = Integer.parseInt(strBuf.substring(2*i, (2*i)+2), 16);
    buffer[i] = (byte) digit;
    }

    return buffer;
      }


      }

    Threaded Messages (13)

  2. ViewState Pattern[ Go to top ]

    from my point of view, it would be much more elegant - as well as much more efficient - to send back just a unique identifier, that identifies the hashtable (shouldn´t this be a ValueObject instead ?) in the scope of the session.

    this way you get the obvious advantage of
    1. avoid (de)serialization/encoding overhead
    2. avoid sending data that might be modified/corrupted at the client.
  3. ViewState Pattern[ Go to top ]

    I agree with Uwe and suggest using an MD5/SHA hash of the serialized object as the unique identifier. If security is an issue sign the serialization before hashing it. You know the value is not corrupted if the returned hash matches a stored hash. The objects and hashes can be stored in a Map in a session in the web tier.
  4. ViewState Pattern[ Go to top ]

    So do u guys think that by using the the Session objects to store presentation logic/state, it will be costly to the server memory.
  5. Storing objects into a session[ Go to top ]

    So do u guys think that by using the the Session objects to store presentation logic/state, it will be costly to the server memory.
    Generally it is, because that would involve a lot of read and write to the database that you have no control over.

    In the framework I am trying to build myself (for learning purposes only, I don't think it will see the light of day) I store as little state as possible (within the framework, an application might do something else).

    One thing I do if I need to maintain state (which is usually within the scope of a request or series of requests, not a session) I store a "PageBean" into a web level database. If I don't care about clustering I can put it in a synchronized map, but since I do I store it into a database. Then I restore the data via a query parameter which is used as the key along with the session ID.

    I also use the Post-Redirect-Get pattern as the only way of doing form handling (which limits what you can do with the framework, but like I said its for testing out ideas and may not be finished). The only way I can do it properly without storing everything in a session was to create a store for the request objects to reassemble the data as needed.

    The pagebean is then stored as part of the request attribute and can be queried using <jsp:useBean>
  6. ViewState Pattern[ Go to top ]

    Hi Ryan,

    I personnally see a few disadvantages in that mechanism :

    1/ huge data transfer... Hey I'm still on an old-school dial-up at home, believe me it's getting harder and harder to browse any web site now (special mention to TSS : 10 secs average to browse a page :-/) !

    2/ if you played a bit with Java serialization you surely realize that you'll often serialize you whole app - excepted if you use value objects, but that's unnecessary work for a webapp IMHO and moreover it has a performance cost... This also implies to care more about what you actually do, mark transient attrs, etc... I personnally decided to *never* use serialization any more excepted for very specific purposes !

    3/ Is the ViewState map really heavy ? So much that it would kill the server ? Can't you store the map on the server side (independently of the session) for the time of your "transaction" (compare checkboxes) ?

    When it comes to "transporting object references over HTTP" (being able to send something in a web page that allows to identify an instance when posted later on to the server, of course with no knowledge about the object's class), I personnally use a System.getIdentityHashCode() based approach. You don't need any other identifier actually !
    You can check JWebView's so called "ReferencePool" that does this for the framework (I use it everyday these times to develop an intranet, no problem, it works :-) ). It's in the JWebViews docs at
    http://www.rvkb.com/jwebviews/jwebviews.html, and you can even download the source code (in the .war file) to check it out (it's damn simple !)...

    This should allow you to keep the "items map" on the server, and compare posted parameters to this instead of looking-up the db...
    Of course, this is dangerous : db could be updated while you do the comparison with older "in-memory" objects ! But that's similar with your "serialization-based" approach... Concurrency issue here :-P

    Have fun,

    Remi
  7. ViewState Pattern[ Go to top ]

    1/ huge data transfer... Hey I'm still on an old-school dial-up at home, believe me it's getting harder and harder to browse any web site now [...]

    :)
    this problem should disappear with time and may not be issued on Intranet applications.
    [...] This also implies to care more about what you actually do, mark transient attrs, etc... I personnally decided to *never* use serialization any more excepted for very specific purposes !

    don't you care about what you do? :)
    actually, if application servers were a bit less flexible, they would force you to make sure what you put in the session is serializable... just in case you'd have to cluster your application...


    In Ryan Chok's approach (ViewState sent to the client), you could be able to recover state after session expiration, thus enabling to log on again and perform the operation straight forward.

    One client once asked their application to be totally fail-safe: if the database should fail, users should be allowed to keep a state of what they were doing at that time. In error pages, we had the ViewState data to copy/paste and save in a file so that it could be used later to recover state when the server would be up and running again.

    I would just add something about compression: make sure your compression algorithm produces safe ASCII (no binary, blank, newline or quote characters) so that you can use ViewState data about anywhere in your client code.
  8. ViewState Pattern[ Go to top ]

    :) this problem should disappear with time

    Well the ones I try to buy an ADSL from don't seem to agree ! I'm waiting since months !!!
    ;-)
    and may not be issued on Intranet applications.

    Agreed.
    don't you care about what you do? :)

    Yes yes I care : I don't use built-in serialization 'cause I precisely care about what I do !
    actually, if application servers were a bit less flexible, they would force you to make sure what you put in the session is serializable... just in case you'd have to cluster your application...In Ryan Chok's approach (ViewState sent to the client), you could be able to recover state after session expiration, thus enabling to log on again and perform the operation straight forward.

    Mhhhh... Not sure about this. OK, you'll have part of the "state" in that "web page", but you may be inconsistent with the database (rows may have changed during the time you were away) so it may require sync anyway...

    Also I must admit I can't figure out the usefulness of keeping state after session expiration at first sight...
    One client once asked their application to be totally fail-safe: if the database should fail, users should be allowed to keep a state of what they were doing at that time.

    That's slighly different IMHO than sending data back and forth at every HTTP request, isn't it ?
    I mean, what your "state" is used for if anyway you can't use it along with "living data" (in the DB which is down...)

    Also, why not just maintaining the logs on the server (you got the page with that serialized things in it, so the server was up, it could have written your "instructions" in a dedicated space instead of polluting the UI tier) ?
    In error pages, we had the ViewState data to copy/paste and save in a file so that it could be used later to recover state when the server would be up and running again.

    Why don't you maintain a server-side log file instead of bothering my dial up at every single click ?
    I mean it's supposed to be a "light" client, please don't pass the whole damn app at every user interaction !
    :-)

    Seriously, what is this used for ?
    I still don't get it, don't hesistate to enlight me...

    Have fun,

    Remi
  9. Enlightment... :)[ Go to top ]

    [...] but you may be inconsistent with the database (rows may have changed during the time you were away) so it may require sync anyway...

    I agree with you on the fact that it may sometimes require database synchronisation.

    In this case, synchronisation (or at least it's control) was performed at the end of the process (fail-over or not), in one transaction, allowing to be sure all data was correct at the time of the final operation.
    [...] I mean it's supposed to be a "light" client, please don't pass the whole damn app at every user interaction !:-)Seriously, what is this used for ?I still don't get it, don't hesistate to enlight me

    The state was only written to the UI when the application went badly (when technical exceptions appeared), with the usual "Sorry, your request f***ed up!". This was needed because users were not identified (but were able IT users) and writing to a log on the server would have required user identification when recovering from the failure. Most of all, sensitiveness of information wouldn't allow us to write anything on the hard drive nor to be able to link a user to this information.

    CU.
  10. Enlightment... :)[ Go to top ]

    Hi again Guillaume,
    The state was only written to the UI when the application went badly (when technical exceptions appeared), with the usual "Sorry, your request f***ed up!". This was needed because users were not identified (but were able IT users) and writing to a log on the server would have required user identification when recovering from the failure.

    Hmmmm...
    So the "serialized" transaction is played again later but not with any user consideration.
    At least you identify the browsers (through session) don't you ?
    Most of all, sensitiveness of information wouldn't allow us to write anything on the hard drive nor to be able to link a user to this information.

    I'd bet you work in the health sector, people there are paranoid !
    Is it about patient data ?
    :-)

    Cheers

    Remi
  11. jsf does that[ Go to top ]

    ----------------------------------------------------------
    It is inspired by the use of ViewState in ASP.NET application. I have not seem anything similar on the internet yet and therefore decided to share the idea.
    -----------------------------------------------------

    JSF provides the flexibility to save the session information on client side or server side. If you choose client side, it uses viewstate pattern
  12. ViewState Pattern[ Go to top ]

    Sending state information over the wire is a really sucky pattern. I am glad that JSF by default stores viewstate on server.
  13. Right[ Go to top ]

    Sure, state context shouldn't be stored at client side. Never. Almost never. There are some exceptions to this rule, but client must not store any sensitive information, helpers only, like last entered login, last entered search queries; and btw browsers handle this kind of data well without any programming effort.
  14. IMHO this has its uses[ Go to top ]

    Am a little late to the party here. But I actually have a need for this. First of all, ViewState if compressed and encrypted (MD5/SHA/whatever) then ascii encoded for HTTP consumption is an option provided the amount of data in question is not so large so as to cause excessive latency from browser to server. Secondly, when rolling out one's own implementation in Java or .Net (not talking about in-built .Net implementation here, I'm thinking it can make the application more scaleable. In lieu of using an HttpSession, one can get away without using "sticky sessions". Now of course, most people I know use "sticky sessions". But when not for whatever reason, the ViewState "pattern" could be used with good effect. Finally, under .Net, I think each server on which the application is deployed can be configured to use the same encrpytion keys. This enables the ViewState to be encrypted on one server at the time of delivery and decrypted on another at the time of arrival. If this is not done, then the implementation will work as long as sticky sessions are used. All of us use https all the time. I can write a "spy" to get the stream of bytes going from and to my browser. Why is that not a security risk, while an encrypted-ascii encoded string in a hidden field is? Can someone set me straight. Also I haven't seen Microsoft get any grief about their implementation. So that's at least a small argument in favor of ViewState. I consider myself quite technology agnostic and believe in using the best tool for the job. I think ViewState is very viable. I believe Spring MVC provides an implementation. So it's all good. No?