Tuesday, July 8, 2014

Web Service using Spring-WS with HTTP Digest Authentication

We have seen 'A Simple Web Service Using Spring-WS' in the previous post.
Now we need to secure the service from unauthorized access. We are going to apply HTTP Digest Authentication[1][2] for this.

Note that we are not implementing Message Signing or Encryption here. We will only ensure 'Authentication' using Spring XwsSecurityInterceptor[3], so that only authenticated users can access the add service we defined in the previous post.

First modify the ws-servlet.xml file and add the following bean definitions:

  • XwsSecurityInterceptor bean (inside the <sws:interceptors/> tag),
  • callBackHandlerDigest bean definition,
  • userDetailsService


ws-servlet.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:context="http://www.springframework.org/schema/context"
 xmlns:sws="http://www.springframework.org/schema/web-services"
 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.xsd
       http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd">

 <sws:annotation-driven />

 <!-- To detect @Endpoint, @Service, @Component etc -->
 <context:component-scan base-package="com.test.ws" />

 <!-- To generate dynamic wsdl -->
 <sws:dynamic-wsdl id="wstest" portTypeName="add"
  locationUri="/services/add" targetNamespace="http://develop-for-fun.blogspot.com/spring-ws">
  <sws:xsd location="/WEB-INF/spring/service-definitions.xsd" />
 </sws:dynamic-wsdl>

 <!-- For validating your request and response -->
 <!-- So that you don't send a string instead of an integer -->

 <sws:interceptors>
  <bean id="validatingInterceptor"
   class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
   <property name="schema" value="/WEB-INF/spring/service-definitions.xsd" />
   <property name="validateRequest" value="true" />
   <property name="validateResponse" value="true" />
  </bean>
  <bean id="wsSecurityInterceptor"
              class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
            <property name="policyConfiguration" value="/WEB-INF/spring/securityPolicy.xml"/>
            <property name="callbackHandlers">
                <list>
                    <ref bean="callbackHandlerDigest"/>
                </list>
            </property>
        </bean>
 </sws:interceptors>

    <bean id="callbackHandlerDigest" class="org.springframework.ws.soap.security.xwss.callback.SpringDigestPasswordValidationCallbackHandler">
        <property name="userDetailsService" ref="userDetailsService"/>
    </bean>
    <bean id="userDetailsService" class="com.test.ws.services.CustomUserDetailsService" />

</beans>

security-policy.xml

<xwss:securityconfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
    <xwss:requireusernametoken noncerequired="true" passworddigestrequired="true">
</xwss:requireusernametoken></xwss:securityconfiguration>

Add a Role enumeration to define User's role:

com.test.ws.enumeration.Role

package com.test.ws.enumeration;



public enum  Role {

    ROLE_ADMIN(1),

    ROLE_MEMBER(2);



    private final int value;



    Role(int p) {

        this.value = p;

    }



    public int getValue() {

        return this.value;

    }

}

Add the domain(/model/entity) class:

com.test.ws.domain.User

package com.test.ws.domain;

import com.test.ws.enumeration.Role;

/**
 * The User entity
 */

public class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private String name;
    private Role role;

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getName() {
        return name;
    }

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

Now add the dao class (with dummy user population):

com.test.ws.dao.UserDao

package com.test.ws.dao;

import com.test.ws.domain.User;
import com.test.ws.enumeration.Role;

public class UserDao {

    private static final String DEFAULT_ADMIN_PASS = "adminpass";
    private static final String DEFAULT_MEMBER_PASS = "memberpass";
    private static final String DUMMY_ADMIN_EMAIL = "admin@domain.com";
    private static final String DUMMY_MEMBER_EMAIL = "member@domain.com";

