Sunday, 31 October 2010

Ajax XML response and Struts2

Ajax and Struts2 are really cool! I really enjoy combining these two together in my web applications.
Few days ago I was working on some application, and needed to update some values in my JSP using Ajax. I decided to use XML as an Ajax response, parse it and do whatever I want with it...

In this post I will show you how to make Struts2 return XML as an Ajax response.

Here is an example of how you can do this:

public class CustomAction extends ActionSupport
{

public HttpServletResponse getResponse() 
{
        return ServletActionContext.getResponse();
}

@Override
    public String execute() throws Exception {
        PrintWriter printWriter = null;
        getResponse().setContentType("text / xml;charset = UTF-8");
        getResponse().setHeader("Cache - Control", "no - cache");
        
        StringBuffer sb = new StringBuffer("");
        // let's say you have A Movie object "movie" that needs to be represented as XML
try
        {
            printWriter = getResponse().getWriter();
            sb.append("" + movie.getDirector() + "");
            sb.append("" + movie.getLanguage() + "");
            sb.append("" + movie.getYear() + "");
            sb.append("");
            printWriter.print(sb.toString());
        }
        catch (IOException e)
        {
            e.printStackTrace();
            throw e;
        }
        finally
        {
            printWriter.close();
            printWriter = null;
        }
        return NONE;
    }

} 

And that's it! Just create a PrintWriter, adjust some values in response and print your XML.

And now, in your JavaScript, you can parse this xml and do something with it:

directors=xmlhttp.responseXML.documentElement.getElementsByTagName("director");
        languages=xmlhttp.responseXML.documentElement.getElementsByTagName("language");
        years = xmlhttp.responseXML.documentElement.getElementsByTagName("year");
        director = directors[0].firstChild.nodeValue;
        language = languages[0].firstChild.nodeValue;
        year = years[0].firstChild.nodeValue;
document.getElementById('director').value=director;
document.getElementById('language').value=language;
document.getElementById('year').value=year;

That's it.
I hope I helped someone...

Saturday, 21 August 2010

Just another implementation of string splitting function in PL/SQL

Here are some of my implementation of string splitting function in PL/SQL.
It is something developers need often, and still can't believe there isn't a function that does something like this in oracle 10g...???

Some developers parse delimited text using substr(text,X,Y) for every token they need to use in their code…

My advice is: Don’t ever do this!!! Use some available tokenizer function!

I found several implementations on the internet, but those functions either does not support delimiter with length more than 1, either it does not return tokens that are NULL, or does not return table of varchar2 index by pls_integer ( what I needed), etc.

So I wrote it myself…

Anyway, here is my first implementation, written entirelly in PL/SQL:

CREATE OR REPLACE FUNCTION splitString(str VARCHAR2,delimit VARCHAR2) RETURN dbms_sql.Varchar2_Table IS
  
  inputString VARCHAR2(32000);
  delimiter VARCHAR2(32);                         

  delimiters dbms_sql.Number_Table;
  tokens dbms_sql.Varchar2_Table;

  array_index PLS_INTEGER := 1;
  pos PLS_INTEGER := 1;
  delimiter_pos PLS_INTEGER;

  delimiter_length PLS_INTEGER;
  inputString_length PLS_INTEGER;

