Data Services 1.4 Developers Guide
| Navigation | ||
|---|---|---|
| caGrid | caGrid 1.4 Documentation | |
| Data Services | Data Services 1.4 Documentation | Data Services 1.4 Developers Guide |
This guide is intended for both developers creating caGrid data services using the Introduce toolkit in conjunction with the data services extension and developers using the various Java APIs to interact with and customize data services.
Creating a Data Service with Introduce
Data services may be created using the Introduce toolkit in conjunction with the data services extension.
Start Introduce from the top level of your caGrid installation:

ant introduce
Editing a Data Service with Introduce
Data services may be edited via the Introduce toolkit in conjunction with the data services extension. When a data service is created or opened with Introduce, the data service extension adds a tab to the main service modification window titled "Data Service." This tab has a number of sub-tabs which control or display various aspects of the data service.
Domain Model Tab
The first tab shown is the Domain Model tab. This tab allows the service developer to control aspects of the service's exposed data model.
This tab allows the service developer to select the project and packages from the caDSR which the data service should expose. Individual classes may be added or removed from the model by using the tree of packages and classes and checking the box next to classes to be included at the bottom. The "Visualize Domain Model" button shows a graphical representation of the current domain model, including classes, their attributes, and associations. The "Advanced Options" button gives the service developer access to options for no domain model and a model from the local file system. In the case either of these options is selected, the class selection tree on the Domain Model tab is disabled.Query Processor Tab
The next tab is the Query Processor tab. This tab allows the service developer to set the query processor class which will be used to handle CQL against the service's backend data store, as well as configure the query processor's parameters.
The selected class dropdown menu shows all classes found in the jars list which extend from the base abstract CQL query processor class. To add a new class to this list, it must appear in a jar file listed in the Additional Jars list. Jars can be added by using the Add Jar button and browsing to the jar file on your local file system. This will copy the jar into your service. The Remove Jars button removes the selected jars from the list.The Launch Query Processor Configurator button will launch a special dialog for configuring the selected query processor, if it supplies one. If it does not, a message will be displayed indicating as much.
The Processor Parameter Configuration table shows the configuration properties of the selected query processor, their default value, and the currently configured value. The values may be edited in this table, or in the service properties table directly. Changes in one of these tables are reflected in the other, with the exception that the properties on this page are not prefixed for readability.
Details Tab
The details tab allows the service developer to control mapping between XML schema types and the data types in the exposed domain model, as well as enable or disable query validation.
The serializer and deserializer fields may be edited by right-clicking and choosing an option from the popup menu which appears. Selecting custom serialization allows the service developer to manually enter class names, and default serialization resets the fields to be blank, allowing Globus and Axis to handle serialization and deserialization.The targetable field contains a check box which indicates that a class is eligible to be the target of a CQL query. If deselected, a class can still be part of a query (i.e. an Association somewhere within the query), but cannot ever be returned by a query. Queries against classes which are not targetable will generate an error.
Auditing Tab
The data service framework supports some rudimentary auditing support, which can be configured with the Auditing tab in the Introduce toolkit. Multiple auditors may be added to the service, each of which may handle auditing events in its own way. Multiple instances of the same auditor type may be added as well, allowing configuration options to dictate their behavior and handling of auditing events.
Clicking the Discover button causes the panel to locate all Java classes which implement the Auditor interface currently in the service's lib directory. Instances of any class it locates may be selected from the dropdown menu and configured.Four points of the data service query process may be audited:
- Query Begins
- This event is fired when a query is first submitted to the data service before any validation or processing has been done.
- Validation Failure
- This event is fired when a query fails the validation process. If validation is not enabled, this event will never be fired.
- Query Processing Failure
- If a query should fail to process correctly, this event is fired. The reason (exception) causing the failure is included in this event.
- Query Results
- When a query completes successfully, this event is fired. The results of the query are available at this point as well.
Other style-specific tabs
Data Service Styles may optionally provide a custom tab which will appear as a subtab of the Data Service tab in Introduce. This tab may contain configuration or information specific to the service style. For example, tn the above screenshots, a tab for the caCORE SDK 4.0 style is visible.
Client API
caGrid Data Services provide a standard query method which all data services have in common. This query method is exposed to the grid via a uniform WSDL using request and response messages of a consistent namespace and type. This allows for a uniform client to invoke any arbitrary data service. Such a client is provided with the data services infrastructure, along with several helper classes. This is also true for data services which support WS-Enumeration.
Creating a Query
Data services in caGrid use CQL or CQL 2 to compose queries. A query can be produced programmatically, building up parts of the query using the supplied object model.
CQLQuery query = new CQLQuery();
Object target = new Object();
target.setName(Gene.class.getName());
Attribute symbolAttribute = new Attribute("symbol", Predicate.LIKE, "IL%");
target.setAttribute(symbolAttribute);
query.setTarget(target);
Alternatively, a CQL query can be loaded from a string of XML text, or an XML file and deserialized into the object model.
// from a string
CQLQuery query2 = (CQLQuery) Utils.deserializeObject(
new StringReader("<CQLQuery ... />"), CQLQuery.class);
// from a file
CQLQuery query3 = (CQLQuery) Utils.deserializeObject(
new FileReader(cqlFile), CQLQuery.class);
Standard Data Services
Standard data services are those which support the basic query and executeQuery methods. A standard data service client may be used to query any caGrid data service via these methods, rather than requiring a separate client for each data service on the grid. This is true of all caGrid data services, and other specialized query methods may be included in addition to this one.
| The executeQuery method takes a CQL 2 query parameter and returns CQL 2 query results. Since CQL 2 is a new feature of caGrid 1.4, attempting to invoke data services created with caGrid 1.3 and earlier using this method will fail with an error similar to 'operation not defined' |
Initializing the Client
The generic data service client can be initialized simply by passing the URL of the remote data service service to the constructor:
String url = "http://localhost:8080/wsrf/services/cagrid/ExampleDataService";
DataServiceClient standardClient = new DataServiceClient(url);
The generic data service client has only the query and executeQuery methods in its public API. To make use of any additional methods you may have added to your service, the specific client generated by Introduce for your service must be used.
| client-config.wsdd All CaGrid client programs need to have the file client-config.wsdd on their classpath. There are two recommended ways to arrange this:
|
Submitting a Query
A query can be submitted to the standard data service client, which will return the query results when processing is complete. The query method can throw two typed exceptions:
- Query Processing Exception
- Thrown when an error occurs in actually processing the query or formulating a result set. This might include database errors and misconfiguration of the query processor.
- Malformed Query Exception
- This is generally thrown from the query validation process, and indicates a query which violates the CQL schema, or attempts to reach parts of a domain model which are either excluded from queries or do not exist.
- Query processor implementations may also throw this exception in response to queries which attempt to use features of CQL which are not supported by that particular implementation (eg. Attribute Results)
try {
CQLQueryResults results = standardClient.query(query);
} catch (QueryProcessingExceptionType ex) {
// handle processing exception
} catch (MalformedQueryExceptionType ex) {
// handle malformed query
} catch (RemoteException ex) {
// handle remote exception
}
Handling the Results
The results of a CQL query are returned in an object model which can hold one of either object results, attribute results, or a count result. These results can be iterated as single items using a specialized implementation of the standard Java Iterator interface.
Iterator iter = new CQLQueryResultsIterator(results,
InvocationExample.class.getResourceAsStream("client-config.wsdd"));
while (iter.hasNext()) {
Gene g = (Gene) iter.next();
System.out.println("Found a gene:");
System.out.println(g.getFullName() + " -- " + g.getSymbol());
}
Alternatively, the data service infrastructure provides a simplified handle class which hides the complexity of setting up an iterator to handle the query results.
try {
String url = "http://localhost:8080/wsrf/services/cagrid/ExampleDataService";
DataServiceClient standardClient = new DataServiceClient(url);
DataServiceHandle handle = new DataServiceHandle(standardClient);
Iterator i = handle.query(query);
// iterate
} catch (QueryProcessingExceptionType ex) {
// handle query processing exception
} catch (MalformedQueryExceptionType ex) {
// handle malformed query
} catch (MalformedURIException ex) {
// malformed URI
} catch (RemoteException ex) {
// handle remote exception
}
Handling of CQL 2 query results is described in the CQL 2 documentation.
Enumeration Data Services
Data Services optionally support use of WS-Enumeration for retrieving query results. Since this is also a standard operation with a consistent WSDL, a single Enumeration Data Service Client can be used to query any data service which supports Enumeration.
Initializing the Client
Just as the standard data service client, the enumeration data services client can be initialized with the URL of your grid service:
String url = "http://localhost:8080/wsrf/services/cagrid/ExampleDataService";
EnumerationDataServiceClient client = new EnumerationDataServiceClient(url);
Submitting a Query
The generic enumeration client supports a single method:
EnumerationResponseContainer responseContainer = client.enumerationQuery(query);
When this method is invoked, the service executes the CQL query as it would for a standard data service, but rather than returning the result directly, an enumeration resource is created to store the results, and an EnumerationResponseContainer instance is returned.
The EnumerationResponseContainer is a caGrid data type which encapsulates both the WS-Enumeration spec EnumerationContext and the endpoint reference (EPR) of the enumeration service context and the resource key of created enumeration resource. More information on caGrid's support for WS-Enumeration is provided here.
Handling the Results
The data service infrastructure provides tooling to assist in creating a ClientEnumIterator instance which can communicate with the remote enumeration service context.
EnumerationResponseContainer responseContainer = client.enumerationQuery(query);
InputStream wsddStream =
ClassUtils.getResourceAsStream(getClass(), "client-config.wsdd");
ClientEnumIterator iterator = EnumerationResponseHelper.createClientIterator(
responseContainer, wsddStream);
// constraints to retrieve 10 results, no char limit, timeout of 5 sec
IterationConstraints cons = new IterationConstraints(10, -1, DurationUtils.toDuration(5000));
iterator.setIterationConstraints(cons);
while (iterator.hasNext()) {
SOAPElement elem = (SOAPElement) iterator.next();
// process element
}
The contents of each SOAP Element are an XML representation CQLObjectResult instances, and can be deserialized as such.
Alternatively, the whole querying and result handling process can be condensed to a few lines using the supplied EnumDataServiceHandle class:
EnumDataServiceHandle handle = new EnumDataServiceHandle(client);
Iterator i = handle.query(query);
// iterate
Transfer Data Services
Data Services optionally support the use of caGrid Transfer for retrieving query results. Since this is also a standardized operation with consistent WSDL, a single Transfer Data Service Client can be used to query any data service which supports Transfer.
| The support of caGrid Transfer is a new feature in caGrid 1.4, and attempting to query a data service generated with caGrid 1.3 or earlier using this client and the associated operations will result in an error similar to 'operation not supported' |
Submitting a Query
The generic transfer data service client supports two public operations; one for CQL named transferQuery, and one for CQL 2 named executeTransferQuery.
String url = "http://localhost:8080/wsrf/services/ExampleTransferDataService";
TransferDataServiceClient client = new TransferDataServiceClient(url);
TransferServiceContextReference transferRef = client.transferQuery(cqlQuery);
Once the TransferServiceContextReference has been retrieved from the data service, the client can obtain the query results from it by following the [caGrid Transfer developers guide]
Handling the Results
The transfer context will return an input stream. This input stream will retrieve the query results as XML text. This text can be deserialized as CQL or CQL 2 query results and handled with the standard results handling utility APIs.
Other Data Service APIs
The caGrid data services infrastructure supplies many client and service side APIs.
Utility Client APIs
The caGrid Data Services infrastructure provides a number of utility classes to make invocation of remote data services a simpler process for the application developer. The package gov.nih.nci.cagrid.data.utilities contains utilities can invoke standard enumeration as well as tools for handling domain models and working with wsdd and castor mapping files.
Iterating Query Results
When a query is performed using the standard caGrid Data Service client's query method, a CQLQueryResults object is returned. This object is a container for both the results themselves and some information pertaining to their type. This container can contain object results, attribute name/value pairs, or a count of the total number of items in the result set. The difficulty of manipulating a container which may contain such a wide variety of result types stored in it may be handled by an iterator class provided with the data service infrastructure.
The interface DataServiceIterator specifies a single query() method, which takes a CQL Query and returns an instance of java.util.Iterator. The iterator can be used to walk through the results of a query issued to a data service. Three concrete implementations of the DataServiceIterator interface are provided, each for communicating with a different type of data service. The DataServiceHandle class can be used to invoke a standard caGrid Data Service while the EnumerationDataServiceHandle is designed for WS-Enumeration.
Additionally, this package contains an Iterator utility for handling CQLQueryResults instances directly. The class CQLQueryResultsIterator implements the java.util.Iterator interface, and has three constructors. The choice of constructor affects the behavior of calling the next() method.
- CQLQueryResultsIterator(CQLQueryResults)
- Creates an Iterator over the results which will return materialized objects deserialized using the default type mappings.
- CQLQueryResultsIterator(CQLQueryResults, boolean)
- Creates an Iterator over the results, and the value of the Boolean parameter indicates if XML strings should be returned from the next() method.
- If the Boolean value is true, XML text of each item is returned, otherwise the results will be deserialized using the default type mappings.
- CQLQueryResultsIterator(CQLQueryResults, InputStream)
- Creates an Iterator over the results, and expects the InputStream will point to a client or server side wsdd.
- The contents of this wsdd file will be used to configure deserialization of the objects contained in the results.
- Creates an Iterator over the results, and expects the InputStream will point to a client or server side wsdd.
The class gov.nih.nci.cagrid.data.utilities.CQLQueryResultsIterator implements the java.util.Iterator interface, and so can be used in a while() loop like any other iterator over a Java collection. Depending on what the query to the data service asked for, calls to the next() method of this iterator will return different types of objects.
- If the query was for object results, then:
- The iterator returns objects of the type specified as the target for the query.
- Objects which require custom serialization and/or deserialization require that the iterator be configured with an InputStream to the client-config.wsdd file containing the type mappings for the objects.
- Alternatively, the iterator can be configured to return only the XML representation of those objects.
- If the query was for attribute results, including distinct attributes, then:
- Each successive call to next() returns an array of TargetAttribute types.
- These types contain the name of an attribute and its value.
- The value in the TargetAttribute instance will be null if the value was null on the object satisfying the query.Each array of TargetAttributes corresponds to one object instance which satisfied the CQL query criteria.
- If the query was for a count of object instances, then:
- The iterator returns a single java.lang.Long value.
An example usage of this iterator is below:
import gov.nih.nci.cagrid.cqlquery.CQLQuery; import gov.nih.nci.cagrid.cqlresultset.CQLQueryResults; import gov.nih.nci.cagrid.data.utilities.CQLQueryResultsIterator; import java.util.Iterator; public class SampleDataServiceInvocation { public static void main(String[] args) { try { DataServiceClient client = new DataServiceClient(args[0]); CQLQuery query = new CQLQuery(); // build up the query CQLQueryResults results = client.query(query); Iterator iter = new CQLQueryResultsIterator(results, SampleDataServiceInvocation.class .getResourceAsStream( "client-config.wsdd")); while (iter.hasNext()) { java.lang.Object result = iter.next(); // do something with the result object } } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } } }
Determining Service Capabilities
Since caGrid 1.4 data services introduce several new features, a utility API has been added which allows clients to determine what features a given caGrid data service supports. The gov.nih.nci.cagrid.data.utilities.DataServiceFeatureDiscoveryUtil class provides several static methods which return boolean flags indicating if the service supports a given feature.
- serviceSupportsCql2(EndpointReferenceType)
- Returns true if the Endpoint Reference points to a caGrid data service which supports CQL 2.
- serviceHasCql2TransferOperation(EndpointReferenceType)
- Returns true if the Endpoint Reference points to a data service which supports CQL 2 and has the transfer operation available
- serviceHasCql1TransferOperation(EndpointReferenceType)
- Returns true if the Endpoint Reference points to a data service which supports CQL 1 and has the transfer operation available. Note that if the service supports CQL 2, support for CQL 1 is implicit.
- serviceHasCql2EnumerationOperation(EndpointReferenceType)
- Returns true if the Endpoint Reference points to a data service which supports CQL 2 and WS-Enumeration.
- serviceHasCql1EnumerationOperation(EndpointReferenceType)
Returns true if the Endpoint Reference points to a data service which supports CQL 1 and WS-Enumeration. Note that if the service supports CQL 2, support for CQL 1 is implicit.
This utility class also contains an additional method which can be used to determine more generally if a given service supports a specific WSDL operation:
- getOperation(EndpointReferenceType epr,
QName inputMessage, QName outputMessage, String operationName) -> Operation- Returns the Operation from the service identified by the endpoint reference with input and output messages of the given QNames and of the name specified.
Utility Data Service APIs
The caGrid data services infrastructure includes several utility classes which can be used to ease development and use of data services. These classes are found in the gov.nih.nci.cagrid.data.utilities package distributed with the data service infrastructure.
Creating CQL Query Results
The CQLResultsCreationUtil class provides convenience methods for creating CQLQueryResults instances for object results, attribute results, and a counting result. A convenience method for identifier results may be added in the future. The class provides three public static methods, one for each type of results currently supported.
- public static CQLQueryResults createObjectResults(List objects, String targetName, Mappings classToQname)
- objects - a list of Java objects to be placed in a new CQLQueryResults object.
- targetName - the name of the class targeted by the query which produced these object results. All items in the objects list should be of this type.
- classToQname - a mapping from class name to QName. This is a generated Java bean from the XML schema for the data service infrastructure and contains an array of name/value pairs that map class names to QNames.
- public static CQLQueryResults createAttributeResults(List attribArrays, String targetClassname, String[] attribNames)
- attribArrays - a List of Object arrays. Each array should have one value for one attribute of an object. These values may be null. The values must be in an order corresponding the ordering of attribute names
- targetClassname - the name of the class targeted by the query which produced these attribute results. All attribute arrays should have some from this type.
- attribNames - the names of the attributes returned by the query. These should be in the same ordering used by the attribute arrays.
- public static CQLQueryResults createCountResults(long count, String targetClassname)
- count - the number of resulting items (objects, attribute sets) from a query
- targetClassname - the name of the class which was the target of the query
Querying and Iterating
The DataServiceIterator is an interface which provides for a query to be submitted to a data service and an Iterator over the result set to be returned. There are two implementations of this interface; one for the standard data service and one for data services with enumeration enabled.
- DataServiceHandle
- The data service handle is the implementation of the data service iterator class for a base caGrid Data Service. It has three constructors, all of which take a DataServiceClient instance. The default constructor needs only this parameter. The other two constructors should be used when custom serialization and deserialization of types has been specified for the service. The extra parameter can be either the filename of a wsdd file containing this mapping information, or an InputStream to the same information.
- EnumDataServiceHandle
- The enum data service handle is the implementation of the data service iterator interface for a WS-Enumeration enabled caGrid Data Service. It has two constructors, both of which take an enumeration data service client instance. The default constructor needs only this parameter. The second constructor takes an IterationConstraints instance, which contains information about how data should be requested from the enumeration data service.
Domain Model Manipulation
The DomainModelUtils class provides a means to extract useful information from a domain model.
- public static UMLClass getReferencedUMLClass(DomainModel model, UMLClassReference reference)
- To save on document size, domain models do not duplicate class information when an association is defined, but rather use class references based on ID values. These reference values can be traced back to their original UML Class instance with this function.
- public static UMLClass[] getAllSuperclasses(DomainModel model, String className)
- Superclasses of a UML Class can be determined by traversing UML class references and generalization information. There are two methods which perform this task in the Domain Model Utils class. One uses a class name and the other extracts the name from an UMLClass instance and passes it to the other.
WSDD Manipulation
The WsddUtil utility class contains functions to set parameters on a wsdd file. This class is used internally to the Introduce data service extension to edit the wsdd files and change the castor mapping file name.
- public static void setGlobalClientParameter(String clientWsddFile, String key, String value)
- clientWsddFile - the name of the client side wsdd file to edit. When edits are complete, the changed file is saved to the same location.
- key - the key of the parameter. This is the name by which the parameter can be accessed.
- value - the value stored in the parameter
- public static void setServiceParameter(String serverWsddFile, String serviceName, String key, String value)
- serverWsddFile - the name of the server side wsdd file to edit. When edits are complete, the changed file will be saved to the same location
- key - the key of the parameter. This is the name by which the parameter can be accessed
- value - the value stored in the parameter
Query Validation Tools
The caGrid Data Services infrastructure provides for validation of queries with respect to the domain model exposed by a service and the CQL schema, as well as query results for validity with respect to the exposed data types.
CQL Query Syntax
The caGrid Data Service infrastructure provides mechanisms to validate CQL queries for syntactic correctness. While the Axis engine prevents malformed XML from ever being turned into CQL objects, it does not handle XML that does not conform to certain schema restrictions. For example, Axis does not prevent populating multiple child elements of an XML schema 'choice'. For this reason, CQL syntax validation can be enabled on a caGrid data service. This mechanism will reject invalid queries before they ever reach a CQL Query Processor implementation, saving the processor's developer from having to handle them. This same validation can be performed either on the client side or offline completely by using the query validation utilities. For syntax validation, the interface gov.nih.nci.cagrid.data.cql.validation.CqlStructureValidator is provided, as are two implementations of this interface. The interface provides the validateCqlStructure() method, which takes a single CQLQuery instance parameter, and throws a MalformedQueryException if an error is encountered. The default implementation of this interface is the gov.nih.nci.cagrid.data.cql.validation.ObjectWalkingCQLValidator class. As its name suggests, this class walks through the CQL object model, seeking out inconsistencies with the published CQL schema. This class also has a main()' method, which allows it to be run from the command line with a list of CQL query XML files specified as arguments. The data service infrastructure uses this class by default when query validation is enabled. This can be changed to any other class which implements the CqlStructureValidator interface by editing the value of the dataService_cqlValidatorClass service property in a generated data service.
Domain Model Conformance
The Data Service infrastructure also provides mechanisms to validate a structurally sound CQL query against a Domain Model to ensure its restrictions are supported by the domain model's exposed structure. Domain Model validation may be enabled for a caGrid data service, and will be performed on every query submitted to the service before it is passed to the CQL query processor. The interface gov.nih.nci.cagrid.data.cql.validation.CqlDomainValidator is provided, along with a single implementation. The interface provides the validateDomainModel() method, which takes a single CQLQuery instance parameter, and throws a MalformedQueryException if an error is encountered. The lone implementation provided with the caGrid Data Service infrastructure is the gov.nih.nci.cagrid.data.cql.validation.DomainModelValidator class. Like the CQL validation instance, this class has a main() method, which allows it to be run from a command line. The arguments should be first a domain model XML file, then a list of CQL query files to be validated. The data service infrastructure uses this class when domain model validation is enabled. This implementation may be substituted for another by editing the value of the dataService_domainModelValidatorClass service property in a generated data service.
Query Results Validation
The data service infrastructure also provides a means to both validate the results of a CQL query against a known set of targets, and to determine what target data types are allowed to be returned by a caGrid Data Service. Every data service exposes a schema through its WSDL that enumerates the data types which may be returned by the data service. This schema appears in generated services under the schemas/<ServiceName> directory as <ServiceName>_CQLResultTypes.xsd.
The utility class gov.nih.nci.cagrid.data.utilities.validation.CQLQueryResultsValidator has been provided to both retrieve this file and verify that a CQLQueryResults instance conforms to this schema. An instance of this class can be constructed with either the full path to a data service's WSDL file, or an endpoint reference to a running data service.
The validator exposes two public methods:
- public void saveRestrictedCQLResultSetXSD(File fileLocation) throws SchemaValidationException
- This method locates the restriction XSD file and saves its contents into the file specified.
- fileLocation - a file into which the restriction XSD will be saved.
- public void validateCQLResultSet(CQLQueryResults resultSet) throws SchemaValidationException
- resultSet - a set of results generated by a query into a caGrid Data Service. The object contents of this result set will be processed against the restriction XSD.
The CQLQueryResultsValidator class also has a main() method, which takes two arguments. The first argument is a URL to a caGrid Data Service, which will be used to retrieve the result restriction schema. The second argument should be the filename of a CQLQueryResults instance serialized to an XML document.
Determining Available Features and CQL 2 Support
Since caGrid 1.4, data services have added support for CQL 2 in addition to continued support for CQL 1. A new resource property has been added to all caGrid 1.4 data services which indicates if they support the CQL 2 specification and operations, and also a list of any supported extensions to the CQL 2 language. Accessing this resource property is simplified by the utility class gov.nih.nci.cagrid.data.utilities.DataServiceFeatureDiscoveryUtil. This class contains several static public methods which can be used to determine the features a data service offers:
- public static boolean serviceSupportsCql2(EndpointReferenceType epr)
- This method determines if the service targeted by the EPR supports CQL 2. CQL 2 support in this case is the presence of the QueryLanguageSupport resource property, and that resource property indicating that a CQL 2 query processor is present in the data service.
- public static boolean serviceHasCql2TransferOperation(EndpointReferenceType epr)
- This method returns true if the service both supports CQL 2 and has the operation to return results with caGrid Transfer
- public static boolean serviceHasCql1TransferOperation(EndpointReferenceType epr)
- This method returns true if the service supports returning CQL query results via caGrid Transfer
- public static boolean serviceHasCql2EnumerationOperation(EndpointReferenceType epr)
- This method returns true if the service both supports CQL 2 and has the operation to return results via WS-Enumeration
- public static boolean serviceHasCql1EnumerationOperation(EndpointReferenceType epr)
- This method returns true of the service supports returning CQL query results via WS-Enumeration
CQL
The caGrid Query Language, or CQL is the query language used for all caGrid Data Services to express object-oriented queries against a data service. It is defined in an XML document conforming to a well defined schema with the URI http://CQL.caBIG/1/gov.nih.nci.cagrid.CQLQuery
.
Essentially a CQL query is a request for instances of a particular class. Which instances are returned can be constrained by the value of their attributes, which kinds of objects they are associated with and by what the values of their attributes are. A CQL query also specifies which attributes should be included in the returned instances or if the result should just be a count of the instances.
The following XML schema diagram shows the required structure of a CQL query.
A CQL query consists of some or all the following XML elements:
- CQLQuery
A simple top-level XML element at the head of every CQL query document. A CQLQuery has no attributes. It contains a Target element and an optional QueryModifier element.
<CQLQuery>
<Target …> … </Target>
<QueryModifier …> … </QueryModifier>
</CQLQuery>
- Target
The Target XML element specifies the class that the query's result objects will be an instance of. It may contain elements that constrain which instances of the target class are included in the result.
A Target XML element has a required attribute named name. The value of the Target element's name attribute is the name of the class whose instances the query will return. We refer to the class named by the name attribute as the query's target class. The target class must exactly match a class named in the data service's domain model.
A Target element may contain either an Attribute, Association or Group element to constrain which instances of the target class are to be included in the result.<Target name="foo.bar"/>
or
<Target name="foo.bar">
<Attribute …/>
</Target>or
<Target name="foo.bar">
<Association …/>
…
</Association>
</Target>or
<Target name="foo.bar">
<Group …/>
…
</Group>
</Target> - QueryModifier
A QueryModifier is an XML element that specifies how objects will be included in the query's results. A QueryModifier element has a required attribute named countOnly. The value of the countOnly attribute must be either true or false. If the value of the countOnly attribute is true then the result of the query will contain just the number of objects included in the query rather and not contain any of the actual result objects.
If the value of a QueryModifier element's countOnly attribute is false, then the query's results will contain instances of the target class that match the query. Which of the class's attributes are included in the results depends in what AttributeNames elements, if any, that the QueryModifier contains.
A QueryModifier element may contain zero or more AttributeNames elements. If the QueryModifier element contains zero AttributNames elements, then the returned objects will contain just their id attribute. Every class in a data service's domain model should have an id attribute whose value uniquely identifies an instance of the class within the data service.
An AttributeNames element contains just the name of a single attribute of the target class. An AttributeNames element has no attributes or child elements. If a QueryModifier element contains any AttributeNames elements, then the query results will include each of the attributes named by the AttributeNames elements.
A QueryModifier element may also contain zero or more DistinctAttribute elements. A DistinctAttribute element contains just the name of a single attribute of the target class. A DistinctAttribute element has no attributes or child elements.
If a QueryModifier element contains DistinctAttribute elements, then the results of the query will only include instances of the target class whose attributes named by the DistinctAttribute elements have a unique combination of values. This means that some instances of the target class will be excluded from the query results. Which instances of the target class are excluded is left up to the data service.
The inclusion of a QueryModifier element in a query is optional. If a query does not contain a QueryModifier element, then the results of the query will contain the instances of the target class that match the query. The instances of the target class will contain just their id attribute.
Note that CQL does not know or care about the type of value (number, string, date, etc.) that a class's attributes may have.
<QueryModifier countOnly="true" />
or
<QueryModifier countOnly="true">
<AttributeNames>foo</AttributeNames>
<AttributeNames>bar</AttributeNames>
<AttributeNames>zip</AttributeNames>
⋮
<DistinctAttribute>foo</DistinctAttribute>
<DistinctAttribute>bar</DistinctAttribute>
</QueryModifier>
- Association
An Association XML element can appear as a child element of a Target, Association or Group XML element. Target, Association and Group elements have a target class. If a Target, Association or Group element has any child Association elements, the presence of the Association child elements places a constraint on which instances of the enclosing element's target class will be considered by the query. Instances of the enclosing XML element's target class are considered for a query only if they are associated with an instance of the child Association element's target class through the association identified by the child Association element.
Association XML elements have two attributes that are named roleName and name. The value of the roleName attribute must be the name of an association in the data service's data model that can be navigated away from the enclosing XML element's target class. The value of the name attribute must be the name of the class that the association can be used to navigate to. This class is considered to be the target class of the Association element.
The CQL schema specifies that the roleName attribute is optional and that the name attribute is required. However, it good practice to always specify both attributes. The value of just one of the attributes may be insufficient to uniquely identify an association in the data service's data model. Also, some data services treat the roleName attribute as required.
Only those instances of the Association XML element's target class that are connected to instances of the enclosing XML element's target class though the association identified by the Association element will be considered in satisfying the Association element's constraint.
An Association XML element can have a child element that is an Association, Attribute or Group element. If an Association element does have a child element, then the child element is used to further constrain which instances of the Association element's target class will be considered by the query.<Association
roleName="owner"
name="org.foo.id"/>or
<Association
roleName="owner"
name="org.foo.id">
<Association …>
…
</Association>
</Assocation>or
<Association
roleName="owner"
name="org.foo.id">
<Attribute … />
</Assocation>or
<Association
roleName="owner"
name="org.foo.id">
<Group …>
…
</Group>
</Assocation> - Attribute
An Attribute XML element can appear as a child element of a Target, Association or Group XML element. Target, Association and Group elements have a target class. If a Target, Association or Group element has any child Attribute elements, the presence of the Attribute child elements places a constraint on which instances of the enclosing element's target class will be considered by the query. Instances of the enclosing XML element's target class are considered for a query only if their value for the attribute named by the Attribute element passes the test specified by the Attribute element.
An Attribute element has three XML attributes, which define its constraint. The attribute name is required. Its value is the name of the attribute of the enclosing XML element's target class to be restricted.
The attribute value is required. The value of the XML value attribute is a value to be compared to the named value in instances of the enclosing element's target class.
The attribute predicate describes what type of test to be performed on the value of the named attribute in instances of the enclosing element's target class. Allowable values for this include: EQUAL_TO, NOT_EQUAL_TO, LIKE, LESS_THAN, LESS_THAN_EQUAL_TO, GREATER_THAN and GREATER_THAN_EQUAL_TO. These tests all involve a comparison between the value of an instance attribute and the value of the value XML attribute. The exact nature of the comparison that corresponds to each value of predicate is not defined by CQL; it is determined by the particular data service.
The two other permitted values for the predicate attribute are IS_NOT_NULL and IS_NULL. These values imply a test only for the presence or absence, respectively, of the instance attribute's value. They do not constrain the value of the instance attribute. The value of the value XML attribute is ignored when the value of the predicate attribute is IS_NULL or IS_NOT_NULL.
<Attribute name="size" predicate="EQUAL_TO" value="3">
Always specify a value for predicate
The CQL schema specifies that the predicate attribute is optional with a default value of EQUAL_TO. However, some data services treat the predicate attribute as required. It is recommended that the value of the predicate attribute is always specified.
- Group
Group XML elements combine two or more constrains under a single Target or {Association}} element. A Group XML element contains two or more Attribute, Association or Group elements.
Group elements have an attribute named logicOperator, whose value may be either AND or OR. The value of the logicOperator attribute determines how the constraints of the Group element's child elements are combined into a single constraint for the Group element's enclosing element.
If the value of the logicOperator attribute is AND, then the constraints of the Group element's child elements are combined into a single constraint that is satisfied only if the constraints of all of the child elements are satisfied.
If the value of the logicOperator attribute is OR, then the constraints of the Group element's child elements are combined into a single constraint that is satisfied only if the constraints of any of the child elements are satisfied.
Combining AND and OR
Sometimes you may want to combine constraints in ways that involves both AND and OR logic. This can be accomplished by nesting Group elements inside of each other, with the nested Group elements specifying a different value for its logicOperator attribute the the enclosing Group element.
Overview of the Process of Constructing a CQL Query
To construct a CQL query, first identify the data type that you would like to retrieve. This data type (the class from the UML model) becomes the '''Target''' in your CQL query. Next, identify the criteria that you would like to use to retrieve only a subset of all available data. For example, if you specify the "Gene" class as the Target, you will retrieve all Gene objects in the database, which probably is not what you want. To limit the subset of Gene objects that you retrieve, you must identify "filtering" criteria.
To specify "filtering criteria", use the Group, Attribute and Association CQL elements. For example, to retrieve only Gene objects where the Gene name matches a given pattern, you would specify an attribute filter on the Gene class (the "name" attribute, for example).
If the attributes that you would like to filter upon are in another class, specify an association from the Target to a (associated) class. At that point, you can specify Attributes in the associated class to filter on.
CQL Examples
Several example CQL queries are available on this wiki that demonstrate how to create a few common types of CQL queries.
Creating a CQL Query In Code
Data services in caGrid use CQL to compose queries. A query can be produced programmatically, building up parts of the query using the supplied object model:
Programmatic query building
The data services project in caGrid provides a Java object model for CQL which can be used to build queries.
gov.nih.nci.cagrid.cqlquery.CQLQuery query =
new gov.nih.nci.cagrid.cqlquery.CQLQuery();
gov.nih.nci.cagrid.cqlquery.Object target =
new gov.nih.nci.cagrid.cqlquery.Object();
target.setName(gov.nih.nci.cabio.domain.Gene.class.getName());
gov.nih.nci.cagrid.cqlquery.Attribute symbolAttribute =
new gov.nih.nci.cagrid.cqlquery.Attribute(
"symbol",
gov.nih.nci.cagrid.cqlquery.Predicate.LIKE,
"IL%");
target.setAttribute(symbolAttribute);
query.setTarget(target);
Load CQL query from a Reader
Alternatively, a CQL query can be loaded from Reader
. The code examples below illustrate loading from a string of XML text or an XML file on disk and deserialized into the object model:
// from a string
CQLQuery query2 = (CQLQuery) gov.nih.nci.cagrid.common.Utils.deserializeObject(
new StringReader("<CQLQuery ... />"), CQLQuery.class);
// from a file
CQLQuery query3 = (CQLQuery) gov.nih.nci.cagrid.common.Utils.deserializeObject(
new FileReader(cqlFile), CQLQuery.class);
Write CQL query out to a file
The following code illustrates how to write a CQL query out to a file. The Utils.serializeObject method takes any Writer
as input.
// obtain a CQL query instance
CQLQuery someQuery = ...;
// open a writer to send XML to
StringWriter writer = new StringWriter();
// serialize
Utils.serializeObject(someQuery, DataServiceConstants.CQL_QUERY_QNAME, writer);
// print XML to the console
System.out.println(writer.getBuffer().toString());
Schemas
The CQL schemas are available on this wiki.
Caveats
- CQL does not permit querying for attributes with values that are XML schema complex types.
- Only values that can be represented as XML schema simple types are allowed.
- CQL Attribute Results cannot contain attribute values which are XML schema complex types.
- Only values that can be represented as XML schema simple types are allowed.
- CQL does not provide a facility for returning object instances other than the targeted data type.
- This includes subclasses of the targeted data type. These cannot be returned because their XML representation will differ from that of the requested object, which violates the expected results schema.
- CQL cannot return populated associations on instances of the targeted data type.
- This has some implications when dealing with uni-directional associations. For example:
Assume two classes: Person -name Address -street And there is a uni-directional association between Person and Address (Person->Address) With CQL you can say: "Give me the name of the Person at '123 Main St'" You can just write the CQL with target Person, and criteria of Association to Address where Address.street='123 Main St' But you can't say: "Give me the Address of 'Scott'" Because Address needs to be the target, and there is no way to express constraints on the Person (as there is no association). However, if the association is bi-directional, you CAN do both. To do the second query, you just would express the query as target Address, and criteria of Association to Person where Person.name='Scott'. You basically need to "invert" the criteria.
- This has some implications when dealing with uni-directional associations. For example:
CQL Query Processors
| This page contains information pertaining to CQL 2 query processors used by caGrid 1.4 data services. CQL 2 query processors can handle CQL 1 queries at runtime through conversion by the caGrid Data Services infrastructure. For information specific to CQL 1 query processors, please refer to the caGrid 1.3 documentation. |
The CQL 2 Query Processor is a pluggable implementation which handles the details of processing CQL 2 against some backend data source and produces a CQLQueryResults instance. The particular implementation used is determined by a value in the service's deployment properties, and an instance of the processor is loaded at runtime via reflection. The query processor may optionally supply a set of properties via the getRequiredParameters(). These properties may be configured prior to deployment of the service, and are passed into the query processor when it is first instantiated via the initialize() method. Additionally, the query processor may implement the method getParametersFromEtc(). This method returns a java.collections.Set<String> containing a subset of keys from the getRequiredParameters() method whose values should be returned as file system paths relative to the etc directory of the deployed grid service.
When a query is issued to the data service, the query will be passed along to the CQL 2 Query Processor instance's processQuery() method. This method may throw both a QueryProcessingException in the case of an error in handling the query and a MalformedQueryException in cases where the query was found to be invalid for any reason.
Implementation
See Also: How-to Implement CQL 2 Query Processors
All query processor implementations are required to extend the abstract base class gov.nih.nci.cagrid.data.cql2.CQL2QueryProcessor. This base class declares several methods which are meant to be overridden, however the only method a query processor is required to implement is the processQuery() method. This method takes a CQL 2 query and returns a CQLQueryResults instance. This method is declared abstract in the base class, which enforces this implementation requirement. Generally, this method should be able to translate CQL 2 into whatever native query language is required by the back end data resource, and translate the result set into a CQLQueryResults instance.
The base class also provides the processQueryAndIterate() method, which takes CQL 2 and returns an Iterator over CQLResult instances. A default implementation of this method is provided, however developers may wish to override it to obtain better performance or interact more efficiently with a lazy-loaded result set.
CQL Query Processors are designed to be configurable at runtime by a set of properties. These properties are modifiable via the data service extension to the Introduce toolkit, or manually by editing a configuration file once a service has been built. The base CQL 2 query processor class provides a method to retrieve required configuration parameters and their associated default values:
- public Properties getRequiredParameters()
- This method is provided by default and returns an empty java.util.Properties instance. CQL implementers who require properties to be configured should override this method to return a populated Properties instance. If a property is optional, its value should be set to an empty string. All property keys must be valid Java identifiers meaning that there cannot be any spaces or punctuation in the key.
Additionally, a method is provided to specify a subset of those properties are meant to be file locations:
- getParametersFromEtc()
- This method returns a java.util.Set<String> containing a subset of keys from the getRequiredParameters() method whose values should be returned as file system paths relative to the etc directory of the deployed grid service.
The query processor base class has two protected methods which provide access to any user configured parameters and an input stream to the server side wsdd configuration file. The method getConfiguredParameters() returns a java.util.Properties instance containing all the keys defined in the properties returned by getRequiredParameters(), but with either the default or a developer configured value associated with each. The method getConfiguredWsddStream() returns an InputStream instance which will read in the contents of the server side wsdd configuration file. The call to the query processor's initialize method, and in turn the population of these values, occurs when the data service is first instantiated, typically when the container is started. Calls to these methods before this time will return null. For this reason, the constructor of the CQL 2 Query Processor implementation must be fairly simple, and any initialization should take place in the overridable initialize() method.
/**
* The primary query processing method.
*
* @param query
* @return
* @throws QueryProcessingException
* Thrown when an error occurs while handling the query
* @throws MalformedQueryException
* Thrown when the query is found to be defective
*/
public abstract CQLQueryResults processQuery(CQLQuery query) throws
QueryProcessingException, MalformedQueryException;
The only method which is absolutely required to be implemented by CQL 2 query processors is the processQuery() method. This is the method which executes the CQL 2 query against its data source and generates an appropriate set of results. There are utilities (discussed in the CQL 2 documentation) to make generation of this result set a relatively simple process. At the time this method is called by the data service infrastructure, the return values of getConfiguredParameters() and getConfiguredWsddStream() will be non-null.
The processQuery() method throws both a MalformedQueryException and a QueryProcessingException. Malformed query exceptions should be thrown under conditions where the query is somehow incorrect syntactically, or uses features of the CQL 2 language which are not yet supported in the query processor implementation. If query syntax validation is enabled in the data service infrastructure, then it may be assumed that all queries reaching the processQuery() method are at least well formed CQL 2. Query processing exceptions should be thrown when some error occurs which prevents successful resolution of the query request. These conditions may include database errors, file system problems, or misconfiguration of properties.
Data Service Styles
The caGrid Data Services Infrastructure supports varying and pluggable service styles. Service styles are intended to allow service developers to repeatedly create data services which require a specific set of functionality to be added or have a well defined configuration and setup process. Styles can add logical functionality to the data service creation and modification processes by implementing specific interfaces which are invoked by the data services extension as it runs. Styles may also add graphical functionality to the service development process by adding a set of wizard panels to the creation process, and optionally including a tab in the service modification UI to further manage configuration of the style. Examples of data service styles include the caCORE SDK backend data source support features. The pluggable nature of service styles allows the main data services infrastructure to remain decoupled from the implementation details of caGrid-provided (or third party) query processors, and ensures that future development and support for new data sources will not always necessitate changes to the core codebase.
Service Styles Architecture
![]() |
| Layout of the Styles Directory Layout |
Functionality Extended by Styles
Data Service styles may add functionality to any or all of the following areas of service development with the Introduce toolkit:
- Creation Wizard
- The service style may supply a list of wizard panels to be displayed and chained together in a wizard-like fashion to break the setup process for the service style into a series of steps. These panels will be shown in a wizard dialog when a service style is selected at service creation time.
- Post-creation processing
- Just as Introduce extensions may add functionality to the service creation process, data service styles may add processing capabilities to this step.
- Modification User Interface
- The style may supply a graphical panel which will be added to the data service tab in the Introduce service modification viewer. This tab can be used to configure any style-specific options in the service.
- Post-code generation processing
- The style may add functionality to the code generation process of service modification. This processing will be invoked each time the service is modified and saved in Introduce.
How To Create Data Service Styles
Creating a data service style is a straightforward process, similar to writing an extension to the Introduce toolkit. New styles may be created by building up a few components and placing them in the appropriate subdirectories of the Introduce toolkit (as described here).
Components
The caGrid Data Service styles infrastructure requires style implementations to conform to a specific format, and requires that the classes which compose the style's implementation inherit from certain classes.
Style Description Document
A single XML document describes the style to the data services infrastructure. This document must be named style.xml, and placed in a unique directory under the <introduce>/extensions/data/styles directory. This style description document must conform to the schema provided with the data services infrastructure with the namespace http://gov.nih.nci.cagrid.data/Style
, which can be found at the end of this guide.
The following is an example of the style description document:
<DataServiceStyle xmlns="http://gov.nih.nci.cagrid.data/Style" name="caCORE SDK v 3.2(.1)" version="1.1"> <CompatibleCaGridVersions> <Version>1.1</Version> </CompatibleCaGridVersions> <StyleDescription>Configures the data service to utilize a data source generated by the caCORE SDK, versions 3.2 and 3.2.1</StyleDescription> <CreationWizardPanels> <CreationWizardPanel classname="gov.nih.nci.cagrid.data.style.cacore32.wizard.SDK32InitializationPanel"/> <CreationWizardPanel classname="gov.nih.nci.cagrid.data.style.cacore32.wizard.SDKClientSelectionPanel"/> <CreationWizardPanel classname="gov.nih.nci.cagrid.data.style.cacore32.wizard.AppserviceConfigPanel"/> <CreationWizardPanel classname="gov.nih.nci.cagrid.data.style.sdkstyle.wizard.DomainModelPanel"/> <CreationWizardPanel classname="gov.nih.nci.cagrid.data.style.sdkstyle.wizard.SchemaTypesPanel"/> </CreationWizardPanls> <CodegenHelpers postCodegenClassname="gov.nih.nci.cagrid.data.style.sdkstyle.helpers.PostCodegenHelper"/> <ModificationUiPanel classname="gov.nih.nci.cagrid.data.style.cacore32.modification.CaCoreVersionPanel"/> </DataServiceStyle>
Each part of this document influences the behavior or appearance of the style as the data service infrastructure executes it.
Name and Version
The root element of the style document attributes which define the name of this style, along with the version of the style. The name is displayed to the service developer at service creation time, allowing selection of a style. The name and version uniquely identify a style to the data service extension framework at runtime.
Compatible Versions
The style document allows for defining which versions of the caGrid Introduce toolkit and data service extension the style is compatible with. The document may define multiple <Version> elements indicating compatibility with multiple versions.
Style Description
The document allows for a brief description of the style to accompany the style itself. This information is displayed at data service creation time when the user is given a chance to select a style to use with their data service.
Creation Wizard Panels
This optional element defines a sequence of panels which will be loaded as part of the pre code generation process of creating a new caGrid Data Service. The panels are displayed in the order in which they are defined here, and can be used to configure aspects of the service style, or customize the underlying data service extension.
Each wizard panel's Java class must extend from the base class gov.nih.nci.cagrid.data.ui.wizard.AbstractWizardPanel. This class is essentially a JPanel with accessor methods for the Introduce service model and the data service extension data. The class also provides access to wizard functionality, such as enabling and disabling navigation buttons, and indicating that the wizard has been completed. Additionally, the base class has three abstract methods which must be implemented:
- update()
- This method is called by the wizard when the panel is to be displayed. This provides a callback to update the UI and reflect changes to the model which may impact the appearance of the wizard panel.
- movingNext()
- This method is new for caGrid 1.2
- This method is called by the wizard itself when the user clicks the 'next' or 'finish' button to move to the next wizard panel or finish the wizard. This method gives the panel a chance to synchronize its state with that of the service model (ie. copying schemas and libraries, storing service properties).
- getPanelTitle() -> String
- This method should return the title you wish to be displayed by the wizard when the panel is visible on the screen.
- getPanelShortName() -> String
- This method should return a very short name to be displayed in the navigation buttons of the wizard. It should generally be one or two words long.
Creation Process Helpers
The data service creation process can be extended by the service style. The post-creation process helper is defined by the CreationHelper element. This element has an attribute called postCreationClassname, which defines the class name of the post-creation processor class. This class must implement the interface gov.nih.nci.cagrid.data.style.StyleCreationPostProcessor.
Code Generation Process Helpers
The data service code generation process can be extended by the service style. The pre code generation process, defined by the preCodegenClassname attribute, is executed after the data service pre code generation options have been completed, but before any other extensions have run. The post code generation process, defined by the postCodegenClassname is executed similarly.
The pre-codegen class must implement the interface gov.nih.nci.cagrid.data.style.StyleCodegenPreProcessor, and the post-codegen class must implement the interface gov.nih.nci.cagrid.data.style.StyleCodegenPostProcessor.
Service Modification Panel
The style can optionally include a panel to be loaded into the data service modification UI. This panel can provide information on configuration options specific to the style (as in the case of the caCORE SDK styles), manage configuration, or present any other information the style developer may choose.
This class must extend from the base class gov.nih.nci.cagrid.data.ui.DataServiceModificationSubPanel. This class is essentially a JPanel with additional methods for accessing the underlying Introduce service model and the data service specific extension data.
Style Library Directory
Each style must provide any jar files it depends on for Java classes and resources in a directory named lib within the style directory itself. At runtime, classes referenced from the style document are loaded from the jars provided here. The classes contained in these jars may safely depend on other caGrid and Globus libraries, as the runtime classpath of the Introduce toolkit is appended to the library directory's contents.
Schema
http://gov.nih.nci.cagrid.data/Style![]()
The style description document.
<xsd:schema xmlns:tns="http://gov.nih.nci.cagrid.data/Style" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://gov.nih.nci.cagrid.data/Style" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:element name="DataServiceStyle" type="tns:DataServiceStyle"/> <xsd:complexType name="DataServiceStyle"> <xsd:sequence> <xsd:element ref="tns:CompatibleCaGridVersions"/> <xsd:element name="StyleDescription" type="xsd:string" minOccurs="0"/> <xsd:element name="CreationWizardPanels" minOccurs="0"> <xsd:complexType> <xsd:sequence> <xsd:element ref="tns:CreationWizardPanel" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element ref="tns:ModificationUiPanel" minOccurs="0"/> <xsd:element ref="tns:CodegenHelpers" minOccurs="0"/> <xsd:element ref="tns:CreationHelper" minOccurs="0"/> <xsd:element ref="tns:VersionUpgrade" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="version" type="xsd:string" use="required"/> </xsd:complexType> <xsd:element name="CompatibleCaGridVersions" type="tns:CompatibleCaGridVersions"/> <xsd:complexType name="CompatibleCaGridVersions"> <xsd:sequence> <xsd:element name="Version" maxOccurs="unbounded"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"/> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> <xsd:element name="CreationWizardPanel" type="tns:CreationWizardPanel"/> <xsd:complexType name="CreationWizardPanel"> <xsd:annotation> <xsd:documentation>Must extend from gov.nih.nci.cagrid.data.ui.wizard.AbstractWizardPanel</xsd:documentation> </xsd:annotation> <xsd:attribute name="classname" type="xsd:string" use="required"/> </xsd:complexType> <xsd:element name="ModificationUiPanel" type="tns:ModificationUiPanel"/> <xsd:complexType name="ModificationUiPanel"> <xsd:annotation> <xsd:documentation>Must extend from gov.nih.nci.cagrid.data.ui.DataServiceModificationSubPanel</xsd:documentation> </xsd:annotation> <xsd:attribute name="classname" type="xsd:string" use="required"/> </xsd:complexType> <xsd:element name="VersionUpgrade" type="tns:VersionUpgrade"/> <xsd:complexType name="VersionUpgrade"> <xsd:attribute name="fromVersion" type="xsd:string" use="required"/> <xsd:attribute name="toVersion" type="xsd:string" use="required"/> <xsd:attribute name="classname" type="xsd:string" use="required"/> </xsd:complexType> <xsd:element name="CodegenHelpers" type="tns:CodegenHelpers"/> <xsd:complexType name="CodegenHelpers"> <xsd:annotation> <xsd:documentation>Pre codegen must implement Must implement interface gov.nih.nci.cagrid.data.style.StyleCodegenPreProcessor, post codegen must implement Must implement interface gov.nih.nci.cagrid.data.style.StyleCodegenPostProcessor</xsd:documentation> </xsd:annotation> <xsd:attribute name="preCodegenClassname" type="xsd:string" use="optional"/> <xsd:attribute name="postCodegenClassname" type="xsd:string" use="optional"/> </xsd:complexType> <xsd:element name="CreationHelper" type="tns:CreationHelper"/> <xsd:complexType name="CreationHelper"> <xsd:annotation> <xsd:documentation>Must implement interface gov.nih.nci.cagrid.data.style.StyleCreationPostProcessor</xsd:documentation> </xsd:annotation> <xsd:attribute name="postCreationClassname" type="xsd:string" use="required"/> </xsd:complexType> </xsd:schema>