    public User getUser(String email) {
        /** We are only allowing now two dummy users here
         * Actually here we have to retrieve the users by the email address from Database **/

        User user = new User();
        if(email.equals(DUMMY_ADMIN_EMAIL)) {
            user.setId(1);
            user.setName("Administrator");
            user.setPassword(DEFAULT_ADMIN_PASS);
            user.setRole(Role.ROLE_ADMIN);
        } else if(email.equals(DUMMY_MEMBER_EMAIL)) {
            user.setId(2);
            user.setName("Member");
            user.setPassword(DEFAULT_MEMBER_PASS);
            user.setRole(Role.ROLE_ADMIN);
        }
        user.setEmail(email);
        return user;
    }
}



We need to create a CustomUserDetailsService which implements UserDetailsService

com.test.ws.services.CustomUserDetailsService

package com.test.ws.services;

import com.test.ws.dao.UserDao;
import com.test.ws.domain.User;
import com.test.ws.enumeration.Role;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

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

@Service
public class CustomUserDetailsService implements UserDetailsService {

    UserDao userDao = new UserDao();

    @Override
    public UserDetails loadUserByUsername(String email) {
        try {
            // Retrieve the user by email
            User user = userDao.getUser(email);

            int roleId = user.getRole().getValue();
            return new org.springframework.security.core.userdetails.User (
                    user.getEmail(), user.getPassword(), true, true, true, true, getAuthorities(roleId)
            );
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    public Collection<? extends GrantedAuthority> getAuthorities(Integer role) {
        List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
        return authList;
    }

    public List<String> getRoles(Integer role) {

        List<String> roles = new ArrayList<String>();

        if (role.intValue() == Role.ROLE_ADMIN.getValue()) {
            roles.add(String.valueOf(Role.ROLE_ADMIN));
        } else if (role.intValue() == Role.ROLE_MEMBER.getValue()) {
            roles.add(String.valueOf(Role.ROLE_MEMBER));
        }
        return roles;
    }

    public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

        for (String role : roles) {
            authorities.add(new SimpleGrantedAuthority(role));
        }
        return authorities;
    }
}

This is how the project-structure should look like (underlined items are newly added over the project in the previous post):

Project Structure



The project can be downloaded using git from spring-ws-test project (secured_user_auth_digest branch):
git clone https://github.com/tariqmnasim/spring-ws-test.git -b secured_user_auth_digest

References:
[1] HTTP Authentication: Basic and Digest Access Authentication
[2] Wikipedia: Digest access Authentication
[3] Securing your web services using Spring-WS

Friday, June 13, 2014

A Simple Web Service Using Spring-WS

In this post I will describe the way to write a very simple SOAP-based web service that will take as input two numbers and return the sum of those numbers.

Create the Project Structure:
We can start our development based on a Java-Web project using maven. [ See maven web project directory layout  and creating maven webapp project ].

Project Structure



Define Data Contract (XSD):
Spring-WS focuses on Contract-First development style [See Why]. So, we first define the data exchange (reuest-response) format of the web service, i.e. the Data Contract.

webapp/WEB-INF/spring/service-definition.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://develop-for-fun.blogspot.com/spring-ws" xmlns:wst="http://develop-for-fun.blogspot.com/spring-ws">
  
  <xs:element name="AddServiceRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="firstNumber" type="xs:integer"/>
        <xs:element name="secondNumber" type="xs:integer"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  
  <xs:element name="AddServiceResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="sum" type="xs:integer"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  
</xs:schema>


Generate Request/Response Models:
You can generate (un-marshal) Java classes using JAXB from the above XSD. You can use XJC for this or you can use features of your IDE to convert XML-to Java. In IntelliJ IDEA, right click on the .xsd file in the project explorer, click "Web Services" --> "Generate Java classes from XML Schema using JAXB". (for eclipse see this).
AddServiceRequest.java, AddServiceResponse.java and ObjectFactory.java will be generated in this case. Put the generated classes in a separate package (e.g. com.test.ws.wsmodels).

Then write the service interfaces and an implementation of the service interface.

AddService.java

package com.test.ws.services;

import java.math.BigInteger;

public interface AddService {
 public BigInteger addNumbers(BigInteger number1, BigInteger number2);
}

AddServiceImpl.java

package com.test.ws.services;

import java.math.BigInteger;

import org.springframework.stereotype.Service;

@Service
public class AddServiceImpl implements AddService {

