Sunday, August 10, 2014

Using reexport with Require-Bundle in Manifest.mf.

Hi,

Today I am going to give a small description on use of  'reexport' with Require-Bundle in Manifest.mf.

Require-Bundle is used to add dependencies to other bundles.

Example:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: P2
Bundle-SymbolicName: p2
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: p2.Activator
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
Export-Package: p2

What is reexport feature in Require-Bundle.

OSGI has given a directive called 'visibility' which can be used with 'Require_bundle'.
If the value is private (Default), then all visible packages from
the required bundles are not re-exported. If the value is reexport then
bundles that require this bundle will transitively have access to these
required bundle’s exported packages.

Eg:

Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime,
 p1;bundle-version="1.0.0";visibility:=reexport

Here P1 bundle is re-exported to other dependent plugins.
Let us understand this with a simple exmaple.

1. Create 3 plugin projects P1, P2, P3.
2. Situation is : P3 requires P2. P2 requies P1. Now add add theses dependencies.
-----------------------------------------------------------------------------------------------------
Eg:
Manifest of  P3: 
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: P3
Bundle-SymbolicName: p3
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: p3.Activator
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime,
 p2;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy

Manifest of P2:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: P2
Bundle-SymbolicName: p2
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: p2.Activator
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime,
 p1;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
Export-Package: p2

Manifest of P1:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: P1
Bundle-SymbolicName: p1
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: p1.Activator
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
Export-Package: p1
------------------------------------------------------------------------------------------------------

3. Now if you try to access any class of p1 from p3 it will say that p1 is not resolvable.
4. How can i still access P1 exported package? They way left is adding P1 as require bundle in P3.

5. There is another way of doing it. As we see that P3 requires P2.
    And P2 as access to P1, So P2 can re-export the P1 bundle to its dependents for access.
    This can be done using visibillity:reexport.

eg:

Manifest of P2:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: P2
Bundle-SymbolicName: p2
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: p2.Activator
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime,
 p1;bundle-version="1.0.0";visibility:=reexport
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy

Export-Package: p2


So, Now I am able to access P1 from P3 as well.


----------------------------------------------------------------------------------------------------------
Another use of using visibility:reexport:

Situation: Let us suppose that we have a Plugin A and Plugin B requires Plugin A.
                 Now there is a business requirement to break Plugin A into smaller bundle due to some re factoring or so.
Now breaking break Plugin A as Plugin A, Plugin A1, Plugin A2.

So Plugin A----> requires  Plugin A1 and Plugin A2.

What changes needs to be done in Plugin B to work this application correctly?
Yes correct, No change in Plugin B would be required if we use visibility:reexport derivative.

Simply, re-export the bundles which Plugin A requires and Plugin B will be able to use it without any error.

eg:
Entry in Plugin A manifest.

Require-Bundle: A1;visibility:=reexport,
                          A2:visibility:=reexport

----------------------------------------------------------------------------------------------------------------------------------

Please do give your valuable suggestions to improve it and your queries.
Cheers. :)

Thursday, August 7, 2014

Beyond Hello World.

Hi, I got a question from someone to write program to convert Number to word.
I thought to write an simple looking algorithm, but when i started doing this it was not so simple.

Let me rephrase the question.

Convert  Number in the Range of [-999999 , 999999] to words.

Example :  Input no = 45678

output =  Forty Five Thousand Six Hundred And Seventy Eight

Input = -43675
output = Minus Forty Three Thousand Six Hundred And Seventy Five


Program:

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;

public class StringManupulation {

    private static  Map<Integer,String> valueWordMap = new HashMap<>();
   
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
       