BEGIN

  IF str IS NULL THEN
  RAISE_APPLICATION_ERROR(-20000,'str cannot be null!');
  END IF;
  
  IF delimit IS NULL OR delimit = '' THEN
  RAISE_APPLICATION_ERROR(-20000,'delimiter cannot be null or empty string!');
  END IF;

  inputString := str;
  delimiter := delimit;

  delimiter_length := length(delimiter);
  inputString_length := length(inputString);

  -- Prepare inputText for parsing
  IF substr(inputString,inputString_length - delimiter_length + 1,delimiter_length) != delimiter THEN
      inputString := inputString || delimiter;
  END IF;

  IF substr(inputString,1,delimiter_length) = delimiter THEN
      inputString := substr(inputString,delimiter_length + 1,inputString_length);
  END IF;
  ---------------------


  -- find delimiter occurrences in inputText
   LOOP
      delimiter_pos := instr(inputString,delimiter,pos);
      EXIT WHEN delimiter_pos = 0;
      delimiters(array_index) := delimiter_pos;
      array_index := array_index + 1;
      pos := delimiter_pos + delimiter_length;
   END LOOP;
  --------------------
  
  -- reset temp variables
  array_index := 1;
  pos := 1;
  ---------------------

  -- iterate through delimiters and create tokens
  FOR j IN delimiters.first..delimiters.last LOOP
      tokens(array_index) := substr(inputString,pos,delimiters(j)-pos);
      array_index := array_index + 1;
      pos := delimiters(j)+ delimiter_length;
  END LOOP;
  --------------------

  RETURN tokens;

END;
/
Function’s parameters are string that needs to be tokenized, and a delimiter ( that can have length greater than 1).

Yoy could enchance it by setting


TOKENS     DBMS_SQL.VARCHAR2_TABLE;

to

TYPE t IS TABLE OF varchar2(32000) INDEX BY PLS_INTEGER;
TOKENS t;

if  you are dealing with tokens of length > 2000.
Also, these are case-sensitive functions. You can make it case-insensitive very easy...

Dejan  gave me an idea to write it using SQL.
So I did it, because his implementation using SQL to parse a string is cool:



CREATE OR REPLACE FUNCTION SPLITSTRING_USING_SQL(STR VARCHAR2, DELIMIT VARCHAR2)
  RETURN DBMS_SQL.VARCHAR2_TABLE IS

  INPUTSTRING    VARCHAR2(32000);
  INPUTDELIMITER VARCHAR2(32);

  TOKENS DBMS_SQL.VARCHAR2_TABLE;

  DELIMITER_LENGTH   NUMBER;
  INPUTSTRING_LENGTH NUMBER;

BEGIN

  IF STR IS NULL THEN
    RAISE_APPLICATION_ERROR(-20000, 'str cannot be null!');
  END IF;

  IF DELIMIT IS NULL OR DELIMIT = '' THEN
    RAISE_APPLICATION_ERROR(-20000,
                            'delimiter cannot be null or empty string!');
  END IF;

  INPUTSTRING    := STR;
  INPUTDELIMITER := DELIMIT;

  DELIMITER_LENGTH   := LENGTH(INPUTDELIMITER);
  INPUTSTRING_LENGTH := LENGTH(INPUTSTRING);

  -- Prepare inputText for parsing
  IF SUBSTR(INPUTSTRING,
            INPUTSTRING_LENGTH - DELIMITER_LENGTH + 1,
            DELIMITER_LENGTH) != INPUTDELIMITER THEN
    INPUTSTRING := INPUTSTRING || INPUTDELIMITER;
  END IF;

  IF SUBSTR(INPUTSTRING, 1, DELIMITER_LENGTH) != INPUTDELIMITER THEN
    INPUTSTRING := INPUTDELIMITER || INPUTSTRING;
  END IF;
  
  SELECT SUBSTR(INPUTTEXT,
                INDEKS + DELIMITER_LENGTH,
                NAREDNI - DELIMITER_LENGTH - INDEKS) TOKEN BULK COLLECT
    INTO TOKENS
    FROM (SELECT INDEKS,
                 LEAD(INDEKS) OVER(ORDER BY INDEKS) NAREDNI,
                 INPUTTEXT
            FROM (SELECT LEVEL INDEKS,
                         INPUTSTRING INPUTTEXT,
                         INPUTDELIMITER DELIMITER,
                         (CASE
                           WHEN SUBSTR(INPUTSTRING, LEVEL, DELIMITER_LENGTH) =
                                INPUTDELIMITER THEN
                            1
                           ELSE
                            0
                         END) IS_DELIMITER
                    FROM DUAL
                  CONNECT BY LEVEL <= LENGTH(INPUTSTRING))
           WHERE IS_DELIMITER = 1)
   WHERE NAREDNI IS NOT NULL;

  RETURN TOKENS;