 /**
  * Returns the sum of two input numbers.
  */
 public BigInteger addNumbers(BigInteger number1, BigInteger number2) {
  return number1.add(number2);
 }

}
Don't forget the @service annotation.

Now write the endpoint class.

AdditionEndpoint.java

package com.test.ws.endpoints;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

import com.test.ws.wsmodels.*;
import com.test.ws.services.AddService;

@Endpoint
public class AdditionEndpoint {
   //To calculate sum of two input.
   @Autowired
   private AddService addService;
   
   //This is similar to @RequestMapping of Spring MVC
   @PayloadRoot(localPart="AddServiceRequest", namespace="http://develop-for-fun.blogspot.com/spring-ws")
   @ResponsePayload
   public AddServiceResponse generateRandomNumber(@RequestPayload AddServiceRequest request) {
       
    AddServiceResponse response = new ObjectFactory().createAddServiceResponse();
       
    response.setSum(addService.addNumbers(request.getFirstNumber(), request.getSecondNumber()) );
       
    return response;
    
   }
}


All the java classes are ready now. We need to configure the spring servlet definition and the web.xml file.

webapp/WEB-INF/spring/ws-servlet.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:context="http://www.springframework.org/schema/context"
 xmlns:sws="http://www.springframework.org/schema/web-services"
 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.xsd
       http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd">

 <sws:annotation-driven />

 <!-- To detect @Service, @Endpoint etc -->
 <context:component-scan base-package="com.test.ws" />

 <!-- To generate dynamic wsdl -->
 <sws:dynamic-wsdl id="wstest" portTypeName="add"
  locationUri="/services/add" targetNamespace="http://develop-for-fun.blogspot.com/spring-ws">
  <sws:xsd location="/WEB-INF/spring/service-definitions.xsd" />
 </sws:dynamic-wsdl>

 <!-- For validating your request and response -->
 <!-- So that you don't send a string instead of an integer -->

 <sws:interceptors>
  <bean id="validatingInterceptor"
   class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
   <property name="schema" value="/WEB-INF/spring/service-definitions.xsd" />
   <property name="validateRequest" value="true" />
   <property name="validateResponse" value="true" />
  </bean>
 </sws:interceptors>


</beans>

webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <display-name>Addtion Service</display-name>

