menu

Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Thursday, November 27, 2014

Using hashCode(), equals() and toString() Methods in Java

Introduction:

     The Object class being the super class of all the classes in Java has the methods hashCode(), equals(Object) and toString() addition to some other methods like clone(), getClass() and so on. I'll try to illustrate the important points of the use of hashCode(), equals() and toString() methods today.

Default Implementation:

     By default hashCode() is a native method with a signature "public native int hashCode()". The Java doc. says that 
* It is used to return a hash code value of an object to be used in hash tables like HashMap and HashSet which we introduce in later writes. 
* The hashCode() must return the same integer value if it's invoked more than once, however it's not required to be the same value with another execution. 
* You have to obey the contract of "equal objects must have equal hash codes", however two unequal objects also can have the same hash code which decrease the performance of hash tables.
* It is not a must that the hashcode method of Object class return distinct integers for different objects so don't rely on that.
* It is typically implemented to return the internal address of the object converting to an integer, but it's not a requirement of Java programming language and it's JVM dependent.

Overriding Default Implementation:

     If you override the hashCode() method you have to rely on the contract of "equal objects must have equal hash codes" and define the fields that you want to be included in the hashCode and equals implementations.Then you should use a prime number as a multiplier and use the primitive fields adding to the result, and use the hashCode() methods of Object fields like String's hashCode() implementation used in the Example 1. Many of the IDE's have the ability of creating a reasonable hashCode() and equals() implementations as well as the toString() method. For example in eclipse you can use Source -> Generate hashCode() and equals(). Below is an example of hashCode(), equals() and toString() implementations created for a String (named innerStr) and an int(innerInt) using the eclipse.
For the equals() method, you should consider the null conditions, direct equality of references, runtime classes of the object instance (if you want the same runtime class for both instance), and the the equality of the required fields using == for primitives and using the correspending equals() methods for the Objects. The default equals method just compare the references not the values as can be shown below.

    public boolean equals(Object obj) {
        return (this == obj);

    }

Example 1:

      @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + innerInt;
result = prime * result + ((innerStr == null) ? 0 : innerStr.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
HashSetEx other = (HashSetEx) obj;
if (innerInt != other.innerInt)
return false;
if (innerStr == null) {
if (other.innerStr != null)
return false;
} else if (!innerStr.equals(other.innerStr))
return false;
return true;
}

@Override
public String toString() {
return "Test [innerStr=" + innerStr + ", innerInt=" + innerInt + "]";

}

Using System.identityHashCode(Object o) Method:

     Even if you override the hashCode() method, you can still get the default behaviour's result using the System.identityHashCode method. It returns as if you don't override the hashCode() method. Remember again that, the default behaviour need not to be a distinct integer for all different objects and also need not to be an integer indicating the internal address of the object.

Example 2:

     Assuming we use the default toString() implementation as below;

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    public class Test {

private String innerStr;
private Integer innerInt;

public Test(String innerStr, int innerInt) {
this.innerInt = innerInt;
this.innerStr = innerStr;
}
public static void main(String[] args) {
Test test = new Test("a", 1);
System.out.println(test);
System.out.println(Integer.toHexString(System.identityHashCode(test)));
}
    }

The output will be as below. 

hash.Test@38da9246
38da9246

Now, if you override hashCode() as below;

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((innerInt == null) ? 0 : innerInt.hashCode());
result = prime * result + ((innerStr == null) ? 0 : innerStr.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Test other = (Test) obj;
if (innerInt == null) {
if (other.innerInt != null)
return false;
} else if (!innerInt.equals(other.innerInt))
return false;
if (innerStr == null) {
if (other.innerStr != null)
return false;
} else if (!innerStr.equals(other.innerStr))
return false;
return true;
}

And run again, you will get the following result;

hash.Test@441
7448bc3d

As you see we get the default behaviour with the System.identityHashCode method. If we run again we get the same hashCode with the overrided hashCode() method, but get different hashCode with the System.identityHashCode method as you see below.

hash.Test@441
68c884e

See, we use the hex representation of the returned integer of hashCode() method as it's used in the default toString() implementation.
   
