55
SAP Scripting Framework: How to Write a Scripting Generator SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 1 SAP Scripting Framework: How to Write a Scripting Generator Applies To SAP Scripting Framework 0.9.4; Eclipse 3.2; Java 1.4; Python; Java Emitter Templates Summary This article gives an introduction in developing custom scripting generators for the SAP Scripting Framework. The latter may generate scripting code utilizing backend access in any scripting language or even pass the service connection data to any kind of text file or data consumer. Editor's Note: Download associated ZIP archive with the sample projects . Author: Vasil Bachvarov ([email protected] ) Company: SAP AG Date: 16 February 2007 Version: 1.0.4 Author Bio Vasil Bachvarov has been working for SAP AG since January, 2005. He has developed demo applications and tests for the Composite Applications Framework project, Guided Procedures and does research in the area of scripting language integration with SAP software. Currently considered languages are PHP, Ruby, Perl and Perl. Vasil is a graduate student at the Technical University of Darmstadt, Germany, major Informational and Communicational Technology. He has about 6 years experience in software development.

SAP Scripting Framework: How to Write a Scripting Generator

  • Upload
    others

  • View
    35

  • Download
    0

Embed Size (px)

Citation preview

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 1

SAP Scripting Framework: How to Write a Scripting Generator

Applies To SAP Scripting Framework 0.9.4; Eclipse 3.2; Java 1.4; Python; Java Emitter Templates

Summary This article gives an introduction in developing custom scripting generators for the SAP Scripting Framework. The latter may generate scripting code utilizing backend access in any scripting language or even pass the service connection data to any kind of text file or data consumer. Editor's Note: Download associated ZIP archive with the sample projects. Author: Vasil Bachvarov ([email protected]) Company: SAP AG Date: 16 February 2007 Version: 1.0.4

Author Bio Vasil Bachvarov has been working for SAP AG since January, 2005. He has developed demo applications and tests for the Composite Applications Framework project, Guided Procedures and does research in the area of scripting language integration with SAP software. Currently considered languages are PHP, Ruby, Perl and Perl. Vasil is a graduate student at the Technical University of Darmstadt, Germany, major Informational and Communicational Technology. He has about 6 years experience in software development.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 2

Abstract SAP Scripting Framework is an innovative technology that enables scripting developers to rapidly integrate SAP service calls into their scripts. The product is based on the Eclipse platform and therefore inherits its native flexibility and extensibility. The main goals of SAP Scripting Framework are:

• Repository browsing for common SAP backend systems (R/3 BAPIs, R/3 web services, ESR, SAP-XI, etc.);

• Generation of scripting code in any scripting language (the variety of languages is limited only by what scripting generators are installed);

• Plug-in based extensibility enabling developers to write their own code generators for other languages or connectors for other backend systems;

• Support for concurrent backend service connectors for the same language (e.g. PHP);

• Achieving user friendly approach to download and use out of the box the framework as well as easy installation of new features or updates of the current ones. This is possible thanks to the Eclipse update mechanism;

• Integrated documentation, links and sample applications, consuming the generated code, installable per one click from the update site.

This article helps you to learn creating custom code generators for SAP Scripting Framework and understand its extension API. As example we will take the Python scripting language and we will write a Python code generator and integrate it into SAP Scripting Framework. Target audience is scripting developers or any person with Java knowledge, willing to develop custom generators for the Framework. Although Eclipse plug-in development knowledge is essential for understanding the concepts of extending SAP Scripting Framework, this article tries to make possible even for people that do not know Eclipse architecture in details to develop custom generators. Knowledge of XML is a prerequisite for understanding the text.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 3

Table of Contents Preparation ...................................................................................................................................... 4 Basic Concept of Extending Eclipse and Particularly SAP Scripting Framework ........................... 4

Eclipse Plug-In Mechanism.......................................................................................................... 4 Extension Points .......................................................................................................................... 4 SAP Scripting Framework Extension Points ................................................................................ 5

Writing a Custom Scripting Generator............................................................................................. 6 Creating the Python Language Plug-in ........................................................................................ 6 Creating the Plug-in Project for the Generator and Basic Plug-in Settings ................................. 7 Extending the Generators Extension Point .................................................................................. 8 Creating the JET Template ........................................................................................................ 10 Creating the Java Classes for the Generator............................................................................. 11 Customizing the Generator UI ................................................................................................... 14 Writing the Script Generation Code ........................................................................................... 20

Testing the Python Generator........................................................................................................ 27 Packaging ...................................................................................................................................... 29 Conclusion ..................................................................................................................................... 29 Appendix A. Python Generator Source Code................................................................................ 30

plugin.xml ................................................................................................................................... 30 META-INF/Manifest.mf............................................................................................................... 30 build.properties........................................................................................................................... 31 com.sap.scripting.ws.generators.python.Data........................................................................... 31 com.sap.scripting.ws.generators.python.Generator .................................................................. 36 com.sap.scripting.ws.generators.python.GeneratorsPlugin ...................................................... 44

Appendix B. Python Language Plug-in for SAP Scripting Framework Source Code.................... 45 plugin.xml ................................................................................................................................... 49 META-INF/Manifest.mf............................................................................................................... 49 build.properties........................................................................................................................... 50 com.sap.scripting.languages.python.LanguagePythonMessages............................................. 50 com.sap.scripting.languages.python/messages.properties ....................................................... 51 com.sap.scripting.languages.python.preferences.IPreferencesConstants................................ 51 com.sap.scripting.languages.python.preferences.Page ............................................................ 51

Related Content............................................................................................................................. 54 Scripting Languages Support for SAP Services ........................................................................ 54 Eclipse Plug-in Development ..................................................................................................... 54 Python Specific .......................................................................................................................... 54

Disclaimer and Liability Notice....................................................................................................... 55

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 4

Preparation Before starting with the code generator development one must have an Eclipse 3.2 environment with JDT, PDE and EMF plug-ins (if you are confused just download the full Eclipse SDK package) and obtain the binaries of SAP Scripting Framework. Eclipse can be downloaded from its web site http://www.eclipse.org (please follow the standard Eclipse installation instructions) and SAP Scripting Framework is available on the SAP Developer Network site http://sdn.sap.com. For installation instructions, please refer to Frederic Ahring’s article SAP Scripting Framework: an Introductions How to Use It (https://www.sdn.sap.com/irj/servlet/prt/portal/prtroot/docs/library/uuid/591c31cf-0d01-0010-8ab7-a1f7d032a66c). Now the workspace should be ready to start developing the new scripting generator.

Basic Concept of Extending Eclipse and Particularly SAP Scripting Framework If you have experience with Eclipse development you can skip the following two sections.

Eclipse Plug-In Mechanism Every contribution to the SAP Scripting Framework and Eclipse itself is done in the form of plug-ins. A plug-in is simply a set of java classes and a plug-in descriptor, distributed to the files plugin.xml and META-INF/Manifest.mf. When Eclipse starts, it reads the contents of its plugins subdirectory and for each plug-in it loads the plug-in description file without loading the java classes that belong to the plug-in. The classes are loaded only when the plug-in functionality is requested, but for displaying its contribution in the environment loading is still not necessary. The contributions of the plug-in are described in the plug-in descriptor and loaded on start up. The approach is also known as lazy initialization. It enables the workbench to have potentially hundreds of active plug-ins and at the same time start in a reasonable time. Besides that one does not use all the plug-ins on each start of the workbench. Sometimes one uses C Development, sometimes - Java Development, sometimes - PHP Development.

Extension Points Another aspect of Eclipse’s architecture is the use of extension points. This is the mean of a plug-in to define how it can be extended by other plug-ins. Each of them contributes some extended functionality to the extension points of the considered plug-in. Here is a short example. Let someone have developed a plug-in that adds the submenu Links to the Help menu of Eclipse and let Links has a single menu item – Eclipse Web Site. By clicking on this menu item the user opens a web browser and displays in it http://www.eclipse.org. The standard approach when defining such menus is to define an extension point for additional menu items there. If another developer decides to add another link there (for example SAP Web Site), the only thing he should do is to define an extension to this extension point. This is done in the plugin.xml of his plug-in.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 5

In the extension definition he can specify the caption of the menu item and the address it points to. It is even not necessary to write Java code for opening the browser, since this task is accomplished by the first developer’s Java code. It has a list with all plug-ins that contribute to this extension point and from their properties (caption and URI) it has all the necessary information. Furthermore it is a standard approach for each menu to specify a special menu separator called additions so all plug-ins that want to insert additional menu items in a specific menu can do this in additions.

