Google

Dec 29, 2012

Technical Blogging Tips -- 1 million page views and lessons learned in technical blogging


Firstly, thanks to all my followers and readers for your support in reaching this milestone of 1 million page views.

Here are a few technical blogging tips based on my experience.

1. You need to be patient and keep at it

It took me around 9 months to go from 100 to 4000 daily page views. It was a gradual and slow process, and  I promoted my site via publishing articles at www.javalobby.com and helping out fellow professionals via industry specific forums like www.javaranch.com. Paid attention to Google key words that are not highly competitive and ensured that my contents had the key words to come up on google search for key words like "Java interview questions". The Google analytics revealed the following growth.






2. Sign-up to Google, and get the right tools 


  
-- track your progress and gather metrics (e.g. Google analytics) 
-- Sign up for Google adsense  to earn a small passive income.
-- Feedburner to enable your readers to subscribe to your bog feeds.
-- Google+ to network with your followers.



3. Pay attention to "repeated visitors" and "bounce rate" in Google analytics

Google analytics is a great tool to monitor how well your blog is doing. Two of the key metrics that I constantly look at are

The number of returning or repeated visitors. The slow and steady increase in this number indicates that you are getting some loyal readers who like reading your blog posts.

Jan 2012: 2,825 
Feb 2012: 4,007 
March 2012: 7,131 
April 2012: 10, 321
May 2012: 14,304 
June 2012: 19,122
July 2012: 22, 327 
Aug 2012: 24, 390 
Sep 2012: 25, 994

The "bounce rate" needs to be kept around  70% or less

You can't please everyone who comes to your site. Make sure that the landing page is interesting and informative enough to keep the bounce rate below 70%. If the bounce rate is high, then the problems may include irrelevant information, poor design or that your campaign is targeting unqualified visitors, too many advertisements putting people off, the content is not unique enough and freely available in many other sites, etc. You need to come up with an idea that will differentiate both your site and your content from others in the same niche. Not easy, but possible. For example, there are so many matured sites on "Java Tutorials" and very hard to compete on. The small number of tutorials provided in this blog are mainly to provide some familiarity with the sought-after technologies and frameworks.The real differentiating factor for this site is proving quality Java job interview questions with concise and easy to grasp answers.


4. Use the social media like "Facebook" and "Google+" to network and stay in touch with your readers.

It is vital to network and stay in touch with your readers and fellow professionals to open more doors. Help others and ask for feedback as to how you can improve the quality of your blog posts. Learn the problems faced by your followers and provide solution. Nothing beats the "word by mouth" marketing.


5. Sign up for "google adsense" and "infolinks" advertisements to earn a small pocket money

Don't place any advertisements until you get around 5000+ repeated visitors. Once you get enough repeated visitors you can sign up for "google adsense" and "infolinks" advertisements to be placed. Don't over do it as too many advertisements can annoy your readers. Generally, vertical and horizontal banners perform better. Set up custom adsense channels to see which advertisements are doing better. Don't expect too much from these advertisements, but can be a good passive pocket money in the order of $6.0 to $20.0 per 4000 page views.

6. The main reason for blogging is to open more doors in other areas


As an independent contractor, my blog helps me capture my experience and stay relevant.

Q. Why capture myexperience?
A.

  • Firstly, it will serve as handy notes for my future references.
  • Secondly, I can refresh or jog my memory prior to job interviews to provide a more convincing answers to open-ended questions like -- tell me about yourself? what are your strengths? give me an example where you applied your problem solving skills? what are your recent accomplishments?
  • Finally, my blog contents can potentially become an inspiration to self-publish my own book. Publishing my own book has never been easier with the advent of POD (Print On Demand) publishers like createspace.com, lulu.com, etc. 

It also gives me an opportunity to network. Some of my past and current employers have read my blog posts, and it has certainly helped me win new contracts. Also, it has improved my researching and written skills. In future, if you have a reasonable size followers, you could promote other products and services. You can increase your understanding of the fundamentals from relevant questions and intelligent doubts raised by your readers.


7. People don't have whole day to read your blog posts

So, it needs to be short and sweet. The headings need to be catchy and informative. For example, I have come across some catchy titles like "How I taught my dog polymorphism", "I quit my job today, and so should you", etc.  It needs to be laid out well enough to navigate between topics. Add diagrams and code snippets where applicable.  Consult the "google  key words tool" to optimize your blog titles for SEO.

8. You need to consistently post blog entries, and can't afford to be complacent.

The times that I had been a bit slack in posting new blog posts, my google search rank had dropped. Currently, I have about 135 blog entries. Post about 2 to 4 per week. Don't post multiple entries the same day. One entry per day. The way the SEO works for the blog posts, it not only looks at the backlinks and the key word concentration, but also the reader involvement in terms of the number of comments posted, site popularity with repeated visits, etc.

Labels:

Dec 20, 2012

Spring batch advanced tutorial -- writing your own reader


My previous 3 part spring batch tutorial covered a high level overview with examples. This tutorial demonstrates how to wrap your own File Reader  with the FileItemReader to peek the data and group them the way you wanted to provide some customization. For example, if you have a CSV file like shown below where

  1. The first line is the header with the portfolio name, transaction from date and transaction to date.
  2. The remaining rows are transaction detail records grouped by account code. The detail records contain portfolio code, account code, transaction type, and transaction amount.
  3. When you read the records we need to read them by account grouping and process them. in other words, we have 2 groups in the csv feed shown below. The records 2- 5 is one group, and records 6 -8 is another group. In other words starting from the transaction type "OPENBAL" to the record before the next "OPENBAL" is one group