Conclusion:

     We see some important points of using hashCode(), equals() and toString() methods. You should now what the Java doc. says and now where you can rely on or not to the behaviour of that methods.

Monday, November 10, 2014

Using Gmail Servers in JavaMail API

Introduction:

     In the previous post we mention about the basics of email protocols and show how to configure Apache James server to use in JavaMail API.Today we see how to use Gmail servers instead of using local Apache James server.The JavaMail API part is same but we have to configure the properties of the email session according to Gmail servers in addition to obtaining an application password from the gmail.

Obtain Application Password:

     First of all, we have to get an application password to use in our JavaMail API. When we try to use our gmail password an error occurred indicating "Username and password are not accepted" giving the following link.
http://support.google.com/accounts/bin/answer.py?answer=185833
This link says that you have to create an application password instead of using the gmail password for security reasons. Follow the steps shown in the link and create your application password.

Sending Mail Using Gmail SMTP Server:

      The following java code can be use to send an email using Gmail SMTP server.If you want to use SSL enabled you have to comment out  line 3 and 4 while commenting the line 1 and 2.As you can understand while the SMTP port of Gmail is 587 when you enable SSL it is 465.If you are not using SSL you have to set true to attribute "mail.smtp.starttls.enable". You don't have to set the FROM attribute as the user you provided in authentication will be automatically used as the FROM attribute.

package tr.com.aligelenler;

import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendMailUseGmail {

private static final String USER = "your_email@gmail.com";
private static final String PASSWORD = "your_app_password";

public static void main(String[] args) {
try {
Properties props = new Properties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true");
props.put("mail.debug", "true");
props.put("mail.smtp.host", "smtp.gmail.com");

1 props.put("mail.smtp.port", "587");
2 props.put("mail.smtp.starttls.enable", "true");

3 //props.put("mail.smtp.socketFactory.port", "465");
4 //props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");

Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(USER, PASSWORD);
}
});
MimeMessage msg = new MimeMessage(session);
// msg.setFrom(new InternetAddress(USER)); No need to specify FROM attribute
msg.addRecipients(Message.RecipientType.TO, InternetAddress.parse("sendmail1@gmail.com, sendmail2@gmail.com"));
msg.setSubject("You have a new mail");
msg.setText("This is a test message send at " + new SimpleDateFormat("dd.MM.yyyy HH:mm:ss.SSSZ").format(new Date()));
Transport.send(msg);
} catch (MessagingException e) {
System.out.println(e.getMessage());
}
}

}

Reading Mail Using Gmail POP3 or IMAP Server:

     You can use the following java code to read your gmail inbox folder.The code that delete your mails is not working here, that's because i think a restriction of gmail server to prevent accidentally deleting emails. Here I use imap as the mail fetch protocol.If you want to use pop3 protocol you have to change the properties as below. Using SSL is mandatory when reading your emails.

props.put("mail.store.protocol", "pop3");
props.put("mail.pop3.host", "pop.gmail.com");
props.put("mail.pop3.socketFactory.port", "995");
props.put("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");

package tr.com.aligelenler;

import java.io.IOException;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeMessage;

public class ReadMailUseGmail {

private static final String USER = "your_email@gmail.com";
private static final String PASSWORD = "your_app_password";
private static final boolean CLEAR = false;

public static void main(String[] args) {
Store store = null;
Folder inbox = null;
try {
Properties props = new Properties();
props.put("mail.store.protocol", "imap");
props.put("mail.imap.host", "imap.gmail.com");
props.put("mail.imap.socketFactory.port", "993");
props.put("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.debug", "true");

Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(USER, PASSWORD);
}
});
store = session.getStore();
store.connect();
Folder root = store.getDefaultFolder();
inbox = root.getFolder("inbox");
inbox.open(Folder.READ_WRITE);
Message[] mails = inbox.getMessages();
if (mails.length == 0) {
System.out.println("There are no messages");
}
for (int i = 0; i < 10; i++) {
MimeMessage mail = (MimeMessage) mails[i];
System.out.println("From: " + mail.getFrom()[0]);
System.out.println("To: " + mail.getRecipients(Message.RecipientType.TO)[0]);
System.out.println("Subject: " + mail.getSubject());
System.out.println("Content: " + mail.getContent());
if (CLEAR) {
mail.setFlag(Flags.Flag.DELETED, true);
}
}
} catch (MessagingException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
if (inbox != null && inbox.isOpen())
inbox.close(true);
if (store != null)
store.close();
} catch (MessagingException e) {
System.out.println(e.getMessage());
}
}
}
}