SAP Scripting Framework Extension Points Now let us see how the extension point concept can be applied to the SAP Scripting Framework and how can it help us to develop easily custom scripting generators. SAP Scripting Framework provides a number of extension points for extending its functionality with new backend service repository connectors and scripting generators. Thus it is fairly easy to make the framework generate scripts in any scripting language or connect to any backend system, provided that one writes the necessary plug-ins. These extension points are located in the com.sap.scripting.core plug-in: languages – for describing which languages are present and what are the default extensions for script files in them; generators – for implementing custom code generators; connectorTypes – for specifying which types of backend systems can be connected to; connectors – for custom backend connectors. In this document we will concentrate on the first two ones.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 6

Writing a Custom Scripting Generator

Creating the Python Language Plug-in First we have to register the Python language in the SAP Scripting Framework because:

• The SAP Scripting Framework must be aware of what languages are present in the environment. Every scripting generator is coupled to a specific language.

• A set of language properties is common for every generator for this language (language name, default script file extension, etc). These properties are located in the specific scripting language plug-in of SAP Scripting Framework.

This task is straightforward and must be accomplished by creating the com.sap.scripting.languages.python plug-in. The latter is necessary only in case that the Python language is still not registered in SAP Scripting Framework (the Python language plug-in is not installed). If this is not the case you can simply skip this section and use the existing com.sap.scripting.languages.python plug-in. First create a new plug-in project in Eclipse (File » New » Project » Plug-in Project). Name it Language.Python and click Next. Provide the following details for the project: ID – com.sap.scripting.languages.python, version – 0.9.4, name - SAP Scripting Python definition, provider - www.sap.com. Now edit the generated plug-in files, according to the information below. You may have to create some of the files manually. Furthermore you can delete the Activator class, since we need the metadata files only. Here is how the plugin.xml, META-INF/Manifest.mf and build.properties must look like: plugin.xml

<?xml version="1.0" encoding="UTF-8"?>

<?eclipse version="3.2"?>

<!--

Plugin.xml for the Python language plug-in.

Copyright 2007 SAP AG

-->

<plugin>

<extension

point="com.sap.scripting.core.languages">

<language

default_extension="py"

display_name="Python"

id="com.sap.scripting.languages.python"/>

</extension>

<extension

point="org.eclipse.ui.preferencePages">

<page

category="com.sap.scripting.core.preferences.PreferencePageMain/com.sap.scripting.core.preferences.PreferencePageLanguages"

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 7

class="com.sap.scripting.languages.python.preferences.PreferencePage"

id="com.sap.scripting.languages.python.preferences.PreferencePage"

name="Python"/>

</extension>

</plugin>

META-INF/Manifest.mf Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: SAP Scripting Python definition

Bundle-SymbolicName: com.sap.scripting.languages.python; singleton:=true

Bundle-Version: 0.9.4

Bundle-Vendor: www.sap.com

Bundle-Localization: plugin

Require-Bundle: com.sap.scripting.core,

org.eclipse.core.runtime,

org.eclipse.ui,

com.sap.scripting.common.ui

Export-Package: com.sap.scripting.languages.python.preferences

build.properties source.. = src/

output.. = bin/

bin.includes = META-INF/,\

.

Regarding the preference page declarations and the supplementary Java classes in the Language.Python sample project, preference pages (displayed in the Eclipse Preferences window) are not obligatory or relevant to the generator and will not be discussed here. You can remove them or create preference pages. If you would like to learn more about Eclipse preference pages, please consult the Java Developer’s Guide to Eclipse or other reference.

Creating the Plug-in Project for the Generator and Basic Plug-in Settings Now we are ready to start with the development of the custom scripting generator. From the File menu select New » Project and then select Plug-in Project from the Plug-in Development category » Next. Give a project name (for this example we use WS.Generators.Python) and leave the other options without changes » Next. Provide the plug-in details ID, Version, Name, Provider (ID is com.sap.scripting.ws.generator.python, version is 0.9.4, description is WS.Generators.Python Plug-in and the provider is www.sap.com), set the name of the activator class to com.sap.scripting.ws.generators.python.GeneratorsPlugin. » Finish. Open the Runtime tab and click on the Add… button. Type in com.sap.scripting.ws.generators.python and click OK. This will export this package for access from other clients. You should be able to see a screen like the shown on the next figure.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 8

At this point we have to convert the project to a JET (Java Emitter Templates) project. Right-click the project and from the menu select New » Other… and then from the category Java Emitter Templates select Convert Projects to JET Projects. Then check only the combo box of our WS.Generators.Python project and click on Finish. This will add the JET nature to our project, which will allow Eclipse to automatically generate the necessary java source from our python file template and we do not have to care much about writing the Java code for the python files generation. We have to set up the template and the source folder for the JET files. Right click the project and select Properties. In the property page JET Settings enter templates in the Template Containers box and src in the Source Container box. Now every template file that we save in the templates subfolder of the project will cause automatic generation of the Java source code which generates files from this template. Now we are ready to start writing the source code of the generator.

Extending the Generators Extension Point It is necessary to extend the generators extension point in order to display our generator in the available generators list in the framework. For this purpose we have to edit plugin.xml and add the declarations for the extension. Here is how our plugin.xml should look like:

<?xml version="1.0" encoding="UTF-8"?>

<?eclipse version="3.2"?>

<!--

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 9

Plugin.xml for the Python scripting generator.

Author: Vasil Bachvarov

Date: 20 Sept. 2006

Copyright 2006-2007 SAP AG

-->

<plugin>

<extension

point="com.sap.scripting.core.generators">

<generator

language="com.sap.scripting.languages.python"

id="com.sap.scripting.ws.generators.python.Generator"

name="SAP Web Service for Python Generator">

<connector

type="com.sap.scripting.connectors.types.ws"/>

<source_object>

<module/>

</source_object>

<workers>

<worker class="com.sap.scripting.ws.generators.python.worker.WSGeneratorPythonWorker"/>

</workers>

<uis>

<ui class="com.sap.scripting.ws.generators.python.ui.WSGeneratorPythonUI"/>

</uis>

</generator>

</extension>

</plugin>

Now let us describe the elements in this XML file. The extension element defines the extension point that we extend: com.sap.scripting.core.generators, which was already discussed. The generator element defines the properties of our generator: language; class; id; name. The connector element shows which backend connectors supports our generator (it will generate code for connecting to web services). The uis element defines the generator-specific UI pages, which will be shown to the user, when the generator is executed. For example a scripting generator may want to display a page with log-in information, in which the log-in data is not user name and password, but bank branch code, account number and PIN number. Each of these UIs is stored in a Java class in the plug-in. The workers element defines the workers of the generator. Each worker is responsible for generating output files. You can have more than one worker if necessary. They are started consequently. The source_object element is reserved for future use to specify if the generator supports generation of classes or only functions, but is currently not used. The file META-INF/Manifest.mf contains the rest of the plug-in description:

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 10

Bundle-Name: WS.Generators.Python Plug-in

Bundle-SymbolicName: com.sap.scripting.ws.generator.python; singleton:=true

Bundle-Version: 0.9.4

Bundle-ClassPath: .

Bundle-Activator: com.sap.scripting.ws.generators.python.GeneratorsPlugin

Bundle-Localization: plugin

Require-Bundle: org.eclipse.ui,

org.eclipse.core.runtime,

com.sap.scripting.common.ui,

com.sap.scripting.core,

com.sap.scripting.metadata,

com.sap.scripting.ws.connector,

com.sap.scripting.languages.python,

org.eclipse.ant.core,

org.eclipse.core.resources

Export-Package: com.sap.scripting.ws.generators.python

Bundle-Vendor: www.sap.com

After creating plugin.xml and Manifest.mf we have to create the JET template, the class with the worker com.sap.scripting.ws.generators.python.worker.WSGeneratorPythonWorker, the UI and some supplementary classes.

Creating the JET Template The JET template contains the layout of a generated file. It has some special tags (similar to the server-side tags in PHP or JSP) which contain Java code for inserting dynamic content. This code will call some functions of the Generator class, which will be implemented in a bit. Here is how the Python JET template looks like: Please, note that some lines have been broken. Python is a language that is line driven and new lines do matter. In order to have a correct view of the code you can copy and paste the source in another text editor or look at the supplementing sample archive.

<%@ jet package="com.sap.scripting.ws.generators.python.templates" imports="com.sap.scripting.ws.generators.python.worker.Data java.util.Date java.text.SimpleDateFormat" class="CodeTemplate" %><%

