Search This Blog

Monday, January 21, 2013

Spring 3.0 MVC & Hibernate

Spring has an awesome feature to deal with Hibernate. For a traditional Hibernate application, you need a hibernate configuration file, a number of mapping files for tables. But Spring reduces that overhead and introduces a new Annotation based mapping. At last, we dont need to brag with that XML files and much cleaner when it looks in POJO.
Thanks Patrick Grimard for giving such wonderful article. I just altered his code according to my need and the tutorial was written by him.
Lets have a look at this. First we need to map the DispatcherServlet in the web.xml file.

    springmvc
    org.springframework.web.servlet.DispatcherServlet
    1



    springmvc
    *.html

The next thing to configure will be your minimal web application context for Spring.
The spring config file is




    
    
    
    
        
        
        
    

    
        
        
        
        
    

    
        
        
            
                com.springmvc.model.User
            
        
        
            
                ${hibernate.dialect}
                ${hibernate.show_sql}
                ${hibernate.connection.pool_size}
            
        
    

    
        
    

With Spring having introduced schema based configuration in Spring 2.0, it greatly reduces the amount of XML verbosity in your configuration file, hence this minimal web application context.
The context:property-placeholder element which we use to tell the Spring container where to find some properties files for resolving ${} type placeholders within our application context.
The context:component-scan element that tells Spring where to begin scanning our package for annotated components like @Repository, @Service, @Controller, etc.  Using this element also automatically implies the context:annotation-config element’s behavior to scan for things like @Autowired and several other annotations.  Therefore you don’t need both elements in your application context.
The tx namespace is responsible for handling our database transactions.  Using the tx:annotation-driven element, we’re telling Spring to look for beans annotated with @Transactional and handle them according to the parameters defined in those annotations.  You’ll also notice on line 58, we’ve defined a TransactionManager implementation bean that gets automatically wired into our annotated configuration for handling the transactions.  Because we named our TransactionManager simply “transactionManager” in our configuration, it automatically gets wired into our annotated configuration, this is the Spring default.  If we had given it a different name, we would have had to add the transaction-manager attribute to the tx:annotation-driven element and specify the id of our TransactionManager implementation bean.
Our TransactionManager defines one property named sessionFactory, which references our sessionFactory bean. Our sessionFactory bean is required for Hibernate and more importantly, being an AnnotationSessionFactoryBean, it will allow us to annotate domain objects at the code level, rather than define our mappings to the database tables in separate mapping XML files.  We define Hibernate specific properties within our configuration file, rather than in a hibernate configuration XML file.
The parameters within the ${} place-holders can be accessed from a properties file. Just make sure that you dropped your properties file somewhere in the classpath.
One of the main reasons for using Hibernate is to persist domain objects to a datasource without the need for writing ugly SQL statements, acquiring connections and cleaning up those connections, etc.  Hibernate does this for you.
A Simple class definition for User entity
package com.springmvc.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "USER")
public class User {

	@Id @GeneratedValue
	@Column(name = "USER_ID" )
	private Long id;

	@Column(name = "USERNAME")
	private String username;

	@Column(name = "PASSWORD")
	private String password;

	public User() {}

	public Long getId() {
		return id;
	}

	private void setId ( Long id ) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername ( String username ) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword ( String password ) {
		this.password = password;
	}

}
Integrating Hibernate with Spring, the standard JPA annotations work just as well and that’s what I’m using here.
First we’ve annotated the class with @Entity which tells Hibernate that this class represents an object that we can persist.
The @Table(name = “USER”) annotation tells Hibernate which table to map properties in this class to.
The first property in this class is our object ID which will be unique for all events persisted.  This is why we’ve annotated it with @Id.  The @GeneratedValue annotation says that this value will be determined by the datasource, not by the code.  Lastly the @Column(name = “USER_ID”) annotation is used to map this property to the USER_ID column in the USER table.  The other two properties are annotated in the same fashion, but merely with the @Column attribute.
Here is our simple Controller implementation for a Controller which handles User registration and viewing it back.
package com.springmvc.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.springmvc.model.User;
import com.springmvc.service.UserService;

