Friday, February 12, 2010

IBM: DB Tools dbbeans.jar

DBBeans.jar

IBM DBBeans.jar comes with elegant APIs for JDBC and simplifies JDBC. Approx +/- 25 JAVA files implemented to do this. This jar is shipped as part of WSAD/RAD in datatools plugin. This jar is DB acqnostic and ready to use directly in application

In JDBC implementation, we have to establish DB connection and then create statement from connection. However, in this jar, we can tag a connection in a statement bean object.

DBStatement is the super class which helps to define statements. DBStatement offers API to release the resource in various levels by calling close(...) API. DBStatement comes with three different flavours

DBSelect
created and used to select rows from DB, which gives facility to retrieve number of rows fetched.
DBModify
makes insert or update or delete operation in DB
DBProcedureCall
calls stored procedure in DB. This class is subclass of DBSelect

DBSelectBeanInfo, DBModifyBeanInfo, DBProcedureCallBeanInfo are the beans stores information for the above listed statements.

DB Events

This implementation facilitate to triggers events before/after calling/executing the DBStatement. We can achive this by registering listener(DBBeforeListener/DBAfterListener) implemented classes in DBStatement.


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.ibm.db.beans.DBModify;
import com.ibm.db.beans.DBProcedureCall;
import com.ibm.db.beans.DBSelect;
import com.ibm.db.beans.DBStatement;

public class DBStatementFactory {

 public static DBSelect getDBSelect() {
  DBSelect dbSelect = new DBSelect();
  dbSelect = (DBSelect) initializeDBStatement(dbSelect);
  return dbSelect;
 }

 public static DBModify getDBModify() {
  DBModify dbModify = new DBModify();
  dbModify = (DBModify) initializeDBStatement(dbModify);
  return dbModify;
 }

 public static DBProcedureCall getDBProcedureCall() {
  DBProcedureCall dbProcedureCall = new DBProcedureCall();
  dbProcedureCall = (DBProcedureCall) initializeDBStatement(dbProcedureCall);
  return dbProcedureCall;
 }

 public static DataSource getDataSource() throws ServiceLocatorException {
  //write a logic to get DataSource
 }

 private static DBStatement initializeDBStatement(DBStatement dbStatement) {
  try {
   Connection conn = getDataSource().getConnection();
   dbStatement.setConnection(conn);
   dbStatement.setOptimizeForNoListeners(true);
  } catch (Exception e) {
   e.printStackTrace();
  }
  return dbStatement;
 } 
}

DBConnectionSpec

If we want to establish connection without any of connection pooling mechanism, this class helps to do that.

private static DBStatement initializeDBStatement(DBStatement dbStatement) {
 try {
 DBConnectionSpec connectionSpec = new DBConnectionSpec();
 connectionSpec.setUsername(user);
 connectionSpec.setPassword(password);
 connectionSpec.setDriverName(driver);
 connectionSpec.setUrl(url);
 
 dbStatement.setConnectionSpec(connectionSpec);
 } catch (Exception e) {
    e.printStackTrace();
 }
}

DBSelectMetaData

DBSelectMetaData stores meta data of DBSelect which will be resulted out after execution

DBSelectMetaData dm= dbSelect.getMetaData();
for(int i=0;i<dm.getColumnCount();i++)
{
System.out.println(dm.getColumnName(i)+" Type:"+dm.getColumnType());
}

DBSelect and ResultSet

Create DBSelect statement and tag with DB connection using DBStatementFactory class and then set SQL command using setCommand(). Once all set to go then execute() has to be called to retrieve data from DB.


String SELECT_ALL_SHIRTS_CATALOGS = "SELECT SHIRTNAME, SHIRTDESC FROM catalogs";
public void displayAllShirtsCatalogs() throws Exception { 
  DBSelect dbSelect = null;
  try {
   DBSelect dbSelect = DBStatementFactory.getDBSelect();
   dbSelect.setCommand(SELECT_ALL_SHIRTS_CATALOGS);

   dbSelect.execute();

   if (dbSelect.onRow()) {
    int size = dbSelect.getRowCount();
    do {
  System.out.println(dbSelect.getColumn(1) 
  + " " + dbSelect.getColumn(2)); 
    } while (dbSelect.next());
   }

  } finally {
   dbSelect.close(DBStatement.LEVEL_CONNECTION);
  } 
 }
 

