Sunday, 22 October 2017

Vending Machine : OOAD Interview question and solution

Recently I came across below link which lists top 5 OOAD questions (and answers also).

Top 5 Object Oriented Design Interview Questions for Programmers and Engineers

I have decided to give a try one problem at a time.
Following is my first try for the problem (Design a Vending Machine in Java)

Vending Machine :

The solution is centered among below three classes .

1)Product : Abstract class for Product. The actual products (like NUTS,CANDY) are derived
  from abstract class
2)Currency : Since price for products can be 1,5,10,15 cents as well as 1,2 dollar , currency
  class models denomination (cents/dollar) and value (1/2/10)
  Curreny class will have required routines like subtract , compareTo for currency related
  operations
3)Deliverable : It contains Product and Currency classes since the change (user input amount - product amount) also need to be delivered along with requested product.
3)VendingMachine : Core class supporting vending machine operations.

The class diagram for solution is given below




Comparing the solution with answer given Design a Vending Machine in Java - Interview Question 
I have derived below Pros and Cons of both solutions.

Pros :

1)Currency and Products classes are modeled better as compared to solution given.
  The various denominations and value has not been modelled in solution.
  The operations pertaining to amount calculation are moved to Currency class.
  Products can be added easily without more modifications since they are encpsulated behind abstract class.

2)The VendingMachine has state associated with it . The vending machine goes through various states as it performs varipus operations.
  e.g: It cannot deliver product if it is not in CURRENY_ACCEPTD state. This  ensures that random operations are not allowed.

Cons :

1)I completely missed maintaining inventory of Products. The solution also maintain inventory of COINS as coins can also be run out of stock.
2)I deliberately didn't code VendingMachine to any interface or abstract class since I treated it as a concrete concept rather than abstraction.

What still needs to added :

1)Junits Need to be added for all scenarios. Currently added for only testAcceptCurency and testGetProduct.
2)Detailed exception handling

The code for the above solution is available on bitbucket on repository -  https://joshiaatul24@bitbucket.org/joshiaatul24/ooad-probs-solns.git

Sunday, 5 April 2015

JAX-WS WebSevice Implementation using Top Down Approach


This post is about developing a JAX-WS web service and deploying on tomcat 6.
The top down approach is used to develope Web Service.

Environment :

Eclipse Juno
Tomcat 6
Apache maven 3
JAX-WS reference implementation - Sun's Metro

Steps to create Web Service :

1)Create a WSDL file using eclipse WSDL editor :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.atulajoshi.org/userDetails/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="userDetails" targetNamespace="http://www.atulajoshi.org/userDetails/">
  <wsdl:types>
    <xsd:schema targetNamespace="http://www.atulajoshi.org/userDetails/">
      <xsd:element name="getUserDetails">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="userId" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
      <xsd:element name="getUserDetailsResponse">
        <xsd:complexType>
          <xsd:sequence>
          <xsd:element name="userFirstName" type="xsd:string" />
          <xsd:element name="userLastName" type="xsd:string"></xsd:element>
          <xsd:element name="userAddress" type="xsd:string"></xsd:element>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="getUserDetailsRequest">
    <wsdl:part element="tns:getUserDetails" name="parameters"/>
  </wsdl:message>
  <wsdl:message name="getUserDetailsResponse">
    <wsdl:part element="tns:getUserDetailsResponse" name="parameters"/>
  </wsdl:message>
  <wsdl:portType name="userDetails">
    <wsdl:operation name="getUserDetails">
      <wsdl:input message="tns:getUserDetailsRequest"/>
      <wsdl:output message="tns:getUserDetailsResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="userDetailsSOAP" type="tns:userDetails">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="getUserDetails">
      <soap:operation soapAction="http://www.atulajoshi.org/userDetails/getUserDetails"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="userDetails">
    <wsdl:port binding="tns:userDetailsSOAP" name="userDetailsSOAP">
      <soap:address location="http://localhost:8080/UserDetailsService"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>


2)Create a maven project with archtype as webapp. It will create a pom.xml file.
  Add a jax-ws maven plugin with wsimport as goal. Below is the pom.xml I used.

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.atul</groupId>
  <artifactId>jaxws</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>jaxws Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
     <dependency>
       <groupId>com.sun.xml.ws</groupId>
       <artifactId>jaxws-rt</artifactId>
       <version>2.2.8</version>
    </dependency>  
  </dependencies>
  <build>
    <finalName>jaxws</finalName>
     <plugins>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
       <version>3.1</version>
       <configuration>
         <source>1.7</source>
         <target>1.7</target>
       </configuration>
     </plugin>      
     <plugin>
           <groupId>org.jvnet.jax-ws-commons</groupId>
           <artifactId>jaxws-maven-plugin</artifactId>
           <version>2.3</version>
           <executions>  
   <execution>
     <id>execution</id>
 <goals>
