Google

Mar 28, 2013

Apache Camel asynchronous processing unit testing

In the previous post entitled Apache Camel for asynchronous processing demonstrates the power of Apache camel. In this post, I will provide a sample code that unit tests the Apache camel.

package com.myapp.camel;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import com.myapp.config.MyappConfig;
import com.myapp.model.FeedGenerationRequest;
import com.myapp.model.JobType;
import com.myapp.service.MyappService;

import java.util.ArrayList;
import java.util.List;

import org.apache.camel.CamelContext;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spring.javaconfig.CamelConfiguration;
import org.apache.camel.spring.javaconfig.test.JavaConfigContextLoader;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;

@ContextConfiguration(
        locations =
        {
            "com.myapp.camel.JobHandlingRouteBuilderTest$ContextConfig"
        },
        loader = JavaConfigContextLoader.class)
public class JobHandlingRouteBuilderTest extends AbstractJUnit4SpringContextTests
{
    
    @Produce(uri = DIRECT_START)
    private ProducerTemplate template;
    
    private static final String DIRECT_START = "direct:start";
    
    @Mock
    FeedGenerationRequest request;
    
    private static MyappService MyappService = mock(MyappService.class);
    
    @Before
    public void setUp()
    {
        MockitoAnnotations.initMocks(this);
    }
    
    @Test
    @Ignore
    public void testConfigureJobHandlingRoute() throws Exception
    {
        template.sendBodyAndHeader(request,
                JobHandlingRouteBuilder.JOB_TYPE_HEADER, JobType.FEED_GENERATION);
        Thread.sleep(1000);
        verify(MyappService, times(1)).produceGroupLevelCashFeed(any(FeedGenerationRequest.class));
        verify(MyappService, times(1)).produceGroupLevelPositionFeed(any(FeedGenerationRequest.class));
    }
    
    @Test
    @Ignore
    public void testConfigureJobHandlingRouteOnFailure() throws Exception
    {
        doThrow(new Exception()).when(MyappService).produceGroupLevelCashFeed(any(FeedGenerationRequest.class));
        template.sendBodyAndHeader(request,
                JobHandlingRouteBuilder.JOB_TYPE_HEADER, JobType.FEED_GENERATION);
        Thread.sleep(1000);
        verify(MyappService, times(1)).markControllableJobFailed(any(FeedGenerationRequest.class),
                any(String.class));
    }
    
    @Configuration
    @Import(
    {
        MyappConfig.class
    })
    public static class ContextConfig extends CamelConfiguration
    {
        @Bean
        public MyappService myappService()
        {
            return MyappService;
        }
        
        private MyappConfig MyappConfig;
        
        @Autowired
        public void setMyappConfig(MyappConfig MyappConfig)
        {
            this.MyappConfig = MyappConfig;
        }
        
        @Bean
        public RouteBuilder route()
        {
            return new RouteBuilder()
            {
                @Override
                public void configure()
                {
                    from(DIRECT_START)
                            .to(JobHandlingRouteBuilder.JOB_QUEUE);
                }
            };
        }
        
        @Override
        public List<routebuilder> routes()
        {
            List<routebuilder> routes = new ArrayList<routebuilder>();
            MyappConfig.setCamelContext(mock(CamelContext.class));
            routes.add(MyappConfig.jobHandlingRouteBuilder());
            routes.add(route());
            return routes;
        }
        
    }
    
}



The MyappConfig class will be as shown below.

package com.myapp.config;

import com.myapp.camel.JobHandlingRouteBuilder;
import com.myapp.service.MyappForecastService;

import javax.annotation.Resource;

import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MyappConfig implements CamelContextAware
{
    
    private CamelContext context;
    
    @Resource(name = "myappService")
    private MyappService myappService;
    
    @Bean
    public ProducerTemplate template()
    {
        if (context != null)
        {
            return context.createProducerTemplate();
        }
        //For unit tests
        else
        {
            return null;
        }
    }
    
    @Bean
    public RouteBuilder jobHandlingRouteBuilder()
    {
        return new JobHandlingRouteBuilder(cashForecastService);
    }
    
    @Override
    public void setCamelContext(CamelContext camelContext)
    {
        context = camelContext;
    }
    
    @Override
    public CamelContext getCamelContext()
    {
        return context;
    }
    
}



Labels: , , ,

Mar 26, 2013

RUP Interview Questions and Answers -- overview

Q: What is RUP?
A: Rational Unified Process (RUP) is a general framework that can be used to describe a development process. The software development cycle has got 4 phases in the following order Inception, Elaboration, Construction, and Transition


The core of the phases is state-based, and the state is determined by what fundamental questions you are trying to answer:

Inception - During the inception phase, you work out the business case for the project. You also will be making a rough cost estimate and return on investment. You should also outline the scope and size of the project.

What key question do you ask at the end of this phase? Do you and the customer have a shared understanding of the system?

--> Elaboration - At this stage you have the go ahead of the project, however only have vague requirements. So, at this stage, you need to get a better understanding of the problem. Some of the steps involved are:
  • What is it you are actually going to build?
  • How are you going to build it?
  • What technology are you going to use? 
  • Gather requirement risks, technological risks, skill risks, political risks etc.
  • Develop a domain model, use case model and a design model. The UML techniques can be used for the model diagrams (e.g. class diagrams, sequence diagrams etc).
An important result of the elaboration phase is that you have a baseline architecture. This architecture consists of:
  • A list of use cases depicting the requirements.
  • The domain model, which captures your understanding of the domain with the help of the class diagrams.
  • Selection of key implementation technology and how they fit together. For example: Java/JEE with Spring, JSF, Hibernate, XML, etc.

What key question do you ask at the end of this phase? Do you have a baseline architecture to be able to build the system?

Construction - In this phase, you will be building the system in a series of iterations. Each iteration is a mini project. You will be performing analysis, detailed design, unit testing, coding, system testing, and integration testing for the use cases assigned to each iteration. The iterations within the construction phase are incremental and iterative. Each iteration builds on the use cases developed in the previous iterations. The each iteration will involve code rewrite, refactoring, use of design patterns, etc.

The basic documentation required during the construction phase is:
  • A class diagram and a sequence diagram.
  • Some text to pull the diagrams together.
  • If a class has complex life cycle behavior then a state diagram is required. 
  • If a class has a complex computation then an activity diagram is required. 


The fundamental question you ask at the end of this phase:  do you have a developed product?

Transition - During this phase, you will be delivering the finished code regularly. During this phase there is no coding to add functionality unless it is small and essential. There will be bug fixes, code optimization, etc during this phase. An example of a transition phase is that the time between the beta release and the final release of a product. The hand over documentation and training manuals need to be produced.