"Portfolio1","29/02/2012","11/03/2012",
"Portfolio1","Account1","OPENBAL", 2000.00
"Portfolio1  ","Account1","PURCHASE",1000.00
"Portfolio1  ","Account1","EXPENSE",500.00
"Portfolio1  ","Account1","ADJUSTMENT ", 200.00
"Portfolio1","Account1","OPENBAL ", 12000.00
"Portfolio1  ","Account2","PURCHASE",1000.00
"Portfolio1  ","Account3","ADJUSTMENT",1000.00


So, wee need to write a custom file reader that can peek into the next record before reading it.

Step 1: Snippets of the spring batch context configuration file.E..g.applicationContext-myapp.xml.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:batch="http://www.springframework.org/schema/batch"
 xmlns:task="http://www.springframework.org/schema/task" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:int="http://www.springframework.org/schema/integration"
 xmlns:file="http://www.springframework.org/schema/integration/file"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
 http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
 http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
 http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
 http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file-2.0.xsd
 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

     <!-- load properties file-->
 <context:property-placeholder location="classpath:myapp.properties" />
 <!-- annotation driven injection -->
 <tx:annotation-driven />

 <!-- define the job that reads from a CSV file and write to a database-->
 <job id="myAppJob" xmlns="http://www.springframework.org/schema/batch">
  <listeners>
   <listener ref="myAppJobExecutionListener" />
  </listeners>

  <step id="loadMyAppFeedData">
   <tasklet transaction-manager="transactionManager">
    <listeners>
     <listener ref="stepExecutionListener" />
    </listeners>

    <chunk reader="groupMyAppDetailsReader" writer="myAppFileItemWriter" commit-interval="10" />
   </tasklet>
  </step>
  
 </job>

 
    <!-- Spring supplied File Item Reader that reads CSV file line by line--> 
 <bean id="myAppFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
  <property name="resource" value="#{jobParameters['dataFileName']}" />
  <property name="lineMapper">
   <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
    <property name="lineTokenizer">
     <bean
      class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
      <property name="names"
       value="portfolioCd,accountCd,transactionType, Amount" />
     </bean>
    </property>
    <property name="fieldSetMapper">
     <bean
      class="com.myapp.mapper.MyAppFieldSetMapper" />
    </property>
   </bean>
  </property>
  <property name="linesToSkip" value="1" />
  <property name="skippedLinesCallback" ref="myAppFileHeaderLineCallbackHandler" />
 </bean>

    <!-- My custom CSV file Reader that groups data but it internally makes use of the Spring's FileItemReader-->
 <bean id="groupMyAppDetailsReader"  class="com.myapp.item.reader.myAppItemReader">
  <property name="delegate" ref="myAppFileItemReader" />
 </bean>

 <!-- My custome File Item Writer -->
 <bean id="myAppFileItemWriter" class="com.myapp.item.writer.MyAppItemWriter" />

    <!-- The Step execution context listener that can be injected to propagate step values -->
 <bean id="stepExecutionListener" class="com.myapp.StepExecutionListenerCtxInjecter" />


</beans>


Step 2: The custom reader can be implemented as shown below. The key here is that  peeking the next record to enable grouping and making use of the Spring provided FileItemReader as a delegate to read each CSV line.

package com.myapp.item.reader;

import java.util.ArrayList;

import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemStreamReader;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;

import com.myapp.model.TransactionDetail;
import com.myapp.model.MyAppPortfolioParent;

public class MyAppFileItemReader implements ItemStreamReader<MyAppPortfolioParent> {

 private ItemStreamReader<TransactionDetail> delegate;
 private TransactionDetail curItem = null;

 @Override
 public MyAppPortfolioParent read() {
  MyAppPortfolioParent parent = null;
  try {

   if (curItem == null) {
    curItem = delegate.read();
   }

   if (curItem != null) {
    parent = new MyAppPortfolioParent();
    parent.setBalanceDetail(curItem);
   }

   curItem = null;

   if (parent != null) {
    parent.setTxnDetails(new ArrayList<TransactionDetail>());
    TransactionDetail detail = peek();
    while (detail != null && !"OPENBAL".equalsIgnoreCase(peek().getTxnCd())) {
     parent.getTxnDetails().add(curItem);
     curItem = null;
     detail = peek();
    }
   }

  }

  catch (Exception e) {
   e.printStackTrace();
  }

  return parent;
 }

 public TransactionDetail peek() throws Exception, UnexpectedInputException, ParseException {
  if (curItem == null) {
   curItem = delegate.read();
  }

  return curItem;
 }

 @Override
 public void close() throws ItemStreamException {
  delegate.close();
 }

 @Override
 public void open(ExecutionContext arg0) throws ItemStreamException {
  delegate.open(arg0);
 }

 @Override
 public void update(ExecutionContext arg0) throws ItemStreamException {
  delegate.update(arg0);

 }

 public void setDelegate(ItemStreamReader<TransactionDetail> delegate) {
  this.delegate = delegate;
 }
}



Step 3: The utility class that can be used to inject the step and job execution contexts into your reader, processor, or writer classes.

package com.myapp.util;

import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.item.ExecutionContext;


public class StepExecutionListenerCtxInjecter
{
    private ExecutionContext stepExecutionCtx;
    
    private ExecutionContext jobExecutionCtx;
    
    @BeforeStep
    public void beforeStep(StepExecution stepExecution)
    {
        stepExecutionCtx = stepExecution.getExecutionContext();
        jobExecutionCtx = stepExecution.getJobExecution().getExecutionContext();
    }


