Dear Reader,
This is a quite confusing topic. However I hope my explanations will clear your doubt.
I am writing here wait() and notify() method use case. This is also called producer-consumer
problem. Just to remind: you can replace notify() with notifyAll() in the given examples below.
The only difference is notify() awakens only one thread which is waiting to get lock on an object.
notifyAll() awakens all threads who are waiting to get hold of that object. However it is always CPU's
task to which thread CPU allows first to get hold of object. More discussions with example below:
In my example, I have a Bucket Object and two methods on it "InsertIntoBucket" and "DeleteFromBucket".
I have put a Bucket size, so that it shouldn't grow unlimited. Also one more variable is required
for checking whether Bucket is full or not. If full, don't insert data. If empty, don't delete data.
Wanted behavior: If bucket is full, don't insert data. If bucket is empty, don't delete the data.
Unwanted behavior: Even If bucket is full, try to insert data. Even If bucket is empty, try to delete data. And cause Exceptions..
Points to remember, read carefully:
1) Wait(), Notify() and NotifyAll() are methods of Object class and it is the father of all APIs in Java so
these methods are accessible to Thread class objects too.
2) Each object has its own lock means When multiple threads are trying to access only one object, the Variables
of Object may result in unwanted states causing wrong output to the caller threads. Remember Threads are also
objects but here I am not talking about those Thread objects.
Assume same bucket is trying to get filled and vacated by data by two different Threads. So Bucket is the common
resource being shared by multiple threads.
3) If we allow these 2 threads to access these two methods, they will access randomly as it is decided by the
CPU and we don't have control on the Scheduling, Causing unwanted behaviour.
4) If we make these two methods as Synchronized, only one thread will enter each method (for sake, two threads are
trying to access two methods, you can add as many threads you want to access these two methods). Now even if Bucket
is full, DataInserter thread will try to insert data and if Bucket is empty, DataDeleter thread will try to delete
the data as both have entered into separate blocks, causing Unwanted behavior. Means no thread to going to wait,
till other thread does the task: Means:
a) Bucket is full, DataInserter thread is not waiting, so that DataDeleter will vacate the bucket for allowing
other thread to insert data successfully.
b) Bucket is empty, DataDeleter thread is not waiting, so that DataInserter will insert some data for allowing
other thread to delete data successfully.
5) Wait() and Notify() can only be within Synchronized and non static methods. Many times interviewers ask what if
write just wait() or notify() in main method. Please note: Compiler will not compile your code as wait() and
notify() are non-static methods and you can't access them in main method directly.
6) After implementing this tool, DataDeleter thread will wait for getting some data into Bucket by DataInserter thread.
Once DataInserter thread inserts the data, it will call Notify(), so that waiting thread will come to know the data
is available now in bucket. Same thing for other thread too.
7) Wait() means, current thread (which is running inside that block, where Wait() is defined) will leave the object(Bucket)
lock, but it is still there in that block. Once Notify() is called from other thread, this thread will come into action
and will start executing from that line of code.
8) Common point: Notify() will wake up only one waiting thread (which thread, chosen by CPU), NotifyAll() will wake-up all
waiting threads. Check at the beginning of this article.
Now Coding Implementation (It is quite easier):
//Please note, there are 4 java files, all are in same package (default):
BucketDeleter.java (Thread File)
BucketInserter.java (Thread File)
TestWaitNotify.java (Main Java File to start/run this tool).
WaitNotify.java (Object with methods and variables)
==========================TestWaitNotify.java===================
public class TestWaitNotify {
public static void main(String[] args) {
WaitNotify commonObject = new WaitNotify();
//new BucketDeleter(commonObject);
new BucketDeleter(commonObject);
new BucketInserter(commonObject);
//new BucketInserter(commonObject);
//new BucketInserter(commonObject);
//Un-comment the above thread creation code to see better output, as if
//more number of threads are created then result can be seen better.
System.out.println("Running in infinite loop, Press Control-C to stop.");
}
}
===========================WaitNotify.java====================
import java.util.*;
public class WaitNotify {
int number;
public List bucket = null;
public WaitNotify(){
bucket = new ArrayList();
}
public synchronized void insertIntoBucket(int tempNumber) {
if(bucket.size()<10) {
bucket.add(tempNumber);
System.out.println("Number getting Inserted: "+tempNumber+", Size after insertion: "+bucket.size());
}
else {
System.out.println("List is full, no more insertion");
try {
System.out.println("Waiting now in insertion method...");
wait();
}
catch(Exception e) {
}
}
notify(); //Never put this method in above else block else it will cause deadlock after full insertion.
}
public synchronized void deleteFromBucket() {
if(bucket.isEmpty()) {
System.out.println("Bucket is empty, can't delete the data");
try {
System.out.println("Waiting now in Deletion method...");
wait();
}
catch(Exception e) {
}
}
else {
Object obj = bucket.remove(bucket.size()-1);
System.out.println("Deleting one number from bucket: "+ obj+", Size after deletion: "+bucket.size());
notify();
}
}
}
========================BucketInserter.java====================
public class BucketInserter implements Runnable {
WaitNotify commonObject;
BucketInserter(WaitNotify commonObject) {
this.commonObject = commonObject;
new Thread(this, "BucketInserter").start();
}
public void run() {
int i = 0;
while(true) {
try {
Thread.sleep(1000); //You can comment this, added just to see output properly.
} catch (InterruptedException e) {
e.printStackTrace();
}
i=i+1;
commonObject.insertIntoBucket(i);
}
}
}
=========================BucketDeleter.java=====================
public class BucketDeleter implements Runnable {
WaitNotify commonObject;
BucketDeleter(WaitNotify commonObject) {
this.commonObject = commonObject;
new Thread(this, "BucketDeleter").start();
}
public void run() {
while(true) {
try {
Thread.sleep(1000); //You can comment this, added just to see output properly.
} catch (InterruptedException e) {
e.printStackTrace();
}
commonObject.deleteFromBucket();
}
}
}
====================
//Now Run the main Class (TestWaitNotify.java) and analyze the output.
//Run the Main Class after commenting Wait() and Notify() methods.
//Run the Main Class after removing Synchronized keyword and Wait() and Notify().
================Another sample example of wait() method I am writing:
//wait() method throws InterruptedException which is a CheckedException, so must
//be declared else code will not compile.
public class MainWait {
public static void main(String[] args) throws InterruptedException {
new MainWait().waitForMe();
}
//public synchronized void waitForMe() throws InterruptedException{
public void waitForMe() throws InterruptedException{
wait(); //Unhandled Exception InterruptedException
}
}
//wait() must be called inside a synchronized method or block, so above code gives output:=====
Exception in thread "main" java.lang.IllegalMonitorStateException: current thread not owner
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:474)
at MainWait.waitForMe(MainWait.java:7)
at MainWait.main(MainWait.java:3)
But if you make the method synchronized as :
public synchronized void waitForMe() throws InterruptedException
or put wait() inside synchronized(this) like below:
public void waitForMe() throws InterruptedException{
synchronized(this){
wait(); //Unhandled Exception InterruptedException
}
}
//Then your code will run fine and output will be waiting....You have to close the application, I mean click the RED Square button on MyEclipse....
Also deadlock can be seen here: http://deepakmodi2006.blogspot.in/2011/12/deadlock-in-java.html
-------------------------------END---------------------------------
Friday, January 21, 2011
Wait() and Notify() in Java
Thursday, January 13, 2011
Difference between Struts 1.x and Struts 2.x
Difference between Struts 1.x and Struts 2.x
1) Action classes
Struts1 extends the abstract base class by its action class.
The problem with struts1 is that it uses the abstract classes rather than interfaces.
While in Struts 2 an Action class implements an Action interface along with other interfaces use optional and custom services.
Struts 2 provides a base ActionSupport class that implements commonly used interfaces. Although an Action interface is
not necessary any POJO object along with an execute signature can be used as a Struts 2 Action object.
2) Threading Model
Struts 1 Actions are singletons therefore they must be thread-safe because only one instance of a class
handles all the requests for that Action. The singleton strategy restricts to Struts 1 Actions and requires extra
care to make the action resources thread safe or synchronized while developing an application.
Struts 2 doesn't have thread-safety issues as Action objects are instantiated for each request. A servlet
container generates many throw-away objects per request and one more object does not impose a performance penalty or
impact garbage collection.
3) Servlet Dependency
Actions are dependent on the servlet API because HttpServletRequest and HttpServletResponse is passed to
the execute method when an Action is invoked therefore Struts1.
Container does not treat the Struts 2 Actions as a couple. Servlet contexts are typically represented
as simple Maps that allow Actions to be tested in isolation. Struts 2 Actions can still access the original request and
response if required. While other architectural elements directly reduce or eliminate the need to access the
HttpServetRequest or HttpServletResponse.
4) Testability
Struts1 application has a major problem while testing the application because the execute method exposes
the Servlet API. Struts TestCase provides a set of mock object for Struts 1.
To test the Struts 2 Actions instantiate the Action set the properties and invoking methods.
Dependency Injection also makes testing easier.
5) Harvesting Input
Struts 1 recieves an input by creating an ActionForm object. Like the action classes all ActionForms class
must extend a ActionForm base class. Other JavaBeans classes cannot be used as ActionForms while developers
create redundant classes to receive the input. DynaBeans is the best alternative to create the conventional
ActionForm classes.
Struts 2 requires Action properties as input properties that eliminates the need of a second input object.
These Input properties may be rich object types since they may have their own properties. Developer can access
the Action properties from the web page using the taglibs.
Struts 2 also supports the ActionForm pattern POJO form objects and POJO Actions as well.
6) Expression Language
Struts1 integrates with JSTL so it uses the JSTL EL. The EL has basic object graph traversal but
relatively weak collection and indexed property support.
Struts 2 can use JSTL but the framework also supports a more powerful and flexible expression language
called "Object Graph Notation Language" (OGNL).
7) Binding values into views
Struts 1 binds object into the page context by using the standard JSP mechanism.
Struts 2 uses a ValueStack technology to make the values accessible to the taglibs without coupling
the view to the object to which it is rendering. The ValueStack strategy enables us to reuse views across a
range of types having same property name but different property types.
8) Type Conversion
Struts 1 ActionForm properties are almost in the form of Strings. Commons-Beanutils are used by used by Struts 1
for type conversion. Converters are per-class which are not configurable per instance.
Struts 2 uses OGNL for type conversion and converters to convert Basic and common object types and primitives as well.
9) Validation
Struts 1 uses manual validation that is done via a validate method on the ActionForm or by using an extension
to the Commons Validator. Classes can have different validation contexts for the same class while
chaining to validations on sub-objects is not allowed.
Struts 2 allows manual validation that is done by using the validate method and the XWork Validation framework.
The Xwork Validation Framework allows chaining of validations into sub-properties using the validations defined for
the properties class type and the validation context.
10) Control Of Action Execution
Each module in Struts 1 has a separate Request Processors (lifecycles) while all the Actions in the module must
share the same lifecycle.
In Struts 2 different lifecycles are created on a per Action basis via Interceptor Stacks.
Custom stacks are created and used with different Actions as
In the following section, we are going to compare the various features between the two frameworks.
Struts 2.x is very simple as compared to struts 1.x, few of its excellent features are:
1. Servlet Dependency:
Actions in Struts1 have dependencies on the servlet API since the HttpServletRequest and HttpServletResponse
objects are passed to the execute method when an Action is invoked but in case of Struts 2, Actions are not
container dependent because they are made simple POJOs. In struts 2, the servlet contexts are represented as
simple Maps which allows actions to be tested in isolation. Struts 2 Actions can access the original request
and response, if required. However, other architectural elements reduce or eliminate the need to access the
HttpServetRequest or HttpServletResponse directly.
2. Action classes
Programming the abstract classes instead of interfaces is one of design issues of struts1 framework that
has been resolved in the struts 2 framework.
Struts1 Action classes needs to extend framework dependent abstract base class. But in case of Struts 2
Action class may or may not implement interfaces to enable optional and custom services. In case of Struts 2,
Actions are not container dependent because they are made simple POJOs. Struts 2 provides a base ActionSupport
class to implement commonly used interfaces. Albeit, the Action interface is not required. Any POJO object with
an execute signature can be used as an Struts 2 Action object.
3. Validation
Struts1 and Struts 2 both supports the manual validation via a validate method.
Struts1 uses validate method on the ActionForm, or validates through an extension to the Commons Validator.
However, Struts 2 supports manual validation via the validate method and the XWork Validation framework.
The Xwork Validation Framework supports chaining validation into sub-properties using the validations defined for the
properties class type and the validation context.
4. Threading Model
In Struts1, Action resources must be thread-safe or synchronized. So Actions are singletons and thread-safe,
there should only be one instance of a class to handle all requests for that Action. The singleton strategy places
restrictions on what can be done with Struts1 Actions and requires extra care to develop. However in case of Struts 2,
Action objects are instantiated for each request, so there are no thread-safety issues. (In practice, servlet containers
generate many throw-away objects per request, and one more object does not impose a performance penalty or impact
garbage collection.)
5. Testability
Testing Struts1 applications are a bit complex. A major hurdle to test Struts1 Actions is that the execute method
because it exposes the Servlet API. A third-party extension, Struts TestCase, offers a set of mock object for Struts1.
But the Struts 2 Actions can be tested by instantiating the Action, setting properties and invoking methods. Dependency
Injection support also makes testing simpler. Actions in struts2 are simple POJOs and are framework independent, hence
testability is quite easy in struts2.
6. Harvesting Input
Struts1 uses an ActionForm object to capture input. And all ActionForms needs to extend a framework dependent
base class. JavaBeans cannot be used as ActionForms, so the developers have to create redundant classes to capture input.
However Struts 2 uses Action properties (as input properties independent of underlying framework) that
eliminates the need for a second input object, hence reduces redundancy. Additionally in struts2, Action
properties can be accessed from the web page via the taglibs. Struts 2 also supports the ActionForm pattern,
as well as POJO form objects and POJO Actions. Even rich object types, including business or domain objects,
can be used as input/output objects.
7. Expression Language
Struts1 integrates with JSTL, so it uses the JSTL-EL. The struts1 EL has basic object graph traversal, but
relatively weak collection and indexed property support. Struts 2 can also use JSTL, however it supports a more
powerful and flexible expression language called "Object Graph Notation Language" (OGNL).
8. Binding values into views
In the view section, Struts1 uses the standard JSP mechanism to bind objects (processed from the model section)
into the page context to access. However Struts 2 uses a "ValueStack" technology so that the taglibs
can access values without coupling your view to the object type it is rendering. The ValueStack strategy allows
the reuse of views across a range of types which may have the same property name but different property types.
9. Type Conversion
Usually, Struts1 ActionForm properties are all Strings. Struts1 uses Commons-Beanutils for type conversion.
These type converters are per-class and not configurable per instance. However Struts 2 uses OGNL for type
conversion. The framework includes converters for basic and common object types and primitives.
10. Control of Action Execution
Struts1 supports separate Request Processor (lifecycles) for each module, but all the Actions in a
module must share the same lifecycle. However Struts 2 supports creating different lifecycles on a per
Action basis via Interceptor Stacks. Custom stacks can be created and used with different Actions as needed.
Struts, Spring integration with hibernate
Integrate Struts Spring Hibernate Web Application
This example guides you to Integrate Struts Spring Hibernate in a web application.
Struts : View (User Interface)
Spring : Service Layer
Hibernate : DAO layer
Here are the steps for Integration Struts Spring Hibernate Web Application.
Struts Part
Step 1. Add ActionServlet in web.xml
ActionServlet
ActionServlet is the controller in Struts.
ActionServlet loads the struts-config.xml.
On load-on-startup the servlet container Instantiate the ActionServlet .
First Task by ActionServlet : The ActionServlet takes the Struts Config file name as an init-param.
At startup, in the init() method, the ActionServlet reads the Struts Config file and load into memory.
Second Task by ActionServlet : If the user types http://localhost:8081/strutsspringhibernate/userForm.do
in the browser URL bar, the URL will be intercepted and processed by the ActionServlet since the URL has a pattern *.do, with a suffix of "do". Because servlet-mapping is
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Third Task by ActionServlet : Then ActionServlet delegates the request handling to another class called RequestProcessor by invoking its process() method.
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Step 2. add ActionMapping in struts-config.xml
http://localhost:8081/strutsspringhibernate/userForm.do call to /jsp/userForm.jsp jsp.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="UserForm" type="com.UserForm"> </form-bean>
</form-beans>
<action-mappings>
<action path="/userForm"
type="org.apache.struts.actions.ForwardAction"
parameter="/jsp/userForm.jsp"/>
<action path="/saveUser"
type="com.UserSaveAction"
name="UserForm"
scope="request"
validate="false"
input="/pages/Input.jsp">
<forward name="success" path="/jsp/success.jsp"/>
</action>
</action-mappings>
</struts-config>
Enter username and deptname and click the Save button.
Save button calls /saveUser.do , saveUser.do calls com.UserSaveAction based on above configuration in struts-config.xml.
Step 3. userForm.jsp and success.jsp
userForm.jsp is the form where you enter the User Name and Department
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<html:form action="/saveUser.do" method="post">
User Name : <html:text property="userName" size="30" maxlength="120"/> <br>
Department : <html:text property="deptName" size="30" maxlength="120"/> <br>
<html:submit>Save</html:submit> </html:form>
success.jsp
<h2>User Data saved </h2>
com.UserSaveAction.java
UserSaveAction get the user entered information (RequestProcessor set the user entered data into the UserForm). Get the service from applicationContext.xml using
UserService userservice = (UserService) ServiceFinder.getContext(request) .getBean("userservice");
In the Action class just get the data from UserForm and call to userservice.saveUser(userbean);
package com;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class UserSaveAction extends Action{
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception{
UserService userservice = (UserService) ServiceFinder.getContext(request)
.getBean("userservice");
UserForm userForm = (UserForm) form;
UserBean userbean = new UserBean();
userbean.setUserName(userForm.getUserName());
userbean.setDeptName(userForm.getDeptName());
userservice.saveUser(userbean);
return mapping.findForward("success");
}
}
com.UserForm.java
UserForm is the Form which contain the entered user information.
(RequestProcessor set the user entered data into the UserForm).
package com;
import org.apache.struts.action.ActionForm;
public class UserForm extends ActionForm{
String userName;
String deptName;
/**
* @return Returns the deptName.
*/
public String getDeptName() {
return deptName;
}
/**
* @param deptName The deptName to set.
*/
public void setDeptName(String deptName) {
this.deptName = deptName;
}
/**
* @return Returns the userName.
*/
public String getUserName() {
return userName;
}
/**
* @param userName The userName to set.
*/
public void setUserName(String userName) {
this.userName = userName;
}
}
Spring Part
Step 1. Add ContextLoaderServlet in web.xml
ContextLoaderServlet
ContextLoaderServlet register an ApplicationContext using the the below configuration in web.xml file.
You can get any service (Defind in applicationContext.xml) using request.getSession().getServletContext().getBean("userservice");
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Step 2. applicationContext.xml
applicationContext.xml contains all the Dependency Injections . And it contains hibernate SessionFactory information also. Here Hibernate integatred with Spring.
userservice object has userdao object as setter Injection
userdao object has sessionFactory object as setter Injection.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://localhost:3306/techfaq</value></property>
<property name="username"><value>techfaq</value></property>
<property name="password"><value>techfaq</value></property>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource"><ref bean="myDataSource"/></property>
<property name="mappingResources">
<list>
<value>/com/user.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
</value>
</property>
</bean>
<bean id="userdao" class="com.UserDAO">
<property name="sessionFactory"><ref bean="mySessionFactory"/></property>
</bean>
<bean id="userservice" class="com.UserService">
<property name="userdao"><ref bean="userdao"/></property>
</bean>
</beans>
com.UserService.java
package com;
public class UserService {
private UserDAO userdao;
public void saveUser(UserBean user){
getUserdao().saveUser(user);
}
/**
* @return Returns the userdao.
*/
public UserDAO getUserdao() {
return userdao;
}
/**
* @param userdao The userdao to set.
*/
public void setUserdao(UserDAO userdao) {
this.userdao = userdao;
}
}
com.ServiceFinder.java
package com;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
public class ServiceFinder {
public static ApplicationContext getContext(HttpServletRequest httpRequest) {
return WebApplicationContextUtils.getRequiredWebApplicationContext(
httpRequest.getSession().getServletContext());
}
}
Hibernate Part
Step 1. Create Table in Data Base
CREATE TABLE `techfaq`.`user_test`
( `user_id` int(10) unsigned NOT NULL auto_increment,
`user_name` varchar(45) default NULL,
`dept_name` varchar(45) default NULL,
PRIMARY KEY (`user_id`));
Step 2. user.hbm.xml which maps to user_test TABLE
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.UserBean" table="USER_TEST">
<id name="userId" column="USER_ID" type="int">
<generator class="native"/>
</id>
<property name="userName" column="user_name"/>
<property name="deptName" column="dept_name"/>
</class>
</hibernate-mapping>
Step 3. UserBean.java which maps to user.hbm.xml and user_test TABLE
package com;
public class UserBean {
int userId;
String userName;
String deptName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
}
Step 4. UserDAO.java which is used to save user details into Data Base
package com;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.orm.hibernate.support.HibernateDaoSupport;
public class UserDAO {
private SessionFactory sessionFactory;
public void saveUser(UserBean user){
Session session = getSessionFactory().openSession();
try {
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
}
catch(Exception e){e.printStackTrace();}
finally{session.close();}
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Database Triggers in Oracle
Triggers in Oracle
A Database trigger is:
• A stored PL/SQL block associated with a table, a schema, or the database or
• An anonymous PL/SQL block or a call to a procedure implemented in PL/SQL or Java
Oracle Database automatically executes a trigger when specified conditions occur.
When you create a trigger, the database enables it automatically. You can subsequently disable and enable a trigger with the DISABLE and ENABLE clause of the ALTER TRIGGER or ALTER TABLE statement.
Prerequisites
Before a trigger can be created, the user SYS must run a SQL script commonly called DBMSSTDX.SQL. The exact name and location of this script depend on your operating system.
• To create a trigger in your own schema on a table in your own schema or on your own schema (SCHEMA), you must have the CREATE TRIGGER system privilege.
• To create a trigger in any schema on a table in any schema, or on another user's schema (schema.SCHEMA), you must have the CREATE ANY TRIGGER system privilege.
• In addition to the preceding privileges, to create a trigger on DATABASE, you must have the ADMINISTER DATABASE TRIGGER system privilege.
If the trigger issues SQL statements or calls procedures or functions, then the owner of the trigger must have the privileges necessary to perform these operations. These privileges must be granted directly to the owner rather than acquired through roles.
Insert Triggers:
BEFORE INSERT Trigger
AFTER INSERT Trigger
Update Triggers:
BEFORE UPDATE Trigger
AFTER UPDATE Trigger
Delete Triggers:
BEFORE DELETE Trigger
AFTER DELETE Trigger
Drop Triggers:
Drop a Trigger
Disable/Enable Triggers:
Disable a Trigger
Disable all Triggers on a table
Enable a Trigger
Enable all Triggers on a table
A BEFORE INSERT Trigger means that Oracle will fire this trigger before the INSERT operation is executed.
The syntax for an BEFORE INSERT Trigger is:
CREATE or REPLACE TRIGGER trigger_name
BEFORE INSERT
ON table_name
[ FOR EACH ROW ]
DECLARE
-- variable declarations
BEGIN
-- trigger code
EXCEPTION
WHEN ...
-- exception handling
END;
Restrictions:
• You can not create a BEFORE trigger on a view.
• You can update the :NEW values.
• You can not update the :OLD values.
For example: If you had a table created as follows:
CREATE TABLE orders ( order_id number(5), quantity number(4), cost_per_item number(6,2),
total_cost number(8,2), create_date date,created_by varchar2(10) );
We could then create a BEFORE INSERT trigger as follows:
CREATE OR REPLACE TRIGGER orders_before_insert
BEFORE INSERT
ON orders
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
-- Find username of person performing INSERT into table
SELECT user INTO v_username
FROM dual;
-- Update create_date field to current system date
:new.create_date := sysdate;
-- Update created_by field to the username of the person performing the INSERT
:new.created_by := v_username;
END;
An AFTER INSERT Trigger means that Oracle will fire this trigger after the INSERT operation is executed.
The syntax for an AFTER INSERT Trigger is:
CREATE or REPLACE TRIGGER trigger_name
AFTER INSERT
ON table_name
[ FOR EACH ROW ]
DECLARE
-- variable declarations
BEGIN
-- trigger code
EXCEPTION
WHEN ...
-- exception handling
END;
Restrictions:
• You can not create an AFTER trigger on a view.
• You can not update the :NEW values.
• You can not update the :OLD values.
For example: If you had a table created as follows:
CREATE TABLE orders ( order_id number(5), quantity number(4), cost_per_item number(6,2),
total_cost number(8,2));
We could then create an AFTER INSERT trigger as follows:
CREATE OR REPLACE TRIGGER orders_after_insert
AFTER INSERT
ON orders
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
-- Find username of person performing the INSERT into the table
SELECT user INTO v_username
FROM dual;
-- Insert record into audit table
INSERT INTO orders_audit ( order_id, quantity, cost_per_item, total_cost, username )
VALUES ( :new.order_id,:new.quantity,:new.cost_per_item,:new.total_cost, v_username );
END;
A BEFORE UPDATE Trigger means that Oracle will fire this trigger before the UPDATE operation is executed.
The syntax for an BEFORE UPDATE Trigger is:
CREATE or REPLACE TRIGGER trigger_name
BEFORE UPDATE
ON table_name
[ FOR EACH ROW ]
DECLARE
-- variable declarations
BEGIN
-- trigger code
EXCEPTION
WHEN ...
-- exception handling
END;
Restrictions:
• You can not create a BEFORE trigger on a view.
• You can update the :NEW values.
• You can not update the :OLD values.
For example: If you had a table created as follows:
CREATE TABLE orders
( order_id number(5),
quantity number(4),
cost_per_item number(6,2),
total_cost number(8,2),
updated_date date,
updated_by varchar2(10)
);
We could then create a BEFORE UPDATE trigger as follows:
CREATE OR REPLACE TRIGGER orders_before_update
BEFORE UPDATE
ON orders
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
-- Find username of person performing UPDATE on the table
SELECT user INTO v_username
FROM dual;
-- Update updated_date field to current system date
:new.updated_date := sysdate;
-- Update updated_by field to the username of the person performing the UPDATE
:new.updated_by := v_username;
END;
An AFTER UPDATE Trigger means that Oracle will fire this trigger after the UPDATE operation is executed.
The syntax for an AFTER UPDATE Trigger is:
CREATE or REPLACE TRIGGER trigger_name
AFTER UPDATE
ON table_name
[ FOR EACH ROW ]
DECLARE
-- variable declarations
BEGIN
-- trigger code
EXCEPTION
WHEN ...
-- exception handling
END;
Restrictions:
• You can not create an AFTER trigger on a view.
• You can not update the :NEW values.
• You can not update the :OLD values.
For example: If you had a table created as follows:
CREATE TABLE orders
( order_id number(5),
quantity number(4),
cost_per_item number(6,2),
total_cost number(8,2)
);
We could then create an AFTER UPDATE trigger as follows:
CREATE OR REPLACE TRIGGER orders_after_update
AFTER UPDATE
ON orders
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
-- Find username of person performing UPDATE into table
SELECT user INTO v_username
FROM dual; -- Insert record into audit table
INSERT INTO orders_audit ( order_id, quantity_before, quantity_after, username )
VALUES ( :new.order_id,:old.quantity, :new.quantity, v_username );
END;
A BEFORE DELETE Trigger means that Oracle will fire this trigger before the DELETE operation is executed.
The syntax for an BEFORE DELETE Trigger is:
CREATE or REPLACE TRIGGER trigger_name
BEFORE DELETE
ON table_name
[ FOR EACH ROW ]
DECLARE
-- variable declarations
BEGIN
-- trigger code
EXCEPTION
WHEN ...
-- exception handling
END;
Restrictions:
• You can not create a BEFORE trigger on a view.
• You can update the :NEW values.
• You can not update the :OLD values.
For example: If you had a table created as follows:
CREATE TABLE orders
( order_id number(5),
quantity number(4),
cost_per_item number(6,2),
total_cost number(8,2)
);
We could then create a BEFORE DELETE trigger as follows:
CREATE OR REPLACE TRIGGER orders_before_delete
BEFORE DELETE
ON orders
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
-- Find username of person performing the DELETE on the table
SELECT user INTO v_username
FROM dual;
-- Insert record into audit table
INSERT INTO orders_audit ( order_id, quantity, cost_per_item, total_cost, delete_date, deleted_by )
VALUES( :old.order_id,:old.quantity,:old.cost_per_item,:old.total_cost,sysdate, v_username );
END;
An AFTER DELETE Trigger means that Oracle will fire this trigger after the DELETE operation is executed.
The syntax for an AFTER DELETE Trigger is:
CREATE or REPLACE TRIGGER trigger_name
AFTER DELETE
ON table_name
[ FOR EACH ROW ]
DECLARE
-- variable declarations
BEGIN
-- trigger code
EXCEPTION
WHEN ...
-- exception handling
END;
Restrictions:
• You can not create an AFTER trigger on a view.
• You can not update the :NEW values.
• You can not update the :OLD values.
For example: If you had a table created as follows:
CREATE TABLE orders
( order_id number(5),
quantity number(4),
cost_per_item number(6,2),
total_cost number(8,2)
);
We could then create an DELETE UPDATE trigger as follows:
CREATE OR REPLACE TRIGGER orders_after_delete
AFTER DELETE
ON orders
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
-- Find username of person performing the DELETE on the table
SELECT user INTO v_username
FROM dual;
-- Insert record into audit table
INSERT INTO orders_audit ( order_id, quantity, cost_per_item, total_cost, delete_date, deleted_by)
VALUES( :old.order_id, :old.quantity, :old.cost_per_item, :old.total_cost, sysdate, v_username );
END;
Dropping a trigger:-
If you had a trigger called orders_before_insert, you could drop it with the following command:
DROP TRIGGER orders_before_insert;
Disabling and Enabling a trigger:-
If you had a trigger called orders_before_insert, you could disable it with the following command:
ALTER TRIGGER orders_before_insert DISABLE;
ALTER TABLE orders DISABLE ALL TRIGGERS;
ALTER TRIGGER orders_before_insert ENABLE;
ALTER TABLE orders ENABLE ALL TRIGGERS;
Firing Triggers One or Many Times (FOR EACH ROW Option):-
The FOR EACH ROW option determines whether the trigger is a row trigger or a statement trigger. If you specify FOR EACH ROW, then the trigger fires once for each row of the table that is affected by the triggering statement. The absence of the FOR EACH ROW option indicates that the trigger fires only once for each applicable statement, but not separately for each row affected by the statement.
For example, you define the following trigger:
CREATE TABLE Emp_log (Emp_id NUMBER, Log_date DATE, New_salary NUMBER, Action VARCHAR2(20));
CREATE OR REPLACE TRIGGER Log_salary_increase
AFTER UPDATE ON Emp_tab
FOR EACH ROW
WHEN (new.Sal > 1000)
BEGIN
INSERT INTO Emp_log (Emp_id, Log_date, New_salary, Action)
VALUES (:new.Empno, SYSDATE, :new.SAL, 'NEW SAL');
END;
Then, you enter the following SQL statement:
UPDATE Emp_tab SET Sal = Sal + 1000.0 WHERE Deptno = 20;
If there are five employees in department 20, then the trigger fires five times when this statement is entered, because five rows are affected.
The following trigger fires only once for each UPDATE of the Emp_tab table:
CREATE OR REPLACE TRIGGER Log_emp_update
AFTER UPDATE ON Emp_tab
BEGIN
INSERT INTO Emp_log (Log_date, Action)
VALUES (SYSDATE, 'Emp_tab COMMISSIONS CHANGED');
END;
InsteadOf Triggers:-
Direct Triggers can’t be applied on views. For them InsteadOf triggers are applied. Views are commonly used to separate the logical database schema from the physical schema. Unfortunately the desired transparency often falls short in the case of UPDATE, DELETE or INSERT operations, since all but the simplest views are not updatable.
Delete the Duplicate rows from a table:-
DELETE from address A
WHERE (A.name, A.vorname, A.birth) IN
(SELECT B.name, B.vorname, B.birth FROM address B
WHERE A.name = B.name AND A.vorname = B.vorname
AND A.birth = B.birth AND A.rowid > B.rowid);
Q. How many valid / invalid objects exist owned by this oracle user?
Often we should know, how many valid and invalid objects an oracle user owes. Especially if we compare a schema on two different databases.
SELECT DISTINCT (object_type) object, status, COUNT(*) FROM user_objects GROUP BY object_type, status;
This line implements sleep function in PL/SQL code. Put either in exception or inside <begin> <end> block.
DBMS_LOCK.SLEEP(10);
Get version of Oracle:-
select * from v$version;
Wednesday, January 12, 2011
Struts Validation configuration: Struts-config.xml and Validation
Struts Validation configuration: Struts-config.xml and Validation
Here I have written complete Struts-config.xml and Validation related configuration.
=========================Struts-config.xml=====================================
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<data-sources />
<!-- All Form Beans Declaration -->
<form-beans>
<form-bean name="loginForm" type="com.dmodi.admin.login.form.LoginForm"></form-bean>
<form-bean name="forgotPasswordForm" type="com.dmodi.admin.login.form.ForgotPasswordForm"/>
</form-beans>
<global-exceptions></global-exceptions>
<global-forwards>
<forward name="InternalError" path="/jsp/internalError.jsp" />
<forward name="CustomerSearchAction" path="/CustomerSearch.do" redirect="true" />
</global-forwards>
<!-- All Action Declarations. -->
<action-mappings>
<action path="/Error" forward="/jsp/error.jsp" name="ErrorPage"/>
<action path="/Login" name="loginForm" type="com.dmodi.admin.login.action.LoginAction"
input="LoginPage" validate="true" scope="request">
<forward name="LoginPage" path="/jsp/login/login.jsp"/>
<forward name="CustomerSearchPage" path="/CustomerSearch.do" redirect="true"/>
<forward name="ResetPasswordPage" path="/ResetPassword.do" redirect="true"/>
<forward name="CustomerFileUploadPage" path="/customerFileUpload.do" redirect="true" />
</action>
<action path="/ResetPassword" name="resetPasswordForm"
type="com.dmodi.admin.login.action.ResetPasswordAction" validate="true" input="ResetPasswordPage">
<forward name="ResetPasswordPage" path="/jsp/login/resetPassword.jsp"/>
<forward name="LoginPage" path="/jsp/login/login.jsp"/>
</action>
</action-mappings>
<controller processorClass="com.dmodi.admin.DModiWebRequestProcessor" />
<message-resources parameter="com.dmodi.admin.resource.path.ApplicationResources" />
<message-resources key="fiResources" parameter="com.dmodi.admin.resource.path.ApplicationResources" />
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" />
<set-property property="stopOnFirstError" value="false" />
</plug-in>
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<!-- Path to XML definition file -->
<set-property property="definitions-config" value="/WEB-INF/tiles-def.xml" />
<!-- Set Module-awareness to true -->
<set-property property="moduleAware" value="true" />
</plug-in>
</struts-config>
==================================================================
//Sample tiles-def.xml
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd">
<tiles-definitions>
<definition name="default" path="/layout/defaultAdminTemplate.jsp">
<put name="header" value="/layout/header.jsp" />
<put name="menu" value="/layout/menu.jsp" />
<put name="footer" value="/layout/templateFooter.jsp" />
</definition>
<definition name="new" path="/layout/newAdminTemplate.jsp">
<put name="header" value="/layout/newheader.jsp" />
<put name="menu" value="/layout/newmenu.jsp" />
<put name="footer" value="/layout/newtemplateFooter.jsp" />
</definition>
<definition name="NewCustomerSearchPage" extends="new">
<put name="body" value="/jsp/newsearchCustomer.jsp" />
</definition>
<definition name="CustomerSearchPage" extends="default">
<put name="body" value="/jsp/searchCustomer.jsp" />
</definition>
<definition name="ExceptionDetailsPage" extends="default">
<put name="body" value="/jsp/exceptionDetails.jsp" />
</definition>
</tiles-definitions>
================================OurValidatator.java==============================
//OurValidatator.java (see use of this class in validator-rules.xml below)
package com.dmodi.utility;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.Var;
import org.apache.commons.validator.util.ValidatorUtils;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.validator.FieldChecks;
import org.apache.struts.validator.Resources;
public class OurValidatator extends FieldChecks implements Serializable {
public static final String CLASS_NAME = OurValidatator.class.getName();
public static boolean validateTwoFieldsAreNotSame(Object bean, ValidatorAction va, Field field,
ActionMessages errors, Validator validator, HttpServletRequest request) {
String value = ValidatorUtils.getValueAsString(bean, field.getProperty());
String sProperty2 = field.getVarValue("secondProperty");
String value2 = ValidatorUtils.getValueAsString(bean, sProperty2);
LogHelper.logMessage("In OurValidatator for values: " + value+ " and secondProperty: " + value2);
if (!GenericValidator.isBlankOrNull(value)) {
try {
if (value.equals(value2)) {
errors.add(field.getKey(), Resources.getActionMessage(request, va, field));
return false;
}
} catch (Exception e) {
return true;
}
}
return true;
}
}
==============================ApplicationResources.properties==============================
//ApplicationResources.properties
errors.header=Please correct the following error(s):
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.twofieldsAreNotSame ={0} and {1} cannot be the same
=============================validator-rules.xml=====================================
//validator-rules.xml
<form-validation>
<global>
//User defined validation:
<validator name="twofieldsAreNotSame"
classname="com.dmodi.utility.OurValidatator"
method="validateTwoFieldsAreNotSame"
methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field, org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator, javax.servlet.http.HttpServletRequest"
depends="" msg="errors.twofieldsAreNotSame" />
//User defined validation:
<validator name="validatePinCode"
classname="com.ewp.fiadmin.utility.EwpValidator"
method="validatePinCode"
methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field, org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator, javax.servlet.http.HttpServletRequest"
depends="" msg="errors.pinCodeNotValid" />
//Existing validation: Struts provide this
<validator name="minlength"
classname="org.apache.struts.validator.FieldChecks"
method="validateMinLength"
methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field, org.apache.struts.action.ActionMessages,
org.apache.commons.validator.Validator, javax.servlet.http.HttpServletRequest"
depends="" msg="errors.minlength"
jsFunction="org.apache.commons.validator.javascript.validateMinLength" />
</global>
</form-validation>
=============================validation.xml=====================================
//validation.xml: These validations are called from Form-Bean's validate method.
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
<form-validation>
<global>
<constant>
<constant-name>phone</constant-name>
<constant-value> ^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$ </constant-value>
</constant>
<constant>
<constant-name>zip</constant-name>
<constant-value>^\d{5}\d*$</constant-value>
</constant>
</global>
<formset>
<form name="loginForm">
<field property="userName" depends="required">
<arg0 key="loginForm.userName" />
</field>
<field property="password" depends="required">
<arg0 key="loginForm.password" />
</field>
<field property="partnerId" depends="required">
<arg0 key="loginForm.partnerId" />
</field>
</form>
//Here you have to write the method name defined in validator-rules.xml in parameter "depends"
<form name="updateCustomerForm">
<field property="pinCode" depends="integer,minlength,maxlength,validatePinCode,twofieldsAreNotSame">
<arg0 key="NPcustomerCreation.label.PinCode" />
<arg1 name="minlength" key="${var:minlength}" resource="false" />
<arg1 name="maxlength" key="${var:maxlength}" resource="false" />
<var>
<var-name>secondProperty</var-name>
<var-value>product</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>6</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>6</var-value>
</var>
</field>
</form>
<form name="forgotPasswordForm">
<field property="userName" depends="required,minlength,i18nmask">
<msg name="i18nmask" key="errors.maskUserName" />
<arg0 key="forgotPasswordForm.userName" />
<arg1 name="minlength" key="${var:minlength}" resource="false" />
<var>
<var-name>minlength</var-name>
<var-value>7</var-value>
</var>
<var>
<var-name>maskKey</var-name>
<var-value>alphaNumericOnly_key</var-value> //This key comes from ApplicationResource.properties
</var>
</field>
<field property="email" depends="required,email">
<arg0 key="forgotPasswordForm.email" />
</field>
</form>
</formset>
</form-validation>
==================================================================
Monday, January 10, 2011
Exception handling in Struts
There are two approaches available for the exception handling in struts:
1) Declarative:
Exceptions are defined in the struts-config.xml file and if the exception occurs the control is
automatically passed to the appropriate error page. The <exception> tag is used to define the
exception in the struts-config.xml file.
For Example:( If RuntimeException occurs in SaveEmpAaction class, control goes to exception.jsp)
<action path="/saveEmp" type="com.techfaq.SaveEmpAaction" input="/empform.jsp">
<exception key="error.system" type="java.lang.RuntimeException" path="/exception.jsp" />
</action>
Where
key:The key defines the key present in MessageResources.properties file to describe the exception occurred.
type: The class of the exception occurred.
path: The page where the control is to be followed in case exception occurred.
handler: The exception handler which will be called before passing the control to the file specified in path attribute
OR
Defining the Exceptions Globally for the struts-config.xml: (If RuntimeException in any Action class , control goes to exception.jsp)
<global-exceptions>
<exception key="error.system" type="java.lang.RuntimeException" path="/exception.jsp" />
</global-exceptions>
2) Programmatic:
In this approach the exceptions are caught using normal java language try/catch block and instead
of showing the exception some meaningful messages are displayed.
In this approach the flow of control is also maintained by the programs.
The main drawback of the approach is the developer has to write the code for the flow of the application.
File upload in Struts Example
Step 1. Create a form bean
public class FileUploadForm extends ActionForm {
private FormFile file;
public FormFile getFile() {
return file;
}
public void setFile(FormFile file) {
this.file = file;
}
}
Step 2.
In the struts-config.xml file add:
<form-bean name="FileUploadForm" type="com.techfaq.form.FileUploadForm"/>
Step 3.
Add action mapping entry in the struts-config.xml file:
<action path="/FileUploadAndSave" type="com.techfaq.action.FileUploadAndSaveAction" name="FileUploadForm"
scope="request" validate="true" input="/pages/fileupload.jsp">
<forward name="success" path="/jsp/success.jsp"/>
</action>
Step 4.
In the JSP
<html:form action="/FileUploadAndSave" method="post" enctype="multipart/form-data">
File Name :
<html:file property="file"/>
<html:submit>Upload File</html:submit>
</html:form>
Step 5.
In the Action class write the code
public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
FileUploadForm myForm = (FileUploadForm)form;
// Process the FormFile
FormFile file = myForm.getFile();
String contentType = file.getContentType();
//Get the file name
String fileName = file.getFileName();
int fileSize = file.getFileSize();
byte[] fileData = file.getFileData();
//Get the servers upload directory real path name
String filePath = getServlet().getServletContext().getRealPath("/") +"uploadfile";
/* Save file on the server */
if(!fileName.equals("")) {
System.out.println("Server path:" +filePath);
//Create file
File fileToCreate = new File(file, fileName);
//If file does not exists create file
if(!fileToCreate.exists()) {
FileOutputStream fileOutStream = new FileOutputStream(fileToCreate);
fileOutStream.write(file.getFileData());
fileOutStream.flush();
fileOutStream.close();
}
}
return mapping.findForward("success");
}
File will be uploaded to "uploadfile" directory og your server.
DynaActionForm Example
DynaActionForm is specialized subclass of ActionForm that allows the creation of form beans with dynamic sets of
properties, without requiring the developer to create a Java class for each type of form bean.
DynaActionForm eliminates the need of FormBean class and now the form bean definition can be written into the struts-config.xml file.
So, it makes the FormBean declarative and this helps the programmer to reduce the development time.
For Example: You have a EmpForm and you don't want a java class (EmpForm).
EmpForm has propertis firstName, lastName, country.
In the struts-config.xml file , declare the form bean:
<form-bean name="EmpForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="firstName" type="java.lang.String"/>
<form-property name="lastName" type="java.lang.String"/>
<form-property name="country" type="java.lang.String" />
</form-bean>
Add action mapping in the struts-config.xml file:
<action path="/saveEmp" type="com.techfaq.action.EmpSaveAction" name="EmpForm" scope="request" validate="true" input="/pages/empform.jsp">
<forward name="success" path="/jsp/success.jsp"/>
<forward name="failure" path="/jsp/error.jsp" />
</action>
In the Action class.
public class EmpSaveAction extends Action {
public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
DynaActionForm empForm = (DynaActionForm)form;
// this is the way you can retrive the value which is set in the JSP Page
String firstName = (String)empForm.get("firstName");
String lastName = (String)empForm.get("lastName");
return mapping.findForward("success");
}
}
In the JSP page
<html:text property="firstName" size="30" maxlength="30"/>
<html:text property="lastName" size="30" maxlength="30"/>
LookupDispatchAction in Struts
*******************LookupDispatchAction*******************
This is an abstract Action that dispatches to the sub-class mapped execute method. This is useful in
cases where an HTML form has multiple submit buttons with the same name. The button name is specified
by the parameter property of the corresponding ActionMapping. So basically there are two usage:
a) Avoiding Method name declaration in JSP.
b) Getting localization for buttons as Button levels are defined in Properties file.
To configure the use of this action in
our struts-config.xml file, create an entry like this:
<action path="/test" type="org.example.MyAction" name="MyForm"
scope="request" input="/test.jsp" parameter="method">
<forward name="add-success" path="addEmpSuccess.jsp" redirect="true"/>
<forward name="delete-success" path="deleteEmpSuccess.jsp" redirect="true"/>
<forward name="update-success" path="updateEmpSuccess.jsp" redirect="true"/>
</action>
And our JSP would have the following format for submit buttons:
<html:form action="/test">
<html:submit property="method">
<bean:message key="button.add"/>
</html:submit>
<html:submit property="method">
<bean:message key="button.delete"/>
</html:submit>
</html:form>
Which will use the value of the request parameter named "method" to locate the corresponding key in
ApplicationResources.properties. For example, we might have the following keys:
button.add=Add Record
button.delete=Delete Record
button.update=Update Record
Our subclass must implement both getKeyMethodMap() and the methods defined in the map. An
example of such implementations are:
==============
public class EmpAction extends LookupDispatchAction {
protected Map getKeyMethodMap() {
Map map = new HashMap();
map.put("button.add", "add"); //Or you can read properties file's keys using iterator
map.put("button.delete", "delete");
return map;
}
public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
// do add
// Create a User DTO and copy the properties from the userForm
User user = new User();
BeanUtils.copyProperties(user, form); //(destination, source)
DataSource dataSource = getDataSource(request, "userDB");
Connection conn = dataSource.getConnection();
UserDAO dao = DAOFactory.createUserDAO(conn);
dao.createUser(user);
return mapping.findForward("success");
}
public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
//your logic
return mapping.findForward("delete-success");
}
public ActionForward update(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
//your logic
return mapping.findForward("update-success");
}
}
==============
If duplicate values exist for the keys returned by getKeys, only the first one found will be returned.
If no corresponding key is found then an exception will be thrown.
At last: Flow of LookupDispatchAction:
For every form submission, LookupDispatchAction does the reverse lookup on the resource bundle to
get the key and then calls the method for fetching value using the key from getKeyMethodmap() method.
a) Form the button name "Add" get the key "button.add" from resource bundle.
b) then in the Map getKeyMethodMap() find the value associated with the key "button.add".
c) value from the Map is "add", so call add() method of the same action class.
------------------------------END-------------------------
DispatchAction in Struts
======================DispatchAction======================
This is an abstract Action that provides user defined methods rather than standard "execute()"
method of Action class. The method name to execute comes as request parameter (may be from hidden
field or JSP page). This Action is useful for developers who prefer to combine many similar actions
into a single Action class, in order to simplify their application design.
Ex: Suppose you have 3 operations "Update, Insert, Delete" then basically you need to write
3 Action classes UpdateEmpAction, InsertEmpAction and DeleteEmpAction having "execute()" method in
each class causing duplicacy of codes.
Using DispatchAction you need to write only one Action class with 3 different methods.
To configure the use of this action in our struts-config.xml file, create an entry like this:
<action path="/saveSubscription"
type="org.apache.struts.actions.DispatchAction"
name="subscriptionForm"
scope="request"
input="/subscription.jsp"
parameter="method">
<forward name="insert-success" path="insertEmpSuccess.jsp" redirect="true"/>
<forward name="delete-success" path="deleteEmpSuccess.jsp" redirect="true"/>
<forward name="update-success" path="updateEmpSuccess.jsp" redirect="true"/>
</action>
This configuration uses the value of the request parameter named "method" to pick the
appropriate method in DispatchAction, which must have the same signature of the standard Action.execute().
For example, we should have the following three methods in the same action:
===========*********============
public class EmpAction extends DispatchAction {
Public ActionForward update(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
return mapping.findForward("update-success");
}
Public ActionForward insert(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
return mapping.findForward("insert-success");
}
Public ActionForward delete(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
return mapping.findForward("delete-success");
}
}
===========********=============
Call to this Action will be done using the URL below in "subscription.jsp":
http://localhost:8080/myapp/saveSubscription.do?method=update
http://localhost:8080/myapp/saveSubscription.do?method=insert
http://localhost:8080/myapp/saveSubscription.do?method=delete
Also the same thing can be done by passing parameter as hidden field (parameter attribute in action tag):
<html:hidden property="method" value="update"/>
<html:hidden property="method" value="insert"/>
<html:hidden property="method" value="delete"/>
Rather than having a single execute() method, we have a method for each logical action.
The DispatchAction dispatches to one of the logical actions represented by the methods.
How to avoid double submit in Struts
How to avoid double submit in Struts
Struts has 3 methods used for the token related activities, saveToken(), isTokenValid() and resetToken().
saveToken() - generate the token key and save to request/session attribute.
isTokenValid() - validate submitted token key against the 1 store in request/session.
resetToken() - reset the token key
------------------------
Step 1:
You need to save token first and then forward to JSP page for any submission related activity.
Assuming you wrote "LoadAction" Action class for the same. Call saveToken() in your Action class,
It will create and store the token key. Struts will store the generated key in request/session.
The key will be: Action.TRANSACTION_TOKEN_KEY. See the below code:
------------------------
public class LoadAction extends Action {
public ActionForward execute(ActionMapping mapping,ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
ActionForward forward;
forward=mapping.findForward("FirstPage"); // this is the jsp page where you want to save struts tokens.
saveToken(request);
return forward;
}
}
------------------------
Step 2:
You can see the token if you do "View Source" on the browser, the token key is stored as a hidden field in
the jsp page:
//JSP code
<%@ page import="org.apache.struts.action.Action"%>
<%@ page import="org.apache.struts.taglib.html.Constants"%>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html>
<head> <title> First Page </title> </head>
<body>
<form name="MyForm" method="post" action="/dmodi/getForm/submit.do">
<input type="text" name="name" >
<input type="hidden" name="<%= Constants.TOKEN_KEY %>"
value="<%= session.getAttribute(Action.TRANSACTION_TOKEN_KEY) %>" >
<input type="submit" value="submit">
</form>
</body>
</html>
------------------------
Step 3. Your logic
Once the form submitted, invokes isTokenValid() on the action class, it will validate the submitted token
key(hidden field) with the token key stored previously on request/session. If matches, it will return true.
public class SubmitAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
ActionForward forward=mapping.findForward("submitForm");
DupSubmitForm frm=(DupSubmitForm)form;
if(isTokenValid(request)) {
System.out.println("frm.getName()"+frm.getName());
resetToken(request);
}
else {
System.out.println("frm.getName()"+frm.getName());
System.out.println("Duplicate Submission of the form");
}
return forward;
}
}
------------------------END-------------------------
Tuesday, January 4, 2011
Ant script with all features
Here are two Ant scripts having all features:-
---------------------END of 1----------------------
----------------End of 2---------------
<project name="Deepak kumar Modi" default="main" basedir=".">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="servlet.jar" value="${src.dir}/../lib/servlet-api.jar"/>
<target name="clean">
<delete dir="${classes.dir}"/>
<delete dir="${build.dir}"/>
</target>
<path id="build.path">
<pathelement location="${servlet.jar}"/>
</path>
<target name="prepare" depends="clean">
<mkdir dir="${build.dir}"/>
<mkdir dir="${classes.dir}"/>
</target>
<target name="compile" depends="prepare">
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref ="build.path"/>
</target>
<target name="main" depends="compile">
<echo message="main target completed.." />
</target>
</project>
---------------------END of 1----------------------
<!-- Author Deepak.Modi -->
<project name="ConnectorTool" default="dist" basedir=".">
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="lib" location="lib"/>
<property name="dist" location="dist"/>
<path id="project.classpath">
<fileset dir="${lib}">
<include name="**/*.jar" />
</fileset>
</path>
<target name="init" depends="clean">
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}" classpathref="project.classpath" />
</target>
<target name="dist" depends="compile" description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}/connectorlib"/>
<copy todir="${dist}/connectorlib" overwrite="true" >
<fileset dir="${lib}">
<include name="*.jar" />
</fileset>
</copy>
<copy todir="${dist}" overwrite="true" >
<fileset dir=".">
<include name="*.properties" />
</fileset>
</copy>
<jar jarfile="${dist}/ConnectorTool.jar" basedir="${build}">
<manifest id="MANIFEST.MF">
<attribute name="Built-By" value=" Deepak.Modi"/>
<attribute name="Main-Class" value="com.connector.AutomaticConnector"/>
<attribute name="Class-Path" value=".\connectorlib\classes12.jar .\connectorlib\weblogic.jar .\connectorlib\jmk2api.jar .\connectorlib\xbean_bea.jar"/>
</manifest>
</jar>
</target>
<target name="clean" description="clean up" >
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
----------------End of 2---------------
Subscribe to:
Posts (Atom)