What key question do you ask at the end of this phase? Has the customer taken ownership of the developed product or system?
Q. What are the key underlying principles of RUP?
A. RUP is based on a few important philosophies and principles:
  • A software project team should plan ahead.
  • It should know where it is going.
  • It should capture project knowledge in a storable and extensible form.
The best practices of RUP involve the following major 5 properties:
  • Use case driven: Interaction between the users and the system. 
  • Architecture centricbased on architecture with clear relationships between architectural components.
  • Iterative: the problem and the solution are divided into more manageable smaller pieces, where each iteration will be addressing one of those pieces. 
  • Incremental: each iteration builds incrementally on the foundation built in the previous iteration. 
  • Controlledwith respect to process means you always know what to do next; control with respect to management means that all deliverables, artifacts, and code are under configuration management. 

Q: Why is UML diagrams important? 
A: The more complicated the underlying system, the more critical the communication among everyone involved in developing and deploying the software. UML is a software blueprint language for analysts, designers and developers. UML provides a common vocabulary for the business analysts, architects, developers etc. 

UML is applicable to the Object Oriented problem solving. UML begins with a model; A model is an abstraction of the underlying problem. The domain is the actual world from which the problem comes. The model consists of objects. The objects interact with each other by sending and receiving messages. The objects are characterized by attributes and operations (behaviors). The values of an object’s attributes determine its state. The classes are the blueprints (or like templates) for objects. A class wraps attributes and methods into a single distinct entity. The objects are the instances of classes.

Q: Where can you use RUP? 
A: Principles of RUP can also be used as an agile (i.e. lightweight) process for smaller teams of 20-30 people, or as a heavy weight process for larger teams of 50-100 people. Extreme Programming (XP) can be considered as a subset of RUP. The agile (i.e lightweight) software development process is more popular across organizations. Several methodologies fit under this agile development methodology banner. All these methodologies share many characteristics like iterative and incremental development, test driven development, daily stand up meetings to improve communication, automatic testing, build and continuous integration of code, etc. The best software development process is what works best for your organization. Organizations that are still using the waterfall approach make use of some of the agile practices like stand up meetings to improve communication, automatic testing, build and continuous integration of code, etc.
Many organizations make use of the hybrid approach by cherry picking the practices that work well for them. It basically requires the right processes, tools, and culture in place to build quality software by managing complexities more effectively NOT just efficiently. There is a big difference between being efficient and effective.
  • Being efficient is the process of staying busy without idle moments -- e.g. working overtime, throwing more resources, etc.
  • Being effective is the process of producing the maximum results in the minimum time, with the minimum effort -- e.g. having the right people, process, and the culture.
 So, if you see that the software development process can be improved in your organization, take the initiative to drive the necessary changes. Become a change agent by championing "environment improvement" or "process improvement" programs.

Organizations that are passionate about their agile development process may grill you on this very topic. Here are some external links that I found useful.






Labels: ,

Mar 22, 2013

Java design pattern interview questions and answers: strategy and factory pattern

Design pattern questions are very popular with the job interviewers, and this post covers Java strategy and factory design pattern in a tutorial style. This blog takes you through a scenario where you will be learning 4 key things.

1. Factory design pattern
2. Strategy design pattern
3. Applying logic to calculate variance
4. Making use of the BigDecimal class for the financial calculations. The floating point variables must not be used as they can cause rounding issues.

Q. The scenario is narrated with the diagram below. It is financial application where an investor builds portfolio by buying and selling managed funds and listed securities.



The additional business rules are:

1. The managed funds that are not of type daily, must be funded from the available cash. Which means, you cannot use the proceeds you receive from selling managed funds or listed securities.

2. The daily managed funds and listed securities can be switched. This means you sell some daily managed funds to buy some listed securities.

3. The variance is calculated as total sell amount - total buy amount. The funded from cash amount also needs to be calculated to show the investor.

Let's look at the code samples:


Step 1: Define the InvestmentDetail value object (i.e. a POJO) that defines each investment  detail as shown above.

import java.math.BigDecimal;

public class InvestmentDetail {
 
 enum TRADE_TYPE {BUY, SELL};
 enum FUND_TYPE {MONTHLY, DAILY, NOT_APPLICABLE}
 
 private String investmentCode;
 private String investmentName;
 private TRADE_TYPE tradeType;
 private FUND_TYPE fundType;
 private BigDecimal orderAmount;
 
 public InvestmentDetail(String investmentCode, String investmentName, 
                   TRADE_TYPE tradeType, FUND_TYPE fundType, BigDecimal orderAmount) {
  this.investmentCode = investmentCode;
  this.investmentName = investmentName;
  this.tradeType = tradeType;
  this.fundType = fundType;
  this.orderAmount = orderAmount;
 }
 
 public boolean isDailyManagedFund() {
  return fundType != null && fundType == FUND_TYPE.DAILY;
 }
 
 public boolean isMonthlyManagedFund() {
  if(fundType == null  ) {
   throw new IllegalArgumentException("fundType cannot be null");
  }
  return fundType == FUND_TYPE.MONTHLY;
 }
 
 public boolean isListedSecurity() {
  return fundType != null && fundType == FUND_TYPE.NOT_APPLICABLE;
 }
 
 public boolean isBuy() {
  if(tradeType == null  ) {
   throw new IllegalArgumentException("tradeType cannot be null");
  }
  return tradeType == TRADE_TYPE.BUY;
 }
 
 public boolean isSell() {
  if(tradeType == null  ) {
   throw new IllegalArgumentException("tradeType cannot be null");
  }
  return tradeType == TRADE_TYPE.SELL;
 }

 public BigDecimal getOrderAmount() {
  return orderAmount;
 }
 
 //setters, getters, equals(), hashCode(), and toString() omitted for brevity
}

Step 2: The CashVariance value object (i.e. a POJO) for storing the calculated values like funded from cash and proceed to cash amounts and the variance is derived from these two amounts.

import java.math.BigDecimal;


public class CashVariance {

 BigDecimal fundedFromCash;
 BigDecimal proceedsToCash;
 
 public CashVariance(BigDecimal fundedFromCash, BigDecimal proceedsToCash) {
  super();
  this.fundedFromCash = fundedFromCash;
  this.proceedsToCash = proceedsToCash;
 }

 public BigDecimal getVariance() {
  return this.proceedsToCash.subtract(this.fundedFromCash);
 }
 
 public void setFundedFromCash(BigDecimal fundedFromCash) {
  this.fundedFromCash = fundedFromCash;
 }

 public void setProceedsToCash(BigDecimal proceedsToCash) {
  this.proceedsToCash = proceedsToCash;
 }

 public String toString() {
  StringBuilder buffer = new StringBuilder();
  buffer.append("fromCash:").append(this.fundedFromCash);
  buffer.append("|toCash:").append(this.proceedsToCash);
  buffer.append("|variance:").append(getVariance());
  return buffer.toString();
 }
 