    public ExecutionContext getStepExecutionCtx()
    {
        return stepExecutionCtx;
    }

    public ExecutionContext getJobExecutionCtx()
    {
        return jobExecutionCtx;
    }
}


Step 4: As you could see in the spring config file that we are skipping the first record, which is the header record and defined a LineCallBackHandler to handle the header records. Here is the implementation of this handler.

package com.myapp.handler;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.file.LineCallbackHandler;
import org.springframework.stereotype.Component;

import com.myapp.dao.MyAppingDao;
import com.myapp.model.MyAppMeta;
import com.myapp.util.CashforecastingUtil;
import com.myapp.util.StepExecutionListenerCtxInjecter;

@Component(value = "myAppFileHeaderLineCallbackHandler")
public class MyAppFileHeaderCallbackHandler implements LineCallbackHandler {

 private static final Logger LOGGER = LoggerFactory.getLogger(MyAppFileHeaderCallbackHandler.class);

 public static final String FEED_HEADER_DATA = "feedHeaderData";

 @Resource(name = "myappFeedDao")
 private MyAppDao myappDao;

 @Resource(name = "stepExecutionListener")
 private StepExecutionListenerCtxInjecter stepExecutionListener;

 @Override
 public void handleLine(String headerLine) {
  LOGGER.debug("header line: {}", headerLine);
  //convert CSV data into 
  MyAppMeta cfMeta = MyAppUtil.getMyAppMetaFromHeader(headerLine, null);

  // logical delete current records
  int noOfRecordsLogicallyDeleted = myappDao.logicallyDelete(cfMeta);
  LOGGER.info("No of records logically deleted: " + noOfRecordsLogicallyDeleted);

  //save it in the job execution context
  stepExecutionListener.getJobExecutionCtx().put(FEED_HEADER_DATA, cfMeta);
 }
}



Step 5: The FileItemReader has a mapper defined to map each row to an object. We need to define this object that gets invoked when each CSV line item is read to convert each field to an object as shown below.

package com.myapp.mapper;
import java.math.BigDecimal;
import java.text.ParseException;

import org.apache.commons.lang.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;

import com.myapp.model.MyAppDetail;


public class MyAppFieldSetMapper implements FieldSetMapper<MyAppDetail> {
 
 private final static Logger logger = LoggerFactory.getLogger(CashForecastFieldSetMapper.class);
 
 
 @Override
 public MyAppDetail mapFieldSet(FieldSet fs) throws BindException {

  if (fs == null) {
   return null;
  }
  
  MyAppDetail detail = new MyAppDetail();
  detail.setPortfolioCd(fs.readString("portfolioCd"));
  detail.setAccountCd(fs.readString("accountCd"));
  detail.setTxnCd(fs.readString("txnCd"));
  
  BigDecimal cashValue = fs.readBigDecimal("cashValue");
  detail.setCashValue(cashValue != null ? cashValue : BigDecimal.ZERO);
  
  
  return detail;

 }
}



Step 6: The writer class that is responsible for writing a group of items (i.e. parent and children records)  to the database. 

package com.myapp.item.writer;

import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemWriter;

import com.myapp.dao.myappingDao;
import com.myapp.handler.myappFileHeaderCallbackHandler;
import com.myapp.model.myappDetail;
import com.myapp.model.myappMeta;
import com.myapp.model.myappParent;
import com.myapp.util.StepExecutionListenerCtxInjecter;

public class MyAppItemWriter implements ItemWriter<MyAppParent> {

 @Resource(name = "stepExecutionListener")
 private StepExecutionListenerCtxInjecter stepExecutionListener; // to get the step and job contexts

 @Resource(name = "myappFeedDao")
 private myappingDao myappDao;   //dao class for saving records into database

 private final static Logger logger = LoggerFactory.getLogger(MyappItemWriter.class);

 @Override
 public void write(List portfolioDetails) {

     //retrieving previously stored data from the job context
  myappMeta pfMeta = (myappMeta) stepExecutionListener.getJobExecutionCtx().get(
    MyAppFileHeaderCallbackHandler.FEED_HEADER_DATA);

  int batchJobId = -1;

   //retrieving previously stored data from the job context
  if (stepExecutionListener.getJobExecutionCtx().get("batchJobId") != null) {
   batchJobId = stepExecutionListener.getJobExecutionCtx().getInt("batchJobId");
  }
  pfMeta.setBatchJobId(batchJobId);

  try {
   for (myappParent cfp : portfolioDetails) {

    MyappDetail bd = cfp.getBalanceDetail();

    // save cash forcasting balances
    int noOfRecords = myappDao.saveMyappBalance(bd, pfMeta);
    logger.info("No of cashforcast balance records inserted " + noOfRecords);

    int syntheticId = myappDao.getmyappId(bd, pfMeta);

    // save myapping transaction records
    List<Myappdetail> txnDetails = cfp.getTxnDetails();
    for (myappDetail txd : txnDetails) {
     myappDao.saveMyappDetail(txd, syntheticId);
    }

   }

  } catch (Exception e) {
   logger.error("myappItemWriter error", e);
   throw new RuntimeException(e);
  }

  if (logger.isDebugEnabled()) {
   logger.debug("Commiting chunks to the database ...... ");
  }

 }
}



Labels:

Dec 19, 2012

The pre Java Interview online written test questions that I hate