Tuesday, February 9, 2010

Sample HTTPs Server

HTTPS server

As similar to building HTTP server, we have to establish the ServerSocket with SSL certificates. Client has to confirm the certificate and its validity by checking the Certification Path.

EnabledCipherSuites

SSLServerSocket or SSLSocket provides api to retrieve the supported CipherSuites combinations


String[] ecs=socket.getEnabledCipherSuites();

Results:

SSL_RSA_WITH_RC4_128_MD5
SSL_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_DES_CBC_SHA
SSL_DHE_RSA_WITH_DES_CBC_SHA
SSL_DHE_DSS_WITH_DES_CBC_SHA
SSL_RSA_EXPORT_WITH_RC4_40_MD5
SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA

EnabledProtocols

Supported security protocols are listed by getEnabledProtocols() APIs


String[] eps=socket.getEnabledProtocols()

Results:

SSLv2Hello
SSLv3
TLSv1

This protocol names used while creating SSLContext object.

KeyManagerFactory

This class holds the details of how the keys are managed to secure the sockets. Default would be SunX509. We can parallely come to know from file JAVA_HOME/jre/lib/security/java.security. Similarly, keystore type would be JKS


import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import java.util.Enumeration;
import java.util.Properties;

import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;

public class HTTPs {

 public static final String CONTENT_LENGTH = "Content-length";
 public static final String CONTENT_TYPE = "Content-type";

 private static char NEW_LINE = '\n';

 private static final String EOL = "\r\n";

 private BufferedInputStream is;
 private DataOutputStream os;
 String keystore = "/tmp/keystore.jks";
 char keystorepass[] = "welcome1".toCharArray();
 char keypassword[] = "welcome2".toCharArray();

 private static final String SC_NO_CONTENT = "HTTP/1.1 200 No Content" + EOL
   + "Content-Type: text/plain" + EOL + "Cache-Control: private" + EOL
   + EOL;

 // The port number which the server will be listening on
 public static final int HTTPS_PORT = 7777;

 public ServerSocket getServerSocket() throws Exception {

  KeyStore ks = getKeyStore();

  KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
    .getDefaultAlgorithm());
  kmf.init(ks, keypassword);

  SSLContext sslcontext = SSLContext.getInstance("SSLv3");
  sslcontext.init(kmf.getKeyManagers(), null, null);
  ServerSocketFactory ssf = sslcontext.getServerSocketFactory();
  SSLServerSocket serversocket = (SSLServerSocket) ssf
    .createServerSocket(HTTPS_PORT);

