ODIExperts.com

The blog for Oracle Data Integrator ( ODI )

Jython’s Beginner Guide for ODI

Hello Friends,

There are few days that we don’t have new posts around here… We are pretty busy in the business in the past days!!!

But, here we are with a new post that we, personally, think will be really helpful to those who like “deep” programming in ODI.

I hope you all enjoy it!

When it comes to ODI sooner or later we might have to deal with Jython and some one who have used Java would find that easy ,but not for every one . Considering that we thought of writing this post in understanding how to deal with Jython in relation to ODI . We are not going to teach you Jython 🙂

Generally most of the uses of Jython in ODI is either to capture and raise error in the operator, run OS command and do the appropriate if and else condition , reading and processing records for RDBMS , File processing based on different logic and so on.

When we use jython like java we need to import different modules , Example

import os
import re

we can also import java libraries something like you have seen few of the past codes

import java.lang.sql as sql
import java.lang.io as io

Lets look on few codes which we might use more and more.

Reading , Writing , Re-writing the file

There are different format in jython to process files, but we personally like this format
srcfile=open(‘file_name’,’r’)
Here in the above syntax, we can change the parameters of file by

r – only for reading
r+ – re writing into the same file
w – writing to a new file

When we use W (writing) on an existing file the whole file gets flushed or cleared out,so be careful when pointing to any file.

There are again different format to read the lines of the Files either complete or line by line.
We can write codes using the list format to process records into the memory but if we are dealing many millions of records calling and storing into memory and processing it can throw memory error something like  java.lang.memory exception . Keeping that in mind , we  write codes to read line by line and process accordingly.

Reading Line by Line

srcfile=open('file_name','r')
first_line=srcfile.readline() - Reading First Line
second_line=srcfile.readline() - Reading Second Line

This way when we need to read just one line we can use to readline() command . The pointer of the line keeps moving one line to next line.

Lets say if we want to keep reading all the lines

srcfile=open('file_name','r')
line=srcfile.readline()
i=0
while line:
    print line
    i+=1
    line=srcfile.readline()

print 'Total Number of Lines', i
srcfile.close()

This above simple program reads all the line one by and incremented i for each line it read, so that at the last we are also print the value of ‘i ,denoting the number of lines in File.

Let me cover step by step

srcfile=open('file_name','r')
# opening the File in Read only mode
line=srcfile.readline()
# Reading the First Line
i=0
while line:
# while loop started to read the lines one by one
    print line
    # printing the line . Please note that when ever you write codes under while or for loop ,you need to write after a tab space else the codes wont get  executed.
    i+=1
    # increment the value of i by 1
    line=srcfile.readline()
    #reading the next line of the File

print 'Total Number of Lines', i
# print the value of i
srcfile.close()
#Always close the file which you have open for read , write or any other mode else the file is open by memory in jython and unnecessary data is lying in its #memory.

Reading all the Lines at one shot

srcfile=open('file_name','r')
lines=srcfile.readlines()
print lines
srcfile.close()

Here all the lines of the Files are read a list and stored in the memory error, so in case if we have huge record it can throw memory . To solve either go for Record by record processing which can be a little time consuming or increase the Java memory to handle the processing.

Here  readlines() reads all the lines of the source file and stores in the form of array and pass it to variable lines.

Writing the data into File.

There are different ways we can write the records into File .

If you are writing a string , you can use the write(string )  to write into file

output_write=open('<file_name>','w')
str1='This is a sample program'
output_write.write(str1)
output_write.close()

In case you are planning to write multiple lines say array or list, you can use the writelines()

source_file=open('<file_name>','r')
output_write=open('<file_name>','w')
read_lines=source_file.readlines()
output_write.writelines(read_lines)
source_file.close()
output_write.close()

You can also use the java BufferedWriter.

import java.io as io
writer=io.BufferedWriter(io.OutputStreamWriter(io.FileOutputStream('<file_name_to_be_writtne>')))
writer.write('string or content')
writer.flush()
writer.close()

One of the fastest way to write into File is to store data  into Variable and write them once rather than in a while or for loop that way the overall time is reduced . This idea is great when you running your codes in Server and as we have high memory to process  and store larger records