Some online assessment sites basically try to test your memorizing capabilities with API based questions listed below. Also, about 30% - 50% of the questions are on API that you rarely use or obsolete. When you have the API documentation, why remember the API. Here are a few such questions I came across recently. If you want to ask such questions, then allow people to refer to the online API documentation. These tests are only going to filter out quality candidates.

Q. Which of the following are valid JavaMail message types?

a) Message.RecipientType.CC
b) MessageRecipientType.CC
c) Message.RecipientType.CCList
d) Message.RecipientType.BCC
e) MessageRecipientType.BCC

A. a and d


Q. Which of the following are JNDI event listeners?

a) NamespaceChangeListener
b) ObjectListener
c) ObjectChangeListener
d) UnsolicitedNotificationListener
e) ObjectNotFoundListenr

A. a, c, and d.


Q. Which of the following statements are correct, based on the following code snippet for uploading a file?

<form action="upload"  enctype="multipart/form-data">
    <input type="text" name="description" />
    <input type="file" name="file" />
    <input type="submit" />
</form>


a) The enctype must be "text/form-data"
b) The method attribute is missing in the "form" element and it should be of type "GET"
c) The method attribute is missing in the "form" element and it should be of type "POST"
d) The "input" element must have the attribute "value"
e) The above syntax is correct

A. c. 

The correct format is:

<form action="upload"  method="post" enctype="multipart/form-data">
    <input type="text" name="description" />
    <input type="file" name="file" />
    <input type="submit" />
</form>


Q. Which of the following objects are NOT part of the JavaBean Activation Framework (JAF)?

a) DataSource
b) DataFileHandler
c) DataHandler
d) DataContentHandler
e) FileDateHandler
f) FileTypeMap

A. b and e. All the others are part of JAF.


Q. Which of the following statements are INCORRECT?

a) HttpServletRequest.getRemoteUser( ) return null;
b) HttpServletRequest.isUserInRole(java.lang.String role) throws SecurityException ;
c) HttpServletRequest.getRemoteUser( ) return false;
d) HttpServletRequest.isUserInRole(java.lang.String role) return false;
e) HttpServletRequest.getUserPrincipal( ) throws SecurityException
f) HttpServletRequest.getUserPrincipal( ) return null;


A. b, c, and e are INCORRECT.

Q. Which of the following elements would you see in a SOAP payload with attachments?

a) <soap:header>
b) <soap:footer>
c) <soap:body>
d) <soap:content>
e) <soap:attachment>

A. a and c.


Q. Which of the following can be used in place of "****" in the code snippet shown below?


if(request.getParameter("location").equals("nextPage") {

      *****

}


a) request.sendRedirect("url");
b) response.sendRedirect("url");
c) request.redirect("url");
d) response.redirect("url");
e) response.send("url")


A.b

Q. Which of the following are valid JDBC  result set types?


a) TYPE_FORWARD_ONLY
b) TYPE_BACKWARD_ONLY
c) TYPE_SCROLL_INSENSITIVE
d) TYPE_SCROLL_SENSITIVE
e) TYPE_SCROLL_REVERSE

A. a, c, and d.


Q. Which of the following are valid JSP life cycle methods?

a) jspService( )
b)_jspService( )
c) jspInit( )
d) jspDestroy( )
e) _jspInit()

A. a, c, and d.


Q. Which of the following are CORRECT about JCA?

a)  JCA is a standard architecture for integrating heterogeneous EIS systems not written in Java
b)  JCA is a standard architecture for integrating other JEE systems
c)  JCA can be used to integrate with mainframe systems
d)  JCA can be used to integrate with ERP systems
e)  JCA can be used to integrate with Database systems
f)  The underlying EIS systems are integrated using pluggable resource adapters

A. a, c, d, e and f.

Q. Which of the following are INCORRECT about JAAS?

a) JAAS bring in location based authentication and authorization to JEE.
b) JAAS is designed to bring subject based authentication and authorization to JEE
c) JAAS is modeled after the Pluggable Authentication Module (PAM)-a popular API for defining authentication modules in a portable and extensible manner
d) JAAS can be used across managed resources such as servlet/JSP, EJB, or MBeans and over a variety of connection protocols such as HTTP, RMI/IIOP, or JMX/RMI.
e) JAAS was fully integrated into the core Java security architecture

A. a.

The last 2 questions are not bad, but for most of the other questions, the answers can be found by jumping on a search engine for 5 to 15 minutes. It is not really testing your understanding of the core concepts or hands-on experience.

Is it just me, or do you agree with me? Please post the Java Interview Questions that you hate.

Labels:

Dec 14, 2012

Drools tutorial with Maven

Drools is a popular open source business rules and work flow engine. It helps you externalize the rules as opposed to embedding within the Java code. The rules are executed in the form of when given a($condition) then execute the ($consequence) This tutorial contains a number of artifacts highlighted below.


Step 1: Create a new Maven project with the standard src/main/java, src/main/resources, src/test/java, etc source folder directories. Create a new src/main/rules folder to define the rules using the "mvel" expresion language.
Update the pom.xml file as shown below with relevant dependencies and also add the build/resources to tell maven that sr/main/rules is a source folder.


 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.myapp</groupId>
 <artifactId>drools-poc</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>

 <properties>
  <drools.version>5.3.1.Final</drools.version>
  <junit.version>4.7</junit.version>
 </properties>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>${junit.version}</version>
  </dependency>
  <!-- drools library -->
  <dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-core</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-core</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-compiler</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <!-- required for drools and spring integration -->
  <dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-spring</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <dependency>
   <groupId>com.thoughtworks.xstream</groupId>
   <artifactId>xstream</artifactId>
   <version>1.2.2</version>
  </dependency>
 </dependencies>
 
 
 <build>
    <resources>
        <resource>
           <directory>src/main/rules</directory>
        </resource>
    </resources>
 </build>