  return serversocket;
 }

 private KeyStore getKeyStore() {
  try {
   KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
   ks.load(new FileInputStream(keystore), keystorepass);
   return ks;
  } catch (Exception e) {
   System.out.println(e.getLocalizedMessage());
   System.exit(-1);
  }

  return null;

 }

 // multi-threading -- create a new connection
 // for each request
 public void run() {
  ServerSocket listen;
  try {
   listen = getServerSocket();
   while (true) {
    Socket socket = listen.accept();

    is = new BufferedInputStream(socket.getInputStream());
    os = new DataOutputStream(socket.getOutputStream());
    readHTTPMessage();

    StringBuffer strbuffer = new StringBuffer();

    strbuffer.append(SC_NO_CONTENT);
    writebytes(socket, strbuffer.toString());
   }
  } catch (Exception e) {
   System.out.println("Exception: " + e.getMessage());
  }
 }

 private void writebytes(Socket socket, String data) {
  try {
   //
   os.write(data.getBytes());
   os.flush();
   if (!socket.isClosed())
    is.close();
   if (!socket.isClosed())
    os.close();

  } catch (Throwable e) {
   System.out.println(e);
  }

  try {
   if (!socket.isClosed())
    socket.close();
  } catch (Throwable e) {
   System.out.println("Problem in data writing in channel");
   System.out.println(e);
  }
 }

 public String readHTTPMessage() throws IOException {
  String result = null;
  StringBuffer strb = new StringBuffer();
  int bufferSize = 1024; // is.available()==0 ? 1024:is.available();
  int contentLength = 0;
  int headerLength = 0;
  int bodyLength = 0;
  try {
   byte[] buf = new byte[bufferSize];
   int nread = 0;
   while ((nread = is.read(buf)) != -1) {
    if (nread == 0)
     continue;
    strb.append(new String(buf, 0, nread));
    // System.out.println(strb);
    result = strb.toString();

    if (contentLength == 0) {

     // atleast 50 bytes required to identify content length
     if (result.length() < 50)
      continue;

     HTTPRequest request = new HTTPRequest(result.getBytes());
     String contentStr = getPropertyIgnoreCase(request
       .getHeaders(), CONTENT_LENGTH);

     // if length specified
     if (null == contentStr || "".equals(contentStr))
      break;

     contentLength = Integer.parseInt("" + contentStr.trim());
     bodyLength = request.getBodyContent().length;
     headerLength = result.length() - bodyLength;
    } else {
     bodyLength = result.length() - headerLength;
    }

    if (bodyLength < contentLength) {
     bufferSize = contentLength - bodyLength;
     buf = new byte[bufferSize];
    } else {

     if (bodyLength >= contentLength || result.endsWith(EOL)) {

      // try{socket.shutdownInput();}catch(Exception e){}
      break;
     }

    }
   }
  } catch (Exception e) {
   System.out.println(e);
  } finally {
   // try{is.close();}catch(Exception e){}

  }
  return result;
 }

 // main program
 public static void main(String argv[]) throws Exception {
  HTTPs https = new HTTPs();
  https.run();
 }

 private class HTTPRequest {

  private byte[] request;

  private int headerIndex = 0;

  private Properties headers;
  private byte[] bodyContent;

  public HTTPRequest(byte[] request) {

   this.request = request;
   init();

  }

  private void init() {

   if (request == null)
    return;

   for (int i = 0; i < request.length; i++) {
    if ((NEW_LINE == (char) request[i]) && (13 == request[i + 1])) {
     headerIndex = i;
     break;
    }
   }

   initHeaders();
   initBodyContent();
  }

  private void initHeaders() {
   String httpMethod;
   String httpVersion;
   String path;
   String headerContent = new String(request, 0, headerIndex);

   String[] availbleHeaders = headerContent.split("\n");

   if (availbleHeaders != null && availbleHeaders.length > 0) {
    String[] typeContainer = availbleHeaders[0].split(" ");

    if (typeContainer != null && typeContainer.length > 2) {
     httpMethod = typeContainer[0];
     path = typeContainer[1];
     httpVersion = typeContainer[2];
    }
   }

   if (availbleHeaders.length > 1) {
    this.headers = new Properties();

    for (int index = 1; index < availbleHeaders.length; index++) {
     String key = availbleHeaders[index].substring(0,
       availbleHeaders[index].indexOf(':'));
     String value = availbleHeaders[index].substring(
       availbleHeaders[index].indexOf(':') + 1,
       availbleHeaders[index].length() - 1);
     this.headers.put(key, value);
    }
   }
  }

  private void initBodyContent() {
   int bodyIndex = headerIndex + 3;
   bodyContent = new byte[request.length - bodyIndex];

   for (int i = (bodyIndex), j = 0; i < request.length; i++, j++) {
    bodyContent[j] = request[i];
   }
  }

  public Properties getHeaders() {
   return headers;
  }

  public byte[] getBodyContent() {
   return bodyContent;
  }
 }

 public static String getPropertyIgnoreCase(Properties props, String key) {
  String value = null;

  Enumeration enum0 = props.propertyNames();
  while (enum0.hasMoreElements()) {
   String name = (String) enum0.nextElement();
   if (key.equalsIgnoreCase(name)) {
    value = props.getProperty(name);
    break;
   }
  }

  return value;
 }
}