seek

If you ever want to go to the First line of the file use seek(0) command , so in the above program if i want to go to first line it will be

srcfile.seek(0)  #( seek(zero))

t and n

t moves the pointer to include a tab space
n move the pointer to next line

Concatenate strings

str1='abcd'
str2='efgh'
print str1+str2
#output abcdefgh

Using + we can concatenate two strings .

str1='abcd'
str2=25
print str1+str2
#output Error - TypeError: __add__ nor __radd__ defined for these operands

Reason being we can’t concatenate string and a number

solution 1 - define number in the format of string so - str2='25'
(or)
solution 2 - Convert it into string while printing - str(str2) ,so print str1+str(str2)

to convert from anything to string use str()  function .

Replace

to replace any string  or character with another string or character

str1='123'
str2='456'
action='dist;item'
long_string='ds;sfsdf,sfsdf//'
print str1.replace(str1,str2)
# output  456
print str1.replace('1','7')
# output 723
print action.replace(';',',')
# output dist,item
#you can also have multiple replace at the same time
print long_string.replace(';','').replace(',','').replace('/','')
# output dssfsdfsfsdf

Arrays

Arrays are fun way to handle string and number.To declare a null array use this syntax

str1=['action','item','123']
print str1[0]
# arrays always starts with 0 and so on
# output action
print str1[2]
#output 123

To declare any as null array to this  str1=[]

Converting Arrays to string

str1=['action','item','123']
print ''.join(map(string.strip,str1))
# using this syntax we can convert the array to string
#output actionitem123

Converting String to Array

str1='this is a string'
print list(str)
#output ['t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g']

Converting characters into Array

str1='this is a string'
list1=str1.split(' ')
print list1
#output ['this','is','a','string']
print list1[0]
#output -  this
print list1[1]
#output - is

this split command is useful when you wish to split the string into words and fetch the required on as appropriate.

Raise

Raise is a great command to raise an error and we can use raise to publish the required error into the Operator.Example

raise " This is the following Error " , string
raise str1

Capturing position in String

#first step import module
str='12345'
# assigning value to String
print str[:-1]
# print command is used to print in the output
## when we use -1 it means it starts from the end of the string
## output 1234 as end is 5 and so backwards leave 1 character.
print str[:-2]
## so leave 2 position from end , so output 123
print str[0]
# 0 is treated as the first position
print str[0:3]
#expected output 123
print str[2:4]
#expected output 34

String search

There are some great high level search we can do used regex but here i will be showing you here simple search method using string.find

str1=' This is a program '
print string.find(str1,"is")
if string.find(str1,'is')> 0:
    print str1
else:
    print ' Not available '

# output - This is a program

whenever string.find , finds the particular string in it refers to the position and that’s the reason I use > 0 .

Another simple and efficient search is using Regular Expression (re) .

import re
str1='This is a program'
if  re.search("is",str1):
print ' Match found'
else:
print ' Not Found'

Please look into link for more way to handle simple and complete expression methods and functions.

http://www.jython.org/docs/library/re.html

OS.system

os module helps us to do Operating system based activity either in windows or unix.
os.system run an operating system command fetches the error if fails. If the process is successful then 0 else the required error message .
ODI  have the OS Command and OdiOSCommand to do pretty much the same work without writing any jython
codes .

Lets take another example

import os
if os.system ("copy test.py test1.py"  ) == 0 :
     print "success"
else:
     print " failure "

For os.system  the 0 (zero) is always marked by success and rest of the return codes by failure or error.

Look at this documentation link for os  –   http://www.jython.org/docs/library/os.html

AND  and OR condition

For and condition use this & (and symbol)
OR condition use this | (pipe symbol )

For example

str1= 'Example1'
str2='Example2'

if (( str1 =='Example1' ) & (str2 == 'Example2')):
     print  ' And works '
#output And works
if (( str1 =='Example1' ) | (str2 == 'Example1')):
    print ' OR works '
#output OR works
if ((( str1 =='Example1' ) & (str2 == 'Example3')) | (str2 == 'Example1')):
   print  ' AND and OR combination does not works '