</project>



Step 2: Define the domain classes like Applicant.java.

 

package com.company.license;

public class Applicant {

 private Integer id;
 private String name;
 private int age;
 
 public Applicant(Integer id, String name, int age) {
  super();
  this.id = id;
  this.name = name;
  this.age = age;
 }

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 
 @Override
 public String toString() {
  return "name=" + name + ", age=" + age;
 }

}


Step 3: Define the data access interface and implementation classes that retrieves data from a persistent source like file or database. The implementation is simplified to read from a pre-populated in-memory map.

 

package com.company.license;

public interface ApplicantDao {
    Applicant findApplicant(Integer applicantId);
}


The implementation of the above interface.

package com.company.license;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ApplicantDaoImpl implements ApplicantDao {
 
 private static final Map<Integer, Applicant> data = new ConcurrentHashMap<Integer, Applicant>();
 
 static {
  data.put(1, new Applicant(1, "John", 16));
  data.put(2, new Applicant(2, "Peter", 20));
 }

 public Applicant findApplicant(Integer applicantId) {
  Applicant applicant = data.get(applicantId);
  System.out.println("fetched applicant: " + applicant);
  return applicant;
 }
}



Step 4: Define the value object class that captures the user entry via a GUI. For example, ApplicantForm.java as shown below.

package com.company.license;

public class ApplicantForm {
 
 private Integer applicantId;
 private boolean eligible = true; // eligible by default

 public Integer getApplicantId() {
  return applicantId;
 }

 public void setApplicantId(Integer applicantId) {
  this.applicantId = applicantId;
 }

 public boolean isEligible() {
  return eligible;
 }

 public void setEligible(boolean eligible) {
  this.eligible = eligible;
 }
 
 @Override
 public String toString() {
  return "applicantId=" + applicantId + ", eligible=" + eligible;
 }
}

Step 5: Define the business rules via mvel expression language in a separate external file -- applicant-license.drl.

 

package com.company.license;

import com.company.license.ApplicantForm;
import com.company.license.Applicant;
import com.company.license.ApplicantDao;
import com.company.license.ApplicantDaoImpl;

global ApplicantDao applicantDao;
 
rule "is eligible for licence"
when
   $a : ApplicantForm();
   $applicant: Applicant( age < 18 ) from applicantDao.findApplicant($a.getApplicantId());
then
   $a.setEligible( false );
end


Step 6: Finally, the junit test class that makes use of drools to validate applicants. We will create 2 applicants, one with age >= 18, and another one with age < 18, to test the business rules engine (aka expert systems) of drools in action.


 

package com.company.license;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderErrors;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class ApplicantLicenseTest {

 private KnowledgeBase kbase;

 @Before
 public void setup() {
  KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
  kbuilder.add(ResourceFactory.newClassPathResource("com/company/license/applicant-license.drl"),
    ResourceType.DRL);
  KnowledgeBuilderErrors errors = kbuilder.getErrors();
  if (errors.size() > 0) {
   for (KnowledgeBuilderError error : errors) {
    System.err.println(error);
   }
   throw new IllegalArgumentException("Could not parse knowledge.");
  }
  kbase = KnowledgeBaseFactory.newKnowledgeBase();
  kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());

 }

 @Test
 public void testApplicantLicense() {
  StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
  KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
  KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
  kbase.newStatefulKnowledgeSession();

  ApplicantForm applicant1 = new ApplicantForm();
  applicant1.setApplicantId(1);
  
  ApplicantForm applicant2 = new ApplicantForm();
  applicant2.setApplicantId(2);
    
  ksession.setGlobal("applicantDao", new ApplicantDaoImpl()); // assign the global dao
  
  ksession.insert(applicant1);
  ksession.insert(applicant2);
  ksession.fireAllRules();
  
  ksession.dispose();

  Assert.assertTrue(applicant1.isEligible() == false);//John is not eligible
  Assert.assertTrue(applicant2.isEligible() == true); //Peter is eligible
 }

}



Yo may also like:

Drools with Decision tables (Excel spreadsheet)
Drools example with spreadsheets

Labels:

Dec 13, 2012

Unit testing Spring MVC controllers for web and RESTful services with spring-test-mvc

As Web application and RESTful web services are very common in enterprise applications, it is imperative to unit test the controllers. There are a number of strategies to unit test your controllers in an MVC framework. For example, running an embedded web server like jetty, and then run the unit tests against the web server, etc. The spring-test-mvc project makes testing your Spring MVC controllers very easy without starting an embedded server. This blog post will take you through the key steps involved.