 //getters, equals(), and hashCode()omitted for brevity
}


Step 3: Define a factory class that decides which cash variance calculation strategy to use depending on the product type.

//cannot be extended as it is final
public final class VarianceCalculationFactory {
 
 //can't instantiate from outside
 private VarianceCalculationFactory(){}
 
 //factory that creates and return a relevant strategy
 public static CashVarianceCalculationStrategy getCashVarianceStrategy(String productType) {
  if(productType != null ) {
   return new SpecificCashVarianceCalculationStrategy();
  }
  else {
   return new DefaultCashVarianceCalculationStrategy();
  }
 }

}


Q. Why use a factory design pattern?
A.
Factory pattern returns an instance of several subclasses (like DefaultCashVarianceCalculationStrategy, ManagedInvestmentsCashVarianceCalculationStrategy, etc), but the calling code is unaware of the actual implementation class. The calling code invokes the method on the interface for example CashVarianceCalculationStrategy and using polymorphism the relevant class and correct method gets invoked. So, as you can see, the factory pattern reduces the coupling or the dependencies between the calling code and called objects like DefaultCashVarianceCalculationStrategy, ManagedInvestmentsCashVarianceCalculationStrategy, etc. This is a very powerful and common feature in many frameworks.  You do not have to create a new DefaultCashVarianceCalculationStrategy or a new ManagedInvestmentsCashVarianceCalculationStrategy on each invocation. In future, to conserve memory, you can decide to cache objects or reuse objects in your factory with no changes required to your calling code. You can also load objects in your factory based on attribute(s) read from an external properties file or some other condition. Another benefit going for the factory is that unlike calling constructors directly, factory patterns have more meaningful names like getShape(…), getInstance(…), getStrategy(…) etc, which may make calling code much clear. 



Step 4: Define an interface each strategy class will be implementing.

import java.util.List;

//strategy pattern interface
public interface CashVarianceCalculationStrategy {
 CashVariance calculate (List<InvestmentDetail> investments);
}


Step 5: This is the default implementation of the above interface, and the class that is responsible for calculating the funded from cash and proceed to cash values.




import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;

public class DefaultCashVarianceCalculationStrategy implements CashVarianceCalculationStrategy {

 @Override
 public CashVariance calculate(List<InvestmentDetail> investments) {
  //input validation
  if(investments == null){
   throw new IllegalArgumentException("No investments founds!!!");
  }
  
  List<BigDecimal> buys = new LinkedList<BigDecimal>();
     List<BigDecimal> sells = new LinkedList<BigDecimal>(); 
     List<BigDecimal> switchables = new LinkedList<BigDecimal>(); //pay for buys from the sells
  
  for (InvestmentDetail detail : investments) {
   if(detail.isBuy()){
    processBuy(detail, buys, switchables);
   }
   else if(detail.isSell()){
    processSell(detail, sells, switchables); 
   }
  }
  
  CashVariance variance = calculateVariance(buys, sells, switchables);
  
  return variance;
 }

 private void processSell(InvestmentDetail detail, List<BigDecimal> sells, List<BigDecimal> switchables) {
  if(isSwitch(detail)){
   switchables.add(detail.getOrderAmount()); //+ve amount
  }
  else{
   sells.add(detail.getOrderAmount());
  }
  
 }

 private void processBuy(InvestmentDetail detail, List<BigDecimal> buys, List<BigDecimal> switchables) {
  if(isSwitch(detail)){
   switchables.add(detail.getOrderAmount().negate());  //-ve amount
  }
  else{
   buys.add(detail.getOrderAmount());
  }
  
 }

 //protected so that it can be overridden by another strategy
 protected boolean isSwitch(InvestmentDetail detail){
  return detail != null && (detail.isDailyManagedFund() || detail.isListedSecurity()); //return false if it is a monthly managed fund
                                                                                       //This has to be funded from cash.
 }
 
 protected CashVariance calculateVariance(List<BigDecimal> buys, List<BigDecimal> sells, List<BigDecimal> switchables) {
  BigDecimal switchedSum = sumAll(switchables);
  BigDecimal fundedFromCash = calculateFundedFromCash(buys, switchedSum);
  BigDecimal proceedsToCash = calculateProceedsToCash(sells, switchedSum);
  
  return new CashVariance(fundedFromCash, proceedsToCash);
 }
 
 private BigDecimal calculateFundedFromCash(List<BigDecimal> buys, BigDecimal switchedSum) {
  BigDecimal buysSum = sumAll(buys);
  //if switchedSum has more buy amount (i.e negative) add the switchedSum to buy
  return buysSum.add((switchedSum.signum() == -1) ? switchedSum.abs() : BigDecimal.ZERO);
 }

 private BigDecimal calculateProceedsToCash(List<BigDecimal> sells, BigDecimal switchedSum) {
  BigDecimal sellsSum = sumAll(sells);
  //if switchedSum has more sell amount (i.e positive) add the switchedSum to sell 
  return sellsSum.add((switchedSum.signum() == 1) ? switchedSum : BigDecimal.ZERO);
 }

 
 private BigDecimal sumAll(List<BigDecimal> values) {
  BigDecimal total = BigDecimal.ZERO;
  for (BigDecimal val : values) {
   total = total.add(val);
  }
  return total;
 } 

}

Q. Why use a strategy design pattern?
A.  A strategy design pattern allows you to choose different algorithms at run time depending certain run time conditions like product type. Different algorithms can be isolated in different implementation classes that implement the same interface. Different client classes or invokees can execute different strategies (i.e. algorithms).

Step 6: Finally, the tester class that demonstrates the  above scenario by constructing investment details and calculating the variance as shown below.


import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;

public class VarianceCalcTester {

 public static void main(String[] args) {
  InvestmentDetail ab0001 = new InvestmentDetail("AB0001", "AB Manged Fund", 
                                          InvestmentDetail.TRADE_TYPE.BUY, InvestmentDetail.FUND_TYPE.MONTHLY, 
                                          new BigDecimal("2500.00"));
  
  InvestmentDetail cx0002 = new InvestmentDetail("CX0002", "CX Managed Fund", 
                InvestmentDetail.TRADE_TYPE.BUY, InvestmentDetail.FUND_TYPE.DAILY, 
                new BigDecimal("4500.00"));
  
  InvestmentDetail by007 = new InvestmentDetail("BY007", "BY Managed Fund", 
                InvestmentDetail.TRADE_TYPE.BUY, InvestmentDetail.FUND_TYPE.DAILY, 
                new BigDecimal("2000.00"));
  
  
  InvestmentDetail sh0008 = new InvestmentDetail("SH0008", "BY Managed Fund", 
                InvestmentDetail.TRADE_TYPE.SELL, InvestmentDetail.FUND_TYPE.NOT_APPLICABLE, 
                new BigDecimal("8000.00"));
  
  List<InvestmentDetail> investments = new LinkedList<InvestmentDetail>();
  
  investments.add(ab0001);
  investments.add(cx0002);
  investments.add(by007);
  investments.add(sh0008);
  
  
  //get the variance calculation strategy from the factory

  CashVarianceCalculationStrategy cvCalcStaregy = VarianceCalculationFactory.getCashVarianceStrategy(null); // return the default strategy
  
  CashVariance cv = cvCalcStaregy.calculate(investments);
  
  
  System.out.println(cv); // -ve variance Debit  and +ve variance Credit
 }
}