else:
   print  ' AND and OR combination works  '
#output - AND and OR combination works

IF condition

General format
if  (condition )
results
elif (condition)
results
else
results

Ex

str1='Examples'
if str1 == 'Example' :
   print ' The String is Example '
elif str1 =='example' :
   print ' The String is example'
else:
   print ' The str1 is neither example (nor) Example '

[ Note – there is always a tab space after if condition ]

While Condition

While condition is great when we need to process something one by one and execute something till the end.

Example

File C:output.txt

abc
dba
dsg

file_open=open('C:output.txt','r')
line =file_open.readline()
while line:
    print line
    line =file_open.readline()

[ Note – there is always a tab space after while condition , till the condition is complete ]

Jython + SQL

We also use Jython to play with SQL and write the result either in File , Operator etc. To use the SQL we use the Java libraries.

import java.lang.* as lang
import java.sql.* as sql

When it comes to Jython+SQL the logic , format is pretty much the same as Java  , so in case you find an example with Java you can modify with few simple syntax change and write the codes for Jython.

The most efficient way is to use the sunopsis API getJDBCConnection for connecting to Source system using Java or Jython. This way we don’t have to worry about providing the driver parameters or hard coding them since they can change from the environment to environment. In case if you ever need to get particular info about driver , url or user you can use API getInfo()

Initially create the connection to the Source System

sourceConnection = odiRef.getJDBCConnection("SRC")

Here in Command on source we select the required technology and associated schema.

sqlstring = sourceConnection.createStatement()

Next step is to create the statement for execution .

sqlstmt="SELECT 'Errored Interface t- '||SUBSTR(ORIGIN,INSTR(ORIGIN,')')+1,
LENGTH(ORIGIN))||'nError Message tt- '||ERR_MESS||'nNo of Errored Records t- '||
ERR_COUNT AS OUTPUT FROM  ODI_TEMP.SNP_CHECK_TAB WHERE TRUNC(CHECK_DATE)=TRUNC(SYSDATE)"

In sqlstmt we define the complete select , insert, update string and pass it to this variable. This way we can call it multiple time and if we have to modify , we can change it at one place.
Here we have used t to have the tab space between the column and the output and n to have the next result in second line this way the result can be more organized. For an output example Please visit this link –http://odiexperts.com/error-records-log

result=sqlstring.executeQuery(sqlstmt)

To execute a select query use executeQuery(sqlstmt) and to insert /update query use executeUpdate(sqlstmt) .

while result.next():

In order for you to read and process the select query we tend read it records using a while loop and finally you can use getInt , getString and fetch the required records . Please look into the Java documentation for other APIs.

Also you can other similar example related to Jython + SQL

http://odiexperts.com/displaying-sql-results-in-operator
http://odiexperts.com/writing-sql-counts-using-jython

Looking for Editor to learn and practise Jython.
1. Eclipse [ Plugins such as Pydev , JyDT ]
2. Jython.bat

Jython Sources and Documentation

If you are looking for Documentation on Jython , the best resource would be to look into official documentation of jython

http://www.jython.org/docs/

http://www.jython.org/docs/library/ [ Very Important Link ]

[ Note : The links are for Jython 2.5 and so you might find functions and methods which might not be still supported as ODI 10g is on 2.1  ]

Also you might not find so many codes or example for Jython , but you can refer to Python documentation and example too , as Jython is Java + Python .

You can find Python documentation here  http://python.org/doc/

also look into the Oracle documentation ( http://download.oracle.com/docs/cd/E15985_01/doc.10136/reference/DIJQR.pdf ) there  are some good example covered .

Jython not recognizing Windows 7 as NT

Please look into this link http://odiexperts.com/jython-os-bug-in-windows-7

Handling  spaces in path

While passing the OS system path especially in windows we have issue with spaces causing the error Path does not exists or File not Found etc . In order to solve that , Please have the spaces between folder name between double parenthesis. Say for example

import os
ospath=(r'C:Program" "FilesMicrosoft" "SQL" "Server\100\Tools\Binn\bcp')
if os.system(ospath)  > 0:
    raise 'BCP Unload Failes'

Program File is – Program” “File ( Program<double_quote><space><double_quote>File).
Microsoft SQL Server is Microsoft” “SQL” “Server

\ in windows path

Its good to use the two slashes in windows path , reason being some time some of the combination yields values which are understood by Jython differently  , say for example

c:numberten

In this example the n and t would be understood by Jython as next line and tab space causing to read the line wrong  and would throw errors like file not found or path does not exists etc ,so the correct way to write is (ie using double slash)

C:\number\ten

Hope this should provide beginners a guide towards the world of Jython+ODI .
We have covered few codes of Jython and  might update this post in future too so that we have consolidated Jython guide  at one place.

[ Note: There are numerous other ways to do the above codes in different way , you can explore more by looking into Jython books and documentation. ]

Keep looking into the odiexperts for more tips and tricks .

“is”,str1

29 Comments

  1. Hi Guys,

    Is there any way to capture the response value into the ODI variable?

  2. Hai all,

    i have problem when i’m using jython.

    i want to extract file with jython code, but i don’t find good tutorial about it..

    so, if you find resolve about it or you have clear tutorial, can i to see it?

    Thank you so much

    ardi

  3. Hi,
    I am using jython procedure in ODI to read the list of files I have in some directory In my pc.
    Everything works fine while I execute it as a procedure. List of files is generated and
    I store the filenames into database.
    But when I generate a scenario and schedule it at a particular
    time, it fails and gives me “File not found error while reading path in home directory
    Odi od.jy”.

    Does anyone ever faced this issue?
    Any help will be really apriciated.

    Thanks

  4. Can you please help me with reading the following sample ‘error’ file using ODI Jython Procedure, where if it finds ‘ERROR’ it should ‘RAISE’ and error.
    ************
    ERROR- 1003065 – Data load stream contains [815] zero and [1] #MISSING cells.
    WARNING – 1003065 – Data load stream contains [815] zero and [1] #MISSING cells.
    WARNING – 1241114 – There were errors, look in DMdata.err.
    ************

    Thank you very much for your time on this.

  5. Hi Experts ,

    I just started using Jython.
    As the code given above to get the number of rows in a file and print it.
    I have just copy pasted and ran the code .It is not printing anything ; not even the string part but its not giving any error .
    My code is :–
    import os
    import string
    import sys
    import java.lang as lang
    import java.sql as jsql
    import java.lang.String
    import re

    srcfile=open(‘c:\count_write.txt’,’r’)
    lines=srcfile.readlines()
    print lines
    srcfile.close()

    1> File location is correct.
    2> File is having some junk records without any delimiter.
    3> In Operator I am unable to see the message Total Number of Lines’, i

    Thanks In Adv

    • Sorry I have tried with the below code first to get the number of rows in the file..
      srcfile=open(‘c:\count_write.txt’,’r’)
      line=srcfile.readline()
      i=0
      while line:
      print line
      i+=1
      line=srcfile.readline()

      print ‘Total Number of Lines’, i
      srcfile.close()

  6. Hi Guys,

    I want to send an ODI mail based on the count of a bad file. I have written a procedure in jython to find the count of bad file. But
    is it possible to trigger odiSendMail tool from a jython procedure?

  7. Hi,
    I am trying to use the replace string to be able to change the writePictureTo file name, so I can change the input and the file name changes automatically.
    Any assistance would be appriciated,
    thanks.

  8. Hi i am trying to import random class as below in eclipse
    from java.util import Random
    but i get an error as “Unresolved import: Random”
    please let me know what setting i need to make inorder to make it working

  9. Hi,

    I need to write error tables (E$) to files (one file for every error table). I was thinking it would be interesting to write a Jython command with a loop that iterates for every error table generated. In every iteration I would call OdiSqlUnload odi tool, but… it’s possible to call an odi command from Jython?

    Also, I want to write the error tables headers on those files.

    How would you approach this problem?

    Thanks in advance.

    • Hi Javi,

      See if you want with out the header , the easy way would be be
      Solution 1
      —————
      Command on Source
      Select table_name from all_tables where table_name like ‘E$_%’

      Command on Target – Sunopsis API
      OdiSqlUnload (required option ) – query= select * from #table_name

      Issue with this solution you cannot generate header

      Solution 2
      ————–
      Command on Target – Sunopsis API
      using Java

      OdiSqlUnload Select * from

      Solution 3
      —————
      You can also use Jython for OdiSqlUnload then you may need to generate startcmd statement for each statement and keep calling it .

      Please let me know if you need any more help.
      Thanks
      Kshitiz Devendra

  10. Hi ,

    i have ODI 11g and jdk 1.6 in my machine.

    i am trying to run custom class’s method from ODI, for that i created a class, made jar for the class and then copied it to the location “C:oracle11.1.0ODIoraclediagentdrivers”

    as given at “http://www.business-intelligence-quotient.com/?p=941″ site also
    then created one procedure in ODI

    using Java Bean Shell as Technology and

    import Hello

    h =Hello()
    h.ShowHello()

    using Jython as technology

    but in both the cases i am getting some exception like

    1. in Jython case
    org.apache.bsf.BSFException: BeanShell script error: Parse error at line 1, column 8. Encountered: Hello BSF info: Command 0 at line: 0 column: columnNo
    at bsh.util.BeanShellBSFEngine.eval(Unknown Source)
    at bsh.util.BeanShellBSFEngine.exec(Unknown Source)
    at com.sunopsis.dwg.codeinterpretor.SnpScriptingInterpretor.execInBSFEngine(SnpScriptingInterpretor.java:345)
    at com.sunopsis.dwg.codeinterpretor.SnpScriptingInterpretor.exec(SnpScriptingInterpretor.java:169)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.scripting(SnpSessTaskSql.java:2374)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.execScriptingOrders(SnpSessTaskSql.java:1615)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.execScriptingOrders(SnpSessTaskSql.java:1580)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.treatTaskTrt(SnpSessTaskSql.java:2755)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.treatTask(SnpSessTaskSql.java:2515)
    at com.sunopsis.dwg.dbobj.SnpSessStep.treatAttachedTasks(SnpSessStep.java:534)
    at com.sunopsis.dwg.dbobj.SnpSessStep.treatSessStep(SnpSessStep.java:449)
    at com.sunopsis.dwg.dbobj.SnpSession.treatSession(SnpSession.java:1954)
    at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor$2.doAction(StartSessRequestProcessor.java:322)
    at oracle.odi.core.persistence.dwgobject.DwgObjectTemplate.execute(DwgObjectTemplate.java:224)
    at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor.doProcessStartSessTask(StartSessRequestProcessor.java:246)
    at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor.access$0(StartSessRequestProcessor.java:237)
    at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor$StartSessTask.doExecute(StartSessRequestProcessor.java:794)
    at oracle.odi.runtime.agent.processor.task.AgentTask.execute(AgentTask.java:114)
    at oracle.odi.runtime.agent.support.DefaultAgentTaskExecutor$2.run(DefaultAgentTaskExecutor.java:82)
    at java.lang.Thread.run(Thread.java:619)

    2. in Java Bean shell Case

    java.lang.Exception: BeanShell script error: Sourced file: inline evaluation of: “ import Hello; Hello h =new Hello(); h.ShowHello(); ;” : Typed variable declaration : Class: Hello not found in namespace : at Line: 6 : in file: inline evaluation of: “ import Hello; Hello h =new Hello(); h.ShowHello(); ;” : Hello
    BSF info: Command 0 at line: 0 column: columnNo
    at com.sunopsis.dwg.codeinterpretor.SnpCodeInterpretor.transform(SnpCodeInterpretor.java:635)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.codeInterpretation(SnpSessTaskSql.java:418)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.execScriptingOrders(SnpSessTaskSql.java:1615)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.execScriptingOrders(SnpSessTaskSql.java:1580)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.treatTaskTrt(SnpSessTaskSql.java:2755)
    at com.sunopsis.dwg.dbobj.SnpSessTaskSql.treatTask(SnpSessTaskSql.java:2515)
    at com.sunopsis.dwg.dbobj.SnpSessStep.treatAttachedTasks(SnpSessStep.java:534)
    at com.sunopsis.dwg.dbobj.SnpSessStep.treatSessStep(SnpSessStep.java:449)
    at com.sunopsis.dwg.dbobj.SnpSession.treatSession(SnpSession.java:1954)
    at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor$2.doAction(StartSessRequestProcessor.java:322)
    at oracle.odi.core.persistence.dwgobject.DwgObjectTemplate.execute(DwgObjectTemplate.java:224)
    at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor.doProcessStartSessTask(StartSessRequestProcessor.java:246)
    at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor.access$0(StartSessRequestProcessor.java:237)
    at oracle.odi.runtime.agent.processor.impl.StartSessRequestProcessor$StartSessTask.doExecute(StartSessRequestProcessor.java:794)
    at oracle.odi.runtime.agent.processor.task.AgentTask.execute(AgentTask.java:114)
    at oracle.odi.runtime.agent.support.DefaultAgentTaskExecutor$2.run(DefaultAgentTaskExecutor.java:82)
    at java.lang.Thread.run(Thread.java:619)
    Caused by: org.apache.bsf.BSFException: BeanShell script error: Sourced file: inline evaluation of: “ import Hello; Hello h =new Hello(); h.ShowHello(); ;” : Typed variable declaration : Class: Hello not found in namespace : at Line: 6 : in file: inline evaluation of: “ import Hello; Hello h =new Hello(); h.ShowHello(); ;” : Hello
    BSF info: Command 0 at line: 0 column: columnNo
    at bsh.util.BeanShellBSFEngine.eval(Unknown Source)
    at bsh.util.BeanShellBSFEngine.exec(Unknown Source)
    at com.sunopsis.dwg.codeinterpretor.SnpCodeInterpretor.transform(SnpCodeInterpretor.java:621)
    … 16 more

    Please guide whats the problem in this. Am i missing something ??

  11. Ok, I want import ODI objects into repository.

    Now I can read directory and in while execute something like this:

    while
    command=’startcmd.bat OdiImportScen “-FILE_NAME=’full_file_name'” “-IMPORT_MODE=SYNONYM_INSERT_UPDATE”‘
    if os.system(command) 0:
    raise command
    i+=1

    But I want execute
    OdiImportScen not as external OS command, but directly as ODI API function

    • Have the technology as Sunopsis API and write the Import command and see if that helps.
      But in case you are trying to fetch the value through a program try Java instead of Jython.

      Command on Target
      Technology – Sunopsis API

      OdiImportScen “-FILE_NAME=” “-IMPORT_MODE=SYNONYM_INSERT_UPDATE”‘

  12. Or may be another way:
    execute Jyton code as “Command on Source” and in while call execution odi api as “Command on Target”.

    Is it possible ?

  13. Is it possible call odi api function from Jyton code?
    Not via startcmd, but “directly”.

  14. Hi guys,
    while testing “Converting Arrays to string” part, I failed .Do I need to import any java class for this?

  15. Thanks for your answer but

    1 – where i put the jython ?
    import os
    b= os.path.getsize(“/path/MyFile.txt”)

    2 – And if i follow you, in the variable V_MA_variable b
    In Refresh tab i put
    select ” from dual

    It’s allright ?

    thank you in advance.
    Etienne

    • Go with Java and be using the required command in java , fetch this value os.path.getsize(“/path/MyFile.txt”) into a java varaible and then call in the ODI variable with select ” from dual

      Using Jython you cannot call it outside the procedure session so it wont be possible to fetch the jython variable outside in ODI variable so please go for Java codes.

  16. Hi guys,

    Juste one question about Jython and ODI Variable.

    How can I set a variable value with the result of Jython code ?

    I want to know the file size or the creating date from a file :
    import os
    b= os.path.getsize(“/path/MyFile.txt”)

    But i d’ont know, how to affect a variable with jython code.

    Any solution.

    best regards

  17. Hi experts,
    Is it possible to get arraylists or other data of other complex structures from jar files?
    If not which is the best way to get data from jar files?

  18. Hey guys. Great work as always.

    I would suggest to create a PDF from it: ODI Jython cheat sheet. I can distribute through my blog as well. For greater distribution.

    Cheers
    uli

Leave a Reply

Required fields are marked *.