Retrieving objects collection from Oracle procedure

21
Sep/09
1

As I’ve promised in post “Learn to pass a Java Object as Oracle Procedure parameter“, I’ll show how retrieve object that have a collection of objects as attribute through of an Oracle procedure. Is highly recommended to read previous post.

For this tutorial, we’ll need create the table TBL_CLASS and add your primary key as foreign key in TBL_USER table.

--num class is PK and desc_class description
create table TBL_CLASS (num_class number, desc_class varchar(100));
alter table TBL_CLASS add primary key(num_class);

alter table TBL_USER add num_class number;
alter table TBL_USER add constraint FK_CLASS foreign key(num_class) references tbl_class(num_class);

Now we need to include the new types:

create or replace type class_type as object (num_class number, desc_class varchar2(100), users arr_users);
/
create or replace type arr_class as table of class_type;
/

The class_type type will be the Java Object. Notice that in your signature was included the arr_users type, that will be our collection of user_type (read previous post for more information), the arr_class type will be the class_type collection.

Now we’ll include the procedure that returns our class_type collection.

procedure pro_select_class(clas in class_type, class_return in out arr_class)is
  class_ref_cur ref_cur;
  --class_type array
  classes arr_class := arr_class();

  begin
    open class_ref_cur for
      select cast(
                multiset(
                  select num_class,
                         desc_class,
                         (select cast(
                                  multiset(
                                    select user_name,
                                           height,
                                           b_date
                                    from tbl_user
                                    --JOIN with TBL_USER
                                    where tbl_user.num_class = tbl_class.num_class
                                  ) as arr_users)
                          from dual) users
                  from tbl_class
                  --Using num_class attribute of in parameter
                  where num_class = clas.num_class) as arr_class
      ) classes
    from dual;

    --including the return in array
    fetch class_ref_cur into classes;
    --transferring arrar to variable out
    class_return := classes;
end pro_select_class;

Notice that procedure receive class_type as parameter in and returns arr_class type.

Separating code charge back and set up our objects, we have:

--Mount return
select cast(
        multiset(

          --Will returns the objects class_type and your attributes
          select num_class,
                 desc_class,

                 --Populate user_type collection
                 (select cast(
                          multiset(
                            select user_name,
                                   height,
                                   b_date
                            from tbl_user
                            where tbl_user.num_class = tbl_class.num_class
                          ) as arr_users)

                  from dual) users

          from tbl_class
          where num_class = clas.num_class) as arr_class
) classes
from dual;

Oracle objects done, now the Java code!

We’ll create the object that will be interpreted by the Oracle. Called TypeClass:

public class TypeClass implements SQLData{
	public static final String ORACLE_OBJECT_NAME = "CLASS_TYPE"; //Type name in Oracle
	public static final String ORACLE_CLASS_ARRAY_NAME = "ARR_CLASS"; //Array name in Oracle

        //Attibutes of TBL_CLASS table
	private Long number;
	private String desc;
	private Array users; //This will be user_type collection (or TypeUser in Java)

	public String getSQLTypeName() throws SQLException {
		return ORACLE_OBJECT_NAME;
	}

	public void readSQL(SQLInput stream, String typeName) throws SQLException {
		setNumber(stream.readLong());
		setDesc(stream.readString());
		setUsers(stream.readArray());//Used by JDBC driver to read the collection
	}

	public void writeSQL(SQLOutput stream) throws SQLException {
		stream.writeLong(getNumber());
		stream.writeString(getDesc());
		stream.writeArray(getUsers());//Used by JDBC driver to write the collection
	}
	//Getters and setters omitted
}

We need to map types interpreted in request, this way:

Map> typeMaps = connection.getTypeMap();
typeMaps.put(TypeUser.ORACLE_OBJECT_NAME, TypeUser.class);
typeMaps.put(TypeClass.ORACLE_OBJECT_NAME, TypeClass.class);

We need to map the arrays too:

typeMaps.put(TypeClass.ORACLE_CLASS_ARRAY_NAME, TypeClass[].class);//returned by procedure
typeMaps.put(TypeUser.ORACLE_USER_ARRAY_NAME, TypeUser[].class);//returned by class_type collection

