Skip to Content
Technical Articles

A few code snippets while developing an ADT plugin

Introduction

I’m busy developing a plug-in for ADT. It sends information about the currently selected class, program, function group etc. to the back-end, where some analysis is done and the results are presented.

The plug-in itself is not something that would be useful to publish, as the back-end is something useful only to my client, but I thought some snippets of how I achieved some key tasks might be helpful to others who embark on this journey.

These were developed on Eclipse 2020-03 using

  • ABAP Core Development Tools 3.10.2
  • ABAP Connectivity and Integrations Development Tools 1.120.0
  • Eclipse PDE 3.14.300

The backend is version 7.31 sp 17.

Connecting to the backend SAP system (on-premise)

I wanted to connect to the backend using the same credentials as the ABAP project. My application is launched in the same was as ATC, via “Run as…”

For this, I use the org.eclipse.debug.ui.launchShortcuts extension in my PDE project, with a class like this:

public class LaunchShortcut implements ILaunchShortcut {

	@Override
	public void launch(ISelection selection, String mode) {
		new myAppRunner().runFromSelection(selection);
	}

	@Override
	public void launch(IEditorPart editorPart, String mode) {
		if (editorPart instanceof MultiPageEditorPart) {
			MultiPageEditorPart editor = (MultiPageEditorPart) editorPart;
			new myAppRunner().runFromEditor(editor);
		}
	}

}

To be able to get the project credentials, I’m going to need to get some kind of project object. For the first launch method, I can get it from selection.

	public void runFromSelection(ISelection selection) {
		IProject project = ProjectUtil.getActiveAdtCoreProject(selection, null, null,
				IAdtCoreProject.ABAP_PROJECT_NATURE);
		if (project == null) {
			MessageDialog.openInformation(Display.getCurrent().getActiveShell(), "No selection",
					"No ABAP Project selected");
		} else {
   ...
...

For the second launch method it turns out that the editor (if it’s some kind of ABAP editor), implements com.sap.adt.project.IProjectProvider 

	public void runFromEditor(MultiPageEditorPart editor) {
		IProject project = null;
		if (editor instanceof IProjectProvider) {
			IProjectProvider projectProvider = (IProjectProvider) editor;
			project = projectProvider.getProject();
		}
		if (project == null) {
			MessageDialog.openInformation(Display.getCurrent().getActiveShell(), "No selection",
					"No ABAP Project selected");
		}
    ...
...

From the project, I can get the destination, connect via JCo, and run the RFC enabled function module.

	private void callBapi(IProject project, ArrayList<MyAppObjectStr> items) {
		try {
			String destinationId = com.sap.adt.project.AdtCoreProjectServiceFactory.createCoreProjectService()
					.getDestinationId(project);
			JCoDestination destination = JCoDestinationManager.getDestination(destinationId);

			JCoFunction function = destination.getRepository().getFunction("Z_MY_APP");
		...
 			function.execute(destination);
		...
		} catch (JCoException | PartInitException e1) {
			e1.printStackTrace();
		}
	}

Determining what I’ve got

This took ages. Debugging, going through the classes that make up ADT, testing, trying again and again. Until eventually, I got what I wanted without any nasty yellow (or worse red) messages coming up saying things like not an API, use discouraged – or not allowed at all.

Again, I’ve got the two launch shortcuts – one with an ISelection and one with an IEditorPart

selection was quite easy

if (selection instanceof ITreeSelection) {                              
	ITreeSelection treeSelection = (ITreeSelection) selection;  
	ArrayList<myObjects> items = new ArrayList<myObjects>();                                      
	for (final Iterator<?> i = treeSelection.iterator(); i.hasNext();) {                              
		Object nodeObject = i.next();                                                                 
		if (nodeObject instanceof TreeNode) {                                                         
			TreeNode node = (TreeNode) nodeObject;                                                    
			if (node.getValue() instanceof AdtObjectReference) {                                      
				AdtObjectReference value = (AdtObjectReference) node.getValue();                      
				myObject item = new myObject();                                                 
				item.name = value.getName();   // Name of the class for example                                                       
				item.type = value.getType().split("/")[0];  // CLAS/OC for example - I only want the bit before the /                                           
				items.add(item);                                                                      
			}                                                                                         
		}                                                                                
	}                                                                                                 
}                                                                       

IEditorPart took me a bit longer, until i released that the concrete object that’s passed to here is (I think) for every ABAP editor, an implementation of com.sap.adt.tools.core.ui.editors.IAdtFormEditor

if (editor instanceof IAdtFormEditor) {
	String objectName = editor.getTitle();
	IAdtFormEditor formEditor = (IAdtFormEditor) editor;
	String objectType = formEditor.getModel().getType();
	ArrayList<MyObject> items = new ArrayList<MyObject>();
	MyObject myObject = new MyObject();
	myObject.name = objectName.split(" ")[1]; // Splitting "SystemID ObjectName"
	myObject.type = objectType.split("/")[0]; // Splitting e.g. "CLAS/OC"
	items.add(myObject);
	...
}

Things to do

1. Ensure the “Run as myapp” option only appears when it’s contextually correct

2. I’d like to run directly from a launch configuration using the org.eclipse.debug.core.launchConfigurationTypes extension in my PDE project. This would also allow me to run from the Outline of a class, for example.

public class LaunchConfigurationDelegate implements ILaunchConfigurationDelegate {

	@Override
	public void launch(ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor)
			throws CoreException {
		monitor.beginTask("Running ...", 0);
		new myAppRunner().run(config, launch);
		monitor.done();
	}

}

What I’ve not figured out is how to get the current object from config or launch. But I have my suspicions it’ll all become clear when I get the configuration functionality installed.

3. Completely finish my app – but after 2, that’s just a question of Eclipse development, not ADT!

Most irritating aspect

Obviously, it’d be lovely if we could have a fully documented set of APIs! But it doesn’t have to be a stumbling block.

No, the most irritating aspect was when I couldn’t debug my Java code any more. In the end I resolved it by eliminating Larry Eillison’s Java, and replacing it with SAPMachine https://sap.github.io/SapMachine/. That, with a fresh install of the latest Eclipse, PDE and ADT, and everything sprang back to life.

Thanks

Sebastian Ratz and Armin Beil of the ADT development team.

Christian Drumm for his blogs on developing plugins

Andreas Gautsch for the Code Insight plugin  and ABAP Continuous Improvement plugin

Lukasz Pegiel for the ABAP Favourites plugin

Thomas Alexander Ritter for his response to the blog Extensibility Ain’t Just A 13-Letter Word, by “A former member”.

 

 

1 Comment
You must be Logged on to comment or reply to a post.
  • Thx for mentioning my plugin! I keep my fingers crossed for you to finish your project, as I also have some ideas how to use RFC calls to on-prem from Eclipse 🙂