Labels:

Mar 21, 2013

Agile software development methodology questions and answers

Agile Development Interview Questions and Answers

Agile Development methodology Q1 - Q6 Agile Development methodology Q7 - Q16 Agile methodology: theme, epic and user story Pros and cons of agile development methodology and principles


More and more organizations are becoming agile, and it pays to have some understanding of the agile development methodology.

Q. What are the typical roles and responsibilities of an agile core team?
A.
  • The Product Owner represents the stakeholders and is the voice of the customer. He or she is accountable for ensuring that the team delivers value to the business. The Product owner writes typically the user stories, prioritizes them, and adds them to the product backlog. Scrum teams should have one Product Owner.
  • The Development Team is responsible for delivering potentially shippable product in increments at the end of each Sprint. A Development Team is made up of 3–9 people with cross-functional skills who do the actual work (analyze, design, develop, test, technical communication, document, etc.). The development team consisting of developers, testers, operations staff, etc define  the definition of "Done", which includes non-functional requirements like security, performance, cross browser compatibility testing, etc. Generally, you will have the doers and the helpers in the development team. The Development Team in Scrum is self-organizing, even though they may interface with project management organizations (PMOs).
  • Scrum Master Scrum is a facilitator, and is accountable for removing impediments to the ability of the team to deliver the sprint goal/deliverables. The Scrum Master is not the team leader, but acts as a buffer between the team and any distracting influences. The Scrum Master ensures that the Scrum process is used as intended. The Scrum Master is the enforcer of rules. A product manager cannot be the scrum master.


Q. What do you understand by the terms epic and user story?
A. An agile Epic is a group of related user stories. For example, an online shopping cart app will have epics like user administration, product management, and shopping experience. An epic will have a number of broken down user stories. For example, the "user administration" epic can be broken down into user stories like "add. modify, and delete user", "manage user passwords", "generate raw data downloads", "generate aesthetically pleasing reports", etc. Hence, a user story is an Independent, Negotiable, Valuable, Estimatable, Small, Testable requirement (“INVEST Acronym”). User stories are great for Development Teams and Product Managers as they are easy to understand, discuss and prioritize – they are more commonly used at sprint level on the wall. User stories will often be broken down into tasks during the Sprint Planning Process – that is unless the stories are small enough to consume on their own.


So, an epic will have one to many user stories, and each user story can have  zero to many tasks.


Q. Can you given an example of a user story?
A. The user stories are in the format of

"As Who I want What so that Why"

Here is an example.

"As an Investment Manager I want to be able to view client account balances, so that I can make informed investment decisions. "

"As a support staff I want the system to allow me run multiple searches at the same time, so that I can do my job faster. "


Q. What do you understand by the term "Condition Of Satisfaction (aka COS)"?
A. For each story, the business user, analyst, owner, or stake holder will define the "condition of satisfaction (COS)" criteria to satisfy that particular story. You can also think of it as an "acceptance criteria".  A Conditions of Satisfaction questions the User Story, and encourages conversation between the Product Owner and the team. A good way of gathering COS is asking questions such as:

    •    ‘What if … ?’,
    •    ‘Where …?’,
    •    ‘When …?’,
    •    ‘How …?’.

The test cases will be written by the testers and development tasks will be carried out by the developers to satisfy the COS. To be accepted, the development task should also satisfy other non functional tasks like writing unit tests, continuous integration and build, security, performance, data archival, etc. The story will also have to be fully tested. For example, COS will look like
  • A search functionality to be able to search clients by client code.
  • Display the client list sorted in alphabetical order.
  • Ability to click on a particular client to display his or her account balances.
  • The account balances need to be sorted by account type.
  • ....and so on including non functional requirements as well.

Q. How do you estimate development and testing effort of a user story?
A. Agile projects normally have a number of sprints to finish the user stories. Each sprint will be of 2-3 weeks. One or more user stories are allocated to each sprint. The developers and testers will estimate on it to have story developed and fully tested to satisfy the COS. If a story is big enough so that cannot be completed within a sprint (i.e. in 2 weeks), that particular sub story can be split further into 2 or more stories.



The stories are estimated by allocating points. It is known as the "velocity points". The velocity points are allocated to each story. Stories are tagged like T-shirt sizes -- Small, Medium, Large, and Extra Large, etc. Each of these sizes are allocated velocity points using the Fibonacci series values. For example,  3, 5,  8 and 13. Where Small is given 3 points, Medium is given 5 points, Large is given 8 points, and extra large is given 13 points. A the end of each sprint, the velocity points for all the user stories are added and reported to the management in a "showcase" to monitor progress. The points play(i.e. the user stories that are not completed within this sprint) that are added to the next sprint.




In the diagram above, you can see "commitment" and the "completed".

Q. What are some of the key featues and objectives of the daily stand-ups?
A.

Daily Stand-ups are named literally after the way the meeting is conduced -- i.e. while standing up. This method helps ensure the meetings remain time-boxed to 15 minutes and not dragged on.

The general features are:
  • It is a ritual that happens at the same time, in the same location, every day.
  • The meeting is led by the Scrum Master, who keeps all attendees focused on answering the following key questions to meet the project objectives.

  1. What have I achieved since the last Stand-up?
  2. What do I intend to do before the next Stand-up?
  3. What are my impediments to making progress?
Here is the picture of user stories stuck to a board, and this where the daily "stand ups" or "scrum sessions" take place.



Labels:

Mar 19, 2013

Power of HTML, CSS and jQuery -- collapsible CSS Table

It’s generally recommended you ensure the vast majority of your web page content is immediately visible when someone accesses it – but there are exceptions where you would want to display only the summarized view to not clutter up the page and expand to the details as and when required by clicking on a button or an icon. Here is a very simple tutorial on HTML, CSS, and jQuery that shows how to create a collapsible table. The following code snippet has embedded CSS with the style tag and jQuery with the script tag. The HTML defines the DOM (Document Object Model) structure. The CSS is used to hide and unhide the relevant rows. The jQuery is used to add and remove CSS styles.