For request, we do:

cs = conn.prepareCall("{call PAC_BEAN.PRO_SELECT_CLASS(?,?)}");
//registering out type, that will be a TypeClass array
cs.registerOutParameter("class_return", OracleTypes.ARRAY, TypeClass.ORACLE_CLASS_ARRAY_NAME);

//passing parameter object
cs.setObject("clas", classQry);

cs.execute();
//retrieving and looping the TypeClass array
Object[] array = (Object[])cs.getArray("class_return").getArray();

for(Object obj : array){
	TypeClass objClass = ((TypeClass)obj);

	System.out.println("Description: "+objClass.getDesc());

        //Here we obtains user_type(TypeUser) array returned by query.
	Object[] userArray = (Object[])objClass.getUsers().getArray();
	for(Object user : userArray){
		System.out.println("\tName: " + ((TypeUser)user).getName());
		System.out.println("\tHeight: " + ((TypeUser)user).getHeight());
		System.out.println("\tBirth: " + sdf.format(((TypeUser)user).getBirth())+ "\r\n");
	}
}

In the end you’ll have a java.sql.Array of TypeUser in getUsers() attribute of TypeClass.

Here I fulfilled my promise. Download the source code of this sample (with previous post sample too) here.

Until next time!

You liked it? Then, please, make a comment! Campaign: "Comment doesn't make your fingers falls".

Taking Screen Shots with Java

17
Sep/09
0

Here I’ll show how to implements a class to take Screen shots.

I thinking about the complexity of a class that takes screen shots and store the files in hard disk and, asking to “uncle G”, I fonded the class Robot, that provide createScreenCapture method.

Now I’ll show how to implement this functionality:

Robot robot = new Robot();
//Setting the rectangle that mark capture area. In this case, will be all screen..
Rectangle rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());

BufferedImage img = robot.createScreenCapture(rect);

Here we defined capture area and obtained a BufferedImage, our image. Now, we needed to persist in hard disk.

//Capturing the ImageWriter and ImageWriterParam
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam iwp = writer.getDefaultWriteParam();

//Setting compression mode and the image quality
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(1);

//Persisting the image
writer.setOutput(new FileImageOutputStream(arquivo));

IIOImage iioimage = new IIOImage(img, null, null);

writer.write(null, iioimage, iwp);
writer.dispose();

We captured the ImageWriter and ImageWriterParam to set the compression method and the image quality.

In line 07 we defined the image quality as 1, where the value can be between 0 (zero), more compression and less quality and 1 (one), less compression and more quality. Then we have kept the file in HD.

We’ve done! Simple, isn’t?

Download this sample here.

See ya!

You liked it? Then, please, make a comment! Campaign: "Comment doesn't make your fingers falls".

Setting maximum number of characters in JTextField

1
Sep/09
0

The default implementation of JTextField not allow set maximum number of characters. To enable this resource you need implements a Document, overriding insertString method.

public class MaxLengthTextDocument extends PlainDocument {
	//Store maximum characters permitted
	private int maxChars;

	@Override
	public void insertString(int offs, String str, AttributeSet a)
			throws BadLocationException {
		if(str == null || (getLength() + str.length() > maxChars)){
			str = str.substring(0, maxChars);
		}
		super.insertString(offs, str, a);
	}

	//getter e setter omitted
}

Here we defined one class called MaxLengthTextDocument that extends PlainDocument. In insertString attribute, we checked if quantity of characters greater than maxChars attribute, cutting String if true.

After this, only insert our implementation in JTextField, this way:

	...
	MaxLengthTextDocument maxLength = new MaxLengthTextDocument();
	maxLength.setMaxChars(50);//50 is a maximum number of character 

	jTextField.setDocument(maxLength);
	...

And voilà!

See ya!

You liked it? Then, please, make a comment! Campaign: "Comment doesn't make your fingers falls".

Introducing padding in a JLabel

22
Aug/09
0

To introduce padding in a JLabel can we use an EmptyBorder, where the attribute width will be our padding. Like this:

...
JLabel jLabel = new JLabel("My JLabel");
//Border used as padding
Border paddingBorder = BorderFactory.createEmptyBorder(10,10,10,10);