<goal>wsimport</goal>
 </goals>
 <configuration>
   <wsdlDirectory>src/wsdl</wsdlDirectory>
 <packageName>com.atul.jaxws.service</packageName>
 <sourceDestDir>src/main/java</sourceDestDir>
 </configuration>
 </execution>
</executions>
         </plugin>      
    </plugins>
  </build>
  <repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2</url>
</repository>
  </repositories>
</project>



3)Import this project into eclipse.
4)Now run mvn clean install
5)It will generate following important classes  :

1)UserDetails.java : an interface corresponding to service element in wsdl with a method same as operation element defined in portType element.
2)GetUserDetails.java and GetUserDetailsResponse.java : corresonding to input and output message parts.
3)UserDetails_Service.java : A service stub used by client

6)Now implement a web service by implementing the interface UserDetails as below

package com.atul.jaxws.service;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebParam.Mode;
import javax.xml.ws.Holder;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
import javax.jws.WebService;


@WebService(serviceName = "userDetails", portName = "userDetailsSOAP",
targetNamespace = "http://www.atulajoshi.org/userDetails/", wsdlLocation = "userDetails.wsdl",
endpointInterface = "com.atul.jaxws.service.UserDetails")
public class UserDetailsImpl implements UserDetails {

@WebMethod(action = "http://www.atulajoshi.org/userDetails/getUserDetails")
@RequestWrapper(localName = "getUserDetails", targetNamespace = "http://www.atulajoshi.org/userDetails/", className = "com.atul.jaxws.service.GetUserDetails")
@ResponseWrapper(localName = "getUserDetailsResponse", targetNamespace = "http://www.atulajoshi.org/userDetails/", className = "com.atul.jaxws.service.GetUserDetailsResponse")
public void getUserDetails(
@WebParam(name = "userId", targetNamespace = "") String userId,
@WebParam(name = "userFirstName", targetNamespace = "", mode = Mode.OUT) Holder<String> userFirstName,
@WebParam(name = "userLastName", targetNamespace = "", mode = Mode.OUT) Holder<String> userLastName,
@WebParam(name = "userAddress", targetNamespace = "", mode = Mode.OUT) Holder<String> userAddress) {
// TODO Auto-generated method stub
System.out.println("input param got .."+userId);

userFirstName.value = "Atul";
userLastName.value = "Joshi";
userAddress.value = "Pune";


}

}
The important thing to note here is parameters with Holder classes (userFirstName ,userLastName and userAdress). Please see how these parameters are set with values which are sent back to client. Also please note that their mode is set as OUT meaning they will be filled up with values and sent back to client.

7)Run maven : mvn clean install

8)Since we are deploying this on tomcat6 with Sun'S RI, sun-jaxws.xml should be added which should look like below : (web.xml should be standard one using WSServlet and corresponding listener for Sun's RI)

<?xml version="1.0" encoding="UTF-8"?>
<endpoints
    xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
    version="2.0">

    <endpoint
        name="userDetails"
        implementation="com.atul.jaxws.service.UserDetailsImpl"
        url-pattern="/UserDetailsService" />

</endpoints>

8)Deploy the .war file in tomcat.I prefer modofying server.xml file to deploy the exploded web app directory on tomcat.
Following is the Host element snippet from server.xml file
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
        -->
      <Context docBase="F:/study/jaxws/target/jaxws" path="/jaxws" reloadable="true"/>
     
      </Host>

9)Access the WSDL of web service by :

http://localhost:8080/jaxws/UserDetailsService?wsdl

Problems Faces :
1)While running mvn clean install , I got below maven error :
Failed to execute goal org.jvnet.jax-ws-commons:jaxws-maven-plugin:2.3:wsimport (execution2) on project jaxws: Execution execution2 of goal org.jvnet.jax-ws-commons:jaxws-maven-plugin:2.3:wsimport failed: String index out of range: -1 -> [Help 1]
After I made my eclipse use JDK path as JVM instead of JRE , this error got resolved.

2)The class implementing the interface must be annotate with @WebService annotation.

Friday, 20 February 2015

Migrating JSF 1.2 - JSF2 and RichFaces 3 to 4

The motive of this blog post is to share my experience of migrating an application from JSF 1.2 to JSF 2.1  and RichFaces 3.3 to 4.5.

To start with , following is the custom facelet component designed to implement sorting in rich:dataTable

Sorting In RichDataTable : 

Since built in sorting has been removed for rich:dataTable , the sorting has to be achieved programmatically.  After referring rich faces showcase in point 3 ,  I have designed a new facelet custom component with supporting java class as shown below :

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:a4j="http://richfaces.org/a4j"
                xmlns:c="http://java.sun.com/jsp/jstl/core"
                xmlns:fn="http://java.sun.com/jsp/jstl/functions">
             