Try using this example on Firefox with Firbug turned on or on Goggle chrome with the dEV tools turned on with the "F12" function key. This will enable you to inspect the HTML elements and the styles.

<!DOCTYPE html>
<html>
<head>
    <title></title>

    <script src="http://code.jquery.com/jquery-1.8.3.js"></script>

</head>
<body>

<h1>demo for hiding and unhiding table rows </h1>

<button id="myappSummaryCollapse">
    <span class="collapse">Collapse</span>
    <span class="expand">Expand</span>
</button>

<table class="collapsible">
    <tr class="collapsible"><td>collapsible row</td></tr>
    <tr><td>not collapsible row</td></tr>
</table>


<script>

    jQuery('#myappSummaryCollapse').click(function () {
        var button = jQuery(this);
        var tables = jQuery('table.collapsible');

        if (button.hasClass('collapsed')) {
            button.removeClass('collapsed');
            for (var i = 0; i < tables.length; i++) {
                jQuery(tables[i]).removeClass('collapsed');
            }
        } else {
            button.addClass('collapsed');
            for (var i = 0; i < tables.length; i++) {
                jQuery(tables[i]).addClass('collapsed');
            }
        }
    });

</script>



<style>

    #myappSummaryCollapse .expand,
    #myappSummaryCollapse.collapsed .collapse,
    table.collapsed tr.collapsible {
        display: none;
    }

    #myappSummaryCollapse.collapsed .expand {
        display: inline;
    }

</style>


</body>
</html>


Very often, simple examples like the one above can clarify things to go on and do more complex scenarios. In the CSS, #myappSummaryCollapse is the element id and ".expand" is the style class name. "display:none" is used to hide and "display:inline" is used to display. The jQuery is used to add and remove the CSS classes.


Similar results can be achieved using JavaScript directly as shown below.

document.getElementById("p2").style.color="blue";


or

<button onclick="document.getElementById('id1').style.color='red'" type="button">
</button>



But, jQuery selectors are very powerful and let you achieve similar results with less code.

Labels: , ,

Mar 15, 2013

Spring MVC Test -- Testing the Spring MVC Controllers

In the previous post entitled "Unit testing Spring MVC controllers for web and RESTful services with spring-test-mvc" I covered examples for an HTTP get. In this post, I will show an example of testing an HTTP POST that takes "JSON data" as the body. Here is the code snippet.

public class MyAppControllerTest {

 private MyAppService mockMyAppService;
 private MyAppController controller;

 @Before
 public void setup() {
   controller = new MyAppController();
   mockMyAppService = mock(MyAppServiceImpl.class);
   controller.setMyAppService(mockMyAppService);
 }
 
 @Test
 public void testAddOrModifyAdjustment() throws Exception {
     //mock the service call within the controller.
  when(mockMyAppService.addOrModifyAdjustment((MyAppDetail) Mockito.any())).thenReturn(getMyAppDetail());

  standaloneSetup(controller)
    .build()
    .perform(
      MockMvcRequestBuilders.post("/addOrModifyAdjustment").contentType(MediaType.APPLICATION_JSON)
        .body(getAdjustmentDetailJsonString().getBytes()).accept(MediaType.APPLICATION_JSON))
    .andExpect(status().isOk()).andExpect(content().type("application/json"))
    .andExpect(jsonPath("MyAppId").value(874))
    .andExpect(jsonPath("MyAppDetailId").value(48515))
    .andExpect(jsonPath("portfolioCd").value("3927"))
    .andExpect(jsonPath("txnCd").value("ADJUSTMNT"))
    .andExpect(jsonPath("txnTypeCd").value("59"))
    .andExpect(jsonPath("txnTypeDesc").value("PURCHASE"))
    .andExpect(jsonPath("cashValue").value(1100000.02))
    .andExpect(jsonPath("sourceUnits").value(200.00))
    
 }

 private String getAdjustmentDetailJsonString(){
  String jsonStr =
  "{\r\n" + 
  "  \"MyAppId\":874,\r\n" + 
  "  \"MyAppDetailId\":48515,\r\n" + 
  "        \"portfolioCd\": \"3927\",\r\n" + 
  "  \"currencyCd\": \"AUD\",\r\n" + 
  "        \"accountCd\": \"CURR-AUD\",\r\n" + 
  "  \"txnCd\":\"ADJUSTMNT\",\r\n" + 
  "  \"txnTypeCd\":\"59\",\r\n" + 
  "  \"txnTypeDesc\":\"PURCHASE\",\r\n" + 
  "  \"cashValue\": 1100000.02000000,\r\n" + 
  "        \"sourceUnits\":200.00,\r\n" + 
  "}";
  
  return jsonStr;
 }
  
 private MyAppDetail getMyAppDetail() {
  MyAppDetail cfDetail = new MyAppDetail();
  cfDetail.setMyAppId(BigInteger.valueOf(874));
  cfDetail.setMyAppDetailId(BigInteger.valueOf(48515));
  cfDetail.setPortfolioCd("3927");
  cfDetail.setTxnCd("ADJUSTMNT");
  cfDetail.setTxnTypeCd("59");
  cfDetail.setTxnTypeDesc("PURCHASE");
  cfDetail.setPositionIndicator("OUT");
  return cfDetail;
 }
}



The actual Spring MVC controller that is being tested will be defined as

@Controller
public class MyAppController {

    @Resource(name = "myAppService")
 private MyAppService myAppService;

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

    @RequestMapping(value = "/addOrModifyAdjustment", method = RequestMethod.POST,  headers="Accept=application/json")
 public @ResponseBody MyAppDetail addOrModifyAdjustment(@RequestBody MyAppDetail adjDetail) throws Exception 
 {
  logger.info("adjustMyAppDetail cfDetail={}, MyApp={}", new Object[] {adjDetail});
  
  MyAppDetail addOrModifyAdjustment = myAppService.addOrModifyAdjustment(adjDetail);

  return addOrModifyAdjustment;
 }
 
}

Labels: ,

Mar 13, 2013

Apache Camel for asynchronous processing

Apache Camel is a very powerful and can be used with Java to solve various problems. In this example, I will discuss how it can be used to generate feeds asynchronously. You don't have to write any multi-threading code. Sending email can be done with the MVEL expression language.

Following is a simple example where some feed files are processed asynchronously by retrieving the job request from an in-memory queue. In the event of error, email notification is sent. "from" is a consumer, and "to" is the destination.