END;
/
It’s basically very similar to his function.
The only difference is that unlike Dejan’s function, this one returns NULL tokens too…

You can test theese two functions easy:


declare 
  
  input VARCHAR2(32000) := 'one***two***three***four***five***six***seven***eight***nine***ten';
  delimiter varchar2(10) := '***';
  result dbms_sql.Varchar2_Table;
  
begin

  result := splitString(input,delimiter);
  --result := splitString_using_sql(input,delimiter);
  
  for i in result.first..result.last loop
      dbms_output.put_line(result(i));
  end loop;
                        
  
end;





Conclusion:
There are CERTAINLLY better ways to write this function, and these are just an example how this could be done.

This is one possible approach, to return an array of tokens. For me , probably the better way would be to create an Object that does something like StringTokenizer Java class. Not to return an array, but to provide a way to iterate through tokens using it’s hasMoreTokens() and nextToken() methods.
I think this is better approach if you are dealing with very large input strings and tokens. If you are dealing with small ones, then it’s OK to use one of my funtions I provided here, or any other similar to this one, that you can find on the internet…

If you intend to use one of these, I suggest  on using first one, because It is much faster than second one.

I didn’t do any optimizations ( which is obvious  ) because I was pleased with speed. Of course, you are welcome to do it yourself

as a matter of fact, I did some speed testing with input strings whose length is ~ 30000, and the first one was (much) faster than many  functions I found on the internet…

Saturday, 27 February 2010

Nakon dugo vremena, opet sam tu...

E zaista nisam odavno pisao na svom blogu. Vjerovatno su najveći razlog za to prevelike obaveze na poslu. Radilo se i dan i noć, pa umor uradi svoje.
Drugi razlog je i nedostatak inspiracije. Pretpostavljam da je to direktna posljedica prvog razloga. Ustvari kada razmislim, više je to nedostatak snage a ne inspiracije ( hm, što je opet posljedica prvog razloga? ) jer sam inspiracije za interesantne teme proteklih mjeseci imao na pretek:
od best practice -a prikupljenih prilikom posljednjeg projekta koristeći Struts2 u sklopu e-governement-a,  preko  kreiranja JAVA framework-a za rapidni ( uz to i deklarativni ) razvoj web aplikacija ,  do know-how tema prilikom učešća na razvoju web servisa različitih vrsta i namjena  ( koje bi mnogima uštedjele mnoooogo vremena i živaca ) i još mnogih drugih interesantnih stvari...
Zaista sve interesantne teme za pisanje, ALI kao što rekoh – umor učini svoje i tu se vraćamo na početnu rečenicu ovog teksta.
I tako ja pomislih da nisam odavno pisao za blog, i taman da po ko zna koji put po redu uhvatim maglu od pisanja, sjetih se da je danas 27. Februar…
E to je dan koji zaslužuje da se pomene, te  ja na ovaj nacin dajem svoj doprinos popularizaciji IT-a u CG: Danas se završava još jedan festival IT-a , ovaj put onaj na Žabljaku: IT 2010!
Doduše, mnogo bi , vjerovatno, smisla imalo da sam se javio 24. Februara, kada je festival pocinjao, ali ni na ovaj nacin ne gubi na “težini” moj doprinos popularizaciji domacih IT festivala :-)
Volio bih kada bi vidjeo i ostale kolege kako na svom blogu pišu o istom.
Ili slicnom, bio bih zadovoljan.
O blogu nekog izlagača i da ne pričam.
Nego, udaljismo se od teme...
Na žalost, ni ove godine nisam posjetio pomenuti festival, i iskreno mi je žao. Jedino što sam mogao ispratiti i procitati u vezi njega je ono što je objavljeno na zvanicnom sajtu ( www.it.ac.me.)
Ove godine je imalo tema koje su me iskreno zainteresovale.