prerequisite: Create keystore and keep the same in /tmp folder as mentioned in http://www.javafundu.com/2010/02/keystore-and-keytool.html

Monday, February 8, 2010

KeyStore and KeyTool

KeyStore

A storage/repository to store/retrieve key entries based on a provider format. This entry can be stored in three different format

KeyStore.PrivateKeyEntry
represents Privatekey entry which will be stored and protected from unauthorized access. This key used to singing and decrypting the message. This key is accompanied by a Publickey.
KeyStore.SecretKeyEntry
entry holds javax.crypto.SecretKey
KeyStore.TrustedCertificateEntry
entry contains a single public key Certificate belonging to another party

KeyTool

As part of JAVA SE, the keytool is shipped which helps to create keystore, import/export/print certificates and etc.,. Following are the list of operations possible to using keytool

  • -certreq
  • -changealias
  • -delete
  • -exportcert
  • -genkeypair
  • -genseckey
  • -help
  • -importcert
  • -importkeystore
  • -keypasswd
  • -list
  • -printcert
  • -storepasswd

Sample Keystore

Create keystore with RSA algorithm, where JAVA_HOME/bin folder is set in PATH environment variable


keytool -genkey -keystore keystore.jks -keyalg rsa -alias mykey
Enter keystore password: welcome1
Re-enter new password: welcome1
What is your first and last name?
  [Unknown]:  my.org
What is the name of your organizational unit?
  [Unknown]:  myorg
What is the name of your organization?
  [Unknown]:  myorg
What is the name of your City or Locality?
  [Unknown]:  blr
What is the name of your State or Province?
  [Unknown]:  ka
What is the two-letter country code for this unit?
  [Unknown]:  in
Is CN=my.org, OU=myorg, O=myorg, L=blr, ST=ka, C=in correct?
  [no]:  yes

Enter key password for <mykey>
        (RETURN if same as keystore password): welcome2
Re-enter new password: welcome2
Export Certificate
keytool -export -alias mykey -keystore keystore.jks -keyalg rsa -file myorg_public.cer
Import Certificate
keytool -import -alias mykey -keystore keystore.jks -keyalg rsa -file myorg_public.cer
List Certificate
keytool -list -keystore keystore.jks -keyalg rsa
JarSigner - If we want to ship jars and monitor that whether it get tempared in medium.
jarsigner -keystore keystore.jks -storepass welcome1 -keypass welcome2 -signedjar smycode.jar mycode.jar mykey

KeyStore in JAVA Object

java.security.KeyStore class loads keysore file and provides APIs to do the above listed operations.


private KeyStore getKeyStore()
 {
  try
  {
   KeyStore ks = KeyStore.getInstance("JKS");
   ks.load(new FileInputStream("keystore.jks"), "welcome1");
   return ks;
  }catch (Exception e)
  {
   System.out.println(e.getLocalizedMessage());
  }
  return null;
 }

Oracle PKI key store will be loaded using following code


private KeyStore getOracleKeyStore()
 {
  try
  {
  Security.addProvider(new oracle.security.pki.OraclePKIProvider());
   KeyStore ks = KeyStore.getInstance("PKCS12", "OraclePKI");
   ks.load(new FileInputStream("keystore.jks"), "welcome1");
   return ks;
  }catch (Exception e)
  {
   System.out.println(e.getLocalizedMessage());
  }
  return null;
 }

While creating keystore file, we have to pass oracle.security.pki.OraclePKIProvider as a provider class to the keytool command.

Sun Key Store:
keytool -genkey -keystore keystore.jks -keyalg rsa -alias mykey -providerName SUN -providerClass sun.security.provider.Sun

Wednesday, February 3, 2010

Java Logger with Custom Formatter