Step 1:  The dependency jars required defined via Maven pom file.

 <properties>
     <camel.version>2.10.3</camel.version>
 </properties>
   
 <dependencyManagement>
  <dependencies> 
   <!-- CAMEL -->
   <dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-core</artifactId>
    <version>${camel.version}</version>
   </dependency>
   <dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-spring</artifactId>
    <version>${camel.version}</version>
   </dependency>

   <dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-test-spring</artifactId>
    <version>${camel.version}</version>
    <scope>test</scope>
   </dependency>

   <dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-spring-javaconfig</artifactId>
    <version>${camel.version}</version>
   </dependency>

   <dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-mvel</artifactId>
    <version>${camel.version}</version>
   </dependency>

   <dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-bean-validator</artifactId>
    <version>${camel.version}</version>
   </dependency>

   <dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-beanio</artifactId>
    <version>${camel.version}</version>
   </dependency>
  </dependencies>
 </dependencyManagement>



Step 2: The next step is to bootstrap Camel via Spring Java based configuration. Making the config class CamelContextAware will inject the camel context via the setter method.


package com.myapp.config;

import com.myapp.camel.JobHandlingRouteBuilder;
import com.myapp.service.MyAppService;

import javax.annotation.Resource;

import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MyAppConfig implements CamelContextAware
{
    
    private CamelContext context;
    
    @Resource(name = "myAppService")
    private MyAppService myAppService;
    
    //constructor injection, where template is the bean id.
    @Bean
    public ProducerTemplate template()
    {
        if (context != null)
        {
            return context.createProducerTemplate();
        }
    }
    
    @Bean
    public RouteBuilder jobHandlingRouteBuilder()
    {
        return new JobHandlingRouteBuilder(myAppForecastService);
    }
    
    @Override
    public void setCamelContext(CamelContext camelContext)
    {
        context = camelContext;
    }
    
    @Override
    public CamelContext getCamelContext()
    {
        return context;
    }
    
}


Step 3: Define the ProducerTemplate within your Service class.  The ProducerTemplate interface allows you to send message exchanges to endpoints in a variety of different ways to make it easy to work with Camel Endpoint instances from Java code. This service class could be invoked via a RESTful Webservice. 

//............

@Service(value = "myAppService")
@Transactional(propagation = Propagation.SUPPORTS)
public class CashForecastServiceImpl implements CashForecastService
{

   private ProducerTemplate template;

   
   //since autowired, injected via MyAppConfig template() method with beanId being template.
   @Autowired
   public void setTemplate(ProducerTemplate template)
   {
       this.template = template;
   }
    
   @Override
    public boolean handleGroupLevelFeedGenerationRequest()
    {
       
    //a pojo Java class with fields like account code, etc and getter/setter methods
    FeedGenerationRequest request = new FeedGenerationRequest();
    request.setAccountCode("12345");
    
       //add headers and body. header will be used to determine processing logic by the RouteBuilder 
        Map<string, object> headers = new HashMap<string,object>();
        headers.put(JobHandlingRouteBuilder.JOB_TYPE_HEADER, JobType.FEED_GENERATION);
        
  //send it to an in memory BockingQueue define in the JobHandlingRouteBuilder class
        template.sendBodyAndHeaders(JobHandlingRouteBuilder.JOB_QUEUE, request, headers);
        
        return true;
    }

    public boolean generateFeed1(FeedGenerationRequest request){
      //logic to generate feed goes here
    }
 
    public boolean generateFeed2(FeedGenerationRequest request){
       //logic to generate feed goes here
    }
  

 //...........................
   
}


Step 4: Finally, define the camel route to queue and asynchronously generate the required feed files.




package com.myapp.camel;


import com.myapp.JobType;
import com.myapp.MyAppService;

import org.apache.camel.builder.RouteBuilder;


public class JobHandlingRouteBuilder extends RouteBuilder
{
    public static final String JOB_QUEUE = "vm:jobQueue?size=50&timeout=1000000&concurrentConsumers=1";
    public static final String FEED_GENERATION_JOB_QUEUE = "vm:feedGenerationJobQueue?size=50&timeout=1000000&concurrentConsumers=1";
    public static final String DIRECT_FEED1 = "direct:feed1";
    public static final String DIRECT_ERROR = "direct:error";
    public static final String DIRECT_FEED2 = "direct:feed2";
    public static final String JOB_TYPE_HEADER = "jobTypeHeader";
    public static final String CONTROLLABLE_JOB_TYPE_HEADER = "controllableJobTypeHeader";
    
    private MyAppService myAppService;
    
    public JobHandlingRouteBuilder(MyAppService myAppService)
    {
        super();
        this.myAppService = myAppService;
    }
    
    @Override
    public void configure() throws Exception
    {
     //build routes
        configureJobHandlingRoute();
        configureFeedGenerationJobHandlingRoute();
    }
    
    /**
     * Main route to handling all jobs
     */
    private void configureJobHandlingRoute()
    {
        
  //from the in memory job queue move it to the in memory feed generation queue
        from(JOB_QUEUE)
            .routeId(JOB_QUEUE)
            .choice()
                .when((header(JOB_TYPE_HEADER).isEqualTo(JobType.FEED_GENERATION)))
                    .log(INFO, "Handling Feed Generation Job")    
                    .to(FEED_GENERATION_JOB_QUEUE);
    }
    
    /**
     * Route to handle Feed Generation jobs
     */
    public void configureFeedGenerationJobHandlingRoute()
    {
        // @formatter:off
          from(FEED_GENERATION_JOB_QUEUE)
              .routeId(FEED_GENERATION_JOB_QUEUE)
              .multicast()                           //multiple destinations  
                  .parallelProcessing()              //multiple threads
                  .to(DIRECT_FEED2, DIRECT_FEED1)
              .end();
          
          //TODO handle exception and mark the status as FAILED
          from(DIRECT_FEED2)
              .routeId(DIRECT_FEED2)
              .setHeader(CONTROLLABLE_JOB_TYPE_HEADER, simple(ControllableJobType.POS_FEED.toString()))
              .doTry()
                  .bean(myAppService, "generateFeed2") //invokes generateFeed2 method on myAppService bean
              .doCatch(Exception.class)
                  .to(DIRECT_ERROR)
               .end();

          from(DIRECT_FEED1)
              .routeId(DIRECT_FEED1)
              .setHeader(CONTROLLABLE_JOB_TYPE_HEADER, simple(ControllableJobType.CASH_FEED.toString()))
              .doTry()
                  .bean(myAppService, "generateFeed1")  //invokes generateFeed2 method on myAppService bean
              .doCatch(Exception.class)
                  .to(DIRECT_ERROR)
               .end();
          
          //Handle failtures
          from(DIRECT_ERROR)
              .routeId(DIRECT_ERROR)
              .log(INFO, " ${headers.controllableJobTypeHeader} Job failed, reason:  ${exception.stacktrace}")
              .bean(cashForecastService, "markControllableJobFailed")
              .end();
    }
}