        String number;
        while(true){
        System.out.println("Please enter the Numeric No Between -999999 and 999999 : ");
        number = scan.nextLine();
        if(checkIfNumberValid(number)){
            break;
        }
        }
        convertNumberToWords(Integer.valueOf(number));
       
    }

    private static void convertNumberToWords(Integer number) {
        TreeMap<Integer,Integer> faceValueMap = new TreeMap<>();
       
        prepareValueWordMap();
        boolean isNoNegative = false;
        if(String.valueOf(number).contains("-")){
            number = Math.abs(number);
            isNoNegative=true;
           
        }
        Integer baseNo = getBaseNo(String.valueOf(number).length());
        boolean reachedEnd=false;
        int length=0;
        while(baseNo>=1 && !reachedEnd){
            if(baseNo==1){
                reachedEnd=true;
            }
            faceValueMap.put(baseNo, number%(baseNo*10)/baseNo);
            length++;
            baseNo = getBaseNo(String.valueOf(number).substring(length).length());
           
        }
        String word="";
        Integer temp = null;
        String appender="";
        String andString=" And";
        int index=-1;
        for(Integer key : faceValueMap.descendingKeySet()){
            index++;
            if(faceValueMap.get(key)!=0 || null!=temp){
                if(key==1000000 || key == 10000 || key==10){
                    temp=faceValueMap.get(key);
                    continue;
                }
                if(key!=1){
                    appender = " " + valueWordMap.get(key);
                    andString="";
                }
                if((checkTrailingZeros(number,index) || key==1) && !word.isEmpty()){
                    andString=" And";
                }
               
                if(null!=temp){
                   
                    word =  word + andString + " " + valueWordMap.get(temp*10) + " " + valueWordMap.get(faceValueMap.get(key)) + appender;
                }
                else{
                    word =  word + andString +" " + valueWordMap.get(faceValueMap.get(key)) + appender;
                }
                temp=null;
            }
            appender="";
        }
        if(isNoNegative){
            word = "Minus" + word;
        }
        System.out.println(word);
    }

    private static boolean checkIfNumberValid(String number) {
        if(number.length()<8){
            try{
                Integer.parseInt(number);
            }
            catch(Exception ex){
                System.out.println("Invalid No");
                return false;
            }
        Integer i = Integer.valueOf(number);
        if(!(i>=-999999 && i<=999999)){
            return false;
        }
        }
        else{
            return false;
        }
        return true;
       
    }

    private static boolean checkTrailingZeros(Integer number, int index) {
        for(int i = index+1;i<String.valueOf(number).length();i++){
            if(String.valueOf(number).charAt(i)=='0'){
                continue;
            }
            else{
                return false;
            }
        }
        return true;
    }

    private static void prepareValueWordMap() {
        valueWordMap.put(100000, "Lakh");
        valueWordMap.put(10000, "Ten Thousand");
        valueWordMap.put(1000, "Thousand");
        valueWordMap.put(100, "Hundred");
        valueWordMap.put(10, "Ten");   
        valueWordMap.put(1, "One");   
        valueWordMap.put(2, "Two");   
        valueWordMap.put(3, "Three");   
        valueWordMap.put(4, "Four");   
        valueWordMap.put(5, "Five");   
        valueWordMap.put(6, "Six");   
        valueWordMap.put(7, "Seven");   
        valueWordMap.put(8, "Eight");   
        valueWordMap.put(9, "Nine");   
        valueWordMap.put(11, "Eleven");    ;
        valueWordMap.put(12, "Twelve");   
        valueWordMap.put(13, "Thirteen");   
        valueWordMap.put(14, "Fourteen");   
        valueWordMap.put(15, "Fifteen");   
        valueWordMap.put(16, "Sixteen");   
        valueWordMap.put(17, "Seventeen");   
        valueWordMap.put(18, "Eighteen");   
        valueWordMap.put(19, "Nineteen");   
        valueWordMap.put(20, "Twenty");   
        valueWordMap.put(30, "Thirty");   
        valueWordMap.put(40, "Forty");   
        valueWordMap.put(50, "Fifty");   
        valueWordMap.put(60, "Sixty");   
        valueWordMap.put(70, "Seventy");   
       
        valueWordMap.put(80, "Eighty");   
        valueWordMap.put(90, "Ninety");   
        valueWordMap.put(0, "");   
       
       
    }

    private static Integer getBaseNo(double d) {
       
        return (int) Math.pow(10, d-1);
    }

}