jLabel.setBorder(BorderFactory.createCompoundBorder(border,paddingBorder));
...

Here, the JLabel contains a padding with 10 pixels in top, right, bottom and left respectively.

0

If you want to put border around the JLabel, can use a CompoundBorder, inserting Border and EmptyBorder (padding). Like this:

...
JLabel jLabel = new JLabel("Meu JLabel");
//Border used as padding
Border paddingBorder = BorderFactory.createEmptyBorder(10,10,10,10);
//JLabel will be involved for this border
Border border = BorderFactory.createLineBorder(Color.BLUE);

jLabel.setBorder(BorderFactory.createCompoundBorder(border,paddingBorder));
...

1

Download the source code of this sample here.

You liked it? Then, please, make a comment! Campaign: "Comment doesn't make your fingers falls".

iBatis tutorial, learning the basic

13
Jul/09
1

When we talk about the persistence framework, we think in Hibernate/JPA. Recently I was presented to iBatis, a framework that so easy to install, to configure and to use. You can download it in your sponsor site, Apache, clicking here.

Setting iBatis

Unlike another frameworks, to configure iBatis you need only one XML file, called SqlMapConfig.

The mains sections of XML are:

<properties resource="tuto/ibatis/config/SqlMap.properties"/>

This code is optional and specifies the .properties file that’ll be used to declare variables used in configuration.

<typeAlias alias="car" type="tuto.ibatis.beans.Car"/>

Defines the JavaBean used and your alias. You can set much lines, depending of modeling complexity.
In example, we’ll Car bean below:

public class Car {
	private Long carId;
	private String company;
	private String model;
	private String color;
	private Integer	hp;
	private Float price;

	//Setters and getters omitted
}
<transactionManager type="JDBC">
    <dataSource type="SIMPLE">
        <property name="JDBC.Driver" value="${driver}"/>
        <property name="JDBC.ConnectionURL" value="${url}"/>
        <property name="JDBC.Username" value="${username}"/>
        <property name="JDBC.Password" value="${password}"/>
    </dataSource>
</transactionManager>

Parameters used in database connection. The variables ${driver}, ${url}, ${username} and ${password} are defined in .properties file in section properties. If you prefer, can put the values directly in fields.

See the complete file:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
        "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>
    <properties resource="tuto/ibatis/config/SqlMap.properties"/>

    <settings
        cacheModelsEnabled="true"
        enhancementEnabled="true"
        lazyLoadingEnabled="true"
        maxRequests="32"
        maxSessions="10"
        maxTransactions="5"
        useStatementNamespaces="false" />

    <typeAlias alias="car" type="tuto.ibatis.beans.Car"/>

    <transactionManager type="JDBC">
        <dataSource type="SIMPLE">
            <property name="JDBC.Driver" value="${driver}"/>
            <property name="JDBC.ConnectionURL" value="${url}"/>
            <property name="JDBC.Username" value="${username}"/>
            <property name="JDBC.Password" value="${password}"/>
        </dataSource>
    </transactionManager>

    <sqlMap resource="tuto/ibatis/sqlmaps/CarSqlMap.xml"/>
</sqlMapConfig>

The properties have this content:

driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@<host>:<porta>:<sid>
username=<login>
password=<senha>

Next you need to configure the SqlMap. This XML contains the querys used in application and your name need be equals described in sqlMap section of SqlMapConfig, in our case will be CarSqlMap.xml

In example only we will see utilization of tags select, insert, update and delete.

<select id="getCars" resultClass="tuto.ibatis.beans.Car"
	parameterClass="java.lang.Long">
    SELECT COMPANY  as company,
           MODEL    as model,
           COLOR    as color,
           HP       as hp,
           PRICE    as price
    FROM TBL_CAR
    WHERE CAR_ID = #var#
</select>

Execute the select statement can return a single object or one collection of objects, the type is same of resultClass attribute, o parameterClass is the type sent to execute the query and the id is the query identification call.

We will use the SqlMap below:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
	"http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Car">
    <select id="getCars" resultClass="tuto.ibatis.beans.Car"
    parameterClass="java.lang.Long">
        SELECT COMPANY  as company,
               MODEL    as model,
               COLOR    as color,
               HP       as hp,
               PRICE    as price
        FROM TBL_CAR
        WHERE CAR_ID = #var#
    </select>

    <insert id="addCar" parameterClass="tuto.ibatis.beans.Car">
        INSERT INTO TBL_CAR (CAR_ID, COMPANY, MODEL, COLOR, HP, PRICE)
        VALUES (#carId#, #company#, #model#, #color#, #hp#, #price#)
    </insert>

    <delete id="delCar" parameterClass="java.lang.Long">
        DELETE FROM TBL_CAR WHERE CAR_ID = #var#
    </delete>

    <update id="updCar" parameterClass="tuto.ibatis.beans.Car">
        UPDATE TBL_CAR
          SET COMPANY = #company#,
              MODEL = #model#,
              COLOR = #color#,
              HP = #hp#,
              PRICE = #price#
        WHERE CAR_ID = #carId#
    </update>
</sqlMap>

Data base connection configured, now we will implements the singleton class the will used as SqlMapClient, called OracleMapConfig.

package tuto.ibatis.connection;

import java.io.Reader;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

public class OracleMapConfig {
	private static final SqlMapClient sqlMapClient;

	static{
		try{
			//Defining path of SqlMapConfig and creating reader
			String res = "tuto/ibatis/config/SqlMapConfig.xml";
			Reader reader = Resources.getResourceAsReader(res);

			//Retrieving the client to SqlMap
			sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
		} catch(Exception e){
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	//Method used to retrieve the client
	public static SqlMapClient getSqlMapClient(){
		return sqlMapClient;
	}
}

The client is responsible for execute the querys configured in SqlMap and return the results.

Executing Querys and treating the return

To call any query is too simple, only execute the correspondent method of client class.

The select can be called this way:

OracleMapConfig.getSqlMapClient().queryForObject("<id>", <parâmetro>);

Theid need be equals of id specified in SqlMap

Only one line is return in code above, to get all lines change to queryForList, this way:

OracleMapConfig.getSqlMapClient().queryForList("<id>", <parâmetro>);

Will be returned a Collection containing the objects;

Select

try{
	Car car = (Car)OracleMapConfig.getSqlMapClient().queryForObject("getCars",
		new Long(readKeyboard()));

	System.out.println("Company: "+car.getCompany());
	System.out.println("Model: "+car.getModel());
	System.out.println("Color: "+car.getColor());
	System.out.println("HP: "+car.getHp());
	System.out.println("Price: "+car.getPrice());
}catch (Exception e) {
	e.printStackTrace();
}

The id “getCars” are defined in select attributes of SqlMap, providing one Long type and retrieving a Car type, both defined in line <select id=”getCars” resultClass=”tuto.ibatis.beans.Car” parameterClass=”java.lang.Long“>.

Insert

try{
	OracleMapConfig.getSqlMapClient().insert("addCar", newCar);
}catch (Exception e) {
	e.printStackTrace();
}

Now we will provide as parameter a Car type, <insert id=”addCar” parameterClass=”tuto.ibatis.beans.Car“>, and call the methods using sharp (#), this way:

INSERT INTO TBL_CAR (CAR_ID, COMPANY, MODEL, COLOR, HP, PRICE)
VALUES (#carId#, #company#, #model#, #color#, #hp#, #price#)

Delete

try{
	int lines = OracleMapConfig.getSqlMapClient().delete("delCar",
		new Long(readKeyboard()));

	System.out.println(lines + " lines deleted");
}catch (Exception e) {
	e.printStackTrace();
}

The method delete of client return a type int, this represents the number of rows deleted.

Update

try{
	int lines = OracleMapConfig.getSqlMapClient().update("updCar", car);

	System.out.println(lines + " cars updated");
}catch (Exception e) {
	e.printStackTrace();
}

Update return a type int, this represents the number of rows affected by update.

How you see, with only three XML and three classes we built a simple storage management and price consulting system.

You can download the source code of this tutorial clicking here.

Until next post!

You liked it? Then, please, make a comment! Campaign: "Comment doesn't make your fingers falls".