Prva je
-    MOGUCNOSTI PRIMJENE SERVIS-ORIJENTISANE ARHITEKTURE (SOA) U PRAKSI jer imam srece da na poslu aktivno koristim ovakvu arhitekturu pri kreiranju informacionih sistema, i jer je tema koja me poprilicno interesuje a tako se malo zna o njoj kod nas.
Kao što procitah negdje: web servisi su kao srednjoškolski sex: svako prica o njemu, a niko ili rijetko ko ga zaista konzumira. A i onaj ko ga konzumira – ne zna ga pravilno konzumirati.
Nevjerovatno je kako je malo dobrih tekstova i  literature na internetu ( napominjem dobrih ) na ovu temu a ima toliko toga da se kaže i demonstrira. Upravo zbog toga me svaka prica na ovu temu interesuje.

Druga je
-    PRIMJENA MPI ZA ODREÐIVANJE BIASA I VARIJANSE KUBICNE FAZNE FUNKCIJE. Ova tema mi je posebno interesantna. Prvi razlog su koautori na ovom radu koji su mi odredeni garant kvaliteta samog rada, a drugi je jer se radi o aplikaciji radenoj za klaster, upotrebom MPI funkcija. Tokom 2006-e godine sam ucestvovao na izradi prve crnogorske aplikacije za klaster ( koliko sam informisan ) , u sklopu CIS-a UCG (http://www.mren.ac.me/eilenberger/ ) i zaista bi mi bilo interesantno vidjeti kako je neko drugi implementirao nešto slicno...

I treca je
- PRIMJER VALIDACIJE XML-A POMOCU DTD-A. Opet kao prvo radi koautora a onda i zbog moje redovne i vrlo ceste upotrebe ovog formata. XML je cesta tema i na ovom blogu...


Ovo, naravno, nisu jedine teme vrijedne slušanja, ali MENI su najinteresantnije. Ne bi bilo loše da su na zvanicnom sajtu obezbjedeni i video snimci predavanja. Eto dobra predlog za organizatore za sljedecu godinu...

Thursday, 4 February 2010

Oblikujte novi Oracle Forms builder

Prenosim svoj novi tekst sa bloga baze-podataka.net
( http://www.baze-podataka.net/2010/02/04/oblikujte-novi-oracle-forms-builder/ )


Nedavno je na Oracle-ovom forumu  pokrenuta tema na kojoj možete predložiti šta bi bilo dobro da se doda u Oracle Forms.

http://forums.oracle.com/forums/thread.jspa?threadID=1021732&start=0&tstart=0

Na ovaj način je ljudima koji koriste ovaj alat je data sjajna prilika da oblikuju  narednu verziji Forms-a.
Naravno, neće se svaki predlog prihvatiti, ali vrijedi pokušati...

Lično, prve stvari koje su mi pale na pamet su

- dodavanje kalendarčića ( ovo trenutno radim preko Java binova, ali bi bilo puno bolje imati neki gotovi formsov objekat )
- poboljšanje editora PL/SQL-a ( trenutni editor je više nego smiješan. Čak kada razmislim - ne znam za gori )
- ugrađena podrška za webutil ( nepotrebno zakomplikovano )

- bolje odrađena podrška za slike ( slike importovane preko Image item-a su neprihvatljivo loše )

- bolje urađena podrška za kreiranje i importovanje Java binova ( nepotrebno zakomplikovano, bez ozbiljnog  modula u samom IDE-u koji bi developerima pomogao pri kreiranju binova )

- veća sloboda pri kreiranju i oblikovanju data blokova. ( Npr. da se može zadati upit na osnovu kojeg će se u run time-u izgenerisati  data blok ( ok, koji bi bio read-only ) . Npr. kao data grid koji imamo u BCB-u, .NET-u... .)

Naravno, ima još toga čime bi se trebalo pozabaviti u formsu, kao što je npr. debugger, VCS , prelaženje sa aplet aplikacija  na ajax aplikacije , standardizacija IDE-a itd i još dosta dosta toga...

Dakle, ko ima ideje - neka predloži...