Conclusion:

    Today I showed how to use simple JavaMail API using Gmail servers to send and read emails.The only trick is to obtain a application password to use in the authentication of Gmail server.

You can download the source code from here.

Sunday, November 9, 2014

Using JavaMail API

Introduction:

     I'll mention about the JavaMail API today.Before go into the details of the API we'll first look at the well known e-mail protocols SMTP, IMAP and POP3.After that we'll see how to use and configure Apache James server to use in our examples.

SMTP, IMAP and POP3 Protocols:

     These are all TCP/IP protocols used for mail delivery.In summary, when you send an email to someone, your email client first connects to your email server.Then your email server uses the receipent email address to determine where the mail will have to go and delivers the mail to the target email server.Up to now the SMTP protocol is used.When the receipent want to see the email that you send she asks to her email server to see the email.At this time IMAP or POP3 has to be used.

SMTP stands for Simple Mail Transfer Protocol and is used when email is delivered from the email client to the server or email is delivered from one email server to another. The default SMPT port is 25.When you are sending an email your email client first contact with the SMTP server in the mail infrastructure.If configured so, SMTP server can authenticate you and then deliver your mail to the target server.After sending the email, the mail client may either keep the sent mail in local sent mail folder as in the POP3 protocol or sent mail folder on the server as in IMAP.

POP3 stands for Post Office Protocol and if you use POP3, when you want to see your emails, the emails will be downloaded from the mail server to your local drive deleting the emails on the server's drive which means you work as offline. POP3 is simpler than IMAP and doesn't offer some of the features of IMAP.The default POP3 port is 110.

IMAP stands for Internet Message Access Protocol and if you use IMAP, when you want to see your emails, besides the ability of downloading the emails to the local drive, they still be kept on the server's drive.Because of that IMAP requires more disk space and more CPU power on the mail server than POP3.The default IMAP port is 143.

Download and Configure the Apache James Email Server:

     First go to the page http://james.apache.org/download.cgi and download the latest stable version of Apache James Server.(At the time of this write it is 2.3.2 version).
Next, you have to configure config.xml according to your need.The config.xml should be under ${JAMES_HOME}/apps/james/SAR-INF directory. Some of the configuration values are listed below.You can change the email delivery method either as pop3 or imap, or you can change the port values like below.
* servername -> localhost...
* pop3server -> port 1110...
* smtpserver -> port 1125...

You can also configure your James server according to the instructions listed in this link.These configuration files should be in ${JAMES_HOME}/apps/james/conf directory.

In the config.xml you may also configure the gateway, gatewayPort,gatewayusername and gatewayPassword properties to be able to send emails to an external SMTP server.Remember however that, if you want to send email to an external SMTP server, you may need to sure that your James server IP address and your domain IP address are same.That's because Email servers do a reverse dns query by comparing the IP of the domain and the IP of the sender email server and doesn't accept the email if they are not the same.You can get more information about reverse dns from this link.

After completing the configuration you can now go to the bin directory and run the run.bat or run.sh file.Be sure to set the JAVA_HOME environment variable at this point. You should see the following command lines now.

Using JavaMail API
Figure 1

You can now connect to the James server by telnet using the following command.

Figure 2

If you are using windows 7 you can enable the telnet as shown in this link.
Enter root for login id and password and use the adduser command to add users as shown in the following figure.We add two users admin and test to use in our examples.

Figure 3

Java Mail API:

     To use Java Mail API you need to download the required jar from this link.You just need javax.mail.jar which include SMTP, IMAP and POP3 protocol providers.

Sending Email:

     Below java code is an example of sending an email from the "admin" user to the "test" user we have just created.

