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.

Thursday, August 1, 2013

MySQL change column text to Title Case / Proper Case / Camel Case

Problem: Change the text-value of a specific column of a mysql table into 'Title Case'

MySQL doesn't support any function for Title-Case conversion.
If the text-values of the column are all of single-word then the conversion can be done using a combination of the functions 'UPPER', 'LOWER', 'SUBSTRING' etc as suggested in this StackOverflow answer by Anupam.
But it will not work If the  text-values are of multiple words.

1. Stored Procedures/Functions can be one solution as suggested in the answers of this StackOverflow question.

2. Writing server side scripts (JSP, Python, PHP etc.) can be another solution.

A PHP solution can be found at this post "CONVERTING TO TITLE CASE IN MYSQL – CAPITALIZING MYSQL (A PHP SOLUTION)".

I am showing here how we can write a JSP script to do this.

First we create our MySQL table and insert data into it:

CREATE  TABLE `test`.`Employee` (
 `id` BIGINT NOT NULL AUTO_INCREMENT ,
 `fullName` VARCHAR(45) NULL ,
 `designation` VARCHAR(45) NULL ,
 PRIMARY KEY (`id`)
);

insert into Employee
    (fullName, designation)
values
    ('ALBERT NASIMSTEIN', 'CUSTOMER RELATIVITY OFFICER'),
    ('SIR ISSAC NASIMTON', 'APPLEICATION MANAGER'),
    ('LOUISE PASTEUR', 'MILK PASTEURISATION MANAGER'),
    ('GALILEO', 'ASTRONOMICAL OFFICER'),
    ('NIKOLA TESLA', 'ELECTRO MAGNETIC FIELD OFFICER'),
    ('ARISTOTLE', 'CHEIF EXECUTIVE OFFICER');

It will result in the following table:

id fullName designation
1 ALBERT NASIMSTEIN CUSTOMER RELATIVITY OFFICER
2 SIR ISSAC NASIMTON APPLEICATION MANAGER
3 LOUISE PASTEUR MILK PASTEURISATION MANAGER
4 GALILEO ASTRONOMICAL OFFICER
5 NIKOLA TESLA ELECTRO MAGNETIC FIELD OFFICER
6 ARISTOTLE CHEIF EXECUTIVE OFFICER

Now, We can write the JSP file, convert_to_titlecase.jsp,  like this:
<%@page import="java.sql.*"%>
<%@page import="org.apache.commons.lang3.text.WordUtils"%>
<%@page contentType="text/html;charset=ISO-8859-15" language="java" %>
<%
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
response.setDateHeader ("Expires", 0);

Statement stmt = null;
Connection conn = null;

// Set response content type
response.setContentType("text/html");
String title = "Title Case Conversion";
String docType = "\n";
out.println(docType + "\n" + "" + title
  + "\n" + "\n"
  + "

" + title + "

\n"); try { // Register JDBC driver Class.forName("com.mysql.jdbc.Driver"); String dbName = request.getParameter("dbName"); // Open a connection conn = DriverManager.getConnection("jdbc:mysql://localhost/" + dbName); // Execute SQL query stmt = conn.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); String tableName = request.getParameter("tableName"); String columnName = request.getParameter("columnName"); out.println("Database: " + dbName + "
"); out.println("Table: " + tableName + "
"); out.println("Column: " + columnName); out.println("
"); String sql; sql = "SELECT * FROM " + tableName; ResultSet rs = stmt.executeQuery(sql); long countColumn = 0; long countFail = 0; while (rs.next()) { String columnValue = rs.getString(columnName); try { rs.updateString(columnName, WordUtils.capitalizeFully(columnValue) ); rs.updateRow(); } catch(Exception exc) { out.println("" + columnValue + " not updated; " + exc.getMessage() + ""); countFail++; continue; } countColumn++; } out.println(countColumn + " columns updated successfully.
"); out.println(countFail + " failed."); out.println(""); rs.close(); stmt.close(); conn.close(); } catch (SQLException se) { // Handle errors for JDBC se.printStackTrace(); } catch (Exception e) { // Handle errors for Class.forName e.printStackTrace(); } finally { // finally block used to close resources try { if (stmt != null) stmt.close(); } catch (SQLException se2) { }// nothing we can do try { if (conn != null) conn.close(); } catch (SQLException se) { se.printStackTrace(); }// end finally try } // end try %>

On Apache Tomcat server we can test it locally by calling this script by passing the parameters dbName, tableName and columnName as follows:
http://localhost:8080/myproject/convert_to_titlecase.jsp?dbName=test&tableName=Employee&columnName=designation

It will change all the texts of designation column to Title-Case as follows:

id fullName designation
1 ALBERT NASIMSTEIN Customer Relativity Officer
2 SIR ISSAC NASIMTON Appleication Manager
3 LOUISE PASTEUR Milk Pasteurisation Manager
4 GALILEO Astronomical Officer
5 NIKOLA TESLA Electro Magnetic Field Officer
6 ARISTOTLE Cheif Executive Officer

Monday, July 2, 2012

MySql select the first row for each group

In the following table the enrollment of students in different program are shown. I want to select the last programme (ordered by date) in which each of the student is enrolled in.
id studentId programmeId startDate endDate
1 444 101 2012-01-01 2012-06-01
2 555 101 2012-01-01 2012-06-01
3 666 101 2012-01-01 2012-06-01
4 444 201 2012-06-15 2012-12-20
5 555 301 2011-07-01 2012-02-01
6 666 201 2012-06-15 2012-12-20
7 444 301 2011-07-01 2012-02-01

We have to make group of students and sort the programmes for each student by the order (descending) of their programme-end-Dates, and then select the first programme from each student-group. And the result should look like this.
studentId programme
444 201
555 101
666 201
To generate the above result the query can be written like this:
select
    R.studentId,
    (
        select
            R1.programmeId
        from
            Registration R1
        where
            R1.studentId=R.studentId
        order by
            R1.endDate DESC limit 1
    ) as "programme"
from
    Registration R
group by
    R.studentId;

Thursday, June 28, 2012

MySql: Select Query- Make A Cumulative Sum Column

Suppose we have a table like following:
transaction_id acc_no amount
1 100001 20000
2 100002 30000
3 100003 30000
4 100004 10000
5 100005 50000

And now we want a query that select a cumulative sum column along with other columns like following:
transaction_id amount cumulative
1 20000 20000.0
2 30000 50000.0
3 30000 80000.0
4 10000 90000.0
5 50000 140000.0
We can use pl/sql variables like below to generate the above result:
select
    transaction_id,
    amount,
    (@cum_sum:=@cum_sum+amount) as "cumulative"
from
    account
    JOIN (select @cum_sum := 0.0) B;

Tuesday, May 29, 2012

MySql Query: PLSQL Conditions within query

Suppose we have a table like:
transaction_id acc_no amount
1 100001 20000
2 100002 30000
3 100003 30000
4 100004 10000
5 100005 50000
Now the query
select
    acc_no,
    SUM(IF(amount>20000,amount,0)) as total_value
from
    account
where
    acc_no=100002
group by acc_no;

will produce the following result:
 
acc_no amount
100002 80000
Case statements can also be used within a query like shown in the answer of this stackoverflow question

Monday, May 14, 2012

Load/Import huge database in MySQL

phpMyAdmin doesn't allow importing database of huge size, so we have to do it from command prompt.

Go to command prompt:
cd ".../mysql5.5.16/bin"
mysql -u root -p[password if any, otherwise keep blank]
use dbname;
source .../.../dbname.sql;

Here dbname is the name of your database.

Tuesday, May 1, 2012

wxPython TextCtrl Handling KayEvent 1


The following code shows how we can Bind a wx.EVT_KEY_UP KeyEvent with a TextCtrl widget:
import wx

class MyForm(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Show Caret Position", size=(400, 140))
        panel = wx.Panel(self, wx.ID_ANY)
        sizer = wx.BoxSizer(wx.VERTICAL)
        text = wx.StaticText(panel, -1, "Text:", (10, 22))
        self.textCtrl = wx.TextCtrl(
                panel,
                -1, "",
                (50,5),
                size=(250, 50),
                style=wx.TE_MULTILINE
            )
        self.textCtrl.SetInsertionPoint(0)
        self.textCtrl.Bind(wx.EVT_KEY_UP,self.onTextKeyEvent)
        self.statusbar = self.CreateStatusBar(1)
        panel.SetSizerAndFit(sizer, wx.VERTICAL)

    def onTextKeyEvent(self, event):
        statusText = "Caret Position: "+str(self.textCtrl.GetInsertionPoint())
        self.SetStatusText(statusText,0)
        event.Skip()


#Run application
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm()
    frame.Show()
    app.MainLoop()

Thursday, April 26, 2012

Create and use preverified JAR files in Blackberry applications

This post "blackberry-tips-bikas.blogspot.com: how-to-create-library-jar-file-and-use" describes how a JAR file can be created and used as a library in Blackberry applications. But I faced some problem after following the approach described there. Then I've tried by skipping the step 5 of "How to create the JAR file" and succeeded. I'm describing the full process again here for both Eclipse and JDE:

For Eclipse:

Create the JAR file:

-- Create your Blackberry project (e.g. "MyLib")
-- Clean and build the project after adding all necessary files in the "src" folder and all necessary
    resource files in the "res" folder.
-- Package the project: right click on the project--> BlackBerry --> Package Projects
-- The "MyLib.jar" file will be created in the "ProjectDirectory\deliverables\Standard\X.0.0\" directory
    (here 'X' will be different depending on the version of OS set for your project.)
-- Go to your Eclipse JDE plugins installation folder (e.g. "C:\Eclipse"

-- Go to "C:\Eclipse\plugins\net.rim.ejde.componentpack5.0.0_5.0.0.25\components\bin\"
    The "componentpack5.0.0_5.0.0.25" can be different depending on your Eclipse JDE plugin version.

-- Copy MyLib.jar file into the "...\components\bin\" folder.
-- Open command prompt and change your current directory to the bin directory
    (>cd "C:\Eclipse\plugins\net.rim.ejde.componentpack5.0.0_5.0.0.25\components\bin\")
-- Then execute the following command:
    preverify -classpath "C:\Eclipse\plugins\net.rim.ejde.componentpack5.0.0_5.0.0.25\components\lib\net_rim_api.jar"  "MyLib.jar"
-- A folder named "output" will be created in the bin directory. The preverified jar file will be found in
   the output directory. 
-- Now extract the jar file with WinZip or such other application. Your project folders and files will be
    extracted there.

-- Delete the .cod, .cls, .cso files from there.
-- Make jar again with the remaining files and folders (i.e. make zip and rename to .jar).
-- Now you can use this jar file in another project as a library.

Use the JAR in other projects:

-- Copy the jar and paste into the lib folder of your project.
-- Right click on the jar file just pasted, and click "Add to Build Path"
-- Right click on the project, go to Build Path --> Configure Build Paths --> Java Build Paths. Select the "Libraries" tab and you will see your jar file in the list of libraries there.
-- Select the "Order and Export" tab and check the checkbox of "MyLib.jar". Press 'Ok'.
-- Your jar is added to your project.


For JDE:

 Create the JAR file:


-- Create your workspace (e.g. MyLib.jdw)
-- Create your project (e.g. MyLib.jdp)
-- Add your classes that you want your jar to contain.
-- Build your project.
-- A .jar file named MyLib.jar will be created in the "jdeworkspace-->MyLib" folder.
-- Go to your JDE installation folder
    (usually: "C:\Program Files\Research In Motion\BlackBerry JDE 5.0.0\bin")
-- Copy MyLib.jar file to the bin folder.
-- Open command prompt and change your current directory to the bin directory
    (execute command > cd "C:\Program Files\Research In Motion\BlackBerry JDE 5.0.0\bin")
-- Then execute the following command:
    preverify -classpath "C:\Program Files\Research In Motion\BlackBerry JDE 5.0.0\lib
        \net_rim_api.jar"  "MyLib.jar"

-- A folder named "output" will be created in the bin directory. The preverified jar file will be found in
   the output directory. 
-- Now extract the jar file with WinZip or such other application. Your project folders and files will be
    extracted there.
-- Delete the .cod, .cls, .cso files from there.
-- Make jar again with the remaining files and folders.
-- Now you can use this jar file in another project as a library.

Use the JAR in other project:

-- Right click on the project on JDE
-- Click properties and click on the "Build" tab.
-- Add "MyLib.jar" as Imported jar files.

Saturday, April 14, 2012

Customizing the Rows of a BlackBerry TreeField

Here is an example of how we can customize a TreeField of BlackBerry:
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.TreeField;
import net.rim.device.api.ui.component.TreeFieldCallback;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;

public class TreeDemo extends MainScreen {
 int parent[] = {1,2,3,4,5,6,7,8,9};
 int child[][] = new int [10][10];
 int child_child[][][] = new int [10][10][10];
 
 int rowHeight = 27;
 
 CustomTreeFieldCallback treeCallback = new CustomTreeFieldCallback();
 VerticalFieldManager vm = new VerticalFieldManager(
         Field.FOCUSABLE 
        |  VERTICAL_SCROLL 
        |  VERTICAL_SCROLLBAR
       );
 TreeField myTree = new TreeField(treeCallback, Field.FOCUSABLE);

 public TreeDemo() {
  vm.add(new LabelField("Table:"));
  myTree.setRowHeight(rowHeight);
  myTree.setIndentWidth(15);
  myTree.setDefaultExpanded(false);
  for(int i = parent.length-1; i >= 0 ; i--) {
   parent[i] = myTree.addChildNode(0, "Parent_" + (i+1));
   child[i] = new int[4];
   for(int j = child[i].length-1; j >=0 ; j--) {
    child[i][j] = 
      myTree.addChildNode(
       parent[i], 
       "Child_"+ (i+1) + "_" + (j+1)
      );
    child_child[i][j] = new int[3];
    for(int k = child_child[i][j].length-1; k >= 0 ; k--) {
     child_child[i][j][k] 
                    = myTree.addChildNode(
                      child[i][j], 
                      "Child_of_Child_"+ 
                        (i+1) + "_" + 
                         (j+1)+ "_" + (k+1)
                      );
    }
   }
  }
  vm.add(myTree);
  add(vm);
 }
 
 private class CustomTreeFieldCallback implements TreeFieldCallback {

  public void drawTreeItem(TreeField treeField, Graphics graphics, int node,
    int y, int width, int indent) {
   // TODO Auto-generated method stub
   String string = (String) treeField.getCookie(node);
   int preservedColor = graphics.getColor();
   
   if(treeField.getCurrentNode() == node) {
    graphics.setColor(0x0CCCC0);
   } else {
    graphics.setColor(0x404040);
   }
   graphics.fillRect(0, y, Display.getWidth(), treeField.getRowHeight());
   
   Bitmap iconImage;
   int iconImageWidth = 0;
   indent -= 20; // decrease the extra indentation for all nodes.
   if(treeField.getFirstChild(node) != -1){ // if the node is not a leaf node
    if(treeField.getExpanded(node)) {
     iconImage = Bitmap.getBitmapResource("icon_arrow_down.png");
     iconImageWidth = iconImage.getWidth();
    } else {
     iconImage = Bitmap.getBitmapResource("icon_arrow_right.png");
     iconImageWidth = iconImage.getWidth();
    }
    graphics.drawBitmap(
       indent, 
       y, 
       indent+iconImageWidth, 
       treeField.getRowHeight(), 
       iconImage, 
       0, 
       0
      );
   }

   if( treeField.getCurrentNode() == node ) {
    graphics.setColor(0x404040);   
   } else {
    graphics.setColor(0x0CCCC0);
   }
   graphics.drawText(string, indent+iconImageWidth, y);
   
   graphics.setColor(preservedColor);
  }

 }
}
In order to associate some actions for clicking on the leaf nodes, the navigationClick or touchEvent methods of TreeField class should be customized.

Tuesday, April 3, 2012

Invoking Google Map From BlackBerry Applications

Google Maps can be invoked as an application from blackberry applications. For that we need to first download Google Maps and then use the following code to invoke google maps as an application:


/**
* Starts the Google Maps application and the specified locatin is shown on map
* @param latitude the latitude of the location to show
* @param longitude the longitude of the location to show
* @param title the title of the location to show
* @param description the description of the location to show
*/
public void showGoogleMap(double latitude, double longitude, String title, String description) {
try {
int mh = CodeModuleManager.getModuleHandle("GoogleMaps");
if (mh == 0) {
throw new ApplicationManagerException("GoogleMaps isn't installed");
}
URLEncodedPostData uepd = new URLEncodedPostData(null, false);
uepd.append("action","LOCN");
uepd.append("a", "@latlon:"+latitude+","+longitude);
uepd.append("title", title);
uepd.append("description", description);
String[] args = { "http://gmm/x?"+uepd.toString() };
ApplicationDescriptor ad = CodeModuleManager.getApplicationDescriptors(mh)[0];
ApplicationDescriptor ad2 = new ApplicationDescriptor(ad, args);
ApplicationManager.getApplicationManager().runApplication(ad2, true);
} catch(final Exception excp) {
Dialog.alert("Sorry, can't start Google Map: " + excp.getMessage());
}
}

For more info, see this StackOverflow Answer.

Monday, February 27, 2012

BlackBerry DateTimePicker: Selecting a date withing 7 days from now


DateTimePicker can be used to select a particular date. After user selects a date, it can be checked whether the date is within a particular period of time using the after() and before() methods of Calendar.

The DateTimePicker is shown each time the DateTimePicker.doModal()  method is called. A Calendar object of the selected date can be found by calling the DateTimePicker.getDateTime() method.
private String dateText;
Calendar todaysDate = Calendar.getInstance();

public void pickDate()
{
DateTimePicker datePicker = null;

Calendar dateAfter7days = Calendar.getInstance();

long millsAfter7Days = System.currentTimeMillis() + 6*24*60*60*1000 ;
dateAfter7days.setTime(new Date(millsAfter7Days));

datePicker=DateTimePicker.createInstance(todaysDate,"MMMM dd, yyyy",null);
if(datePicker.doModal())
{
if(
datePicker.getDateTime().before(todaysDate)
||
datePicker.getDateTime().after(dateAfter7days)
) {
final String current =
todaysDate.get(Calendar.DAY_OF_MONTH) +
"/" +
( todaysDate.get(Calendar.MONTH)+1 ) +
"/"+
todaysDate.get(Calendar.YEAR);

final String after7days =
dateAfter7days.get(Calendar.DAY_OF_MONTH) +
"/" +
( dateAfter7days.get(Calendar.MONTH)+1 ) +
"/"+
dateAfter7days.get(Calendar.YEAR);

UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert("Date should be within "+ current +" to " + after7days );
}
});
} else {
Calendar chosenDate = datePicker.getDateTime();
dateText =
chosenDate.get(Calendar.DAY_OF_MONTH) +
"/" +
( chosenDate.get(Calendar.MONTH)+1 ) +
"/"+
chosenDate.get(Calendar.YEAR);
}
}
}

Tuesday, January 31, 2012

Animated GIF image Field With Text

This is a sample code for an animated GIF image field with a text at the bottom:
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.system.GIFEncodedImage;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.BitmapField;

//A field that displays an animated GIF.

public class ImageTextField extends BitmapField
{
private GIFEncodedImage gifimage; //The image to draw.
private String text;
private int currentFrame; //The current frame in the animation sequence.
private AnimatorThread animatorThread;

private final int vSpace = 6;
private final int padding = 5;

private int xImage = 0;
private int yImage = 0;
private int xText = 0;
private int yText = 0;

public ImageTextField(EncodedImage image, String txt)
{
super(image.getBitmap(), 0);
byte[] arr = image.getData();
gifimage = (GIFEncodedImage) EncodedImage.createEncodedImage(arr, 0, arr.length);
text = txt;

animatorThread = new AnimatorThread(this);
animatorThread.start();
}

public ImageTextField(EncodedImage image, String txt, long style)
{
super(image.getBitmap(), style);
byte[] arr = image.getData();
gifimage = (GIFEncodedImage) EncodedImage.createEncodedImage(arr, 0, arr.length);
text = txt;

animatorThread = new AnimatorThread(this);
animatorThread.start();
}

public int getPreferredWidth() {
return (gifimage==null ? 0 : gifimage.getWidth()) + 50;
}


public int getPreferredHeight() {
int imageHeight = gifimage==null ? 0 : gifimage.getHeight();
int textHeight = getFont().getHeight();
return imageHeight + vSpace + textHeight + 2 * padding;
}


protected void layout(int width, int height) {
width = Math.min(width, getPreferredWidth());
height = Math.min(getPreferredHeight(), height);

int imageWidth = (gifimage==null ? 0 : gifimage.getWidth());
int imageHeight = (gifimage==null ? 0 : gifimage.getHeight());

xImage = (width - imageWidth) / 2;
yImage = padding;

xText = (width - getFont().getAdvance(text)) / 2;
yText = yImage + imageHeight + vSpace;

setExtent(width, height);
}

protected void paint(Graphics graphics)
{

graphics.drawImage(xImage, yImage,
gifimage.getFrameWidth(currentFrame), gifimage.getFrameHeight(currentFrame), gifimage, currentFrame, 0, 0);

int oldColor = graphics.getColor();
graphics.setColor(Color.WHITE);
graphics.drawRoundRect(0, 0, getWidth(), getHeight(), 5, 5);
graphics.drawText(text, xText, yText);
graphics.setColor(oldColor);
}

//Stop the animation thread when the screen the field is on is
//popped off of the display stack.
protected void onUndisplay()
{
animatorThread.stop();
super.onUndisplay();
}


//A thread to handle the animation.
private class AnimatorThread extends Thread
{
private ImageTextField theImageField;
private boolean keepGoing = true;
private int totalFrames; //The total number of frames in the image.
private int loopCount; //The number of times the animation has looped (completed).
private int totalLoops; //The number of times the animation should loop (set in the image).

public AnimatorThread(ImageTextField theField)
{
theImageField = theField;
totalFrames = gifimage.getFrameCount();
totalLoops = gifimage.getIterations();

}

public synchronized void stop()
{
keepGoing = false;
}

public void run()
{
while(keepGoing)
{
//Invalidate the field so that it is redrawn.
UiApplication.getUiApplication().invokeAndWait(new Runnable()
{
public void run()
{
theImageField.invalidate();
}
});

try
{
//Sleep for the current frame delay before
//the next frame is drawn.
sleep(gifimage.getFrameDelay(currentFrame) * 10);
}
catch (InterruptedException iex)
{} //Couldn't sleep.

//Increment the frame.
++currentFrame;

if (currentFrame == totalFrames)
{
//Reset back to frame 0 if we have reached the end.
currentFrame = 0;

++loopCount;

//Check if the animation should continue.
if (loopCount == totalLoops)
{
keepGoing = false;
}
}
}
}
}
}
Now this animated image field can be added to a manager:
VerticalFieldManager mainLayout = getCustomManager();
mainLayout.setBackground(BackgroundFactory.createSolidBackground(Color.BLACK));
EncodedImage ec = EncodedImage.getEncodedImageResource("myimage.gif");
ImageTextField ag = new ImageTextField(ec, "My Text", FIELD_HCENTER);
mainLayout.add(ag);

Tuesday, January 10, 2012

Calculate Distance on Sphere ( Given latitude & longitude values)

This is the code for calculating the distance between two given points by their latitude and longitude values.
public static double getOrthodromicDistance(
double lat1,
double lon1,
double lat2,
double lon2)
{
double R = 6371.0; // km
double dLat = convertDegreeToRadians((lat2 - lat1));
double dLon = convertDegreeToRadians((lon2 - lon1));
lat1 = convertDegreeToRadians(lat1);
lat2 = convertDegreeToRadians(lat2);

double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
double c = 2 * MathUtilities.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = R * c;
return distance;
}

The formula was taken from here.

The MathUtilities.atan2() method is found only in BlackBerry API 4.6 or higher See The definition of atan2 here
This can also be calculated like this:
double atan2t(double y, double x) {
double lo, hi, res, val, resval;
double ERR = 1e-9;
if (Math.abs(x) < ERR) {
if (Math.abs(y) >= ERR) {
return ((y / Math.abs(y)) * PI / 2.0);
} else {
return (0.0);
}
}

val = Math.abs(y / x);
lo = 0.0;

hi = PI / 2;
res = (lo + hi) / 2.0;
resval = Math.tan(res);

while (Math.abs(hi - lo) > ERR) {
if (resval > val) {
hi = res;
} else {
lo = res;
}

res = (hi + lo) / 2.0;
resval = Math.tan(res);
}

if (x < 0.0) {
res = PI - res;
}

if (Math.abs(y) >= ERR) {
return ((y / Math.abs(y)) * res);
} else {
return res;
}
}