@Controller
@RequestMapping("/users")
public class UserController {

	@Autowired
	private UserService userService;

	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public ModelAndView addUser ( @ModelAttribute("user") Event event) {
		return new ModelAndView ( "userAdd" );
	}

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView viewUsers() {
		Map model = new HashMap();
		model.put ( "users", userService.getAllUsers() );

		return new ModelAndView ( "userView", model );
	}

}
I’ve annotated the UserController class with @Controller and @RequestMapping(“/users”) on line 18 and 19.  When Spring scans our package, it will recognize this bean as being a Controller bean for processing requests.  The @RequestMapping annotation tells Spring that this Controller should process all requests beginning with /users in the URL path.  That includes /users/* and /users.html.
An UserService bean will be autowired and injected by Spring since we applied the @Autowired annotation to the private property. The property name is important because Spring will look for a bean named userService to inject.
The first method named addUser is annotated with @RequestMapping(value = “/add”, method = RequestMethod.GET).  The annotation tells Spring that requests to /users/save.html should be processed by this method, but only if the request method is GET.  The method signature annotates one of the parameters with @ModelAttribute(“users”) which has to do with our JSP page. The important part of this method is the userService.addUser ( user ).  This is a call to our service bean to add our domain object to the datasource when it’s entered in the browser.  It returns a ModelAndView object to resolve the view by logical name. Lets say it redirect to /users.html, which will also be handled by this Controller.
The next method viewUsers is basically our default method when a simple GET request is made to /users.html, you can see this by the annotation @RequestMapping(method = RequestMethod.GET) .  This method creates a Map and adds the data to the map by invoking the userService.getAllUsers() method.  That call returns a List object.  The method returns another ModelAndView object, but this time it will try to resolve to a view named userView and the data model is being passed back to the browser so we can access the data within the JSP. The logical view name will resolve to “/WEB-INF/jsp/userView.jsp” when processed by the jspViewResolver configured in the application context.
Next main thing is, having the Business layer. Here comes our ServiceImpl
package com.springmvc.service;

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.springmvc.dao.EventDao;
import com.springmvc.model.User;

@Service("userService")
@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDao userDao;

	public UserServiceImpl() {}

	@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
	public void addUser(User user) {
		userDao.saveUser ( user );
	}

	public List getAllUsers() {
		return usertDao.getAllUsers();
	}

}
This service bean implements the UserService interface which provides our contract of what this implementation will do.
The class is annotated with @Service(“userService”).  This is the meta data that Spring will use when autowiring the userService property in the Controller created in the previous step.  We’ve explicitly defined the name “userSerivice” in the annotation’s value, otherwise without it Spring would have named the bean “userServiceImpl” automatically and the autowiring of this bean in the Controller and other classes would have failed.
The @Transactional(propagation=Propagation.SUPPORTS, readOnly=true) annotation will be recognized by the tx:annotation-driven element in the application context.  Having placed the annotation at the class level means that all methods in this class by default should adhere to these transaction rules.  propagation=Propagation.SUPPORTS means a transaction isn’t necessary, but if one exists, then the method will run in that transaction.  The readOnly=true attribute is pretty straight forward, by default all data retrieved should be read only.  No writes to the datasource are permitted.
An EventDao object gets autowired.  That class will deal with the actual ORM framework, in this case, Hibernate.Another @Transactional annotation has been applied at the method level. This time @Transactional(propagation=Propagation.REQUIRED, readOnly=false) tells the transaction manager that this method requires a transaction.  This is defined by the propagation=Propagation.REQUIRED attribute.  The readOnly=false attribute overrides the class level readOnly=true so that we are permitted to write to the datasource.  That’s an important thing to keep in mind.  When you annotate at the class level, the rules are applied to every method, but if you need to override the class level attributes, you can do so by annotating the methods in question, overriding whatever attributes you need to.  In this case, since the method will write to the datasource, we require a transaction and write permissions.
below is our HibernateDAO Implementation
package com.springmvc.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.springmvc.dao.User;

@Repository("userDao")
public class HibernateEventDao implements EventDao {

	@Autowired
	private SessionFactory sessionFactory;

	public void saveEvent ( Event event ) {
		sessionFactory.getCurrentSession().saveOrUpdate ( event );
	}

	@SuppressWarnings("unchecked")
	public List getAllEvents() {
		return (List) sessionFactory.getCurrentSession().createCriteria ( Event.class ).list();
	}

}
asasasa
The @Repository(“userDao”) meta data tells Spring this class is a DAO object and Spring should name it “userDao” so that it can be properly autowired into the userService bean from the previous step.The Hibernate SessionFactory will be autowired by Spring.  If you remember, the SessionFactory was defined in the application context with the bean id “sessionFactory” and thus Spring will autowire into this property since it has the same name with the @Autowired annotation.The saveUser method is defined.  It interacts with the session factory by getting the current Hibernate Session and calling the saveOrUpdate method, passing in the User object that was passed to the method.  If the User object has an existing USERID, Hibernate will attempt to update that record in the datasource, if it’s not found, it will try to insert it.The listUserdefines the DAO method for retrieving existing Events from the datasource.  It only contains 1 simple line.  First the current Session is retrieved from the SessionFactory, and then a Criteria is created from that Session, into which we simply pass the User.class common name, followed by a call to list().  So what we’ve done is essentially told Hibernate, select all records from the table that User.class is mapped to, and return all property values of the User class in the form of a java.util.List object.
The next part is view. Here we create a file userView.jsp to display all the available users.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>






Existing Events




Existing Users

ID Title Date
No username found in the Database
Next thing would be creating userAdd.jsp page to add a new user
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>





Add Event




Add User

View All Users Username: Password:
No need to define these JSP pages assuming that you’ve a basic knowledge of JSTL.The only important thing to note here was the mapping names. Note that the Mapping we made using Annotations at Controller must match in the JSP pages. Otherwise it’ll not retrieve or do any process. This is a simple Hibernate-Spring Integration project by me. I hadn’t used any ORM’s before and with Hibernate, i am sure that i’m pretty much impressed. Atleast i get rid of those annoying long SQL sentences.
I’d prefer NetBeans over Eclipse as it comes bundled with Spring and Hibernate Framework Support, which means saving a lot of time. It’ll create you the POJO mapping files and everything easily. The Spring 3.0 Module for NetBeans is available for download.
I’ve downloaded the code from the above link and used it as the base for my project.

Saturday, January 19, 2013

Spring MVC Hello World Example

The following example show how to write a simple web based Hello World application using Spring MVC framework. To start with it, let us have working Eclipse IDE in place and follow the following steps to develope a Dynamic Web Application using Spring Web Framework:
StepDescription
1Create a Dynamic Web Project with a name HelloWeb and create a package com.sachin under the src folder in the created project.
2Drag and drop below mentioned Spring and other libraries into the folder WebContent/WEB-INF/lib.
3Create a Java class HelloController under the com.sachin package.
4Create Spring configuration files Web.xml and HelloWeb-servlet.xml under theWebContent/WEB-INF folder.
5Create a sub-folder with a name jsp under the WebContent/WEB-INF folder. Create a view filehello.jsp under this sub-folder.
6The final step is to create the content of all the source and configuration files and export the application as explained below.

The content of HelloController.java file:
package com.sachin;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.ui.ModelMap;

@Controller
@RequestMapping("/hello")
public class HelloController{
 
   @RequestMapping(method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");

      return "hello";
   }

}
Following is the content of Spring Web configuration file web.xml
 id="WebApp_ID" version="2.4"
   xmlns="http://java.sun.com/xml/ns/j2ee" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

   Spring MVC Application
HelloWeb org.springframework.web.servlet.DispatcherServlet 1 HelloWeb /
Following is the content of another Spring Web configuration file HelloWeb-servlet.xml
 xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
   http://www.springframework.org/schema/beans     
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    base-package="com.sachin" />

    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       name="prefix" value="/WEB-INF/jsp/" />
       name="suffix" value=".jsp" />
   
 
Following is the content of Spring view file hello.jsp
<%@ page contentType="text/html; charset=UTF-8" %>


</font><font class="pln" style="margin: 0px; padding: 0px;">Hello World</font><font class="tag" style="margin: 0px; padding: 0px;" color="#000088">

${message}
Finally, following is the list of Spring and other libraries to be included in your web application. You simply drag these files and drop them in WebContent/WEB-INF/lib folder.
  • commons-logging-x.y.z.jar
  • org.springframework.asm-x.y.z.jar
  • org.springframework.beans-x.y.z.jar
  • org.springframework.context-x.y.z.jar
  • org.springframework.core-x.y.z.jar
  • org.springframework.expression-x.y.z.jar
  • org.springframework.web.servlet-x.y.z.jar
  • org.springframework.web-x.y.z.jar
  • spring-web.jar
Once you are done with creating source and configuration files, export your application. Right click on your application and use Export > WAR File option and save your HelloWeb.war file in Tomcat'swebapps folder.
Now start your Tomcat server and make sure you are able to access other web pages from webapps folder using a standard browser. Now try to access the URL http://localhost:8080/HelloWeb/hello and if everything is fine with your Spring Web Application, you should see the following result:

Important SQL Queries Asked in Java Interviews


Important SQL Queries Asked in Java Interviews

·  Find the 3rd MAX salary in the emp table.
select distinct sal from emp e1 where 3 = (select count(distinct sal) from emp e2 where e1.sal <= e2.sal);
·  Find the 3rd MIN salary in the emp table.
select distinct sal from emp e1 where 3 = (select count(distinct sal) from emp e2where e1.sal >= e2.sal);
·  Select FIRST n records from a table.
select * from emp where rownum <= &n;
·  Select LAST n records from a table
select * from emp minus select * from emp where rownum <= (select count(*) - &n from emp);
·  List dept no., Dept name for all the departments in which there are no employees in the department.
select * from dept where deptno not in (select deptno from emp);
alternate solution:  select * from dept a where not exists (select * from emp b where a.deptno = b.deptno);
altertnate solution:  select empno,ename,b.deptno,dname from emp a, dept b where a.deptno(+) = b.deptno and empno is null; 


·  How to get 3 Max salaries ?
select distinct sal from emp a where 3 >= (select count(distinct sal) from emp b where a.sal <= b.sal) order by a.sal desc; 


·  How to get 3 Min salaries ?
select distinct sal from emp a  where 3 >= (select count(distinct sal) from emp b  where a.sal >= b.sal);
·  How to get nth max salaries ?
select distinct hiredate from emp a where &n =  (select count(distinct sal) from emp b where a.sal >= b.sal); 
·  Select DISTINCT RECORDS from emp table.
select * from emp a where  rowid = (select max(rowid) from emp b where  a.empno=b.empno); 
·  How to delete duplicate rows in a table?
delete from emp a where rowid != (select max(rowid) from emp b where  a.empno=b.empno); 
·  Count of number of employees in  department  wise.
select count(EMPNO), b.deptno, dname from emp a, dept b  where a.deptno(+)=b.deptno  group by b.deptno,dname; 
·   Suppose there is annual salary information provided by emp table. How to fetch monthly salary of each and every employee?
select ename,sal/12 as monthlysal from emp;
·  Select all record from emp table where deptno =10 or 40.
select * from emp where deptno=30 or deptno=10;
·  Select all record from emp table where deptno=30 and sal>1500.
select * from emp where deptno=30 and sal>1500;
·  Select  all record  from emp where job not in SALESMAN  or CLERK.
select * from emp where job not in ('SALESMAN','CLERK');
·  Select all record from emp where ename in 'BLAKE','SCOTT','KING'and'FORD'.
select * from emp where ename in('JONES','BLAKE','SCOTT','KING','FORD');
·  Select all records where ename starts with ‘S’ and its lenth is 6 char.
select * from emp where ename like'S_';
·  Select all records where ename may be any no of  character but it should end with ‘R’.
select * from emp where ename like'%R';
·  Count  MGR and their salary in emp table.
select count(MGR),count(sal) from emp;

·  In emp table add comm+sal as total sal  .
select ename,(sal+nvl(comm,0)) as totalsal from emp;
·  Select  any salary <3000 b="b" emp="emp" from="from" nbsp="nbsp" table.="table.">
select * from emp  where sal> any(select sal from emp where sal<3000 span="span">
·  Select  all salary <3000 b="b" emp="emp" from="from" nbsp="nbsp" table.="table.">
select * from emp  where sal> all(select sal from emp where sal<3000 span="span">
·  Select all the employee  group by deptno and sal in descending order.
select ename,deptno,sal from emp order by deptno,sal desc;
·  How can I create an empty table emp1 with same structure as emp?
Create table emp1 as select * from emp where 1=2;
·  How to retrive record where sal between 1000 to 2000?
Select * from emp where sal>=1000 And  sal<2000 span="span">
·  Select all records where dept no of both emp and dept table matches.
select * from emp where exists(select * from dept where emp.deptno=dept.deptno)
·  If there are two tables emp1 and emp2, and both have common record. How can I fetch all the recods but common records only once?
(Select * from emp) Union (Select * from emp1)
·  How to fetch only common records from two tables emp and emp1?
(Select * from emp) Intersect (Select * from emp1)
·   How can I retrive all records of emp1 those should not present in emp2?
(Select * from emp) Minus (Select * from emp1)
·  Count the totalsa  deptno wise where more than 2 employees exist.
SELECT  deptno, sum(sal) As totalsal
FROM emp
GROUP BY deptno HAVING COUNT(empno) > 2

Why Interfaces are there in Java ..?


Most of the developers know how to use interfaces as described in books and sample code available on the internet but they fail to ask what is the need of interfaces. Why they were added to Java?

Interfaces had been added to Java language since its inception. The implements keyword is used in conjunction with interfaces and provides a way to override the methods defined in an interface. All the methods of an interfaces are abstract by default. Any variables defined in an interface are public static final by default.

computer interface

While creating design documents for your application , do watch out for which super type should be interface and which should be an abstract class.

Interfaces are used for binding multiple children of same type. The advantages of using interfaces include:

    Multiple inheritance

    The diamond problem associated with multiple inheritance of concrete methods has been avoided by the use of interfaces. This is because of the fact that the methods in an interface are all abstract.
    

Hierarchy

    Many a times, multiple classes, do fall under one umbrella category but are not very significantly associated with each other in terms of behavior.
    For example the Exception class and String class are Serializable (their object state can be persisted). The Exception and String classes are used in completely different scenario and hence it doesn’t make sense to bind them with the help of a common ancestor. But we definitely need to mark these classes as Serializable. In that, case interfaces come handy which only provide definition of a member variable but don’t provide any implementation code.
    

Difference from Abstract classes

    The interfaces are also used to bind abstract classes. Take the example of Collections hierarchy from the java.util package of JDK. The AbstractCollection class implements the Collection interface. The AbstractCollection class is inherited by AbstractMap, AbstractSet and AbstractList classes and these sub classes in turn also implement Map, Set and List interfaces.
 

    All variables are constants

    Some developer tend not to use classes for declaring constants (the fields marked as public static final) and prefer using interfaces for declaring constants.
    An abstract class with all methods as Abstract?

    Abstract classes could also provide similar behavior as provided by interfaces (when all the methods of an Abstract class are abstract).

    But one feature of Java is that only one class can be the direct parent of another class. Hence if you need to have multiple non-significant behavior and one significant behavior, interfaces are the only rescue. This is because of the fact that a class can implement multiple interfaces.

It is worth mentioning here that the interface keyword should not be confused with @interface annotation. The @interface annotation is used for defining custom annotations for an application.

Sunday, July 11, 2010

Article: Compressing and Decompressing Data Using Java APIs

Decompressing and Extracting Data from a ZIP file


The java.util.zip package provides classes for data compression and decompression. Decompressing a ZIP file is a matter of reading data from an input stream. The java.util.zip package provides a ZipInputStream class for reading ZIP files. A ZipInputStream can be created just like any other input stream. For example, the following segment of code can be used to create an input stream for reading data from a ZIP file format:

FileInputStream fis = new FileInputStream("figs.zip");
ZipInputStream zin = new
ZipInputStream(new BufferedInputStream(fis));

Once a ZIP input stream is opened, you can read the zip entries using the getNextEntry method which returns a ZipEntry object. If the end-of-file is reached, getNextEntry returns null:

ZipEntry entry;
while((entry = zin.getNextEntry()) != null) {
// extract data
// open output streams
}


Now, it is time to set up a decompressed output stream, which can be done as follows:

int BUFFER = 2048;
FileOutputStream fos = new
FileOutputStream(entry.getName());
BufferedOutputStream dest = new
BufferedOutputStream(fos, BUFFER);


Note: In this segment of code we have used the BufferedOutputStream instead of the ZIPOutputStream. The ZIPOutputStream and the GZIPOutputStream use internal buffer sizes of 512. The use of the BufferedOutputStream is only justified when the size of the buffer is much more than 512 (in this example it is set to 2048). While the ZIPOutputStream doesn't allow you to set the buffer size, in the case of the GZIPOutputStream however, you can specify the internal buffer size as a constructor argument.

In this segment of code, a file output stream is created using the entry's name, which can be retrieved using the entry.getName method. Source zipped data is then read and written to the decompressed stream:

while ((count = zin.read(data, 0, BUFFER)) != -1) {
//System.out.write(x);
dest.write(data, 0, count);
}

And finally, close the input and output streams:

dest.flush();
dest.close();
zin.close();

The source program in Code Sample 1 shows how to decompress and extract files from a ZIP archive. To test this sample, compile the class and run it by passing a compressed file in ZIP format:

prompt> java UnZip somefile.zip

Note that somefile.zip could be a ZIP archive created using any ZIP-compatible tool, such as WinZip.

Code Sample 1: UnZip.java

import java.io.*;
import java.util.zip.*;

public class UnZip {
final int BUFFER = 2048;
public static void main (String argv[]) {
try {
BufferedOutputStream dest = null;
FileInputStream fis = new
FileInputStream(argv[0]);
ZipInputStream zis = new
ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
while((entry = zis.getNextEntry()) != null) {
System.out.println("Extracting: " +entry);
int count;
byte data[] = new byte[BUFFER];
// write the files to the disk
FileOutputStream fos = new
FileOutputStream(entry.getName());
dest = new
BufferedOutputStream(fos, BUFFER);
while ((count = zis.read(data, 0, BUFFER))
!= -1) {
dest.write(data, 0, count);
}
dest.flush();
dest.close();
}
zis.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}


It is important to note that the ZipInputStream class reads ZIP files sequentially. The class ZipFile, however, reads the contents of a ZIP file using a random access file internally so that the entries of the ZIP file do not have to be read sequentially.

Note: Another fundamental difference between ZIPInputStream and ZipFile is in terms of caching. Zip entries are not cached when the file is read using a combination of ZipInputStream and FileInputStream. However, if the file is opened using ZipFile(fileName) then it is cached internally, so if ZipFile(fileName) is called again the file is opened only once. The cached value is used on the second open. If you work on UNIX, it is worth noting that all zip files opened using ZipFile are memory mapped, and therefore the performance of ZipFile is superior to ZipInputStream. If the contents of the same zip file, however, are be to frequently changed and reloaded during program execution, then using ZipInputStream is preferred.

This is how a ZIP file can be decompressed using the ZipFile class:

1. Create a ZipFile object by specifying the ZIP file to be read either as a String filename or as a File object:

ZipFile zipfile = new ZipFile("figs.zip");
2. Use the entries method, returns an Enumeration object, to loop through all the ZipEntry objects of the file:

while(e.hasMoreElements()) {
entry = (ZipEntry) e.nextElement();
// read contents and save them
}

3. Read the contents of a specific ZipEntry within the ZIP file by passing the ZipEntry to getInputStream, which will return an InputStream object from which you can read the entry's contents:

is = new
BufferedInputStream(zipfile.getInputStream(entry));



4. Retrieve the entry's filename and create an output stream to save it:

byte data[] = new byte[BUFFER];
FileOutputStream fos = new
FileOutputStream(entry.getName());
dest = new BufferedOutputStream(fos, BUFFER);
while ((count = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}


5. Finally, close all input and output streams:

dest.flush();
dest.close();
is.close();

The complete source program is shown in Code Sample 2. Again, to test this class, compile it and run it by passing a file in a ZIP format as an argument:

prompt> java UnZip2 somefile.zip

Code Sample 2: UnZip2.java

import java.io.*;
import java.util.*;
import java.util.zip.*;

public class UnZip2 {
static final int BUFFER = 2048;
public static void main (String argv[]) {
try {
BufferedOutputStream dest = null;
BufferedInputStream is = null;
ZipEntry entry;
ZipFile zipfile = new ZipFile(argv[0]);
Enumeration e = zipfile.entries();
while(e.hasMoreElements()) {
entry = (ZipEntry) e.nextElement();
System.out.println("Extracting: " +entry);
is = new BufferedInputStream
(zipfile.getInputStream(entry));
int count;
byte data[] = new byte[BUFFER];
FileOutputStream fos = new
FileOutputStream(entry.getName());
dest = new
BufferedOutputStream(fos, BUFFER);
while ((count = is.read(data, 0, BUFFER))
!= -1) {
dest.write(data, 0, count);
}
dest.flush();
dest.close();
is.close();
}
} catch(Exception e) {
e.printStackTrace();
}
}
}


Compressing and Archiving Data in a ZIP File

The ZipOutputStream can be used to compress data to a ZIP file. The ZipOutputStream writes data to an output stream in a ZIP format. There are a number of steps involved in creating a ZIP file.

1. The first step is to create a ZipOutputStream object, to which we pass the output stream of the file we wish to write to. Here is how you create a ZIP file entitled "myfigs.zip":

FileOutputStream dest = new
FileOutputStream("myfigs.zip");
ZipOutputStream out = new
ZipOutputStream(new BufferedOutputStream(dest));

2. Once the target zip output stream is created, the next step is to open the source data file. In this example, source data files are those files in the current directory. The list command is used to get a list of files in the current directory:

File f = new File(".");
String files[] = f.list();
for (int i=0; i System.out.println("Adding: "+files[i]);
FileInputStream fi = new FileInputStream(files[i]);
// create zip entry
// add entries to ZIP file
}


Note: This code sample is capable of compressing all files in the current directory. It doesn't handle subdirectories. As an exercise, you may want to modify Code Sample 3 to handle subdirectories.


3. Create a zip entry for each file that is read:
4. ZipEntry entry = new ZipEntry(files[i])) Before you can write data to the ZIP output stream, you must first put the zip entry object using the putNextEntry method:
5. out.putNextEntry(entry); Write the data to the ZIP file:

int count;
while((count = origin.read(data, 0, BUFFER)) != -1) {
out.write(data, 0, count);
}

6. Finally, you close the input and output streams:

origin.close();
out.close();

The complete source program is shown in Code Sample 3.

Code Sample 3: Zip.java

import java.io.*;
import java.util.zip.*;

public class Zip {
static final int BUFFER = 2048;
public static void main (String argv[]) {
try {
BufferedInputStream origin = null;
FileOutputStream dest = new
FileOutputStream("c:\\zip\\myfigs.zip");
ZipOutputStream out = new ZipOutputStream(new
BufferedOutputStream(dest));
//out.setMethod(ZipOutputStream.DEFLATED);
byte data[] = new byte[BUFFER];
// get a list of files from current directory
File f = new File(".");
String files[] = f.list();

for (int i=0; i System.out.println("Adding: "+files[i]);
FileInputStream fi = new
FileInputStream(files[i]);
origin = new
BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(files[i]);
out.putNextEntry(entry);
int count;
while((count = origin.read(data, 0,
BUFFER)) != -1) {
out.write(data, 0, count);
}
origin.close();
}
out.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}