Updates from October, 2009 Toggle Comment Threads | Keyboard Shortcuts

  • dunithd 11:20 pm on October 27, 2009 Permalink | Reply
    Tags: Hibernate, hibernate events, triggers   

    Create database triggers like features using Hibernate events 

    When you are creating a Java application with database operations, it is obvious to use JDBC as the database communication method. Well, that’s not the case here. Imagine a situation like this, if you are developing an application that manages an inventory and when a product reaches to its re-order level, your application should automatically populate and send a purchase order to the supplier.

    Here you’ll say that “Ok, I can do it by creating a trigger in the database”. But the thing is how that trigger notifies or talks to your application about the product?

    Currently there is no support for triggers in JDBC (This is clearly my opinion. I Googled about this for a day and I found nothing. Guys, you can check this out if you are interested). But I must acknowledge to the changes in the database in real time through my Java application.

    What are the database events that can be monitored by your application?

    Following are the usual CRUD (Create, Read, Update, and Delete) events that occur in any regular database.

    1. Pre – Select:  These types of events occur before executing any select statement against the database.
    2. Post – Select: These types of events occur after executing any select statement against the database.
    3. Pre – Insert: These types of events occur before you execute any insert statement.
    4. Post – Insert: These types of events occur after executing an insert statement.
    5. Pre – Update: These types of events occur before executing any update statements against the database.
    6. Post – Update: These types of events occur after executing any update statement against the database.
    7. Pre – Delete: These types of events occur before executing any delete statement against the database.
    8. Post – Delete: These types of events occur after executing a any delete statement against the database.

    Apart from that, there can be several types of events occur in a database. But for the sake of simplicity, I’ll not consider them because they are not in our scope.

    How to trap those events in  your Java application?

    There are several ways to do that. But we already know using JDBC is impossible at the moment. One way to achieve this is implementing a thread in your application to monitor the changes in the database object (such as a table in the database). If any change occurred, that thread can dispatch the changes in your application. But this is not a good practice. What if your database has more than ten tables? Then you have to create ten threads for each table and that would be a great mess regarding to the performance. So you have to omit that approach.

    But Hibernate (An open source ORM framework) can save your day by using Its Interceptors and event system to trap those events.

    Let’s see how can we do it using hibernate.

    Hibernate Event System

    Before I proceed, I assume that you have some knowledge about Hibernate and its general architecture. (Visit http://www.hibernate.org for more information).

    Hibernate ships with powerful event system. You can browse the org.hibernate.event package for more information, but this package was poorly documented.

    You can react to particular events in the persistence layer using this event architecture. Essentially all of the methods of the Session interface correlate to an event. You have a LoadEvent, aFlushEvent, etc (consult the XML configuration-file DTD or the org.hibernate.event package for the full list of defined event types). When a request is made of one of these methods, the Hibernate Session generates an appropriate event and passes it to the configured event listeners for that type. Out-of-the-box, these listeners implement the same processing in which those methods always resulted. However, you are free to implement a customization of one of the listener interfaces (i.e., the LoadEvent is processed by the registered implementation of the LoadEventListener interface), in which case their implementation would be responsible for processing any load() requests made of the Session.

    A custom listener should implement the appropriate interface for the event it wants to process. There are several types of event listener interfaces. If you want to receive change notifications, all you have to do is implement the appropriate event interface in your program. For example, for pre-select events, you have to implement the LoadEventListener. For post-update events, you have to implement the PostUpdateListener interface.

    Below is the commonly used listener interfaces in hibernate.

    Event Listeners

    Event Listeners in org.hibernate.event package

    Along with these listeners, you can use associated event objects to get information related with a particular event. For instance, after updating an object you can retrieve the updated instance of an object using PostUpdateEvent object.  Then it can be used to set the properties like update timestamp.

    Below is the commonly used event objects associated with event listeners.

    Event Objects

    Event Objects in org.hibernate.event package

    How to use hibernate events in your application?

    1. Implement the appropriate event interface in your application.
    2. Register the listeners in hibernate.cfg.xml file.

    Very simple application to demonstrate the post-update event type

    Here I’m going to create an application to trap an object after updating.

    package com.dunithd.events;
    
    import org.hibernate.event.PostUpdateEvent;
    import org.hibernate.event.PostUpdateEventListener;
    
    import com.dunithd.events.InventoryProduct;
    
    /**
     * A class that implements PostUpdateEventListener interface
     *
     * @author duischen
     * @version 1.0, Oct 27, 2009
     */
    public class ProductUpdateListener implements PostUpdateEventListener {
    
    	@Override
    	public void onPostUpdate(PostUpdateEvent event) {
    		if (event.getEntity() instanceof InventoryProduct) {
    			InventoryProduct product = (InventoryProduct) event.getEntity();
    
    			// Check for quantity and re-order level for this product
    			int quantity = product.getQuantity();
    			int reOrderLevel = product.getReOrderLevel();
    
    			// Check if this product is under the re-order level
    			if (quantity <= reOrderLevel) {
    				System.out.println("Need to purchase.");
    			} else {
    				System.out.println("No Need to purchase.");
    			}
    
    		}
    	}
    
    }

    Then register this listener in hibernate.cfg.xml file.

    <?xml version='1.0' encoding='utf-8'?>
    <!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
    	<session-factory>
    		.....
    	<mapping resource="com/dunithd/events/InventoryProduct.hbm.xml" />
    
    	  <!-- Register the listeners -->
    	  <listener type="post-update"/>
    
    	</session-factory>
    </hibernate-configuration>

    Create the database table as follows.

    create table products (
    	int product_id primary key,
    	varchar(100) description,
    	float price,
    	int quantity,
    	int reorder_level
    )

    When you run your application, you can see the message “Need to purchase.” or “No need to purchase”, depending on the quantity of the product.

     
    • marek 6:35 pm on March 11, 2010 Permalink | Reply

      True, but the hibernate events can only monitor db changes made from within the hibernate session, right ? So if some other application changes your tables, the event will not be fired – am I correct ?

      • duischen 10:31 pm on March 11, 2010 Permalink | Reply

        Yes, you are correct.
        If you need to monitor the changes, you always have to initialize a session and wait for changes to be occurred.
        You can use a daemon thread to watch for changes…

    • Shashank Acharya 12:30 pm on March 26, 2010 Permalink | Reply

      Nice tutorial It will help me in my project.
      Thank You.

    • stewchicken 2:49 am on May 1, 2010 Permalink | Reply

      how do you use daemon thread by hibernate to watch for changes made by another application?

    • LTN 8:10 pm on October 5, 2010 Permalink | Reply

      How would I get the previous state of the object after a post update event?

    • Free 4:53 am on November 9, 2011 Permalink | Reply

      Hibernate is a joke! The fist comment says it all. Use Hibernate DB triggers at your peril!

      • Free 4:55 am on November 9, 2011 Permalink | Reply

        also…these hibernate event listeners are going to be much, much slower than an actual DB trigger – incur additional introspection, method calls, and most importantly additional DB queries. Real DB triggers are designed to minimize performance impact.

    • Mukesh Kumar 12:21 am on April 22, 2012 Permalink | Reply

      Nice Tutorial….

  • dunithd 2:01 pm on October 22, 2009 Permalink | Reply
    Tags: , , , SMTP, STARTTLS   

    Send email using JavaMail API and your Gmail account 

    Sending email using Java is not a difficult task and it’s just about writing few lines of codes. But when you are writing such an application, you’ll end up with lot of exceptions obviously. There are lots of reasons for that, but as my opinion, wrong email configuration settings would cause the exceptions.

    If you need to write a Java application to send an email, you need an outgoing mail server such as SMTP (Simple Mail Transfer Protocol) server. There are many SMTP servers out there, but in order to send an email most servers require authentication (You have to have an account in your SMTP server and you must know account credentials). There exist free SMTP servers without authentication, but I’m not sure about their reliability and Quality of Service (QoS).

    At the authentication process, most developers fail due to bad configurations. There are several configuration settings should be set in your code, before you submit the message to the SMTP server.

    To demonstrate this settings, I’ll create a Java application from the scratch and it will use Gmail as the outgoing SMTP server (You can use any SMTP server with valid credentials. But here I used Gmail because I’m addicted to Google!).

    You can download the complete source code and required libraries here. I developed it using NetBeans IDE, but you can use any IDE to proceed.

    Prerequisites

    Source Code

    package com.dunithd.jmail;
    
    import javax.mail.*;
    import javax.mail.internet.*;
    import javax.mail.internet.MimeMessage.RecipientType;
    
    import java.util.*;
    
    /**
     * Simple Class to send an email using JavaMail API (javax.mail) and Gmail SMTP server
     * @author Dunith Dhanushka, dunithd@gmail.com
     * @version 1.0
     */
    public class GmailSender {
    
        private static String HOST = "smtp.gmail.com";
        private static String USER = "your_username@gmail.com";
        private static String PASSWORD = "put_your_password_here";
        private static String PORT = "465";
        private static String FROM = "put_from_address_here";
        private static String TO = "put_to_address_here";
    
        private static String STARTTLS = "true";
        private static String AUTH = "true";
        private static String DEBUG = "true";
        private static String SOCKET_FACTORY = "javax.net.ssl.SSLSocketFactory";
        private static String SUBJECT = "Testing JavaMail API";
        private static String TEXT = "This is a test message from my java application. Just ignore it";
        
        public static synchronized void send() {
            //Use Properties object to set environment properties
            Properties props = new Properties();
    
            props.put("mail.smtp.host", HOST);
            props.put("mail.smtp.port", PORT);
            props.put("mail.smtp.user", USER);
    
            props.put("mail.smtp.auth", AUTH);
            props.put("mail.smtp.starttls.enable", STARTTLS);
            props.put("mail.smtp.debug", DEBUG);
    
            props.put("mail.smtp.socketFactory.port", PORT);
            props.put("mail.smtp.socketFactory.class", SOCKET_FACTORY);
            props.put("mail.smtp.socketFactory.fallback", "false");
    
            try {
    
                //Obtain the default mail session
                Session session = Session.getDefaultInstance(props, null);
                session.setDebug(true);
    
                //Construct the mail message
                MimeMessage message = new MimeMessage(session);
                message.setText(TEXT);
                message.setSubject(SUBJECT);
                message.setFrom(new InternetAddress(FROM));
                message.addRecipient(RecipientType.TO, new InternetAddress(TO));
                message.saveChanges();
    
                //Use Transport to deliver the message
                Transport transport = session.getTransport("smtp");
                transport.connect(HOST, USER, PASSWORD);
                transport.sendMessage(message, message.getAllRecipients());
                transport.close();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
        public static void main(String[] args) {
           GmailSender.send();
           System.out.println("Mail sent successfully!");
        }
    }
    

    When writing the application, you have to set some Environment Properties that are used by the JavaMail APIs. The JavaMail javadocs contain additional information on properties supported by JavaMail.

    You can use java.util.Properties class to set these properties.

    • mail.smtp.host: Specifies the protocol-specific default Mail server. In your application, set this property to smtp.gmail.com
    • mail.smtp.user: Specifies the protocol-specific default username for connecting to the Mail server. In your application, set this property to your Gmail username.
    • mail.smtp.auth: Specifies whether host requires authentication or not. In our application, set this property to true.
    • mail.smtp.debug: Specifies the initial debug mode. Setting this property to true will turn on debug mode, while setting it to false turns debug mode off. If you need deeper diagnosis, set this to true.
    • mail.smtp.port: Specifies the port that is used by SMTP server. In your application, set this to 465.
    • mail.smtp.starttls.enable: This is the most important one. If you miss this, you’ll definitely get an error. Most SMTP servers support SSL (Secure Socket Layer) connections which can be used for secure login to the server. They use STARTTLS command (see RFC 2487 and RFC 3501) to switch the connection to be secured by TLS.
      Use of the STARTTLS command is preferred in cases where the server supports both SSL and non-SSL connections. This SSL/TLS support in JavaMail works only when JavaMail is used on a version of J2SE that includes SSL support.
      The STARTTLS support is available in the standard “IMAP” and “SMTP” protocols, but must be enabled by setting the appropriate property, mail.imap.starttls.enable or mail.smtp.starttls.enable, to “true”. When set, if the server supports the STARTTLS command, it will be used after making the connection and before sending any login information.

    If everything goes fine, you’ll see an output like this.

    Output of the application

    Output of the application

    Notes

    This application cannot be used in a network that uses a proxy server. You must have a direct connection to the internet otherwise you’ll get UnknownHostException.

    UnknownHostException

    UnknownHostException

    In my next post, I’m gonna explain you how to send an email with an attachment.

    Download source code and required libraries here.

     
      • Bob 2:41 am on November 17, 2009 Permalink | Reply

        How do you enforce TLS? For instance, when you set mail.smtp.starttls.enable to “true” it will use the secure connection, if it’s available. Otherwise, it just sends unsecure. How do I make it so that it only sends if TLS connection is available?

    • gananath 9:08 pm on March 8, 2010 Permalink | Reply

      Good article..please keep it….some article i have posted in gananathsun.blogspot.com

    • Mahesh 6:02 pm on March 23, 2010 Permalink | Reply

      Thank you very much!!! It pulled me out from bad situation. Thanks.

    • Kanishka Dilshan 9:13 pm on June 11, 2010 Permalink | Reply

      Very useful article. Thanks bro.

    • arthur 3:35 pm on July 19, 2010 Permalink | Reply

      Finally smth that works! excellent ! :)

    • arthur 3:06 pm on July 22, 2010 Permalink | Reply

      dunithd, how do we change the TO: string to specify multiple recipients?

      • dunithd 8:08 pm on July 24, 2010 Permalink | Reply

        Hey Arthur,
        That can be done in this way…
        first, change the TO string to contain your recipient addresses. Just concatenate the addresses with comma and a space
        eg: String TO = “john@gmail.com, arthur@gmail.com, foo@ymail.com“;

        Then replace the method message.addRecipient() with this(see line number 57)

        message.addRecipients(RecipientType.TO, TO);

        Thats it and you are done!

    • MahendraBabu 7:53 pm on September 28, 2010 Permalink | Reply

      very very ….Thanks Mr.Dunithd

    • MANJUNATH PATIL 9:18 pm on October 4, 2010 Permalink | Reply

      budy can u post me a program which is used to retrieve the mail from the gmail account

    • hitesh shah 2:45 am on October 30, 2010 Permalink | Reply

      I am trying to call your program in JSP page using following code.but it gives the error

      JSP Page

      Hello World!

      it gives me following output in netbeans 6.8
      Hello World!
      com.myapp.struts.GmailSender@357bdf

    • hitesh shah 2:49 am on October 30, 2010 Permalink | Reply

      it gives me following error in eclipse
      org.apache.jasper.JasperException: /page4.jsp(6,1) Page directive: illegal to have multiple occurrences of contentType with different values (old: text/html; charset=ISO-8859-1, new: text/html)
      org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:40)
      org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:407)
      org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:236)
      org.apache.jasper.compiler.Validator$DirectiveVisitor.visit(Validator.java:132)
      org.apache.jasper.compiler.Node$PageDirective.accept(Node.java:608)
      org.apache.jasper.compiler.Node$Nodes.visit(Node.java:2361)
      org.apache.jasper.compiler.Node$Visitor.visitBody(Node.java:2411)
      org.apache.jasper.compiler.Node$Visitor.visit(Node.java:2417)
      org.apache.jasper.compiler.Node$Root.accept(Node.java:495)
      org.apache.jasper.compiler.Node$Nodes.visit(Node.java:2361)
      org.apache.jasper.compiler.Validator.validateDirectives(Validator.java:1723)
      org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:182)
      org.apache.jasper.compiler.Compiler.compile(Compiler.java:347)
      org.apache.jasper.compiler.Compiler.compile(Compiler.java:327)
      org.apache.jasper.compiler.Compiler.compile(Compiler.java:314)
      org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592)
      org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:317)
      org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
      org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

      note The full stack trace of the root cause is available in the Apache Tomcat/6.0.29 logs.

    • hitesh shah 2:50 am on October 30, 2010 Permalink | Reply

      this is the program i am using

      JSP Page

      Hello World!

    • hitesh shah 4:17 am on October 30, 2010 Permalink | Reply

      it is working now.. thanks

    • Oc 4:15 pm on November 12, 2010 Permalink | Reply

      This a nice piece. You are good.

    • @$# 10:45 pm on March 1, 2011 Permalink | Reply

      thanks a lot for such a useful piece of code.

    • Chathuranga Withana 5:09 pm on March 8, 2011 Permalink | Reply

      Hi,

      How can you change this code to work under network that uses a proxy server….?

      Thanks!

    • Akhtar 4:17 pm on March 20, 2011 Permalink | Reply

      extremely perfect article… keep it up

    • Rafique 10:22 am on May 3, 2011 Permalink | Reply

      Good article..please keep it…but when i sent mail to yahoo it goes to spam folder.. Plz help how to resolve..
      i just modify Transport transport = session.getTransport(“smtp”); to
      Transport transport = session.getTransport(“smtps”);

    • sreejesh 5:32 pm on May 31, 2011 Permalink | Reply

      Thanks for this share, actually i am searching for a mail sending program with javamail api. thanks

    • rahma hichri 1:40 am on June 11, 2011 Permalink | Reply

      thanks for ur article u solved a big problem for me i appreciate that but please i wanna send a link in the email how i can do it??!! and thanks a lot :)

      • dunithd 9:10 pm on June 11, 2011 Permalink | Reply

        Adding a hyper link is a not a difficult task in JavaMail.
        Say for example you want to insert a link to http://www.google.com.

        Then all you have to do is place the necessary HTML in a String.
        Eg: Visit Google

        Note that do the String escaping.

        since you are using java.mail, you should set the text this way:

        message.setText(body, "UTF-8", "html");

        thanks

    • daz 9:19 pm on June 15, 2011 Permalink | Reply

      brillant !!!! it work for me thanks u very much

    • pce0801 2:55 pm on June 30, 2011 Permalink | Reply

      i`ve got this error

      DEBUG: setDebug: JavaMail version 1.4.4
      DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc]
      DEBUG SMTP: useEhlo true, useAuth true
      DEBUG SMTP: trying to connect to host “smtp.gmail.com”, port 465, isSSL false
      javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 465;
      nested exception is:
      java.net.SocketException: Connection reset
      at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1934)
      at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:638)
      at javax.mail.Service.connect(Service.java:295)
      ………………..

      what should i do ?

      thx for advice

      • dunithd 9:40 pm on June 30, 2011 Permalink | Reply

        Seems like you are having a network issue that prevents you from connecting to the Google’s SMTP server. Please check your proxy settings and adjust them accordingly.

    • bright gee varghese 4:49 pm on August 24, 2011 Permalink | Reply

      thanks a lot…… thank u very much

    • Lanka 1:53 pm on August 31, 2011 Permalink | Reply

      Thanks very much brother! This article is good.

    • andres 10:24 pm on September 6, 2011 Permalink | Reply

      Hi, I apriciate your article, but i got this error: 530 5.7.0 Must issue a STARTTLS command first. f17sm709927ani.25, could you help me?, please, thanks a lot

    • Hesham 5:14 am on October 1, 2011 Permalink | Reply

      WooooW
      What a great topic
      thank u it is very helpful

    • arpit singhal 11:57 am on October 14, 2011 Permalink | Reply

      thanx sir 4 this code………

    • mr7l1v35 1:45 pm on November 13, 2011 Permalink | Reply

      Thanx Sir. It is very nice article. Can u tell me how to attach the multiple files while sending the mail…

      • dunithd 9:47 am on November 18, 2011 Permalink | Reply

        Thanks mr7l1v35!
        Please refer to my this blog post for attaching multiple files.

        regards,
        Dunith

    • Ram 4:45 pm on January 20, 2012 Permalink | Reply

      Hi Everybody,

      I have very complicated requirement.. Please share your thoughts on this..
      In a java application, users has to register themeless with their email ids (could be gmail, yahoo or any other).. After registration and login, they can perform some of the activities. In a particular activity user will be accepting certain conditions by clicking a button and an email should be sent from java application.. The twist here is email should go directly from registered user gmail, yahoo or any other email ids to concerned party… i.e. after clicking a button in the java application, registered user should have the mail that has been sent from java application in their Sent Mail box ( like gmail, yahoo or any other).. Something like the registered user logging into his gmail account and sending an email..

      Please need help on this..

      Rgds,
      Ramachandran

    • Venkatesh 4:15 pm on January 28, 2012 Permalink | Reply

      Thank you for the posting. Its very useful for me… Can you post a simple program for file uploading???

    • Ashutosh Gangrade 2:16 pm on March 6, 2012 Permalink | Reply

      Dear I am having javax.mail.MessagingException: 530 5.7.0 Must issue a STARTTLS command first error when I am trying to send a mail from my office. But is is working fine with my office PC.
      Should I change any setting in my home PC regarding STARTTLS.
      Please let me know what should I do?

    • Cadmus 9:29 pm on March 13, 2012 Permalink | Reply

      Hi, I apriciate your article, but i got this error: 530 5.7.0 Must issue a STARTTLS command first. f17sm709927ani.25, could you help me?, please, thanks a lot

    • Phonix the Ace 1:30 pm on April 12, 2012 Permalink | Reply

      i just have to say , Ummmmmmmmaahh , Love you aiya…. :)
      thanks you very much

    • Karthikeyan 5:54 pm on May 9, 2012 Permalink | Reply

      Thanks a lot :) :)

c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel
Follow

Get every new post delivered to your Inbox.