Step 1: You need to have the right third-party libraries. The key ones to take note are spring-test-mvc, spring-test, json-path, hamcrest-library, hamcrest-core, and mockito-core.

 
        <dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-core</artifactId>
   <scope>test</scope>
   <exclusions>
    <exclusion>
     <groupId>org.hamcrest</groupId>
     <artifactId>hamcrest-core</artifactId>
    </exclusion>
   </exclusions>
  </dependency>
  
  <dependency>
   <groupId>org.hamcrest</groupId>
   <artifactId>hamcrest-library</artifactId>
   <version>1.3</version>
  </dependency>
  
  <dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-mapper-asl</artifactId>
   <version>1.9.8</version>
   <scope>runtime</scope>
  </dependency>

  <dependency>
   <groupId>javax.xml.bind</groupId>
   <artifactId>jaxb-api</artifactId>
   <version>2.2.6</version>
   <scope>runtime</scope>
  </dependency>

  <!-- JSON XPATH library -->
  <dependency>
   <groupId>com.jayway.jsonpath</groupId>
   <artifactId>json-path</artifactId>
   <version>0.5.6</version>
  </dependency>
  
  <!-- spring -->
  
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>org.springframework.context</artifactId>
   <version>3.1.0.RELEASE</version>
   <exclusions>
    <!-- Exclude Commons Logging in favour of SLF4j -->
    <exclusion>
     <groupId>org.apache.commons</groupId>
     <artifactId>com.springsource.org.apache.commons.logging</artifactId>
    </exclusion>
   </exclusions>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-aop</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-aspects</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-beans</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>3.1.0.RELEASE</version>
   <exclusions>
    <exclusion>
     <artifactId>commons-logging</artifactId>
     <groupId>commons-logging</groupId>
    </exclusion>
   </exclusions>
  </dependency>
  
  <!-- for tspring testing -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-test</artifactId>
   <version>3.1.0.RELEASE</version>
  </dependency>
  
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-test-mvc</artifactId>
   <version>1.0.0.M1</version>
  </dependency>

  
  

Step 2: The next step is to define a Spring MVC controller that we will be writing unit test for.

 
package com.myapp.accounting.aes.securities.pricehistory.controller;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.security.authentication.LockedException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.myapp.accounting.securities.pricehistory.model.PriceHistory;
import com.myapp.accounting.securities.pricehistory.service.PriceHistoryService;
import com.myapp.accounting.dm.model.refdata.securities.MarketDataSecurityPriceHist;
 

 @Controller
public class PriceHistoryController {
 
    /**
     * Service for accessing the Market Data repository. Contains the business logic.
     */
    @Resource(name = "aes_priceHistoryService")
    private PriceHistoryService securityPriceService;


 @RequestMapping(value = "/pricehistory", 
                 method = RequestMethod.GET)
 @ResponseBody
 public List<MarketDataSecurityPriceHist> getPriceHistory(@RequestParam(value="latestUpdatedTimeStamp", required=true) @DateTimeFormat(pattern="dd MMM yyyy HH:mm:ss") Date latestUpdatedTimeStamp,
                                                     @RequestParam(value="maxRecords", required=false, defaultValue="100") int maxRecords) throws Exception 
 {  
     // call the business service
     PriceHistory result = securityPriceService.getPriceHistory(maxRecords, latestUpdatedTimeStamp);
      
     return result.getHistory();
 }
}


Step 3: The PriceHistory object that holds a list of "MarketDataSecurityPriceHist" objects.

 
package com.myapp.accounting.aes.securities.pricehistory.model;

import com.myapp.accounting.dm.model.refdata.securities.MarketDataSecurityPriceHist;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class PriceHistory implements Serializable
{
    private static final long serialVersionUID = 1L;
    

    private List<marketdatasecuritypricehist> history = new ArrayList<marketdatasecuritypricehist>();

    @XmlElementWrapper(name = "historicalprices")
    @XmlElement(name = "price")
    public List<marketdatasecuritypricehist> getHistory()
    {
        return history;
    }

 public void setHistory(List history) {
  this.history = history;
 }
}


Step 4: Define the MarketDataSecurityPriceHist class that holds the relevant attributes.

 
package com.myapp.accounting.dm.model.refdata.securities;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

import javax.persistence.Entity;
import javax.xml.bind.annotation.XmlElement;

@Entity //persistence entity
public class MarketDataSecurityPriceHist implements Serializable 
{
 private static final long serialVersionUID = 1444498748039607997L;

    private String securityCd;
    private Date priceDttm;
    private BigDecimal bidPrice;
    private BigDecimal closePrice;
    private BigDecimal lastPrice;
    private BigDecimal askPrice;
    private String lastUpdatedAction;
    private String LastUpdatedDetailUser;
    private Date lastUpdatedTimeStamp;
    private Date loadTimeStamp;
    private String pricecondition;
    private String recordType;
    private String priceTime;
    private String source;
    
 public MarketDataSecurityPriceHist()  {}

 @XmlElement
 public String getSecurityCd() 
 {
  return securityCd;
 }

 public void setSecurityCd(String securityCd) 
 {
  this.securityCd = securityCd;
 }

 @XmlElement
 public Date getPriceDttm() {
  return priceDttm;
 }

 public void setPriceDttm(Date priceDttm) {
  this.priceDttm = priceDttm;
 }
 
 @XmlElement
 public BigDecimal getBidPrice() {
  return bidPrice;
 }

 public void setBidPrice(BigDecimal bidPrice) {
  this.bidPrice = bidPrice;
 }

 //other setters and getters are omitted 
}


Step 5: Finally, and most importantly the unit test class that uses mockito to mock the PriceHistoryService implementation and spring-test-mvc to mock the controller that returns a json response.

 
package com.myapp.accounting.aes.securities.pricehistory;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.server.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.server.setup.MockMvcBuilders.standaloneSetup;
import static org.springframework.test.web.server.result.MockMvcResultMatchers.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.http.MediaType;

import com.myapp.accounting.aes.securities.pricehistory.controller.PriceHistoryController;
import com.myapp.accounting.aes.securities.pricehistory.model.PriceHistory;
import com.myapp.accounting.aes.securities.pricehistory.service.PriceHistoryService;
import com.myapp.accounting.aes.securities.pricehistory.service.impl.PriceHistoryServiceImpl;
import com.myapp.accounting.dm.model.refdata.securities.MarketDataSecurityPriceHist;