package tr.com.aligelenler;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendMail {

    private static final String USER = "admin";
    private static final String PASSWORD = "admin";
    public static String FROM = "admin@localhost";
    public static String TO = "test@localhost";

    public static void main(String[] args) {
        try {
            Properties props = new Properties();
            props.put("mail.transport.protocol", "smtp");
            props.put("mail.smtp.host", "localhost");
            props.put("mail.smtp.port", "1125");
            props.put("mail.smtp.auth", "true");
            props.put("mail.debug", "true");
            Session session = Session.getInstance(props, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(USER, PASSWORD);
                }
            });
            MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(FROM));
            msg.addRecipients(Message.RecipientType.TO,InternetAddress.parse(TO));
            msg.setSubject("You have a new mail");
            msg.setText("This is a test message send at " + new SimpleDateFormat("dd.MM.yyyy HH:mm:ss.SSSZ").format(new Date()));
            Transport.send(msg);
        } catch (MessagingException e) {
            System.out.println(e.getMessage());
        }
    }
}

This code will send an email from admin to test and you can check that mail by using the following command lines in Figure 4 after typing the telnet localhost 1110.

Using JavaMail API
Figure 4

You can also use the following properties rather than using the 
msg.setFrom(new InternetAddress(FROM)); line.
   props.put("mail.host", "localhost");
   props.put("mail.user", "admin");

Here we see the USER and the FROM values are same.Actually if the SMTP authentication enabled,the USER given in the authentication is used as the FROM attribute if your user is not an administrator roled user, so there is no need to define FROM attribute.However if the STMP authentication is not enabled you need to set FROM attribute or use the "mail.user" property.

Reading and Deleting Email:

     Below java code is an example of reading and deleting inbox folder of the test user.The user provided with the password in the authenticator which is "test" is used to fetch the inbox.

package tr.com.aligelenler;

import java.io.IOException;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeMessage;

public class ReadMail {

private static final String USER = "test";
private static final String PASSWORD = "test";
private static final boolean CLEAR = false;

public static void main(String[] args) {
Store store = null;
Folder inbox = null;
try {
Properties props = new Properties();
props.put("mail.pop3.host", "localhost");
props.put("mail.pop3.port", "1110");
props.put("mail.store.protocol", "pop3");
props.put("mail.debug", "false");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
                          return new PasswordAuthentication(USER, PASSWORD);
                         }
});
store = session.getStore();
store.connect();
Folder root = store.getDefaultFolder();
inbox = root.getFolder("inbox");
inbox.open(Folder.READ_WRITE);
Message[] mails = inbox.getMessages();
if (mails.length == 0) {
System.out.println("There are no messages");
}
for (int i = 0; i < mails.length; i++) {
MimeMessage mail = (MimeMessage) mails[i];
System.out.println("From: " + mail.getFrom()[0]);
System.out.println("To: " + mail.getRecipients(Message.RecipientType.TO)[0]);
System.out.println("Subject: " + mail.getSubject());
System.out.println("Content: " + mail.getContent());
if (CLEAR) {
mail.setFlag(Flags.Flag.DELETED, true);
}
}
} catch (MessagingException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
if (inbox != null && inbox.isOpen())
inbox.close(true);
if (store != null)
store.close();
} catch (MessagingException e) {
System.out.println(e.getMessage());
}
}
}
}

The output of this java program will be the following.

From: admin@localhost
To: test@localhost
Subject: You have a new mail
Content: This is a test message send at 09.11.2014 15:22:08.841+0200

If you change the CLEAR property to true the inbox folder will be cleared.
When we are reading or deleting email we must provide the username and password using the Authenticator class and the fetched mails will be the mails of the provided user.

Conclusion:

     We see how to send email using SMTP protocol and read/delete email using POP3 protocol using Apache James Server after describing the email protocols and understanding the James server configuration.Normally you need to enable authentication of your SMTP server for security reasons and your client should provide the username and password using the Authenticator class.In this way your authentication user will be the sender.Similarly when you want to read your emails you must provide your username and password.

You can download the source code from here.