<ui:composition>

<h:panelGrid columns="1" styleClass="table_center">
<a4j:commandLink value="#{name}" styleClass="dataTableSortLink" actionListener="#{bean[actionListenerMethod]}" render="#{render}">
              <f:param name="columnKey" value="#{columnKey}"/>
              <span style="padding:1px;"/>
              <h:graphicImage value="/images/icons/arrow-unsorted.jpg" alt="unsorted" styleClass="sortingArrows" rendered="#{sortOrder eq 'unsorted'}"/>
  <h:graphicImage value="/images/icons/arrow-ascending.jpg" alt="ascending" styleClass="sortingArrows" rendered="#{sortOrder eq 'ascending'}"/>
  <h:graphicImage value="/images/icons/arrow-descending.jpg" alt="descending" styleClass="sortingArrows" rendered="#{sortOrder eq 'descending'}"/>              
</a4j:commandLink>
</h:panelGrid>                
</ui:composition>
</html>

and it will be invoked from rich:dataTable as shown below :

<rich:dataTable id="userList" rows="#{bean.rowsPerPage}" value="#{bean.userList}" var="user">

<rich:column sortBy="#{user.name}" sortOrder="#{bean.dataSorterHelper.sortOrderMap['name']}">
<f:facet name="header">
<custom:commandLinkwithSort name="User Name" bean="#{bean.dataSorterHelper}"
                actionListenerMethod="processSortOrder" render="userList" columnKey="name"
                sortOrder="#{bean.dataSorterHelper.sortOrderMap['name']}"/>
</f:facet>
<h:outputText value="#{user.name}"/>
</rich:column>

<rich:column sortBy="#{user.lastname}" sortOrder="#{bean.dataSorterHelper.sortOrderMap['lastname']}">
<f:facet name="header">
<custom:commandLinkwithSort name="User Last Name" bean="#{bean.dataSorterHelper}"
                actionListenerMethod="processSortOrder" render="userList" columnKey="lastname"
                sortOrder="#{bean.dataSorterHelper.sortOrderMap['lastname']}"/>
</f:facet>
<h:outputText value="#{user.lastname}"/>
</rich:column>

</rich:dataTable>


The class used to handle sorting is shown below :
/**
 * Class to help in sorting rich:dataTable.
 * It contains sort keys for columns to sort and processes sort order according to user selected column for sort.
 *
 */

public class DataSorterHelper {

//map to store sort order for columns , this map contains column key and rich faces sort order
private Map<String,SortOrder> sortOrderMap;

public Map<String, SortOrder> getSortOrderMap() {
return sortOrderMap;
}
/**
* Constructor to initialise sortOrderMap with all columns sort order - unsorted
*
*/
public DataSorterHelper(List<String> sortKeys) {

sortOrderMap = new HashMap<String, SortOrder>();
for(String sortKey : sortKeys){
sortOrderMap.put(sortKey,SortOrder.unsorted);
}
}

public DataSorterHelper() {
sortOrderMap = new HashMap<String, SortOrder>();
}
/**
* Method to set user defined sort order for particular column.Some tables require to set default sort order for a column
*
*/
public void init(List<String> sortKeys,String columnKey,SortOrder sortOrder) {

for(String sortKey : sortKeys){

if(sortKey.equalsIgnoreCase(columnKey)){
sortOrderMap.put(sortKey,sortOrder);
}else{
sortOrderMap.put(sortKey,SortOrder.unsorted);
}
}
}

private void setOtherColumnsUnsorted(String sortKey){

if(sortOrderMap != null){
for(Entry<String,SortOrder> sortInfo : sortOrderMap.entrySet()){
if(!sortKey.equals(sortInfo.getKey())){
sortInfo.setValue(SortOrder.unsorted);
}
}
}
}

/**ActionListener to set sorting order of a column under sorting
* It also sets sorting order of other columns to "unsorted"
* @param event
*/
public void processSortOrder(ActionEvent event){
//get colun key and set sort order
String columnKey = VariableStore.getRequestParameter("columnKey");

/*set sort order of other columns to unsoted .Otherwise sorting doesn't work */
setOtherColumnsUnsorted(columnKey);
if(sortOrderMap != null){
if(sortOrderMap.get(columnKey).equals(SortOrder.ascending)){
sortOrderMap.put(columnKey, SortOrder.descending);
}else{
sortOrderMap.put(columnKey, SortOrder.ascending);
}
}

}

public void resetSortOrderMap(){

if(sortOrderMap != null){
for(Entry<String,SortOrder> sortInfo : sortOrderMap.entrySet()){
sortInfo.setValue(SortOrder.unsorted);
}
}
}


}

It is important to note that , is is necessary to set sort order of other columns to "unsorted" when applying sorting to a prticular column.