public class PriceHistoryController2Test {

 private PriceHistoryService mockSecurityPriceService;
 private PriceHistoryController controller;

 @Before
 public void setup() {
  controller = new PriceHistoryController();
  mockSecurityPriceService = mock(PriceHistoryServiceImpl.class);
  controller.setSecurityPriceService(mockSecurityPriceService);
 }

 @Test
 public void getPriceHistory() throws Exception {

  when(
    mockSecurityPriceService.getPriceHistory(
      (Integer) Mockito.any(), (Date) Mockito.any()))
    .thenReturn(getPriceHistoryTestData());

  standaloneSetup(controller)
    .build()
    .perform(
      get(
        "/pricehistory?latestUpdatedTimeStamp=26 Jul 211 12:00:00&maxRecords=3000")
        .accept(MediaType.APPLICATION_JSON))
    .andExpect(status().isOk())
    .andExpect(content().type("application/json"))
    .andExpect(jsonPath("$.[0].securityCd").value("test"))
    .andExpect(jsonPath("$.[0].bidPrice").value(12.50))
          .andExpect(jsonPath("$.[0].closePrice").value(12.50));
         
 }

 //mock data that gets returned when getPriceHistory(...) method is called
 private static PriceHistory getPriceHistoryTestData() {

  PriceHistory ph = new PriceHistory();
  List<marketdatasecuritypricehist> history = new ArrayList<marketdatasecuritypricehist>();
  MarketDataSecurityPriceHist md = new MarketDataSecurityPriceHist();
  md.setSecurityCd("test");
  BigDecimal price = new BigDecimal("12.50");
  md.setAskPrice(price);
  md.setBidPrice(price);
  md.setClosePrice(price);
  md.setLastUpdatedAction("SOME_ACTION");
  md.setRecordType("RECORD_TYPE");
  md.setLastUpdatedDetailUser("tesr");
  Calendar cal = Calendar.getInstance();
  cal.set(2010, 01, 01, 00, 00, 00);
  Date date = cal.getTime();
  md.setLastUpdatedTimeStamp(date);
  md.setPriceDttm(date);
  System.out.println(date);
  
  history.add(md);
  ph.setHistory(history);

  return ph;
 }

}

That's all to it for testing an MVC controller. The URL for above JSON RESTful web service will be something like

 
http://localhost:8080/accounting-server/securities/pricehistory?latestUpdatedTimeStamp=26+Jul+2010+12:00:00&maxRecords=3000

and the JSON data returned will be something like

 
[{"securityCd":"XX123","priceDttm":"2012-01-28","bidPrice":125.50,"closePrice":126.60,"lastPrice":124.50,"askPrice":123.80,"lastUpdatedAction":"NO ACTION","lastUpdatedTimeStamp":1327705288015,"loadTimeStamp":88150,"pricecondition":"NO_CONDITION","recordType":null,"priceTime":"10:01:28.150 AM","source":"HiPort","lastUpdatedDetailUser":"arul"},
{"securityCd":"YY321","priceDttm":"2012-01-28","bidPrice":125.50,"closePrice":126.60,"lastPrice":124.50,"askPrice":123.80,"lastUpdatedAction":"NO ACTION","lastUpdatedTimeStamp":1327705288015,"loadTimeStamp":88150,"pricecondition":"NO_CONDITION","recordType":null,"priceTime":"10:01:28.150 AM","source":"HiPort","lastUpdatedDetailUser":"arul"}]




Labels: , ,

Dec 6, 2012

JDBC Interview Questions and Answers with code examples

The JDBC questions and answers covered here are an extension to the frequently asked questions covered in "Java/J2EE Job Interview Companion" book. The questions discussed below are generally asked in online JEE technical tests.

Q. What will be the out put in the following scenario where the table "Course" has the following records