    <servlet>
        <servlet-name>ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <init-param>
            <param-name>transformWsdlLocations</param-name>
            <param-value>true</param-value>
        </init-param>
  <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/spring/ws-servlet.xml
            </param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>ws</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>

</web-app>



Now the maven configuration.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.test.ws</groupId>
 <artifactId>spring-ws-test</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>Spring-WS Application</name>
 <url>http://www.springframework.org/spring-ws</url>
 <build>
  <finalName>spring-ws-test</finalName>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.5</source>
     <target>1.5</target>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>tomcat-maven-plugin</artifactId>
    <version>1.1</version>
   </plugin>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <executions>
     <execution>
      <goals>
       <goal>xjc</goal>
      </goals>
     </execution>
    </executions>
    <configuration>
     <!-- This should the location of the schema files (*.xsd) for services definition -->
     <schemaDirectory>src/main/webapp/WEB-INF/spring</schemaDirectory>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <dependencies>
  <dependency>
   <groupId>org.springframework.ws</groupId>
   <artifactId>spring-ws-core</artifactId>
   <version>2.0.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>javax.xml.bind</groupId>
   <artifactId>jaxb-api</artifactId>
   <version>2.0</version>
  </dependency>
  <dependency>
   <groupId>com.sun.xml.bind</groupId>
   <artifactId>jaxb-impl</artifactId>
   <version>2.0.3</version>
  </dependency>
  <dependency>
   <groupId>org.apache.xmlbeans</groupId>
   <artifactId>xmlbeans</artifactId>
   <version>2.4.0</version>
  </dependency>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.8.1</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <scope>compile</scope>
   <version>1.2.16</version>
  </dependency>
 </dependencies>
</project>


Now build the file using the maven command:
mvn clean package

Deploy the spring-ws-test.war file in your server (tomcat / glassfish / jboss). If you deploy the application in your localhost, then you can see the wsdl on your browser in the following URL:
http://localhost:8080/spring-ws-test/services/wstest.wsdl

The service can be tested using Soap-UI or other SOAP client.

You can get the whole project from github using git:
git clone https://github.com/tariqmnasim/spring-ws-test.git


References:
JAXB:

Saturday, May 31, 2014

Automatically deploy applications (WAR files) during JBoss AS starting time.

Add a <deployment/> part under <deployments/> tag in the standalone.xml file (<JBoss Installation Directory>/standalone/standalone.xml) to automatically deploy applications (WAR files) during JBoss AS starting time:
<server>
 <!-- ... -->
 <!-- ... -->
 <deployments>
        <deployment name="my.war" runtime-name="my.war">
            <fs-archive path="Path/to/my.war">
        </fs-archive></deployment>
  <deployment name="other.war" runtime-name="other.war">
            <fs-archive path="Path/to/some/other.war">
        </fs-archive></deployment>
    </deployments>
 <!-- ... -->
 <!-- ... -->
</server>

Now, each time you start JBoss AS, application server will try to deploy the wars specified in the standalone.xml file.

Sunday, May 25, 2014

Get first/last date of current Week/Month

import java.util.Calendar;
import java.util.Date;
/**
 * Returns the date of previous Monday
 */
public static Date getFirstDateOfCurrentWeek() {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.clear(Calendar.MINUTE);
    cal.clear(Calendar.SECOND);
    cal.clear(Calendar.MILLISECOND);
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
    return cal.getTime();
}
/**
 * Returns the date of next Sunday.
 */
public static Date getLastDateOfCurrentWeek() {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.clear(Calendar.MINUTE);
    cal.clear(Calendar.SECOND);
    cal.clear(Calendar.MILLISECOND);
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

    Calendar last = (Calendar) cal.clone();
    last.add(Calendar.DAY_OF_YEAR, 7);
    last.add(Calendar.MILLISECOND, -1);
    return last.getTime();
}
/**
 * Get the first Date ( first millisecond ) of current month
 */
public static Date getFirstDateOfCurrentMonth() {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.clear(Calendar.MINUTE);
    cal.clear(Calendar.SECOND);
    cal.clear(Calendar.MILLISECOND);
    cal.set(Calendar.DAY_OF_MONTH, 1);
    return cal.getTime();
}
/**
 * Get the last time ( last millisecond ) of current month
 */
public static Date getLastDateOfCurrentMonth() {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.clear(Calendar.MINUTE);
    cal.clear(Calendar.SECOND);
    cal.clear(Calendar.MILLISECOND);
    cal.add(Calendar.MONTH, 1); // NEXT MONTH
    cal.set(Calendar.DAY_OF_MONTH, 1); // FIRST DAY OF NEXT MONTH
    cal.add(Calendar.MILLISECOND, -1); // Go one Millisecond back, which is the last moment of the last day of current month
    return cal.getTime();
}

Wednesday, May 21, 2014

JBoss Logging Configuration: Write Application Specific Logs in a Different File

In order to write the logs generated from your application into a separate file (not in the default <j-boss-installation-directory>\...\server.log file), follow these steps:

Start JBoss Administrative Console: In your browser hit http://localhost:9990/console/App.html

Configure A File Handler:

  • Go to Profile --> Core --> Logging --> 'Handler' tab --> 'File' sub-tab and Click 'Add' button.
  • In the 'Add File Handlers' pop-up box, enter name, log-level, file-name with extension etc. and 'Save'
  • You may also need to further edit the created handler and set 'Auto Flash' and 'Append' to true.

Add A Log Category:

  • Now go to the 'Log Categories' tab and click 'Add'. Enter the root package of your project in the 'Name' field (e.g. com.mycompany.myproject).
  • Now select (click on) the newly added log-category and click on 'handlers' (under 'Details' section at the bottom).
  • Click 'Add' and add the handler that you created previously.

[You can also configure the handler and Log Category by editing the .../standalone/configuration/standalone.xml file of your server directory.]

Happy Logging:
Now you can log using slf4j from your application like:
private static Logger logger = LoggerFactory.getLogger(MyClass.class);

and all logs of your application will be written to the file-name that you specified for the handler configured above.

I have used EAP 6.2.0 GA (AS 7.3) application server and slf4j (for logging).

Related Links:
JBoss: Configure Logging
slf4j Manual.

Friday, December 20, 2013

বাংলায় 'পাইথন' প্রোগ্রামিং

বাংলায় 'পাইথন' প্রোগ্রাম লিখার একটা উদাহরণঃ
# -*- coding: utf-8 -*-
#!/usr/bin/python3.1

def যোগ_কর(প্রথম, দ্বিতীয়):
    যোগফল= প্রথম + দ্বিতীয়
    return যোগফল

def নাসিমায়ন১(দুই_শব্দের_বাক্য):
    শব্দদ্বয় = (দুই_শব্দের_বাক্য).split(' ')
    প্রথমাংশ = শব্দদ্বয়[0]
    দ্বিতীয়াংশ = শব্দদ্বয়[1]
    নাসিমায়িত_শব্দ = দ্বিতীয়াংশ[0:1]+প্রথমাংশ[1:]+' '+প্রথমাংশ[0:1]+দ্বিতীয়াংশ[1:]
    print(নাসিমায়িত_শব্দ)


if __name__ == '__main__':
    নাসিমায়ন১('নারিক তাসিম')
    নাসিমায়ন১('রাসুদ মশীদ')
    নাসিমায়ন১('মৌফিক তাহমুদ')
    নাসিমায়ন১('তিনাওয়ার মানজিল')
    নাসিমায়ন১('জালেদা খিয়া')
    নাসিমায়ন১('মাদের কোল্লা')
    নাসিমায়ন১('গানির প্লাস')
    নাসিমায়ন১('টরার পেবিল')
    নাসিমায়ন১('ডেন প্রাইভ')
 
    print(যোগ_কর('যোগ', 'কর'))
    print(যোগ_কর(110, 300))


'আউটপুট'

তারিক নাসিম
মাসুদ রশীদ
তৌফিক মাহমুদ
মিনাওয়ার তানজিল
খালেদা জিয়া
কাদের মোল্লা
পানির গ্লাস
পরার টেবিল
পেন ড্রাইভ
যোগকর
410

Tuesday, December 17, 2013

Configure TortoiseGIT with RSA Private Key on Windows

If you are looking for an easy to use GUI for git then TortoiseGIT is the best I think.

  1. Download and install git for windows
  2. Open git bash and generate a RSA key-pair from git bash:
    ssh-keygen.exe -t rsa
    the key-pair will be generated in the default location (C:\Users\[user_name]\.ssh\), you can specify any other location if you wish to.
    You can also specify a passphrase/password for this key before generating the key which you will have to enter while accessing any git repository using this key.

  3. Upload/send your public key (id_rsa.pub) file to the administrator of your git-server.
    Once this public key is added in the server, you can access permitted repositories on git-server from your PC using git.
  4. Configure your name and email address for git:
    git config --global user.name "Your Name"
    git config --global user.email "your@mail.address"
    

    These information will be used to identify you when you perform operations (commit/push) on git repositories.
  5. clone a repository ('my_repo') from the server.
    git clone git@your_git_server_name_or_ip:my_repo
    You will be asked for a passphrase for your rsa key (if you had specified one during key generation) and 'my_repo' will be created in the current directory.
  6. Download and install TortoiseGIT.
  7. Now you have to show TortoiseGIT your private key file. But, TortoiseGIT doesn't recognize private key file unless the file is in '.ppk' format. So, you need to generate a '.ppk' private key form your existing private key ('id_rsa' that was generated in step 2).
  8. Download puTTYgen.exe and run it (No installation required).
    Go to 'Conversions-->Import Key' and select your private key ('id_rsa') file. You will be asked for the passphrase for your rsa key (if you had specified one during key generation).


    'Save private key' in '.ppk' format somewhere.
    Close puTTYgen.
  9. Once you have the private key in '.ppk' format, the repository can also be cloned using TortoiseGIT rather than the command line approach described in step 5. Right click on the folder where you want to clone the repository and click on 'Git clone...'. Then enter the repository url, check 'Load putty key' checkbox and enter the location of the private key ('.ppk' format). Click 'Ok'. The repository ('my_repo') will be created.
  10. Click on 'my_repo' which was cloned in step 5 or 9, open 'TortoiseGIT-->Settings-->Git-->Remote', select origin, select the location of your '.ppk' private key file in the "Putty Key" box and click "Apply" then "Ok".

  11. Now TortoiseGIT is ready to fetch/pull/push on git using your private key. You can check it: right click on 'my_repo', then select "TortoiseGIT-->Fetch". You may be asked to enter the passphrase for your key again.

View the screenshots for TortoiseGIT to get better idea on how to use it.


Important links Related to this post:

Friday, August 16, 2013

jQuery-UI Datepicker: Month and Year selector and the 'Done' button issue

jQuery ui datepicker can be customized to hide the calendar and show only the Month and Year selector dropdowns.
In this excellent StackOverflow answer Ben Koehler has shown how to do that by hiding .ui-datepicker-calendar
.ui-datepicker-calendar {
    display: none;
}
and overriding the onClose event method:
$(function() {
    $('.date-picker').datepicker( {
        changeMonth: true,
        changeYear: true,
        showButtonPanel: true,
        dateFormat: 'MM yy',
        onClose: function(dateText, inst) { 
            var month = $("#ui-datepicker-div .ui-datepicker-month :selected").val();
            var year = $("#ui-datepicker-div .ui-datepicker-year :selected").val();
            $(this).datepicker('setDate', new Date(year, month, 1));
        }
    });
});
Problem with the above implementation: the date field can not be cleared after it is populated once (without re-loading the page). This problem occurred because of overriding the onClose method. Notice that the onClose method is called not only on clicking the 'Done' button, but also on clicking outside the datepicker dialog box.
Check the problem here:


So, we need to find a solution where the date field is populated only if the 'Done' button is clicked. A good solution has been provided in this SO answer from the same question I mentioned above. It also has a problem: the datepicker doesn't load when clicked on the date text box for the first time.
I have combined the above two answers and have made it work perfectly.


Here is the final, flawless solution:
Javascript:
$(function() {
 $('.monthPicker').datepicker({
  changeMonth: true,
  changeYear: true,
  showButtonPanel: true,
  dateFormat: 'MM yy'
 }).focus(function() {
  var thisCalendar = $(this);
  $('.ui-datepicker-calendar').detach();
  $('.ui-datepicker-close').click(function() {
   var month = $("#ui-datepicker-div .ui-datepicker-month :selected").val();
   var year = $("#ui-datepicker-div .ui-datepicker-year :selected").val();
   thisCalendar.datepicker('setDate', new Date(year, month, 1));
  });
 });
});
CSS (same as above):
.ui-datepicker-calendar {
    display: none;
}
HTML:



Check it below:


Here is the jsfiddle for this.