Data data = (Data)argument;

SimpleDateFormat dateFormatter= new SimpleDateFormat("dd.MM.yyyy HH:mm");

%>

# Stub functions for <%=data.getServiceName()%>: <%=data.getMethod()%>

# generated by SAP Scripting Framework for Eclipse: Web Service calls generator for Python.

# Generation time: <%= dateFormatter.format(new Date()) %>

#

# Data source: Web Service

# SOAP entry at <%=data.getPortLocation()%>

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 11

# Connector: Python 2.4.2-SOAPpy (http://pywebsvcs.sourceforge.net/)

# Language: Python 2.4.2

from SOAPpy import SOAPProxy

# <%=data.getMethod()%>

# <%= data.getMethodDescription().replaceAll("\n", "\n# ") %>

def <%=data.getServiceName()%>_<%=data.getMethod()%>(<%=data.getInputParametersPython()%>):

proxy_<%=data.getServiceName()%> = SOAPProxy('<%= data.getPortLocation() %>', '<%= data.getNamespace() %>')

result = proxy_<%=data.getServiceName()%>.<%= data.getMethod() %>(<%=data.getInputParametersWS()%>)

return result

The template contains a comment box and the generated method. The name of the method and the parameters are defined at runtime from the SAP Scripting Framework classes and the WSGeneratorPythonWorker class that will be created in the next sections. The JET syntax is very similar to JSP tags. For more information refer to the JET documentation. Our JET template will generate Python files that access web services via the SOAPpy extension of Python.

Creating the Java Classes for the Worker In the package com.sap.scripting.ws.generators.python.worker we will create first a class, called Data. It encapsulates the properties for connecting to the web service. These properties are populated from the metadata that is passed to the generator. Create a new class Data in com.sap.scripting.ws.generators.python. Create the following private properties:

public class Data {

// WSDL URL

private String url = null;

// Service Name

private String serviceName = null;

// Method Name

private String method = null;

// Method Description - it will be put into the generated comments

private String methodDescription = null;

// Input Parameters (for the python call)

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 12

private String inputParametersPython = null;

// Input Parameters (for the WS call)

private String inputParametersWS = null;

// Port Location (SOAP Port)

private String portLocation = null;

// Name Space

private String namespace = null;

// Target Name Space

private String targetNamespace = null;

}

Then use the built-in Eclipse function for generating getters and setters for the properties. (The full source can be found in Appendix A). The Data class is ready. Now in the same package create a class, called GeneratorsPlugin. This is the Eclipse plug-in class for the Python generator. Every Eclipse plug-in has such a class. Here is how the plug-in class looks like:

/**

* <copyright>

* Copyright 2006-2007 SAP AG

* </copyright>

*/

package com.sap.scripting.ws.generators.python;

import org.eclipse.ui.plugin.*;

import org.eclipse.jface.resource.ImageDescriptor;

import org.osgi.framework.BundleContext;

/**

* The main plugin class to be used in the desktop.

*/

public class GeneratorsPlugin extends AbstractUIPlugin {

//The shared instance.

private static GeneratorsPlugin plugin;

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 13

/**

* The constructor.

*/

public GeneratorsPlugin() {

plugin = this;

}

/**

* This method is called upon plug-in activation

*/

public void start(BundleContext context) throws Exception {

super.start(context);

}

/**

* This method is called when the plug-in is stopped

*/

public void stop(BundleContext context) throws Exception {

super.stop(context);

plugin = null;

}

/**

* Returns the shared instance.

*/

public static GeneratorsPlugin getDefault() {

return plugin;

}

/**

* Returns an image descriptor for the image file at the given

* plug-in relative path.

*

* @param path the path

* @return the image descriptor

*/

public static ImageDescriptor getImageDescriptor(String path) {

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 14

return AbstractUIPlugin.imageDescriptorFromPlugin("WS.Generators.Python", path);

}

}

An Eclipse plug-in class inherits AbstractUIPlugin, which contains the necessary functionality. The methods are standard for a plug-in class. For more information, please refer to Eclipse Developer’s Guide or other Eclipse development reference.

Customizing the Generator UI Now we are ready to implement the generator user interface. Create a package called com.sap.scripting.ws.generators.python.ui and a class WSGeneratorPythonUI in this package. Put the following code into the java file:

/**

* <copyright>

* Copyright 2006-2007 SAP AG

* </copyright>

*/

package com.sap.scripting.ws.generators.python.ui;

import java.util.HashMap;

import org.eclipse.jface.viewers.TreeViewer;

import org.eclipse.jface.wizard.WizardDialog;

import com.sap.scripting.common.ui.generators.CodeGenerateWizard;

import com.sap.scripting.core.CallerContext;

import com.sap.scripting.core.IUI;

import com.sap.scripting.core.generators.output.impl.GeneratorOutputImpl;

public class WSGeneratorPythonUI implements IUI {

private WizardDialog dialog;

public void execute(CallerContext context, String namespace) {

context.putLocal(namespace, CallerContext.GENERATOR_PARAMETERS, new HashMap());

context.putLocal(namespace, CallerContext.GENERATOR_OPTIONS, new HashMap());

context.putLocal(namespace, CallerContext.I_GENERATOR_OUTPUT, new GeneratorOutputImpl());

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 15

context.putLocal(namespace, CallerContext.UI_STATUS, FINISH_CANCEL);

CodeGenerateWizard wizard = new CodeGenerateWizard(context, namespace);

dialog = new WizardDialog(

((TreeViewer)context.getLocal(namespace, CallerContext.TREE_VIEWER)).getControl().getShell(),

wizard);

dialog.setBlockOnOpen(true);

if (dialog.open() == WizardDialog.OK) {

context.putLocal(namespace, CallerContext.UI_STATUS, FINISH_OK);

}

}

}

Let us take a closer look at the execute method. Properties are passed through the workers and the UI via a context object. In this method we receive a reference to this context. First we create hash maps to store the generator’s parameters and options and add them to the context. We create a IGeneratorOutput object, which represents a generated output source file, and set the buttons to Finish and Cancel.

context.putLocal(namespace, CallerContext.GENERATOR_PARAMETERS, new HashMap());

context.putLocal(namespace, CallerContext.GENERATOR_OPTIONS, new HashMap());

context.putLocal(namespace, CallerContext.I_GENERATOR_OUTPUT, new GeneratorOutputImpl());

context.putLocal(namespace, CallerContext.UI_STATUS, FINISH_CANCEL);

Next we create a Wizard for the UI, set its shell to the context’s shell and make it modal (for more information contact SWT developer’s guide).

CodeGenerateWizard wizard = new CodeGenerateWizard(context, namespace);

dialog = new WizardDialog(

((TreeViewer)context.getLocal(namespace, CallerContext.TREE_VIEWER)).getControl().getShell(),

wizard);

dialog.setBlockOnOpen(true);

If the result of the wizard is “OK pressed”, set the OK status in the context.

if (dialog.open() == WizardDialog.OK) {

context.putLocal(namespace, CallerContext.UI_STATUS, FINISH_OK);

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 16

}

The Python generator is fairly simple and has the default UI behaviour, which shows only one page with destination selection, but when necessary, one can create advanced custom UI pages for the wizard. Here is a short example how the source can look like. One needs to create a separate PythonCodeGenerateWizard class, which inherits com.sap.scripting.common.ui.generators.CodeGenerateWizard. In its addPages method the separate pages of the wizard are created. Each page is of class com.sap.scripting.core.UIProvider.

package com.sap.scripting.ws.generators.python.ui;

import com.sap.scripting.common.ui.fileoutput.DefaultFileNameUIProvider;

import com.sap.scripting.common.ui.generators.CodeGenerateWizard;

import com.sap.scripting.common.ui.generators.CodeStyleUIProvider;

import com.sap.scripting.common.ui.generators.DefaultAuthorizationUIProvider;

import com.sap.scripting.common.ui.utils.UIWizardPage;

import com.sap.scripting.core.CallerContext;

import com.sap.scripting.core.IUIProvider;

public class PythonCodeGenerateWizard extends CodeGenerateWizard {

public PythonCodeGenerateWizard(CallerContext context, String namespace) {

super(context, namespace);

}

public void addPages() {

IUIProvider provider;

UIWizardPage page;

provider = new DefaultFileNameUIProvider(context, namespace);

page = new UIWizardPage(provider);

addPage(page);

provider = new DefaultAuthorizationUIProvider(context, namespace);

page = new UIWizardPage(provider);

addPage(page);

provider = new CodeStyleUIProvider(context, namespace);

page = new UIWizardPage(provider);

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 17

addPage(page);

}

}