and the code that is used to access the database is as follows.


    public void executeSelectQuery(Connection con) {
  PreparedStatement ps = null;
  
  try {
   ps = con.prepareStatement("SELECT COURSE_ID, NAME, COURSE  FROM COURSE");
   ResultSet rs = ps.executeQuery(); // read from database
   
   rs.absolute(0); //moves the cursor to the given row number
   
   rs.relative(2); //moves the cursor by 2 rows
   
   
   while(rs.next()){
    Integer id = rs.getInt("COURSE_ID");
    String name = rs.getString("NAME");
    String course = rs.getString("COURSE");
    System.out.println("id:" + id + ", name:" + name + ", course:" + course);
   }
   
  }
  catch (Exception e) {
   System.out.println("ERROR executing query: ");
   e.printStackTrace();
  }
  finally{
   try {
    ps.close();
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }
 }
 




A. The above code should thrown an exception "java.sql.SQLFeatureNotSupportedException: feature not supported".

The cause for this exception is in line where you prepare a statement. You are basically creating a cursor here.

ps = con.prepareStatement("SELECT COURSE_ID, NAME, COURSE  FROM COURSE");

The above method by default values for the resultSetType and resultSetConcurrency.  So, the above line is equivalent to

ps = con.prepareStatement("SELECT COURSE_ID, NAME, COURSE  FROM COURSE", 
                                          ResultSet.TYPE_FORWARD_ONLY,                              ResultSet.CONCUR_READ_ONLY );


The JDBC API definitions for the  resultSetType and resultSetConcurrency are as follows

resultSetType 
  • TYPE_FORWARD_ONLY: The result set cannot be scrolled; its cursor moves forward only, from before the first row to after the last row. The rows contained in the result set depend on how the underlying database generates the results. That is, it contains the rows that satisfy the query at either the time the query is executed or as the rows are retrieved.
  • TYPE_SCROLL_INSENSITIVE: The result can be scrolled; its cursor can move both forward and backward relative to the current position, and it can move to an absolute position. The result set is insensitive to changes made to the underlying data source while it is open. It contains the rows that satisfy the query at either the time the query is executed or as the rows are retrieved.
  • TYPE_SCROLL_SENSITIVE: The result can be scrolled; its cursor can move both forward and backward relative to the current position, and it can move to an absolute position. The result set reflects changes made to the underlying data source while the result set remains open.
resultSetConcurrency 
  • CONCUR_READ_ONLY: The ResultSet object cannot be updated using the ResultSet interface.
  • CONCUR_UPDATABLE: The ResultSet object can be updated using the ResultSet interface.

Q. What will be the output for the following code snippet for the same "Course" table?

public void executeSelectQuery(Connection con) {
  PreparedStatement ps = null;
  
  try {
   ps = con.prepareStatement("SELECT COURSE_ID, NAME, COURSE  FROM COURSE", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
   ResultSet rs = ps.executeQuery(); // read from database
   
   rs.absolute(0); //moves the cursor to the given row number
   
   rs.relative(2); //moves the cursor by 2 rows
   
   
   while(rs.next()){
    Integer id = rs.getInt("COURSE_ID");
    String name = rs.getString("NAME");
    String course = rs.getString("COURSE");
    System.out.println("id:" + id + ", name:" + name + ", course:" + course);
   }
   
  }
  catch (Exception e) {
   System.out.println("ERROR executing query: ");
   e.printStackTrace();
  }
  finally{
   try {
    ps.close();
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }
 }


AResultSet.TYPE_SCROLL_INSENSITIVE type will allow the cursor to scroll forward or backward.

The output will be

id:3, name:paul, course:JSF
id:4, name:jonathan, course:Hibernate
id:5, name:james, course:Spring
id:6, name:Lewis, course:JDBC

The cursor will scroll to the first record when rs.absolute(0); is executed. It will scroll another 2 records when  rs.relative(2); is executed. When it gets to the while(rs.next()){ ...} loop it will start printing from third record onwards. You can practice different scenarios with the JDBC Tutorial.


Q. What is RowSet? What is the difference between RowSet and ResultSet? What are the advantages of using RowSet over ResultSet?

ARowSets are a JDBC 2.0 extension to the java.sql.ResultSet interface. Guess what, it makes life a lot easier for all JDBC programmers. No more Connection objects, statement objects, just a single RowSet will do everything for you. RowSet object follows the JavaBeans model for properties and event notification, it is a JavaBeans component that can be combined with other components in an application.

The ResultSet has an 'open connection' to the database whereas a RowSet works in a 'disconnected' fashion. It has the following advantages over a ResultSet.

  • Since a RowSet works in a disconnected mode, especially for "read-only" queries, it would have better performance in a highly concurrent system.
  • Rowsets have many different implementations to fill different needs. These implementations fall into two broad categories, rowsets that are connected and those that are disconnected. 
  • Rowsets make it easy to send tabular data over a network. They can also be used to provide scrollable result sets or updatable result sets in special cases when the underlying JDBC driver does not support them.

RowSet disadvantages.
  • Rowset keeps all the data from the query result in memory. This is very in-efficient for queries that return huge data.

There are 3 types of RowSets. The JdbcRowset 

JdbcRowSet is a connected type of rowset as it maintains a connection to the data source using a JDBC driver

JdbcRowSet jdbcRowSet = new JdbcRowSetImpl();
jdbcRowSet.setCommand("SELECT * FROM Course);
jdbcRowSet.setURL("jdbc:hsqldb:hsql://localhost/mytestdb");
jdbcRowSet.setUsername("sa");
jdbcRowSet.setPassword("pwd");
jdbcRowSet.execute(); 

CachedRowSet and WebRoeSet are disconnected types of rowsets as they are connected to the data source only when reading data from it or writing data to it.

ResultSet rs = stmt.executeQuery("SELECT * FROM Course");
CachedRowSet crset = new CachedRowSetImpl();
crset.populate(rs); 


WebRowSet wrs = new WebRowSetImpl();
wrs.populate(rs); 
wrs.absolute(2)
wrs.updateString(1, "JNDI");


Q. What is Metadata and why should you use it?
A. JDBC API has 2 Metadata interfaces -- DatabaseMetaData & ResultSetMetaData. The  meta data means data about data, and provides comprehensive information about the database as a whole. The implementation for this interface is implemented by database driver vendors to let users know the capabilities of a Database.

ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");  
ResultSetMetaData resultSetMeta = rs.getMetaData();  
int numberOfColumns = resultSetMeta.getColumnCount();  
boolean b = resultSetMeta.isSearchable(3);  


Q. What are database warnings and why do you need them?
A. Warnings are issued by a database to inform user of a problem which may not be very severe. Database warnings do not stop the execution of SQL statements. Warnings are silently chained to the object. You need warnings for the reporting purpose. Warnings may be retrieved from Connection, Statement, and ResultSet objects.

SQLWarning warning = conn.getWarnings();  
QLWarning nextWarning = warning.getNextWarning();   
conn.clearWarnings();  
...
stmt.getWarnings();  
stmt.clearWarnings();  
...
rs.getWarnings();  
...


Labels: