Monday, September 29, 2014

Using Aspects in Equinox Environment.


 Using Aspects in Equinox Environment.



Aspects can be used to weave into the original code and manipulate it according to our requirement.
Let’s see how we can use Aspects in Equinox environment.
Let us understand when you can need to use Aspect when you are doing some kind of eclipse/Equinox/osgi development.
I will take a very simple example. Suppose Your application shows a view which is provided by  some 3rd party and this view shows some Treeviewer. This TreeViewer has its own content provider and label provider. Now you have a requirement in which you have change the image show for every tree node at runtime depending on some business requirement.
To work on above scenario you would need to have control on label provide or you would like to override it and then do some kind of tweak to provide images at runtime and show it.
I have a better way to do this. Using Aspects!!!!!
What I will do is write an aspect where I will use the pointcut , getImage() method of that original label provider and provide my own image to it. And I am done.
Following Setup is required for  this:
  1. Install the latest version of AJDT from the AJDT update site.
  2. latest build of Equinox Aspects, which contains plugins regarding equinox weaving with aspectJ
Steps to understand this with an example:
  1. Create a sample plugin project, having a view and a treeviewer with label provider.


  1. Export  the above sample project as deployable plugin, so that is can be used as 3rd party jar/contribution of view.
  1. Now put the above sample deployable jar as target in your eclipse.
 
  1. Create a new plugin project, were we will use the 3rd party sample plugin to show its view and it tree.
  2. Make some changes in Menifest.mf to add some dependencies  and attributes:
  • Export the package which contains aspects and provide the name of those aspects(Here ViewAspect is the name of Aspect which we are going to use).
  • ‘Eclipse-SupplimentBundle’ attribute conatins bundle which are to be weaved.

  1. Create the ViewAspect.aj in package we have mentioned in Manifest.mf.
Here you can see, I have created a pointcut which is concerned about getImage() method of ViewLabelProvider. I am returning my image, instead of original image for Tree node.
  1. Now its Time to run our application.
Configure your runtime
  • Tell Equinox to use org.eclipse.equinox.weaving.hook as a framework extension (in the "VM arguments" of your launch configuration,  add                                                -Dosgi.framework.extensions=org.eclipse.equinox.weaving.hook).
  • The AspectJ weaving service (bundle org.eclipse.equinox.weaving.aspectj) must be started before any classes are loaded from any bundles targeted for weaving

  1. We are done now. We can run this application, We will see that Sample view Treeviewer will take my custom image now.
You can Access the code related to above mentioned scenario at GitHub:
Feel Free to comment and provide your responses to understand the topic more.
CHEERS!!!

Tuesday, September 16, 2014

Using Activities in Eclipse Plugin Developments.

Using Activities in Eclipse Plugin Developments.

First lets understand Activities in Eclipse World.
An activity is a logical grouping of functionality that is centered around a certain kind of task. This means we can group few functionality with any kind of task and can identify that group of functionality with an activity. 

Let us understand this with an example. Lets suppose you want to filter some functionality depending on some scenario or permission or business requirement.Here we can use activities. I will demonstrate this with live code here.

1. Requirement: There is are few menu items present in File menu. And on click of toggle button in Run Menu, I want to hide/show menu items in File Menu.

There are 2 ways of doing this using Activities.
     a) Conventional Activities:
     b) Expression Based Activities.


a) Conventional Activities: It is the general way in which we define activity in plugin.xml 
                                              and then use WorkbenchActivitySupport to set those activities which has to be enabled.

Defining activities

Activities are defined using the org.eclipse.ui.activities extension point.

<extension
         point="org.eclipse.ui.activities">
      <activity
            id="TestActivities.customActivity"
            name="CustomActivity">
      </activity>
      <activityPatternBinding
            activityId="TestActivities.customActivity"
            pattern="TestActivities/org.eclipse.ui.file.import">
      </activityPatternBinding>
   </extension>

Activity has: 
         id: Give it a unique name.
        name: Give it some name.

Now bind this activity with a functionality. Here we have done with org.eclipse.ui.file.import identifier.
An activity-pattern binding associates an activity with a regular expression that is used to match identifiers. The syntax of the regular expressions conforms to the usage defined in java.util.regex.Pattern. The identifiers describing functionality that can be filtered from the UI are of the form <plugin-id>/<local-id> or simply <local-id>.

Similarly we can associate activity with some category using <categoryActivityBinding> and associate with another activity also using <activityRequirementBinding>.

Activity pattern bindings can be used to associate large groups of contributions with a particular activity, or to associate very specific contributions with an activity like : 


  • Views and editors
  • Perspectives
  • Preference and property pages
  • Menus and toolbars
  • New wizard
  • Common Navigator Action Providers

Now once we have set the above Activity, we need to use API to enable/disable the desired Activity and enable/disable its associated functionality.

Here I am taking an example , in which I have a Run Menu and it contains a menu item named 'ToggleFileImport' and this button will toggle(show/hide) Import menu item present in File menu.

I have created a commandHandler for 'ToggleFileImport' menu item.


public class CustomHandlerForActivity extends AbstractHandler {


@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
disableRun();
return null;
}
private void disableRun() {
IWorkbench iWorkbench = PlatformUI.getWorkbench();
IWorkbenchActivitySupport activitySupport = iWorkbench.getActivitySupport();
IActivityManager activityManager = activitySupport.getActivityManager();
Set<String> enabledActivityIds = new HashSet<String>         
                                                                          (activityManager.getEnabledActivityIds());
Set<String> definedActivityIds = activityManager.getDefinedActivityIds();
System.out.println(definedActivityIds);
System.out.println(enabledActivityIds);
Iterator<String> iterator = enabledActivityIds.iterator();
boolean activityEnabled=false;
 
IActivity activity = activityManager.getActivity("TestActivities.customActivity");
if(activity.isEnabled()){
enabledActivityIds.remove("TestActivities.customActivity");
}
else{
enabledActivityIds.add("TestActivities.customActivity");
}
activitySupport.setEnabledActivityIds(enabledActivityIds);
}
}

Here we can see that IWorkbenchActivitySupport is responsible for setting the list of enabled Activity ids.


b) Expression Based ActivitiesActivities that filter out UI elements which are not supposed to be shown to the user (e.g. based on their access rights) will be called expression-based activities.

Here I have implemented which a sample expression which is set by clicking a menu Item.
It is similar to the above example , in which I have a Run Menu and it contains a menu item named 'TogglePrint' and this button will toggle(show/hide) Print menu item present in File menu by enabling and disabling the activity.


<activity
            id="TestActivities.activity3"
            name="RemovePrintActivity">
         <enabledWhen>
            <with
                  variable="isCommadToTogglePrintMenu">
               <equals
                     value="enabled">
               </equals>
            </with>
         </enabledWhen>
         
      </activity>
      <activityPatternBinding
            activityId="TestActivities.activity3"
            pattern="TestActivities/org.eclipse.ui.file.print">
      </activityPatternBinding>



Here you can see <enabledWhen>, to set an expression for its enabling.

<extension
         point="org.eclipse.ui.commands">
      <command
            defaultHandler="testactivities.CustomHandlerForActivity"
            id="TestActivities.testCommand"
            name="TestCommand">
      </command>
      <command
            defaultHandler="testactivities.TogglePrintHandler"
            id="TestActivities.togglePrint"
            name="TogglePrint">
      </command>
   </extension>

<extension
         point="org.eclipse.ui.services">
      <sourceProvider
            provider="testactivities.CustomSourceProvider">
         <variable
               name="isCommadToTogglePrintMenu"
               priorityLevel="workbench">
         </variable>
      </sourceProvider>
   </extension>

Here you can see that I am using "org.eclipse.ui.services" extension point to set expression value using source provider.

public class CustomSourceProvider extends AbstractSourceProvider {


public final static String TOGGLE_PRINT = "isCommadToTogglePrintMenu";

private final static Map<String, String> stateMap = new HashMap<String,String>();
private final static String[] PROVIDED_SOURCE_NAMES = new String[] { TOGGLE_PRINT };
public final static String ENABLED = "enabled";
 public final static String DISENABLED = "disabled";
 private boolean enabled = true;
 
public CustomSourceProvider() {
// TODO Auto-generated constructor stub
}

@Override

public void dispose() {
// TODO Auto-generated method stub

}


@Override

public Map getCurrentState() {
stateMap.put(TOGGLE_PRINT, "enabled");
return stateMap;
}

@Override

public String[] getProvidedSourceNames() {
return PROVIDED_SOURCE_NAMES;
}

public void toogleEnabled() {
   enabled = !enabled ;
   String value = enabled ? ENABLED : DISENABLED;
   fireSourceChanged(ISources.WORKBENCH, TOGGLE_PRINT, value);
 }


}


public class TogglePrintHandler extends AbstractHandler {


@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
ISourceProviderService sourceProviderService = (ISourceProviderService) HandlerUtil
       .getActiveWorkbenchWindow(event).getService(ISourceProviderService.class);
   // now get my service
CustomSourceProvider provider = (CustomSourceProvider) sourceProviderService
       .getSourceProvider(CustomSourceProvider.TOGGLE_PRINT);
provider.toogleEnabled();
return null;
}

}


So we can see that Activities can be used on both ways and can be implemented.


Full Sample code can be accessed from following location:

https://github.com/sanjar/Day_Today/tree/master/TestActivities


Your suggestions and queries are invited....

CHEERS!!!

Friday, September 5, 2014

Equinox Transform Revealed

Equinox Transform Revealed

Hey!!!!!

Working with Eclipse plugins is really awesome and challenging.
While working with OSGI stuffs, there are many situation when
* we want to suppress some of the functionality provided by any plugin or
* we want to modify the extension point at runtime to put in our own functionality on top of it.

One answer could be directly go and modify the stuff, may be plugin. xml or Manifest.mf.

But what would we do if we don't have any control on those code? That could be a third party plugin, but I want to suppress its some views to be visible in my application.

Potential Solution

Then there are 2 best solutions to it:

1. Equinox Transform: I will talk on it more.

2. Eclipse Activities : You can get it in details here.


Equinox Transform
As the name 'Transform' tells that it is going to transform. Yes, We can transform the stuffs what we have in Eclipse plugin development.

I will put in some scenario when we could need this.

i) I have Extension point given by a third party, but I don't want this to be in my application.
ii) I want that 3rd party perspective, but I want to give it my name.
iii) I want to add/remove some of the views to that 3rd party Perspective
iv) Modify the bundles name etc

many more.....

We can do anything we want.Nothing is fixed. everything is modifiable.
You can read theories on it here Eclipse wiki .
We will go step by step to do it with an example.

Ensure that you have these plugins in your target. If not you can update with latest OSGI.
  • org.eclipse.equinox.transforms.xslt
  • org.eclipse.equinox.transforms.hook

Step 1: Create Eclipse plugin 1



Step 2: Create a Sample View in it.
Step 3: Create another plugin 2 with a Sample view. (Assume this is a 3rd party plugin)

Now we want to suppress or remove the view contributed by plugin 2.

Step 4:  create a file named 'transform.csv' in plugin 1 with following pattern:

<pluginid>,<resource file>,<xslt file>

<pluginid> : The plugin id whose file is to modified.
<resource file> : Name of the resource that need to be modified.
<xslt file> : location of xslt file which is used for transforming the <resource file>
eg: 
plugin id: com.test.sample.plugin
resource file : plugin.xml
xslt file : xslt/tes.xslt

then transform.csv will have value like the this: 
com\.test\.sample\.plugin,plugin\.xml,/xslt/test.xslt


Step 5: create the xslt file. which exactly modifies the resource file mentioned in transform.csv
Sample content

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions">


<xsl:template match="extension[@point='org.eclipse.ui.views']/view[@id='com.test.sample.plugin.views.SampleView']">
</xsl:template>
<!-- identity transformation - copy everything (nodes and attributes) without 
modifications -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

Now your project structure will look something like this.



Step 6 : Now we need to register our 'transform.csv' with proper transformerType in eclipse services.
For this open the Activator.start() of Plugin 1 and all following line of codes:

Hashtable<String, String> properties = new Hashtable<>();
properties.put("equinox.transformerType", "xslt");
registration= context.registerService(URL.class.getName(), context.getBundle().getEntry("/transform.csv"), properties);


Step 7 : Now include plugin 2(3rd party plugin)  in plugin 1 dependencies.

Step 8 : Now its time to run the application.

Please ensure following to be set in run configuration or config.ini file, before running the application:

i)osgi.bundles=org.eclipse.equinox.common@2:start,org.eclipse.core.runtime@start,org.eclipse.equinox.transforms.xslt@1:start
ii) osgi.bundles.defaultStartLevel=4
iii) osgi.framework=org.eclipse.osgi
iv) osgi.framework.extensions=org.eclipse.equinox.transforms.hook


If we do above mentioned steps correctly , we will see that it has removed the view contributed by plugin 2.

Complete Sample Code:

Plugin 1 : https://github.com/sanjar/Day_Today/tree/master/TestEquinoxTransform
Plugin 2(3rd Party) : https://github.com/sanjar/Day_Today/tree/master/com.test.sample.plugin 

Note: I have added a launch file (in Plugin 1) for help to set the proper plugins and its start levels.

Hope This will help in understanding Equinox (Magic) Transform. :)

Please comment your views and suggestions on it.

CHEERS!!!