If you want to send email notification on error, the routes can be enhanced as shown below.

Firstly, add camel mail component.

    
 <dependency>
     <groupId>org.apache.camel</groupId>
  <artifactId>camel-mail</artifactId>
  <version>${camel.version}</version>
 </dependency>


        public static final String DIRECT_EMAIL_NOTIFICATION = "direct:emailNotification"; 
  public static final String NOTIFICATION_FLAG_HEADER = "notificationFlagHeader";
  public static final String CREATION_FAILURE_EVENT_SUBJECT = "Failed Feed Generation";
  private static final String LOG_URI = "log:" + AbstractCommonRouteBuilder.class.getPackage().getName()
            + "?level=ERROR";
  
  //....

  @Override
        public void doConfigure()
       {
           addPropertiesLocation("classpath:cash/cashforecast.properties");     
       }
  
  //....
  
        from(DIRECT_FEED1)
              .routeId(DIRECT_FEED1)
              .setHeader(CONTROLLABLE_JOB_TYPE_HEADER, simple(ControllableJobType.CASH_FEED.toString()))
              .doTry()
                  .bean(myAppService, "produceGroupLevelCashFeed")
              .doCatch(Exception.class)
                  .to(DIRECT_ERROR)
               .end();
          
          //Handle failtures
          from(DIRECT_ERROR)
              .routeId(DIRECT_ERROR)
              .log(INFO, " ${headers.controllableJobTypeHeader} Job failed, reason:  ${exception.stacktrace}")
              .bean(myApp, "handleControllableJobFailed")
              .to(DIRECT_EMAIL_NOTIFICATION)
              .end();
          
          from(DIRECT_EMAIL_NOTIFICATION)
              .routeId(DIRECT_EMAIL_NOTIFICATION)
              .setHeader(NOTIFICATION_FLAG_HEADER, simple("{{myapp.feed.enable.email.notification}}"))
              .choice()
                  .when(header(NOTIFICATION_FLAG_HEADER).isEqualTo(true))
                      .log(INFO, "Sending email notification on Failture")
                      .setBody(simple("${headers.controllableJobTypeHeader} : ${exception.message}"))
                      .to("smtp:{{myapp.mail.host}}?contentType=text/html&to={{myapp.feed.notification.recipient}}&from={{myapp.feed.notification.sender}}"
                          + "&subject="
                          + CREATION_FAILURE_EVENT_SUBJECT
                          + "&mail.smtp.auth=false&mail.smtp.starttls.enable=false&delete=true&mapMailMessage=false");
 

    //...
 
        
 /*
     * TODO: The better approach would be to use
     * BridgePropertyPlaceholderConfigurer so that it picks up @PropertySource
     * style configuration
     */
    protected void addPropertiesLocation(String... newLocations)
    {
        PropertiesComponent properties = getPropertiesComponent();
        String[] locationsArr = properties.getLocations();
        List<string> locations = new ArrayList<string>();
        if (locationsArr != null)
        {
            for (String location : locationsArr)
            {
                locations.add(location);
            }
        }
        for (String location : newLocations)
        {
            locations.add(location);
        }
        locationsArr = new String[locations.size()];
        locationsArr = locations.toArray(locationsArr);
        properties.setLocations(locationsArr);    
    }
 


The route is defined using MVEL, which is a powerful expression language for Java-based applications. You can also appreciate, how easy it is to build your routes using various protocols.


Labels:

Mar 7, 2013

Logging in Java with Logback and MDC

Logback brings a very large number of improvements over log4j like faster execution, native support for SLF4J,XML or Groovy based configuration files, automatic reloading of config files to name a few. logback builds upon on our previous work on log4j, simply put, logback is just a better log4j.


The MDC(Mapped Diagnostic Context) is a map which stores the context data of the particular thread where the context is running. For example, in servlet, each user will be processed in its own thread and you can make each thread store the "username" and the log4j.xml or logback.xml will have a pattern like %X{key} to retrievce the values that are present in the MDC. The key will be ‘userName’ in our example. Another example would be that you might want to log the RESTful service request parameters as demonstrated below.


Step 1: Require the relevant jar library files.Define the following dependencies in the pom.xml files.


    <properties> 
     <logback.version>1.0.0</logback.version>
  <slf4j.version>1.6.4</slf4j.version>
 </properties>

        <!-- Logging -->

  <dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-classic</artifactId>
   <version>${logback.version}</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>${slf4j.version}</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>log4j-over-slf4j</artifactId>
   <version>${slf4j.version}</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>jcl-over-slf4j</artifactId>
   <version>${slf4j.version}</version>
  </dependency>
  



Step 2: Define the logback.xml file, under src/main/resources folder in the maven structure.

<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="true" scan="false">

<!--
   1. Logback tries to find a file called logback.groovy in the classpath.
   2. If no such file is found, logback tries to find a file called logback-test.xml
      in the classpath.
   3. If no such file is found, it checks for the file logback.xml in the classpath.
   4. In case neither file is found, logback configures itself automatically using 
      the BasicConfigurator which will cause logging output to be directed on the console.
      
      See http://logback.qos.ch/manual/configuration.html
 -->
   <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
   
   <file>logs/app.log</file>
   
   <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
    <fileNamePattern>logs/app.%i.log.gz</fileNamePattern>
    <minIndex>1</minIndex>
    <maxIndex>12</maxIndex>
   </rollingPolicy>
   
   <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
    <maxFileSize>10MB</maxFileSize>
   </triggeringPolicy>
   
   <encoder>
      <!-- Note that MDC is added via myAppMDCMap -->
   <pattern>%d{ISO8601} %-5level [%thread] %logger{36} - [%X{myAppMDCMap}] - %msg%n</pattern>
  </encoder>
  </appender>
  
    <logger level="@LOG_LEVEL@" name="com.jpmorgan" />
    <logger level="INFO" name="org.springframework.web.servlet.mvc.method.annotation" /> 
    <logger level="WARN" name="org.springframework.jdbc.core" /> 
    
    
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder 
            by default
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n
            </pattern>
        </encoder>
    </appender>  -->
      
  <!-- For root loggers, log to FILE appender -->
  <root level="@LOG_LEVEL@">
  <appender-ref ref="FILE" />
  <!-- <appender-ref ref="STDOUT" /> 
 </root>

</configuration>


Step 3: Define the MDC related classes to get context based logging. In this example, we want to log by portfolioCode.



Firstly a holder class that converts the values in a map to string when logging.

package com.myapp.logging;

import java.util.Map;
import java.util.Set;

/**
 * MDC Map holder - to provide custom toString
 */
public class MDCMap
{
    
    private Map<String, String> myAppMDCMap;
    