In production or development environment, log files are playing major role to identify the nature of the issue and how often it raises. This information reduces the number of question needed to ask customer to understand the issue. Most valuable and precised data has to be captured in log files.

Developers, some time log there native language based log information and product also may shipped with these log information to customer. These kind of non-english or non-locale logs makes customer to panic and get back to vendors ;). Software developers and Quality Assurance folks has to spend considerable effort in stopping these kind of log details.

JAVA logger comes as part of JAVA SE and helps us to easy to configure and store/retrieve log information. Major components in Logger are

Level
specifies levels of information needed to be logged. In production, we may need only SEVERE information. In Development, we may need all information for debugging purpose, we may need to set FINEST or ALL. Possible log levels are OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, and ALL
LogRecord
Log level and message forms log record and it internally keeps time of record creation
Formatter
This component decides, in what format data has to go to log file. In JAVA SE, java.util.logging.XMLFormatter is default one
Handler
this holds the details of where to store and how to rotate and etc.,
Filter
filter decides given logrecord is logable or not
Logger
Exposes factory method to create Logger object for given name
Exposes APIs to log messages in various level.

XMLFormatter and custom formatter used to show how the log records are created in log file in /tmp/ folder.


import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.XMLFormatter;

public class LoggerTest {

 public static void main(String[] args) throws IOException {
  final Logger log = Logger.getLogger("LoggerTest", null);
  log.setLevel(Level.FINEST);
  log.setUseParentHandlers(false);
  FileHandler handler = new FileHandler("/tmp/log.log", false);
  log.addHandler(handler);

  // XML formatted log
  handler.setFormatter(new XMLFormatter());
  log.log(Level.FINEST, "Hello world");

  // Custom formatted log
  handler.setFormatter(new Formatter() {
   @Override
   public String format(LogRecord record) {
    return " custom log - " + log.getName() + " : "
      + record.getMillis() + ":" + record.getMessage();
   }
  });

  log.log(Level.FINEST, "Hello world");
 }
}

User Lockout

In general, password guessing raises serious attack to our application server. Weblogic provides the way to stop guessing the password by locking the particular user, if the number of invalid consecutive password attempt made more than configured.
Banking service applications very much needs this user locking mechanism. If customer found that their account is locked then they have to request the Bank to unlock the account by submitting application or sending email from trusted account. Alternate way would be, unlock automatically after some time, may be a day or two.
Lockout Threshold
specifies number of maximum invalid password attempt possible to make in consecutive attempts.
Lockout Duration
specifies number of minutes to wait for auto unlock once the account locked.
Lockout Reset Duration
lock account only Lockout Threshold reached within this specified minutes. For example, user may be tried to log in yesterday with invalid password. If he tries to login today, then he can attempt to login Lockout Threshold time consecutively with invalid password. If we wants to count the first attempt of yesterday's one, then we have to set minutes value to cover 48 hrs.
Steps to reach User Lockout in weblogic
  1. Login weblogic console
  2. Select Security Realms in Domain Structure panel
  3. In Summary of Security Realms, configured realms will be listed and any of select realms,we go with default myrealm
  4. Select User Lockout tab, where we could see the user lock out properties.

Monday, February 1, 2010

Java Mail

In JAVA Platform Enterprise Edition, javax.activation, and javax.mail packages has APIs to send or receive EMAIL. javax.mail.internet.InternetAddress class helps us to construct Address from String object.

Variety of properties which used to control the flow, monitor the flow, per session based properties and global properties for JAVA Mail. It is very tedious to remember all those properties. However, JAVA Doc is nicely written to list all those properties with brief explanation. Mail Session Properties | MIME properties | sMTP Properties

Mail Send

In the following sample, mail server is running with default port mail.smtp.port:25 in same machine, where this program is get executed. If no Mail server is configured to run in local, then we can configure to point thirdparty mailserver like gmail, hotmail, or rediffmail.


import java.util.Properties;

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

public class MailTest {
 private static Session session = null;

 public static void main(String[] args) throws Exception {
  sendMail("krishna.oracleb2b@gmail.com", "abc@abc.com",
    "abc1@abc.com,abc2@abc.com", "Test mail",
    "Hello All, this is test message", true);
 }

 public static void sendMail(String sFrom, String sTo, String sBcc,
   String sSubject, String sBody, boolean sTextBody) throws Exception {
  try {
   Message message = new MimeMessage(getMailSession());
   message.setFrom(new InternetAddress(sFrom));
   InternetAddress to[] = new InternetAddress[1];
   to[0] = new InternetAddress(sTo);
   message.setRecipients(javax.mail.Message.RecipientType.TO, to);

   if (sBcc.length() > 0) {
    message.setRecipients(javax.mail.Message.RecipientType.BCC,
      InternetAddress.parse(sBcc));
   }

   message.setSubject(sSubject);
   if (sTextBody)
    message.setContent(sBody, "text/plain");
   else
    message.setContent(sBody, "text/html");

   Transport.send(message);

  } catch (MessagingException m) {
   m.printStackTrace();
   // throw new ShirtCommonException(m);
  } catch (Exception m) {
   m.printStackTrace();
  }
 }

 /**
  * getMail session
  * 
  * @return
  */
 private static Session getMailSession() {
  if (session == null) {
   // Get system properties
   Properties props = new Properties();

   // Setup mail server
   props.put("mail.smtp.host", "localhost");

   // Get session
   session = Session.getDefaultInstance(props, null);
   session.setDebug(true);
  }
  return session;
 }
}

In the above example, no security details used to send the message. Some server mandates user has to create session with username and password. And even more with SSL enable socket needs to be used to connect. In these cases, Transport has to be instantiated with proper SMTP security properties.Here is the sample for username-password authentication


Transport tr = session.getTransport("smtp");
tr.connect(smtphost, username, password);
msg.saveChanges();
tr.sendMessage(msg, msg.getAllRecipients());
tr.close();

Mail Read

To read mail from MailServer, Mailserver has to support any of the mail reading protocol pop3, imap. Based on this, we have to create instance of javax.mail.Store and get the folder which ever we wants to operate on.


import java.io.InputStream;
import java.util.Properties;

import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Store;

public class MaieReceivelTest {
 private static Session session = null;

 public static void main(String[] args) throws Exception {
  readMail();
 }

 public static void readMail() throws Exception {
  try {
   Store store = getMailSession().getStore();
   store.connect("localhost", "username", "password");
   
   Folder folder = store.getFolder("Inbox");
   System.out.println(folder.getMessageCount());
   Message[] msgs = folder.getMessages();
   if (null != msgs) {
    for (Message msg : msgs) {

     InputStream is = msg.getDataHandler().getInputStream();
     if (is != null) {
      byte[] bytes = new byte[is.available()];
      is.read(bytes);
      System.out.println(new String(bytes));
     } else {
      Multipart mp = (Multipart) msg.getDataHandler()
        .getContent();
      is = mp.getBodyPart(0).getInputStream();
      byte[] bytes = new byte[is.available()];
      is.read(bytes);
      System.out.println(new String(bytes));
     }

    }
   }

  } catch (MessagingException m) {
   m.printStackTrace();
   // throw new ShirtCommonException(m);
  } catch (Exception m) {
   m.printStackTrace();
  }
 }

 /**
  * getMail session
  * 
  * @return
  */
 private static Session getMailSession() {
  if (session == null) {
   // Get system properties
   Properties props = new Properties();

   // Setup mail server
   props.put("mail.smtp.host", "localhost");
//   mail.smtp.user
      
   // Get session
   session = Session.getDefaultInstance(props, null);
   session.setDebug(true);
  }
  return session;
 }
}

Recent Posts

Unix Commands | List all My Posts

Texts

This blog intended to share the knowledge and contribute to JAVA Community such a way that by providing samples and pointing right documents/webpages. We try to give our knowledege level best and no guarantee can be claimed on truth. Copyright and Terms of Policy refer blogspot.com