This example illustrates adding three default UI pages to the wizard. DefaultFileNameUIProvider is for the destination selection, DefaultAuthorizationUIProvider is a standard page with username/password and CodeStyleUIProvider is to define whether a test script should be generated. Furthermore it is possible to create own UI providers. The sample code is given below. It is taken from the PHP code generator for BAPI services and is not directly related to the Python generator, but just an illustration.

/**

* <copyright>

* Copyright 2006-2007 SAP AG

* </copyright>

*/

package com.sap.scripting.bapi.generators.php.ui;

import java.util.Map;

import org.eclipse.swt.SWT;

import org.eclipse.swt.events.SelectionEvent;

import org.eclipse.swt.events.SelectionListener;

import org.eclipse.swt.layout.GridData;

import org.eclipse.swt.layout.GridLayout;

import org.eclipse.swt.widgets.Button;

import org.eclipse.swt.widgets.Composite;

import org.eclipse.swt.widgets.Text;

import com.sap.scripting.bapi.generators.IBAPIGeneratorOptions;

import com.sap.scripting.bapi.generators.php.BAPIGeneratorsPHPMessages;

import com.sap.scripting.common.plugin.UIImages;

import com.sap.scripting.core.CallerContext;

import com.sap.scripting.core.IUIProvider;

import com.sap.scripting.core.IUISite;

import com.sap.scripting.core.metadata.ICommonAttributes;

public class BAPIGeneratorGenOptionsUIProvider implements IUIProvider

{

private IUISite site;

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 18

private Composite container;

private Button checkboxSkipOptionalParams;

private CallerContext context;

private String namespace;

public BAPIGeneratorGenOptionsUIProvider(CallerContext context, String namespace) {

this.context = context;

this.namespace = namespace;

}

public void initialize(IUISite site) {

this.site = site;

site.setTitle(BAPIGeneratorsPHPMessages.BAPI_PHP_GeneratorUIProvider_GenOptionsScreen_Title); //$NON-NLS-1$

site.setDescription(BAPIGeneratorsPHPMessages.BAPI_PHP_GeneratorUIProvider_GenOptionsScreen_Description); //$NON-NLS-1$

site.setImageDescriptor(UIImages.IMAGE_GENERATOR);

}

public void createControls(Composite parent) {

// Create container, take the whole parent area.

container = new Composite(parent, SWT.NULL);

GridLayout layout = new GridLayout();

layout.numColumns = 2;

layout.verticalSpacing = 9;

container.setLayout(layout);

GridData greeddataHorizFillSpan2 = new GridData(GridData.FILL_HORIZONTAL);

greeddataHorizFillSpan2.horizontalSpan = 2;

checkboxSkipOptionalParams = new Button(container, SWT.CHECK);

checkboxSkipOptionalParams.setLayoutData(greeddataHorizFillSpan2);

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 19

checkboxSkipOptionalParams.setText(BAPIGeneratorsPHPMessages.BAPI_PHP_GeneratorUIProvider_GenOptionsScreen_SkipOptionalParams);

checkboxSkipOptionalParams.addSelectionListener(new SelectionListener() {

public void widgetSelected(SelectionEvent e) {

dialogChanged();

}

public void widgetDefaultSelected(SelectionEvent e) {

dialogChanged();

}

});

checkboxSkipOptionalParams.setSelection(true);

GridData greeddataFillBothSpan2 = new GridData(GridData.FILL_HORIZONTAL);

greeddataFillBothSpan2.horizontalSpan = 2;

Text labelSkipOptParamsDesc = new Text(container, SWT.MULTI | SWT.READ_ONLY | SWT.WRAP);

labelSkipOptParamsDesc.setText(BAPIGeneratorsPHPMessages.BAPI_PHP_GeneratorUIProvider_GenOptionsScreen_SkipOptionalParamsDesc);

labelSkipOptParamsDesc.setLayoutData(greeddataFillBothSpan2);

container.layout();

}

public void removeControls(Composite parent) {

container.dispose();

}

public void refresh() {

dialogChanged();

}

public void dispose() {

site = null;

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 20

}

/**

* Ensures that the entered data is plausible

*/

private void dialogChanged() {

Map options = (Map) context.getLocal(namespace, CallerContext.GENERATOR_OPTIONS);

options.remove(IBAPIGeneratorOptions.SKIP_OPTIONAL_PARAMETERS);

if (checkboxSkipOptionalParams.getSelection()) {

options.put(IBAPIGeneratorOptions.SKIP_OPTIONAL_PARAMETERS,

ICommonAttributes.TRUE);

}

updateStatus(null);

}

private void updateStatus(String message) {

site.setErrorMessage(message);

site.setComplete(message == null);

}

}

This code is related to the standard SWT and Eclipse development and is optional; therefore it will not be discussed here.

Writing the Script Generation Code Now we are almost ready with the generator. The only thing to be done is to create the WSGeneratorPythonWorker class and write the code that generates scripting code. Create a class WSGeneratorPythonWorker in the com.sap.scripting.ws.generators.python.worker package. Let it implement the com.sap.scripting.core.IWorker interface. Add the private properties for storing intermediate results:

public class Generator implements IGenerator {

private StringBuffer inputParametersPython = null;

private StringBuffer inputParametersWS = null;

private ArrayList<Data> dataArray = null;

private int paramCounter;

There is no constructor but if necessary, it may content some generator-specific initializations. Create a method execute():

public void execute(final CallerContext context, final String namespace) {

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 21

context.putLocal(namespace, CallerContext.WORKER_STATUS, IWorker.FINISH_OK);

if (generateCode(context, namespace)) {

final IGeneratorOutput generatorOutput = (IGeneratorOutput) context.getLocal(namespace, CallerContext.I_GENERATOR_OUTPUT);

IOutputWriter writer = new OutputWriterImpl();

writer.write(generatorOutput);

final IDisplayService displayService = new DisplayServiceImpl();

Display.getDefault().asyncExec(new Runnable() {

public void run() {

displayService.display(generatorOutput);

}

});

}

}

The execute method calls generateCode and if there was no error, writes the generated files and then opens them in the workspace. Now create two methods: fillDataSourceData and fillFunctionData.

public void fillDataSourceData(final CallerContext context, final String namespace, MiDataSource dataSource){

MiModule[] modules = dataSource.getModules();

for (int i = 0; i < modules.length; i++){

fillFunctionData(context, namespace, modules[i]);

}

}

public void fillFunctionData(final CallerContext context, final String namespace, MiModule module){

Data webServiceData = new Data();

MiModule miModule = module;

// Set the Data object properties from the metadata.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 22

webServiceData.setURL(miModule.getAttribute(IWSParams.URL).getValue());

webServiceData.setMethod(miModule.

getAttribute(IWSParams.METHOD).getValue());

MiAttribute serviceNameAttr = miModule

.getAttribute(IWSAttributes.LOCAL_SERVICE_NAME);

if (serviceNameAttr != null) {

webServiceData.setServiceName(serviceNameAttr.getValue());

}

MiElement root = null;

MiParameterGroup inputGroup = miModule.getParameterGroup(IWSParams.PARAMS_INPUT_ID);

if (inputGroup != null){

root = inputGroup.getParameters();

}

String methodDescription = (miModule

.hasAttribute(IWSAttributes.DESCRIPTION)) ? miModule

.getAttribute(IWSAttributes.DESCRIPTION).getValue() : "";

// Prepare the parameter strings.

inputParametersPython = new StringBuffer();

inputParametersWS = new StringBuffer();

paramCounter = 0;

try {

readParameters(root, "", 0);

} catch (IllegalStateException e){

inputParametersPython = new StringBuffer();

inputParametersWS = new StringBuffer();

methodDescription += "\n\n Error: ";

methodDescription += e.getMessage();

final String message = NLS.bind(WSGeneratorsPythonMessages.Generator_recursiveTypeFunctionWarning,webServiceData.getMethod());

Display.getDefault().syncExec(new Runnable() {

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 23

public void run() {

MessageDialog.openWarning(((TreeViewer)context.getLocal(namespace, CallerContext.TREE_VIEWER)).getControl().getShell(),

WSGeneratorsPythonMessages.Generator_warningTitle, message);

}

});

}

webServiceData.setInputParametersPython(inputParametersPython.toString());

webServiceData.setInputParametersWS(inputParametersWS.toString());

webServiceData.setMethodDescription(methodDescription);

webServiceData.setPortLocation(miModule.getAttribute(IWSParams.PORT_LOCATION).getValue());

webServiceData.setNamespace(miModule.getAttribute(IWSParams.NAMESPACE).getValue());

dataArray.add(webServiceData);

}

fillDataSourceData takes all the metadata of the selected data source and processes the functions in it. This is necessary, so the user is able to generate code for multiple functions, by selecting two or more items in the repository view. fillFunctionData reads the metadata for each function, parses the parameters of the function and creates the resulting strings with the parameters to be generated. Create the method generateCode:

public boolean generateCode(final CallerContext context, final String namespace) {

Map options = (Map) context.getLocal(namespace, CallerContext.GENERATOR_OPTIONS);

// The file name for the destination file.

String scriptFileName = "" + options.get(IGeneratorOptions.DESTINATION_FILE_NAME);

// Is the destination folder a file system folder or an Eclipse resource.

int kind = Integer.valueOf((String) options.get(IGeneratorOptions.DESTINATION_FOLDER_KIND)).intValue();

String path = "" + options.get(IGeneratorOptions.DESTINATION_FOLDER);

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 24

// Initialize the output objects.

IGeneratorOutput generatorOutput = (IGeneratorOutput) context.getLocal(namespace, CallerContext.I_GENERATOR_OUTPUT);

generatorOutput.clear();

IOutputRoot outputRoot = generatorOutput.addRoot(scriptFileName);

outputRoot.setKind(kind);

outputRoot.setPath(path);

IOutputFile outputFile = outputRoot.addFile(scriptFileName);

dataArray = new ArrayList<Data>();

Object[] selectedObjects = (Object[]) context.getLocal(namespace, CallerContext.SELECTED_OBJECTS);

for (int i = 0; i < selectedObjects.length; i++ ){

/* If in the context is selected something else from MiModule output an error message

* for unsupported type.

*/

if(selectedObjects[i] instanceof MiModule){

fillFunctionData(context, namespace, (MiModule)selectedObjects[i]);

} else if (selectedObjects[i] instanceof MiDataSource){

fillDataSourceData(context, namespace, (MiDataSource)selectedObjects[i]);

} else {

//TODO: add Unsupported message.

continue;

}

}

CodeTemplate codeTemplate = new CodeTemplate();

StringBuffer scriptContent = new StringBuffer();

Iterator i = dataArray.iterator();

while(i.hasNext()){

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 25

Data webServiceData = (Data)i.next();

scriptContent.append(codeTemplate.generate(webServiceData));

scriptContent.append("\n\n");

}

outputFile.setContent(scriptContent.toString());

return true;

}

This method first retrieves the generator options from the context. Then it sets the destination file name and the kind of the folder. Each folder can be an Eclipse work space folder, or a file system folder. After this all selected objects in the scripting repository are processed in a cycle – if a whole service is selected, generate for all of its functions (fillDataSourceData), if a single function is selected, call fillFunctionData. After the last iteration the object dataArray contains all parsed metadata for the selected objects. A step creates a JET template object and for each data element in dataArray generates the output file from the JET template, we created before. The last thing to be done is the readParameters() method:

private void readParameters(MiElement _node, String _prefix, int _paramLevel) {

String paramNumber;

String name = WSAttributesUtil.getLocalName(_node);

String paramName = "param_" + name + "_";

MiType elementType = _node.getType();

// Check the type of node with the input from the metadata.

if (elementType instanceof MiSimpleType) {

// If the input is a simple type - write a single parameter to the string.

paramNumber = String.valueOf(paramCounter);

paramCounter++;

inputParametersWS.append(name + "=" + paramName + paramNumber);

inputParametersPython.append(paramName + paramNumber);

} else if (elementType instanceof MiComplexType) {

MiAttribute isRecursive = ((MiComplexType) elementType).getAttribute(ICommonAttributes.RECURSIVE_TYPE);

if (isRecursive != null && isRecursive.getValue().equals(ICommonAttributes.TRUE)){

throw new IllegalStateException(WSGeneratorsPythonMessages.Generator_recursiveTypeFunctionDescription);

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 26

}

// If the input is a complex type - walk recursively and create structure in the output string.

// NOTE: There is a limitation for this generator. It supports only flat structures.

EList elementList = ((MiComplexType) elementType).getElementList();

for (int i = 0; i < elementList.size(); i++) {

MiElement node = (MiElement) elementList.get(i);

readParameters(node, _prefix + "." + name, _paramLevel + 1);

if (i + 1 < elementList.size()) {

inputParametersWS.append(", ");

inputParametersPython.append(", ");

}

}

}

}

We start processing the web service data from the root element. In general it is a tree structure and the method is applied recursively. If the current element is of a simple type, then output to the parameter string <param_name>=<param_name_number>, which will generate a string like „employeeName=param_employeeName_1“. This is done so we distinguish between employeeName, which is the name of the web service parameter, and param_employeeName_1, which is the Python variable we use to store the parameter. Parameter names are not absolutely collision free in this sample, but if desired, the generator must take care of it. In case that the current element is of a complex type (composite object) we first get the list with its elements and for each element we call recursively the same method. In this way we walk through the tree structure and create a flat list with all parameters. This implies that our Python generator supports only flat structures of the input parameters (a list). If nested structure must be considered, one have to use more sophisticated processing procedure. Such algorithms are outside the scope of the article, which main focus is to explain the technology of creating a custom scripting generator. The Python generator is ready. Complete source code can be found in Appendices A and B, as well as in the two supplementing sample projects.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 27

Testing the Python Generator Testing the generator is a very simple task. First you have to open all projects from the SAP Scripting Framework source code and your new WS.Generators.Python project. Then select from the toolbar or from the Run menu Run As… » Eclipse Application.

This will start a copy of Eclipse with all active plug-ins and the runtimes of all plug-in projects. Then open the SAP Scripting Frameworks perspective.

In the SAP Scripting Repository view import a backend system.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 28

When the backend system is added to the repository its metadata is saved locally. Now launch the Python scripting generator you created:

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 29

The rest is pretty straightforward. If everything passed fine the new generated Python file should be loaded in an Eclipse editor.

Packaging The new generator can be exported for other users from File » Export » Deployable Plug-ins and Fragments.

Conclusion In this article we have considered creating a custom scripting generator for the SAP Scripting Framework. Our sample generator was designed to generate Python scripts for accessing web services with the SOAPpy web service connector for Python. In the beginning we have considered shortly the Eclipse architecture and how plug-ins and extension points are used in the SAP Scripting Framework. Our main task has been accomplished in a couple of steps:

• Creating the Language.Python project that registers the Python language in the SAP Scripting Framework.

• Creating the Python generator project and basic plug-in settings.

• JET Template for the generated files.

• Implementing the code that generates the Python strings, customizing the JET template.

These concepts are applicable to any scripting or other language and any backend connector like web service or BAPI connector.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 30

Appendix A. Python Generator Source Code

plugin.xml <?xml version="1.0" encoding="UTF-8"?>

<?eclipse version="3.2"?>

<!--

Plugin.xml for the Python scripting generator.

Author: Vasil Bachvarov

Date: 20 Sept. 2006

Copyright 2006 SAP AG

-->

<plugin>

<extension

point="com.sap.scripting.core.generators">

<generator

language="com.sap.scripting.languages.python"

id="com.sap.scripting.ws.generators.python.Generator"

name="SAP Web Service for Python Generator">

<connector

type="com.sap.scripting.connectors.types.ws"/>

<source_object>

<module/>

</source_object>

<workers>

<worker class="com.sap.scripting.ws.generators.python.worker.WSGeneratorPythonWorker"/>

</workers>

<uis>

<ui class="com.sap.scripting.ws.generators.python.ui.WSGeneratorPythonUI"/>

</uis>

</generator>

</extension>

</plugin>

META-INF/Manifest.mf Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: WS.Generators.Python Plug-in

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 31

Bundle-SymbolicName: com.sap.scripting.ws.generator.python; singleton:=true

Bundle-Version: 0.9.4

Bundle-ClassPath: .

Bundle-Activator: com.sap.scripting.ws.generators.python.GeneratorsPlugin

Bundle-Localization: plugin

Require-Bundle: org.eclipse.ui,

org.eclipse.core.runtime,

com.sap.scripting.common.ui,

com.sap.scripting.core,

com.sap.scripting.metadata,

com.sap.scripting.ws.connector,

com.sap.scripting.languages.python,

org.eclipse.ant.core,

org.eclipse.core.resources

Export-Package: com.sap.scripting.ws.generators.python

Bundle-Vendor: www.sap.com

build.properties source.. = src/

output.. = bin/

bin.includes = META-INF/,\

.,\

plugin.xml

com.sap.scripting.ws.generators.python.worker.Data /**

* <copyright>

* Copyright 2006 SAP AG

* </copyright>

*/

package com.sap.scripting.ws.generators.python.worker;

/**

* <!-- begin-user-doc -->

*

* Data capsulation class for the Python scripting generator.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 32

* Encapsulates the properties URL (WSDL), Service Name, Method Name, Method Description,

* Input Parameters (for python call), Input Parameters (for WS call), Port Location (SOAP Port),

* Name Space, Target Name Space.

*

* <!-- end-user-doc -->

*

* @author Vasil Bachvarov

*/

public class Data {

// WSDL URL

private String url = null;

// Service Name

private String serviceName = null;

// Method Name

private String method = null;

// Method Description - it will be put into the generated comments

private String methodDescription = null;

// Input Parameters (for the python call)

private String inputParametersPython = null;

// Input Parameters (for the WS call)

private String inputParametersWS = null;

// Port Location (SOAP Port)

private String portLocation = null;

// Name Space

private String namespace = null;

// Target Name Space

private String targetNamespace = null;

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 33

/**

* @return Returns the inputParametersPython property.

*/

public String getInputParametersPython() {

return inputParametersPython;

}

/**

* Python procedure parameters

*

* @param _inputParametersPython The inputParametersPython property to set.

*/

public void setInputParametersPython(String _inputParametersPython) {

inputParametersPython = _inputParametersPython;

}

/**

* Web service parameters

*

* @return Returns the inputParametersWS.

*/

public String getInputParametersWS() {

return inputParametersWS;

}

/**

* @param _inputParametersWS The inputParametersWS to set.

*/

public void setInputParametersWS(String _inputParametersWS) {

inputParametersWS = _inputParametersWS;

}

/**

* @return Returns the name of web service.

*/

public String getServiceName() {

return serviceName;

}

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 34

/**

* Web service name

*

* @param value The name of web service to set.

*/

public void setServiceName(String value) {

serviceName = value;

}

/**

* @return Returns the method.

*/

public String getMethod() {

return method;

}

/**

* Web service method

*

* @param _method The method to set.

*/

public void setMethod(String _method) {

method = _method;

}

/**

* @return Returns the methodDescription property.

*/

public String getMethodDescription() {

return methodDescription;

}

/**

* Web service method description

*

* @param _methodDescription The methodDescription property to set.

*/

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 35

public void setMethodDescription(String _methodDescription) {

methodDescription = _methodDescription;

}

/**

* @return Returns the WSDL URL.

*/

public String getURL() {

return url;

}

/**

* URL for WSDL file

*

* @param _url The WSDL URL to set.

*/

public void setURL(String _url) {

url = _url;

}

/**

* @return Returns the namespace.

*/

public String getNamespace() {

return namespace;

}

/**

* Namespace in the WSDL

*

* @param namespace The namespace to set.

*/

public void setNamespace(String namespace) {

this.namespace = namespace;

}

/**

* @return Returns the SOAP entry point.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 36

*/

public String getPortLocation() {

return portLocation;

}

/**

* The SOAP entry point

*

* @param portLocation The port location to set.

*/

public void setPortLocation(String portLocation) {

this.portLocation = portLocation;

}

/**

* @return Returns the target name space in WSDL.

*/

public String getTargetNamespace() {

return targetNamespace;

}

/**

* The target name space

*

* @param targetNamespace The target name space in the WSDL.

*/

public void setTargetNamespace(String targetNamespace) {

this.targetNamespace = targetNamespace;

}

}

com.sap.scripting.ws.generators.python.worker.WSGeneratorPythonWorker /**

* <copyright>

* Copyright 2006 SAP AG

* </copyright>

*/

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 37

package com.sap.scripting.ws.generators.python.worker;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.Map;

import org.eclipse.emf.common.util.EList;

import org.eclipse.jface.dialogs.MessageDialog;

import org.eclipse.jface.viewers.TreeViewer;

import org.eclipse.osgi.util.NLS;

import org.eclipse.swt.widgets.Display;

import com.sap.scripting.common.ui.fileoutput.DisplayServiceImpl;

import com.sap.scripting.core.CallerContext;

import com.sap.scripting.core.IWorker;

import com.sap.scripting.core.generators.IDisplayService;

import com.sap.scripting.core.generators.IGeneratorOptions;

import com.sap.scripting.core.generators.IOutputWriter;

import com.sap.scripting.core.generators.impl.OutputWriterImpl;

import com.sap.scripting.core.generators.output.IGeneratorOutput;

import com.sap.scripting.core.generators.output.IOutputFile;

import com.sap.scripting.core.generators.output.IOutputRoot;

import com.sap.scripting.core.metadata.ICommonAttributes;

import com.sap.scripting.metadata.MiAttribute;

import com.sap.scripting.metadata.MiComplexType;

import com.sap.scripting.metadata.MiDataSource;

import com.sap.scripting.metadata.MiElement;

import com.sap.scripting.metadata.MiModule;

import com.sap.scripting.metadata.MiParameterGroup;

import com.sap.scripting.metadata.MiSimpleType;

import com.sap.scripting.metadata.MiType;

import com.sap.scripting.ws.connector.wsdl.IWSAttributes;

import com.sap.scripting.ws.connector.wsdl.IWSParams;

import com.sap.scripting.ws.connector.wsdl.WSAttributesUtil;

import com.sap.scripting.ws.generators.python.WSGeneratorsPythonMessages;

import com.sap.scripting.ws.generators.python.templates.CodeTemplate;

/**

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 38

*

* <!-- begin-user-doc -->

*

* Main generator class for the WebService Python scripting generator. It uses the Data class

* to store its parameter properties. Use the method <b>execute</b> to

* generate a PHP script from the template.<br/>

* <!-- end-user-doc -->

*

* @author Grigoriy Cherkasov

* @author Vasil Bachvarov

*

*/

public class WSGeneratorPythonWorker implements IWorker {

// Private properties for storing intermediate results.

private StringBuffer inputParametersPython = null;

private StringBuffer inputParametersWS = null;

private ArrayList<Data> dataArray = null;

private int paramCounter;

public void execute(final CallerContext context, final String namespace) {

context.putLocal(namespace, CallerContext.WORKER_STATUS, IWorker.FINISH_OK);

if (generateCode(context, namespace)) {

final IGeneratorOutput generatorOutput = (IGeneratorOutput) context.getLocal(namespace, CallerContext.I_GENERATOR_OUTPUT);

IOutputWriter writer = new OutputWriterImpl();

writer.write(generatorOutput);

final IDisplayService displayService = new DisplayServiceImpl();

Display.getDefault().asyncExec(new Runnable() {

public void run() {

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 39

displayService.display(generatorOutput);

}

});

}

}

public void fillDataSourceData(final CallerContext context, final String namespace, MiDataSource dataSource){

MiModule[] modules = dataSource.getModules();

for (int i = 0; i < modules.length; i++){

fillFunctionData(context, namespace, modules[i]);

}

}

public void fillFunctionData(final CallerContext context, final String namespace, MiModule module){

Data webServiceData = new Data();

MiModule miModule = module;

// Set the Data object properties from the metadata.

webServiceData.setURL(miModule.getAttribute(IWSParams.URL).getValue());

webServiceData.setMethod(miModule.

getAttribute(IWSParams.METHOD).getValue());

MiAttribute serviceNameAttr = miModule

.getAttribute(IWSAttributes.LOCAL_SERVICE_NAME);

if (serviceNameAttr != null) {

webServiceData.setServiceName(serviceNameAttr.getValue());

}

MiElement root = null;

MiParameterGroup inputGroup = miModule.getParameterGroup(IWSParams.PARAMS_INPUT_ID);

if (inputGroup != null){

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 40

root = inputGroup.getParameters();

}

String methodDescription = (miModule

.hasAttribute(IWSAttributes.DESCRIPTION)) ? miModule

.getAttribute(IWSAttributes.DESCRIPTION).getValue() : "";

// Prepare the parameter strings.

inputParametersPython = new StringBuffer();

inputParametersWS = new StringBuffer();

paramCounter = 0;

try {

readParameters(root, "", 0);

} catch (IllegalStateException e){

inputParametersPython = new StringBuffer();

inputParametersWS = new StringBuffer();

methodDescription += "\n\n Error: ";

methodDescription += e.getMessage();

final String message = NLS.bind(WSGeneratorsPythonMessages.Generator_recursiveTypeFunctionWarning,webServiceData.getMethod());

Display.getDefault().syncExec(new Runnable() {

public void run() {

MessageDialog.openWarning(((TreeViewer)context.getLocal(namespace, CallerContext.TREE_VIEWER)).getControl().getShell(),

WSGeneratorsPythonMessages.Generator_warningTitle, message);

}

});

}

webServiceData.setInputParametersPython(inputParametersPython.toString());

webServiceData.setInputParametersWS(inputParametersWS.toString());

webServiceData.setMethodDescription(methodDescription);

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 41

webServiceData.setPortLocation(miModule.getAttribute(IWSParams.PORT_LOCATION).getValue());

webServiceData.setNamespace(miModule.getAttribute(IWSParams.NAMESPACE).getValue());

dataArray.add(webServiceData);

}

/**

* Method to generate the script. It takes the web service metadata and from it generates

* python script for accessing the service.

*

* @param context - Generator context.

* @return TRUE on success.

*/

public boolean generateCode(final CallerContext context, final String namespace) {

Map options = (Map) context.getLocal(namespace, CallerContext.GENERATOR_OPTIONS);

// The file name for the destination file.

String scriptFileName = "" + options.get(IGeneratorOptions.DESTINATION_FILE_NAME);

// Is the destination folder a file system folder or an Eclipse resource.

int kind = Integer.valueOf((String) options.get(IGeneratorOptions.DESTINATION_FOLDER_KIND)).intValue();

String path = "" + options.get(IGeneratorOptions.DESTINATION_FOLDER);

// Initialize the output objects.

IGeneratorOutput generatorOutput = (IGeneratorOutput) context.getLocal(namespace, CallerContext.I_GENERATOR_OUTPUT);

generatorOutput.clear();

IOutputRoot outputRoot = generatorOutput.addRoot(scriptFileName);

outputRoot.setKind(kind);

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 42

outputRoot.setPath(path);

IOutputFile outputFile = outputRoot.addFile(scriptFileName);

dataArray = new ArrayList<Data>();

Object[] selectedObjects = (Object[]) context.getLocal(namespace, CallerContext.SELECTED_OBJECTS);

for (int i = 0; i < selectedObjects.length; i++ ){

/* If in the context is selected something else from MiModule output an error message

* for unsupported type.

*/

if(selectedObjects[i] instanceof MiModule){

fillFunctionData(context, namespace, (MiModule)selectedObjects[i]);

} else if (selectedObjects[i] instanceof MiDataSource){

fillDataSourceData(context, namespace, (MiDataSource)selectedObjects[i]);

} else {

//TODO: add Unsupported message.

continue;

}

}

CodeTemplate codeTemplate = new CodeTemplate();

StringBuffer scriptContent = new StringBuffer();

Iterator i = dataArray.iterator();

while(i.hasNext()){

Data webServiceData = (Data)i.next();

scriptContent.append(codeTemplate.generate(webServiceData));

scriptContent.append("\n\n");

}

outputFile.setContent(scriptContent.toString());

return true;

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 43

}

/**

* Create the strings with parameters for the script calls.

*

* @param _node

* @param _prefix

* @param _paramLevel

*/

private void readParameters(MiElement _node, String _prefix, int _paramLevel) {

String paramNumber;

String name = WSAttributesUtil.getLocalName(_node);

String paramName = "param_" + name + "_";

MiType elementType = _node.getType();

// Check the type of node with the input from the metadata.

if (elementType instanceof MiSimpleType) {

// If the input is a simple type - write a single parameter to the string.

paramNumber = String.valueOf(paramCounter);

paramCounter++;

inputParametersWS.append(name + "=" + paramName + paramNumber);

inputParametersPython.append(paramName + paramNumber);

} else if (elementType instanceof MiComplexType) {

MiAttribute isRecursive = ((MiComplexType) elementType).getAttribute(ICommonAttributes.RECURSIVE_TYPE);

if (isRecursive != null && isRecursive.getValue().equals(ICommonAttributes.TRUE)){

throw new IllegalStateException(WSGeneratorsPythonMessages.Generator_recursiveTypeFunctionDescription);

}

// If the input is a complex type - walk recursively and create structure in the output string.

// NOTE: There is a limitation for this generator. It supports only flat structures.

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 44

EList elementList = ((MiComplexType) elementType).getElementList();

for (int i = 0; i < elementList.size(); i++) {

MiElement node = (MiElement) elementList.get(i);

readParameters(node, _prefix + "." + name, _paramLevel + 1);

if (i + 1 < elementList.size()) {

inputParametersWS.append(", ");

inputParametersPython.append(", ");

}

}

}

}

}

com.sap.scripting.ws.generators.python.ui.WSGeneratorPythonUI /**

* <copyright>

* Copyright 2006-2007 SAP AG

* </copyright>

*/

package com.sap.scripting.ws.generators.python.ui;

import java.util.HashMap;

import org.eclipse.jface.viewers.TreeViewer;

import org.eclipse.jface.wizard.WizardDialog;

import com.sap.scripting.common.ui.generators.CodeGenerateWizard;

import com.sap.scripting.core.CallerContext;

import com.sap.scripting.core.IUI;

import com.sap.scripting.core.generators.output.impl.GeneratorOutputImpl;

public class WSGeneratorPythonUI implements IUI {

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 45

private WizardDialog dialog;

public void execute(CallerContext context, String namespace) {

context.putLocal(namespace, CallerContext.GENERATOR_PARAMETERS, new HashMap());

context.putLocal(namespace, CallerContext.GENERATOR_OPTIONS, new HashMap());

context.putLocal(namespace, CallerContext.I_GENERATOR_OUTPUT, new GeneratorOutputImpl());

context.putLocal(namespace, CallerContext.UI_STATUS, FINISH_CANCEL);

CodeGenerateWizard wizard = new CodeGenerateWizard(context, namespace);

dialog = new WizardDialog(

((TreeViewer)context.getLocal(namespace, CallerContext.TREE_VIEWER)).getControl().getShell(),

wizard);

dialog.setBlockOnOpen(true);

if (dialog.open() == WizardDialog.OK) {

context.putLocal(namespace, CallerContext.UI_STATUS, FINISH_OK);

}

}

}

com.sap.scripting.ws.generators.python.GeneratorsPlugin /**

* <copyright>

* Copyright 2006 SAP AG

* </copyright>

*/

package com.sap.scripting.ws.generators.python;

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 46

import org.eclipse.ui.plugin.*;

import org.eclipse.jface.resource.ImageDescriptor;

import org.osgi.framework.BundleContext;

/**

* The main plugin class to be used in the desktop.

*/

public class GeneratorsPlugin extends AbstractUIPlugin {

//The shared instance.

private static GeneratorsPlugin plugin;

/**

* The constructor.

*/

public GeneratorsPlugin() {

plugin = this;

}

/**

* This method is called upon plug-in activation

*/

public void start(BundleContext context) throws Exception {

super.start(context);

}

/**

* This method is called when the plug-in is stopped

*/

public void stop(BundleContext context) throws Exception {

super.stop(context);

plugin = null;

}

/**

* Returns the shared instance.

*/

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 47

public static GeneratorsPlugin getDefault() {

return plugin;

}

/**

* Returns an image descriptor for the image file at the given

* plug-in relative path.

*

* @param path the path

* @return the image descriptor

*/

public static ImageDescriptor getImageDescriptor(String path) {

return AbstractUIPlugin.imageDescriptorFromPlugin("WS.Generators.Python", path);

}

}

com.sap.scripting.ws.generators.python.wsGeneratorsPythonMessages.properties Generator_unsupportedObjectTypeException=This generator doesn't support code generation for object of this type:

Generator_recursiveTypeFunctionDescription=This function has been generated incorrectly\n because the generator doesn't support code generation for objects which have recursive types

Generator_recursiveTypeFunctionWarning=Cannot generate function {0} because the generator doesn't support code generation for objects which have recursive types

Generator_warningTitle=Warning

com.sap.scripting.ws.generators.python.WSGeneratorsPythonMessages package com.sap.scripting.ws.generators.python;

import org.eclipse.osgi.util.NLS;

public class WSGeneratorsPythonMessages {

private static final String BUNDLE_NAME = "com.sap.scripting.ws.generators.python.wsGeneratorsPythonMessages"; //$NON-NLS-1$

private WSGeneratorsPythonMessages() {

}

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 48

static {

// initialize resource bundle

NLS.initializeMessages(BUNDLE_NAME, WSGeneratorsPythonMessages.class);

}

public static String Generator_unsupportedObjectTypeException;

public static String Generator_recursiveTypeFunctionDescription;

public static String Generator_recursiveTypeFunctionWarning;

public static String Generator_warningTitle;

}

Templates/CodeTemplate.txtjet <%@ jet package="com.sap.scripting.ws.generators.python.templates" imports="com.sap.scripting.ws.generators.python.worker.Data java.util.Date java.text.SimpleDateFormat" class="CodeTemplate" %><%

Data data = (Data)argument;

SimpleDateFormat dateFormatter= new SimpleDateFormat("dd.MM.yyyy HH:mm");

%>

# Stub functions for <%=data.getServiceName()%>: <%=data.getMethod()%>

# generated by SAP Scripting Framework for Eclipse: Web Service calls generator for Python.

# Generation time: <%= dateFormatter.format(new Date()) %>

#

# Data source: Web Service

# SOAP entry at <%=data.getPortLocation()%>

# Connector: Python 2.4.2-SOAPpy (http://pywebsvcs.sourceforge.net/)

# Language: Python 2.4.2

from SOAPpy import SOAPProxy

# <%=data.getMethod()%>

# <%= data.getMethodDescription().replaceAll("\n", "\n# ") %>

def <%=data.getServiceName()%>_<%=data.getMethod()%>(<%=data.getInputParametersPython()%>):

proxy_<%=data.getServiceName()%> = SOAPProxy('<%= data.getPortLocation() %>', '<%= data.getNamespace() %>')

result = proxy_<%=data.getServiceName()%>.<%= data.getMethod() %>(<%=data.getInputParametersWS()%>)

return result

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 49

Appendix B. Python Language Plug-in for SAP Scripting Framework Source Code

plugin.xml <?xml version="1.0" encoding="UTF-8"?>

<?eclipse version="3.2"?>

<!--

Plugin.xml for the Python language plug-in.

Copyright 2006 SAP AG

-->

<plugin>

<extension

point="com.sap.scripting.core.languages">

<language

default_extension="py"

display_name="Python"

id="com.sap.scripting.languages.python"/>

</extension>

<extension

point="org.eclipse.ui.preferencePages">

<page

category="com.sap.scripting.core.preferences.PreferencePageMain/com.sap.scripting.core.preferences.PreferencePageLanguages"

class="com.sap.scripting.languages.python.preferences.PreferencePage"

id="com.sap.scripting.languages.python.preferences.PreferencePage"

name="Python"/>

</extension>

</plugin>

META-INF/Manifest.mf Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: SAP Scripting Python definition

Bundle-SymbolicName: com.sap.scripting.languages.python; singleton:=true

Bundle-Version: 0.9.4

Bundle-Vendor: www.sap.com

Bundle-Localization: plugin

Require-Bundle: com.sap.scripting.core,

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 50

org.eclipse.core.runtime,

org.eclipse.ui,

com.sap.scripting.common.ui

Export-Package: com.sap.scripting.languages.python.preferences

build.properties source.. = src/

output.. = bin/

bin.includes = META-INF/,\

plugin.xml,\

.

com.sap.scripting.languages.python.LanguagePythonMessages /**

* <copyright>

* Copyright 2006 SAP AG

* </copyright>

*/

package com.sap.scripting.languages.python;

import org.eclipse.osgi.util.NLS;

/**

*

* <!-- begin-user-doc -->

*

* <b>LanguagePythonMessages</b>

*

* Utility class for handling messages.

*

* <!-- end-user-doc -->

*

*/

public class LanguagePythonMessages extends NLS {

private static final String BUNDLE_NAME = "com.sap.scripting.languages.python.messages"; //$NON-NLS-1$

private LanguagePythonMessages() {

}

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 51

static {

// initialize resource bundle

NLS.initializeMessages(BUNDLE_NAME, LanguagePythonMessages.class);

}

public static String PreferencePage_DESCRIPTION;

public static String PreferencePage_DIRECTORY;

}

com.sap.scripting.languages.python/messages.properties PreferencePage_DESCRIPTION=Default generated files location:

PreferencePage_DIRECTORY=

com.sap.scripting.languages.python.preferences.IPreferencesConstants /**

* <copyright>

* Copyright 2006 SAP AG

* </copyright>

*/

package com.sap.scripting.languages.python.preferences;

/**

*

* <!-- begin-user-doc -->

*

* <b>IPreferencesConstants</b>

*

* Miscelanous constants regarding the Python interpreter and language.

*

* <!-- end-user-doc -->

*

*/

public interface IPreferencesConstants {

public static final String EXECUTABLE_PATH = "com.sap.scripting.languages.python.preferences.exe_path";

public static final String GENERATED_FILES_PATH = "com.sap.scripting.languages.Pyton.preferences.generated_path";

}

com.sap.scripting.languages.python.preferences.PreferencePage /**

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 52

* <copyright>

* Copyright 2006 SAP AG

* </copyright>

*/

package com.sap.scripting.languages.python.preferences;

import org.eclipse.jface.preference.DirectoryFieldEditor;

import org.eclipse.jface.preference.FieldEditorPreferencePage;

import org.eclipse.ui.IWorkbench;

import org.eclipse.ui.IWorkbenchPreferencePage;

import com.sap.scripting.common.plugin.UIPlugin;

import com.sap.scripting.languages.python.LanguagePythonMessages;

import com.sap.scripting.languages.python.preferences.IPreferencesConstants;

/**

*

* <!-- begin-user-doc -->

*

* <b>PreferencePage</b>

*

* Preference page for the Python language in SAP Scripting Framework.

*

* <!-- end-user-doc -->

*

*/

public class PreferencePage extends FieldEditorPreferencePage implements

IWorkbenchPreferencePage {

public PreferencePage() {

super(GRID);

setPreferenceStore(UIPlugin.getDefault().getPreferenceStore());

setDescription(LanguagePythonMessages.PreferencePage_DESCRIPTION);

}

protected void createFieldEditors() {

addField(new DirectoryFieldEditor(IPreferencesConstants.GENERATED_FILES_PATH,

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 53

LanguagePythonMessages.PreferencePage_DIRECTORY, getFieldEditorParent()));

}

public void init(IWorkbench workbench) {

}

}

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 54

Related Content

Scripting Languages Support for SAP Services

I. ZIP archive with the sample projects

II. SAP Developer Network (http://sdn.sap.com).

III. SAP Scripting Framework Wiki in SDN (https://www.sdn.sap.com/irj/sdn/wiki?path=/display/EmTech/Scripting+Languages).

IV. SAP Scripting Framework Overview (https://www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/4405).

V. Introduction to SAP Scripting Framework (https://www.sdn.sap.com/irj/servlet/prt/portal/prtroot/docs/library/uuid/591c31cf-0d01-0010-8ab7-a1f7d032a66c).

Eclipse Plug-in Development

VI. PDE Does Plug-ins (http://www.eclipse.org/articles/Article-PDE-does-plugins/PDE-intro.html).

VII. PDE Developer’s Guide (http://help.eclipse.org/help30/index.jsp?noscript=1).

VIII. Java Developer’s Guide to Eclipse, Second Edition (http://www.jdg2e.com/).

Python Specific

IX. Python Language (http://www.python.org/).

X. SOAPpy – Python extension for accessing web services (http://pywebsvcs.sourceforge.net/).

SAP Scripting Framework: How to Write a Scripting Generator

SAP DEVELOPER NETWORK | sdn.sap.com BUSINESS PROCESS EXPERT COMMUNITY | bpx.sap.com © 2007 SAP AG 55

Disclaimer and Liability Notice This document may discuss sample coding or other information that does not include SAP official interfaces and therefore is not supported by SAP. Changes made based on this information are not supported and can be overwritten during an upgrade. SAP will not be held liable for any damages caused by using or misusing the information, code or methods suggested in this document, and anyone using these methods does so at his/her own risk. SAP offers no guarantees and assumes no responsibility or liability of any type with respect to the content of this technical article or code sample, including any liability resulting from incompatibility between the content within this document and the materials and services offered by SAP. You agree that you will not hold, or seek to hold, SAP responsible or liable with respect to the content of this document.