    public MDCMap(Map<String, String> gmrdMDCMap)
    {
        super();
        this.myAppMDCMap = gmrdMDCMap;
    }
    
    @Override
    public String toString()
    {
        StringBuilder toString = new StringBuilder();
        Set<String> keys = myAppMDCMap.keySet();
        for (String key : keys)
        {
            toString.append(key + "=" + myAppMDCMap.get(key) + ",");
        }
        return toString.substring(0, toString.length() - 1);
    }
}

Secondly, define the MDCLoggingHelper class. You could usethe MDC.put directly if your requirements are simple enough.

package com.myapp.logging;

import java.util.Map;

import org.slf4j.MDC;

public class MDCLoggingHelper
{
    
    /**
     * Add Cash ForeCast Params to MDC map
     */
    public void addParam(String portfolioCode)
    {
        MDC.put("PortfolioCode", portfolioCode);
        buildMap();
    }
    
    
    
    private void buildMap()
    {
        MDC.remove("myAppMDCMap"); // the names used in logback.xml %X{myAppMDCMap}
        @SuppressWarnings("unchecked")
        Map<String, String> currentMDCMap = MDC.getCopyOfContextMap();
        MDC.put("myAppMDCMap", new MDCMap(currentMDCMap).toString());
    }
}


Step 4: Finally, use it in your RESTFul service controller method as shown below.

@Controller
public class CashForecastController
{

    private final MDCLoggingHelper MDCLoggingHelper = new MDCLoggingHelper();
 private static final Logger logger = LoggerFactory.getLogger(CashForecastController.class);

 @RequestMapping(value = "/cashForecastFeed", method = RequestMethod.GET)
    public  @ResponseBody CashforecastFeedresponse generateCashForecastFeed(
            @RequestParam(value = "portfoliocd", required = true) String portfolioCode,
            @RequestParam(value = "valuationDate", required = true) @DateTimeFormat(pattern = "dd MMM yyyy") Date valuationDate) throws Exception
    {
        
        MDCLoggingHelper.addParam(portfolioCode);
        
        logger.info("Start processing  ");
  
  //....
 }
}

That's all to it. In the logs, now you can see the portfolioCode being added. This can improve your debugging as to which portfolio code is causing the problem.



Labels:

Mar 5, 2013

Spring MVC View Resolvers

Spring Interview Questions and Answers Q1 - Q14 are FAQs

Q1 - Q4 Overview & DIP Q5 - Q8 DI & IoC Q9 - Q10 Bean Scopes Q11 Packages Q12 Principle OCP Q14 AOP and interceptors
Q15 - Q16 Hibernate & Transaction Manager Q17 - Q20 Hibernate & JNDI Q21 - Q22 read properties Q23 - Q24 JMS & JNDI Q25 JDBC Q26 Spring MVC Q27 - Spring MVC Resolvers

Q. What is a Spring MVC ViewResolver?
A. In Spring MVC,  ViewResolver is a strategy and factory object used to map logical view names to actual view resources. The interface for ViewResolver is shown below. The single method resolveViewName(..) maps a logical view name together with the request locale to a View instance.The interface defines the following single method.

public interface ViewResolver {
  View resolveViewName(String name, Locale loc);
}


The ViewResolvers can be defined in your Spring context file as shown below.

<beans ... >
...
  <bean class="org.springframework.web.servlet.view.
               InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
  </bean>

</beans>


Q. Can you write custom resolvers?
A. Yes, you can. Spring provides the following resolvers.

  • AbstractCachingViewResolver: An abstract view resolver which takes care of caching views. Often views need preparation before they can be used, extending this view resolver provides caching of views. 
  • XmlViewResolver: An implementation of ViewResolver that accepts a configuration file written in XML with the same DTD as Spring's XML bean factories. The default configuration file is /WEB-INF/views.xml. 
  • ResourceBundleViewResolver:    An implementation of ViewResolver that uses bean definitions in a ResourceBundle, specified by the bundle basename. The bundle is typically defined in a properties file, located in the classpath. The default file name is views.properties. 
  • UrlBasedViewResolver: A simple implementation of the ViewResolver interface that effects the direct resolution of symbolic view names to URLs, without an explicit mapping definition. This is appropriate if your symbolic names match the names of your view resources in a straightforward manner, without the need for arbitrary mappings. 
  • InternalResourceViewResolver: A convenience subclass of UrlBasedViewResolver that supports InternalResourceView (i.e. Servlets and JSPs), and subclasses such as JstlView and TilesView. The view class for all views generated by this resolver can be specified via setViewClass(..). See the Javadocs for the UrlBasedViewResolver class for details. 
  • VelocityViewResolver / FreeMarkerViewResolver: A convenience subclass of UrlBasedViewResolver that supports VelocityView (i.e. Velocity templates) or FreeMarkerView respectively and custom subclasses of them.

If you have specific requirements, you can define your own.Here is an example where a custom view resolver is defined to use both .jsp and .html files.

-->
Step 1: The Spring context file.

<?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:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
 xmlns:batch="http://www.springframework.org/schema/batch" xmlns:task="http://www.springframework.org/schema/task"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
   http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">

 <mvc:annotation-driven />

 <bean
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="location" value="classpath:/applicationPortal.properties" />
  <property name="placeholderPrefix" value="$ap{" />
  <property name="placeholderSuffix" value="}" />
 </bean>

 <context:annotation-config />

 <context:component-scan base-package="com.myapp.portal.controller" />

 <bean class="com.myapp.portal.resolver.AppPortalViewResolver">
  <property name="htmlResolver" ref="htmlViewResolver" />
  <property name="jspResolver" ref="jspViewResolver" />
 </bean>

 <bean id="htmlViewResolver"
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/"></property>
  <property name="suffix" value=".html"></property>
 </bean>

 <bean id="jspViewResolver"
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass"
   value="org.springframework.web.servlet.view.JstlView"></property>
  <property name="prefix" value="/WEB-INF"></property>
  <property name="suffix" value=".jsp"></property>
 </bean>


</beans>



Step 2: The custom resolver Java class.

package com.myapp.portal.resolver;

import java.util.Locale;

import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

public class AppPortalViewResolver implements ViewResolver {
 
 
 private ViewResolver htmlResolver;
 private ViewResolver jspResolver;
 
 

 public void setHtmlResolver(ViewResolver htmlResolver) {
  this.htmlResolver = htmlResolver;
 }

 public void setJspResolver(ViewResolver jspResolver) {
  this.jspResolver = jspResolver;
 }


 @Override
 public View resolveViewName(String viewName, Locale locale) throws Exception {
  if (viewName.startsWith("/pages")) {
            return jspResolver.resolveViewName(viewName, locale);
        } else {
            return htmlResolver.resolveViewName(viewName, locale);
        }
 }

}


-->

Labels: