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...

Saturday, 28 November 2009

NetBeans subversion update issue

For me , NetBeans is the best IDE I tried so far…
And believe me, I tried and used plenty…
I’m not talking about Java IDE only, but IDE in general…

But there’s a bug in it that made me wonder if there is a need for me to look for another IDE to use when developing applications.

At one moment , I considered moving to Eclipse, maybe a community edition of IntelliJ IDEA, or even a JDeveloper.
After a while I decided not to switch to other IDE in the middle of the project, and I doubt I’ll be moving after because I found a solution to a problem I’ll be talking about now…
After all, this is the only serious issue i have with NetBeans so far…

So, what is it about?

I noticed that every now and then , after I update my local project from subversion repository , I have a problem deploying it…
Just for the record: project in the subversion I updated to is a fully legal and working project.

NetBeans manage to update it, but when I try to deploy a project, all I get is an exception saying:


Caused by: Action class […some Action class…] not found - action - file:/C:/Documents%20and%20Settings/Darko/My%20Documents/NetBeansProjects/MyProject/build/web/WEB-INF/classes/struts.xml:714:99
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.verifyAction(XmlConfigurationProvider.java:405)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addAction(XmlConfigurationProvider.java:355)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addPackage(XmlConfigurationProvider.java:460)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadPackages(XmlConfigurationProvider.java:265)
        at org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages(StrutsXmlConfigurationProvider.java:111)
        at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:189)
        at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:55)
        ... 28 more



But there is no message saying what’s wrong…
As I said, this was a quite frustrating, and it still is, but now I know how to solve it and continue my work…

All you need to do is restart Netbeans and try to deploy your project again.
You’ll fail.
But now , you’ll get a message in your output window saying that some of your classes, is missing.
Find which one is “missing”.
It is not really missing. For some reason NetBeans is just saying it cannot “see” it…
Go to source packages and open this class.
Go to the end of it and just enter few new lines in it and click “save”.
Let NetBeans save it, and then do a right-click on the project and click “Build” and hit the “Clean and Build” button…


 





Now try to deploy it…
You’ll probably succed…
I know I do!

If you don’t, do all the process once again…
Not ALL the process, just the one after restarting NetBeans.

I would really like to see this bug fixed.
I don’t know if this is really a NetBeans bug, or a Subversion bug, or Tomcat bug ( I use Tomcat ) but it exists…

As I said, this is the only serious bug I found so far in NetBeans , and would really like to hear from you if there is a way of solving somehow different… Some regular way …


Friday, 27 November 2009

Oracle OpenScript


Nema, Oracle je zaista Interesantan...
Ono što on napravi MORA ostaviti utisak na vas!
Makar na mene ostavlja...

Nekad cete biti zaprepašceni kako je Oracle nešto loše i/ili nestandardno uradio ( npr. Oracle-ova konzola, code editor u Oracle forms-u, oracle designer, odredene specifičnosti PL/SQL-a… i još mnogo toga) , a nekad ( uglavnom ) cete biti zapanjeni kvalitetom uradenog ( npr. Oracle Discoverer , ADF , oracle Reports, APEX , web util ... i još  mnogo toga )
E, postoji jedan alat koji je posljednji u nizu ostavio više nego pozitivan utisak na mene.
Njegovo ime je Oracle OpenScript.



Svi koji rade na razvoju Oracle Forms ili klasicnih web aplikacija ce biti više nego oduševljeni onim što ovaj alat ima da ponudi.

Rijec je o Eclipse-based IDE-u u kojem možete kreirati skriptove za automatizovano testiranje vaših aplikacija.


Ja ga još nisam detaljno ispitao, ali i sa ovoliko malim iskustvom sa Oracle openScript-om oduševljeno tvrdim da je ovo jedna nova stavka mome spisku must-have alata za razvoj forms i web aplikacija.
I upravo je stigao u savršenom trenutku, što se mene tice!

Kreiranje ogromnih formi je upravo postao mnogo lakši posao ?

E kad se samo sjetim dugometražnih unosa podataka i beskonacnih pozivanja novih i novih formi i LOV-ova da bi dobio samo jednu logicku cjelinu unutar baze novog IS-a zarad testiranja uradenog…
Pa ako nešto ne valja, ispraviš to i sve iz pocetka…

Kako se radi sa Oracle openScriptom?

Ono što sam ja do sada vidjeo – jako jednostavno!

Kreirajte script za automatizovano testiranje vaše aplikacije,



i dobicete novi prayan script sa defaultnim cjelinama :

-    initialize
-    run
-    finish



Rijec je ustvari o vizuelnoj prezentaciji java coda koji se generiše u pozadini, tj. Na jezicku “Java code”




The OpenScript Tree View scripting interface provides a graphical representation of the test script. Multiple script windows can actually be open at the same time. Within each script window, the Tree View is broken down into 3 main script sections:
•    Initialize: For script commands that only execute once on the first iteration
•    Run: Main body of the script for commands that will run on every iteration
•    Finish: For script commands that only execute once on the last iteration
Within each section, script Steps and Navigation nodes can be created automatically during script recording or manually through the Tree View user interface. Additional script commands will also be represented as nodes in Tree View including test cases, data inputs, log messages, etc. Each Tree View node has a corresponding representation in the Java Code View.



A kako se to Javin kod generiše?

Pa, po onome što sam vidio , najjednostavnije npr. klikom na dugme “record” .
Kada kliknemo na ovo dugme, otvorice nam se defaultni browser ( ovo možete promjeniti u podešavanjima unutar samog okruženja ) i Oracle openScript ce na osnovu vašeg djelovanja generisati script ( Java code ) koji ce biti code-prezentacija onoga što ste vi uradili prilikom testiranja.
Dakle, IDE sve pamti, I upravo ce , kada kliknete na dugme “playback” sve sam ponovo uraditi.
Sve adrese koje upišete u adres bar , sve na šta kliknete, koje sve popup ili nove prozore otvorite, koji sve prozori preuzmu fokus, sve ce se “pamtiti” u kodu kreiranjem poziva prema odgovarajucim funkcijama API-ja koji Oracle OpsenScript koristi.

Sjajna stvar!

Ovo je, naravno, najlakši nacin za generisanje skripta.
Postoji i rucno pisanje koda, koje je sigurno naprednije i mocnije, i mnoge druge funkcionalnosti koje IDE nudi, ali kažem – nisam ga mnogo koristio da bih mogao prenijeti tips and tricks…

U svakom slucaju – u pitanju je stvarcica kojoj cu sigurno pružiti šansu. Još jedna od onih iz Oracle-ovih laboratorija koja vas ostavi bez daha…


Dakle, ko je zainteresovan da isproba, i olakša sebi život, download strana je:
http://www.oracle.com/technology/software/products/app-testing/index.html

Ko želi koristiti Oracle openScript sa Oracle Forms developerom , evo i jedan lijep link sa kratkim uvodom u tu materiju:

http://www.scl.com/software-quality/software-quality-resources/testing-oracle-forms-with-openscript


Cujemo se, nadam se , uskoro na ovu temu ponovo...  ;-)

Monday, 19 October 2009

Oracle ROWNUM

Na baze-podataka.net je izašao moj novi post, ovaj put posvećen priči o rownum-u u Oracle RDBMS-u.

Tema može biti interesantna ljudima koji ranije nisu detaljnije čitali o ovoj pseudo koloni.
Objašnjeno je  njeno pravilno korišćenje u upitima , i skrenuta pažnja na neke česte zablude u vezi rownum-a...

Link: http://www.baze-podataka.net/2009/10/19/oracle-rownum/