Before someone decides to build grid services they should at least be familiar with basic grid service architecture and also that of statefull grid services if they plan to create asynchronous services and/or statefull services. To read more about grid service architecture and grid middleware to refresh your memory or get basic understanding please read some of the following basic information:
The Introduce toolkit is designed to support the three main steps of service development: 1) Creation of Basic Service Structure. The service developer describes at the highest level some basic attributes about the service such as service name and service namespace. Once the user has set these basic service configuration properties, Introduce will create the basic service implementation, to which the developer can then add application-specific methods and security options through the service modification steps. 2) Service Modification. The modification step allows the developer to add, remove, and modify service methods, properties, resources, service contexts, and service/method level security. In this step, the developer can create a strongly-typed service interface using well-defined, published schemas, which are registered in a system like the Mobius GME, as the type definitions of the input and output parameters of the service methods. One the operations are added to the service the developer will then be able to add the logic which implements the methods. 3) Deployment. The developer can deploy the service which has been created with Introduce to a Grid service container (e.g., a Globus or Tomcat service container). A service developer can access the functions required to execute these three steps through the Graphical Development Environment (GDE) of Introduce. The runtime support behind the GDE functionality is provided by the Introduce engine, which consists of the Service Creator, Service Synchronizer, and Service Deployer components. The toolkit provides an extension framework that allows Introduce to be customized and extended for custom service types and discovery of custom data types. In the following sections, we describe the software prerequisites, the Introduce Graphical Development Environment, the Introduce Engine, and the Introduce Extension Framework in greater detail.
- Java 1.5 or greater (http://www.java.sun.com)
- Apache Ant 1.6.5 or 1.7.0 (http://www.ant.apache.org)
- The Globus Toolkit Version 4.0.3 or 4.0.4 (http://www.globus.org)
- Added a new target in the service build file which enables fixing the soap bindings to work with custom serialization.
- Added property perform.index.service.registration to the deploy.properties to enable or disable index service registration.
- Added two new properties in the deploy.properties enabling the metadata pub/sub timing to be controlled.
- Added dev build.xml and build-deploy.xml which the user can freely edit without expecting changes by updates
- Moved ant-contrib.jar to ext/lib in the service instead of lib because the service itself does not need that jar as it is only used for building
- Created a soap binding fix that will enable us to use custom serialization of "some" types of a schema and added it to the services build process.
- Descriptions on the service, methods, inputs, outputs, faults, are now used to create javadoc on the "common" service interface.
- Moved to Policy Decision Point (PDP/authz) based authorization
- made the authorization class a PDP
- configures the service security descriptor to use the PDP
- added a gui panel to enable entering a custom PDP chain if desired
- Added support for resource factory/creation code to automatically be generated and placed into any method which is creating and returning a handle to a new service/resource instance.
- Added upgrader framework to enable migration of services from 1.0 - 1.1
- Added updater framework enabling Introduce to find and install extensions and newer versions directly from the software.
- Refactored service resource framework in order to enable registration of resource properties as well as enable the resource class itself to be user modified and extended to there liking. In doing this the BaseResource class was also renamed to <serviceName>Resource to make more sence to the developer. This also caused the renaming of the etc/registration.xml to etc/<serviceName>_registration.xml in order to support registration for the all the resource framework types.
- Only services which have resource properties that are to be registered will attempt to register with the index service.
- Most fields in the GDE which require user input are all dynamically validated and will give graphical feedback to the user if a warning or error is detected.
The Introduce Graphical Development Environment (GDE) can be used to create, modify, and deploy a grid service. It is designed to be very simple to use, enable using community accepted data types, and provide easy configuration of service metadata, operations, resources, and security. It also allows customized plug-ins to be added for such things as discovering data types from grid repositories and for creating custom service style design templates.
The Introduce GDE contains several screens and options for the service developer to 1) create a new service, 2) modify an existing service, 3) discover and use published data types in order to create strongly-typed service methods, and 4) deploy the service.
Service modification can be performed on any new or previously modified Introduce generated service. The service developer can perform a series of operations in order to begin to customize the grid service or modify the existing grid service. The overall flow in the modification of a grid service is to first use the namespaces tab to be sure that all the data types that are desired to be used I the grid service have been selected and added to the service. Next the service can choose to either add/remove or modify operations, metadata in the form of resource properties, service properties, security setting, and service contexts. The following sections will describe in detail how each of the components of the modification viewer can be used to modify the grid service to achieve desired functionality. By selecting the Modify Service button on the main menu a prompt will apear to enable choosing the service to be modified. Once the desired directory containing the service to be modified is selected the modification viewer component will be launched. The modification viewer contains 6 main areas where modifications can occur on the main service:
The first task in the modification of a grid service is to discover the data types that are desired to be used as the input and output types of methods of the service and the data types for describing the resource properties of the service. Adding a data types to the service is equivalent to copying schemas into the schema location of the service and importing the schemas into the WSDL file so that the types can be referenced by the service. This is done via the Types tab of the Graphical Service Modification Environment. This tab shows the current types the service is using, and provides access to the data type discovery components (such as the Mobius GME), for selecting and configuring additional types. The Select Type frame enables several types of ways to locate data types and bring them into the service. Currently there are three main discovery mechanisms (GME, Globus, and File System) that come with introduce, however, this is extensible via the Discovery Extension described in the Extensions section. Once a set of data types from a namespace are brought into the service the user has the ability to describe how these data types will be mapped into there respective Java classes. This can, by default, be done automatically by Introduce via Axis. By default, Axis will create new java beans for each data type and also provide a serializer and deserializer for those objects. If for example, a set of objects already exist for this particular data types then a user can decide to provide there own classes and serialization/deserialization factories.
Using the GDE, developers can obtain the data types that they want to use for operation input parameters and return types from any data type discovery plug-in. Utilizing common and standard data types, which are defined outside of any application-specific service, enables the creation of strongly typed grid service interfaces. This increases service-to-service interoperability. Once a data type is chosen through the GDE, the data type definition is retrieved, written into the schema/<service_name> location of the service, and imported for use in the service WSDL description so that Java beans can be generated and the data types can be programmatically used.
The Introduce toolkit comes with a set of pre-installed discovery plug-ins, such as the Mobius GME and a basic file system browser, which can be used to locate and import schemas. The GME plug-in enables developers to browse, upload, and download schemas published in a GME. These schemas represent the valid data types which can be used during service creation. Using the GME plug-in, a developer can take a schema, create an editable view of the schema, and then submit the schema to the GME. If the namespace of the schema is not managed by the GME, to which the schema is submitted, the plug-in will attempt to add the namespace to the GME before submitting the schema. Once the schema has been uploaded, it can be used by anyone in the Grid through the Introduce toolkit. The GME plug-in browser window enables browsing through all the GME published types by namespace and schema name. It presents the user a quick view of the schema and the option to download the schema bundle. The schema bundle contains the schema and all other schemas which are referenced by that schema.
When importing a data types there are several options in where to acquire the data type definitions. Introduce is build in with the following data type definition tools, however, this is a pluggable piece of Introduce. Once a data type is imported using an import tool that data type can be customized for the generation of Java Beans. If you select data type on the left you will see in the lower left panel that the namespace and package name have been listing. This is called the namespace to package map. This will determine the package name of the Java Beans that get created for the data type. Feel free to alter the package name if the Introduce suggested package name does not work well.
- File System Data Type Importing
The File System tab of the Import Data Types Panel enables the developer to load in schemata which contain data types they wish to use the service from the local filesystem. The developer can browse to choose the schema they wish to import, and the click the add button. Once the add button is clicked the schema and any locally included or imported schemata will be copied to the services schema location in the schema/<service name> directory.
- Global Model Exchange Data Type Importing
The Global Model Exchange Data Type extension enables browsing for schemata from a remote grid service which is responsible for storing them. Introduce can connect to a GME and load in all the available namespaces the GME is storing schemata for. Once the developer selects a namespace the name drop down will be populated with all the available schema names for that schema. Once a namespace and name have been selected then user can select the add button and the schema and any imported schemata will be downloaded and imported into the service. The mainConfigurationmenu at at the top for the GDE will contain the ability for changing the location of the GME to use.
- Globus Data Types Importing
The Globus Data Types extension enable the developer to import schema from the Globus toolkit into their service. There is a drop down containing a list of the available schemata from the current installation of the Globus Tooolkit. Once a namespace has been selected and the add button has been selected then the schema will be added to the service's available data types list.
Introduce will enable re-importing of a data type if the developer wants to re-import a particular schema which may have been modified or extended. In order to do this you must make sure the Namespace Type Replacement Policy configuration setting in the Introduce Configuration-->Preferences menu is set to warn. Once this is done you can simply browse back to the data model and import it again.
Once a namespace and corresponding data types have been imported into the service each data type can be further customized. For a particular data type one can chose to use a Custom Java Bean that already exists instead of having Introduce create the java beans for the service. This can be accomplished by selecting the + button beside the Customize Bean label. This will drop down the customization panel for that particular data type. In this panel, to support using a custom bean for the selected data type definition, the developer must fill out the three fields: the classname of the bean to be used (make sure the package name above matches the package name being entered for the custom beans classname), the deserializer factory class, and the serializer factory class. For more information on using custom serialization or what it means to be a custom bean please refer to the most recent Globus documentation on type mapping.
The developer can add, remove, or modify operations on the service, using the Operations tab of the GDE Service Modification interface. For each operation, the developer needs to set the input parameters, return type, and any fault types that can be thrown from each service method. The security configuration of the operation should also be set if desired. The input and output types can be selected from the types tree on the left. This tree represents the available data types which can be used by this service. If any input parameter or output type is to be an array the array checkbox must be checked in the table on the right. Also, once an input parameter is added the name of the parameter is defaulted. This name can be edited by the developer by selected the cell in the name column and editing the text. There are two ways to add faults, either choose a type from the types tree which extends WSRF BaseFaultType or create a new fault which will tell Introduce to create you a new fault type which extends the BaseFaultType.
The implementation of a described operation may already exist in another class which is provided by a jar file. You can tell Introduce not to stub this methods server side implementation but instead call this provided method implementation directly in the class provided. In order to use this functionality the Provided checkbox must be selected and the Class name attribute must be filled out in the Provider tab. The class name attribute will point to the fully qualified class name of the class which implements this WSDL described operation. The jar file that contains the provided Class which implements this operation must also me copied into the lib directory of the service. This will ensure that the operation will be located at the time the operation is called on the service. For more information on this particular topic refer to the Globus Documentation on Operation Providers.
Operations can also be imported from other services. Importing an operation enables the service to implement the exact same operation signature. This enables the service to have an operation which has the exact same WSDL signature of the operation which is being imported. This would enable either client to invoke this operation on either service. Importing can be done in two ways: (1) from an Introduce generated service, or (2) from a WSDL file. For case 1, importing from an Introduce service, the developer would browse and select the Introduce generated service which contains the operation to be imported. Once the Introduce service is selected a list of services which contain this method will be available to select from. Select the service from which you want to import the operation. The methods signature will be imported and the developer will be prompted to make sure to copy over the WSDL and XSD files needed to import the method into the schema<service name> directory of the service. For case 2, if a method is described in another WSDL but the developer wants to implement this exact method from this WSDL. The developer must have the WSDL and corresponding XSD's in the schema/<service name> directory of the service. Then the developer will be able to browse those WSDL files and select the port type they wish to import the operation from. The importing of a method across services will assure not only that each service has completely protocol compatible methods but also that each service's method can be invoked by the same base client. This enables the notion of basic inheritance in grid services and is discussed further in Operation Importing.
Service state information and metadata in the form of resource properties can be added, removed and configured via the Metadata tab of the GDE Service Modification interface. The metadata elements which are added to the service can be populated by a file statically or managed dynamically within the service. Also, these metadata entities can be registered with an index service so that users can use the metadata to locate the service. Once the Metadata tab is clicked the left panel will contain a list of available data types that can be used for metadata and the right will contain the list of currently chosen data types. By double-clicking on a data type in the left panel it will be added to the main service's metadata list. Any of the service's metadata can be initially populated from a file if desired. If this is chosen then once the service is started up in the container the file will be used to populate the particular metadata object in the service. Each metadata in the service can also be selected to be published to an index service. This will enable some or all of the metadata to be used in to locate the service via an index service.
Service properties are key value pairs which can be set at deployment time and are available to the server side implementation of the service at run time. This enables passing in configuration variables to the server side of the service at deployment. These key value pair properties can be declared in Service Properties tab of the GDE Service Modification interface. Once the Service Properties tab is clicked the main panel will show a table of the service properties. The bottom panel has an entry for which can be used to create a new service property. The properties will be confirmed and/or can be changed from there default values at service deployment time. The variables can then be accessed inside the user's implementation of the operations through the services ServiceConfiguration class. For example, if you add a property called foo under the service properties tab, and then save the service. Then go look at the source code for the <service package>.service.ServiceConfiguration.java class you will seee that it now has available methods for string getFoo() and void setFoo(string foo). These operations are now available to your service and can be used to pass properties into your service at deployment time as well as other users for configuring and sharing properties in your service. The <service package>.service.ServiceConfiguration.java contains a static method for obtaining an instance of itself called getConfiguration(). Any call to that from anywhere in the service will return the handle to the ServiceConfiguration instance and hence access to the service properties.
Introduce exposes the functionality of Globus GSI through a set of panels which enable the user to customize security for the entire service or specific methods on an service context. The user can choose any of the GSI configuration scenarios such as Transport Level Security with Integrity and Secure Communication with Privacy. Introduce also enables configuring a particular service, operation, or resource, for authorization. Introduce comes with capabilities to configure authorization using GridGrouper and/or Common Security Model, or a Custom PDP based authorization chain. Graphical panels will enable the user to describe an authorization policy which must be met in order to give access to the particular service or operation. For detailed knowledge of what the configuration options for Secure Conversation or Secure Credentials are please refer to documentation for the GSI framework.
A Statefull Grid service is comprised of several key components which make it able to maintain state and enable a client to invoke the service several time under the same context. A statefull grid service is composed of the service, a resource home, and the resource type. This service organizaton can be used in many different scenarios. For, example, when an operation on the service is invoked the service can be implemented to handle that operation, or if the operation is addressing a particular resource instance in the service, the service can lookup the resource and call whatever might be necessary to call on the particular addressed resource.
In order to act on this resource it will need to construct a client which can talk to the grid service which represents this resource type. The Counter Context Client will be constructed using the EPR to address the specific resource context for the service. Next the user would like to call the incrementCounter() operation on the Counter Context Grid Service. The client will make the call to the grid service and the service will then look at the EPR sent over by the client. The service will then take the EPR and give it to the resource home and ask for the resource instance back which is represented by the particular EPR. The the service will run it's logic to increment the counter, which in this case is represented as a resource property of the resource.
Below shows an example of the code that would be required to implement the incrementCounter() method in the CounterContextServiceImpl.java.
In Introduce 1.1, the incrementCounter() operation shown above is implemented in the service context implementation class (CounterContextImpl). The context operations implemented in this class are called each time a context client calls an operation. If the service context you are writing (as in the counter case above) maintains state for each context instance between calls, then that state can be accessed via the getResourceHome().getAddressedResource() call shown above. This call returns the specific instance of a CounterContextResource class that holds the state for the context client. In summary, the CounterContextImpl class is a stateless class that simply implements the context operations. The CounterContextImpl class uses the CounterContextResource instance specific to the EPR used by the client to access and maintain state for the client who is currently calling the context operation. In the above example, the state in the CounterContextResource is the current count retrieved in the impl via the getIntValue method (which is a service context property added via Introduce GDE).
When an operation is added in the Introduce GDE and the Save button is clicked, Introduce will add the new stubbed method into the <service package>.service.<service name>Impl.java class. The developer is then responsible for implementing the method prior to deployment. For example the snippet below would be generated in the <service package>.service.<service name>Impl.java if the developer added an add operation to the service with Introduce that took in two integers and returned and integer.
The developer would then have to edit this method to implement the logic the service would execute on invokation.
The deployment option of the GDE allows the service developer to deploy the implemented grid service, which has been created with Introduce, to a Grid service container. The toolkit currently supports deploying a service to either a Globus or Tomcat Grid service container; however, support for other deployment options can easily be added to the GDE. The deployment window allows the service deployer to populate service configuration properties, which the service will have access to at runtime. Then the service is deployed to the selected container.
Introduce generates a client API for the service which is exactly as described within the graphical editing environment (see Auto-boxing/Unboxing or Service Operations). This client API can be used in order to leverage this type of service from another application or service. The API contains four constructors which can use used, each of which is different depending on having a handle or just an address and the need for security to be used.
Once a client handle is constructed each of the operations which were created in the service are available as operations to this newly constructed client instance. Below is an example snippet of code which creates a new client handle to a service called HelloWorld and calls the echo operation.
Introduce is now capable of downloading and installing new extensions, upgrades to older extensions, and newer versions of itself. In the GDE there is a Help menu. In this menu there is a Check for Updates button. This button will take the user to a wizard which will walk them through looking for any software updates or new packages which they may want to download and install.
Introduce has the ability to help migrate a service to a newer version of Introduce. If the developer attempts to open a service generated with an older version of Introduce (1.0 and newer), Introduce will prompt the user to proceed with the migration process. The migration process is fully automated and when it is complete will report out to the developer what might be left for them to adjust based on there potentially custom changes or if there were any errors during the process.
When using Introduce to open a service for modification it will check the service to see which version of Introduce and its Extensions were used to create/modify the service. If those versions are different from those installed in the Introduce being used, it will prompt the user and notify them that the service needs upgrading. When prompted the user will have to decide to either:
- Upgrade: upgrade the service to the version that Introduce can properly work with it
- Open: attempt to have Introduce work with it without upgrading which is potentially dangerous and recommended.
- Close: do nothing to the service and do not proceed with the modification process
If the user chooses to upgrade the service the upgrade process will begin. Once finished, a report indicating the major changes and potential issues will be displayed to the user for their review. Once they are confident they have addressed any issues in the upgrade report, they can select the Proceed option and the Modification Viewer will be opened displaying the newly upgraded service. If the report warns them about potential modification they might need to make in order to finish the Upgrade process then the user can select the Edit button. This will enable them to halt the upgrade process while they make changes. In doing so, they can open the service up for modification at a later time and Introduce should be able to work with the service. If they are not confident in the changes and don't want to upgrade, they can select the Roll Back option to restore the service to its previous state.