This commit is contained in:
Lucio Lelii 2009-08-07 10:52:03 +00:00
parent c3981f7ba8
commit f1124f5c54
14 changed files with 691 additions and 0 deletions

View File

@ -402,6 +402,7 @@ etics.build: (optional) Set to 'true', it indicates that build structures a
<copy todir="${build.class.dir}"> <copy todir="${build.class.dir}">
<fileset dir="${source.dir}"> <fileset dir="${source.dir}">
<include name="org/**/*.xsl"/> <include name="org/**/*.xsl"/>
<include name="org/**/*.xsd"/>
</fileset> </fileset>
</copy> </copy>
<jar jarfile="${build.lib.dir}/${jarfile}" basedir="${build.class.dir}"> <jar jarfile="${build.lib.dir}/${jarfile}" basedir="${build.class.dir}">

View File

@ -0,0 +1,19 @@
package org.gcube.vremanagement.vremodeler;
import java.util.ArrayList;
import java.util.List;
import org.gcube.vremanagement.vremodeler.impl.resources.MainFunctionality;
public class Body {
private List<MainFunctionality> mainFunctionalities= new ArrayList<MainFunctionality>();
public List<MainFunctionality> getMainFunctionalities() {
return mainFunctionalities;
}
public void setMainFunctionalities(List<MainFunctionality> mainFunctionalities) {
this.mainFunctionalities = mainFunctionalities;
}
}

View File

@ -59,6 +59,10 @@ public class DBInterface {
} }
public static Connection getConnection(){
return conn;
}
/** /**
* *
* @param query * @param query

View File

@ -4,7 +4,9 @@ import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
import java.net.URI; import java.net.URI;
import java.rmi.RemoteException; import java.rmi.RemoteException;
import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -22,10 +24,12 @@ import org.apache.axis.components.uuid.UUIDGenFactory;
import org.apache.axis.message.addressing.EndpointReferenceType; import org.apache.axis.message.addressing.EndpointReferenceType;
import org.gcube.common.core.contexts.GHNContext; import org.gcube.common.core.contexts.GHNContext;
import org.gcube.common.core.faults.GCUBEFault; import org.gcube.common.core.faults.GCUBEFault;
import org.gcube.common.core.informationsystem.client.AtomicCondition;
import org.gcube.common.core.informationsystem.client.ISClient; import org.gcube.common.core.informationsystem.client.ISClient;
import org.gcube.common.core.informationsystem.client.queries.GCUBECSQuery; import org.gcube.common.core.informationsystem.client.queries.GCUBECSQuery;
import org.gcube.common.core.informationsystem.client.queries.GCUBECollectionQuery; import org.gcube.common.core.informationsystem.client.queries.GCUBECollectionQuery;
import org.gcube.common.core.informationsystem.client.queries.GCUBEGHNQuery; import org.gcube.common.core.informationsystem.client.queries.GCUBEGHNQuery;
import org.gcube.common.core.informationsystem.client.queries.GCUBEGenericQuery;
import org.gcube.common.core.informationsystem.client.queries.GCUBEGenericResourceQuery; import org.gcube.common.core.informationsystem.client.queries.GCUBEGenericResourceQuery;
import org.gcube.common.core.informationsystem.client.queries.GCUBEMCollectionQuery; import org.gcube.common.core.informationsystem.client.queries.GCUBEMCollectionQuery;
import org.gcube.common.core.informationsystem.client.queries.GCUBERIQuery; import org.gcube.common.core.informationsystem.client.queries.GCUBERIQuery;
@ -41,6 +45,10 @@ import org.gcube.common.core.scope.GCUBEScope;
import org.gcube.common.core.utils.handlers.GCUBEServiceClientImpl; import org.gcube.common.core.utils.handlers.GCUBEServiceClientImpl;
import org.gcube.common.core.utils.logging.GCUBELog; import org.gcube.common.core.utils.logging.GCUBELog;
import org.gcube.vremanagement.vremodeler.impl.ServiceContext; import org.gcube.vremanagement.vremodeler.impl.ServiceContext;
import org.gcube.vremanagement.vremodeler.impl.resources.Functionality;
import org.gcube.vremanagement.vremodeler.impl.resources.MainFunctionality;
import org.gcube.vremanagement.vremodeler.impl.resources.Service;
import org.gcube.vremanagement.vremodeler.impl.resources.kxml.KGCUBEGenericFunctionalityResource;
import org.gcube.vremanagement.vremodeler.impl.util.MBrokerServiceHandler; import org.gcube.vremanagement.vremodeler.impl.util.MBrokerServiceHandler;
import org.gcube.vremanagement.vremodeler.impl.util.MFRelationDerivate; import org.gcube.vremanagement.vremodeler.impl.util.MFRelationDerivate;
import org.gcube.vremanagement.vremodeler.impl.util.MFRelationNative; import org.gcube.vremanagement.vremodeler.impl.util.MFRelationNative;
@ -81,6 +89,8 @@ public class IStoDBUtil {
logger.debug("initialization: GHN"); logger.debug("initialization: GHN");
insertNeededResources(scope); insertNeededResources(scope);
logger.debug("initialization: Needed Resources"); logger.debug("initialization: Needed Resources");
functionalitiesRecovery(scope);
logger.debug("initialization: Functionalities");
logger.info("Database Initialized!!"); logger.info("Database Initialized!!");
} }
@ -105,6 +115,9 @@ public class IStoDBUtil {
DBInterface.deleteAll("ghnrelatedri"); DBInterface.deleteAll("ghnrelatedri");
DBInterface.deleteAll("cs"); DBInterface.deleteAll("cs");
DBInterface.deleteAll("NEEDEDRESOURCES"); DBInterface.deleteAll("NEEDEDRESOURCES");
DBInterface.deleteAll("PORTLETRELTOFUNCT");
DBInterface.deleteAll("SERVICES");
DBInterface.deleteAll("FUNCTIONALITY");
}catch (SQLException e){ }catch (SQLException e){
logger.error("error cleaning sqlDB",e); logger.error("error cleaning sqlDB",e);
throw new GCUBEFault(e); } throw new GCUBEFault(e); }
@ -505,4 +518,62 @@ public class IStoDBUtil {
return sr; return sr;
} }
private static void functionalitiesRecovery(GCUBEScope scope) throws GCUBEFault{
KGCUBEGenericFunctionalityResource resource= new KGCUBEGenericFunctionalityResource();
try{
if (queryClient==null) queryClient= GHNContext.getImplementation(ISClient.class);
GCUBEGenericResourceQuery query= queryClient.getQuery(GCUBEGenericResourceQuery.class);
query.addAtomicConditions(new AtomicCondition("/Profile/Name","FuctionalitiesResource"), new AtomicCondition("/Profile/SecondaryType","VREModelerResource"));
GCUBEGenericQuery genericQuery= queryClient.getQuery(GCUBEGenericQuery.class);
genericQuery.setExpression(query.getExpression());
resource.load(new StringReader(queryClient.execute(genericQuery, scope).get(0).toString()));
}catch(Exception e ){logger.error("Error queryng IS"); throw new GCUBEFault(e); }
try{
DBInterface.connect();
PreparedStatement psFunctionality=DBInterface.getConnection().prepareStatement("INSERT INTO FUNCTIONALITY VALUES(?,?,?,?,?)");
PreparedStatement psServices=DBInterface.getConnection().prepareStatement("INSERT INTO SERVICES VALUES(?,?,?,?)");
PreparedStatement psPortlets=DBInterface.getConnection().prepareStatement("INSERT INTO PORTLETRELTOFUNCT VALUES(?,?)");
int id=0;
for (MainFunctionality mainFunctionality: resource.getBody().getMainFunctionalities()){
psFunctionality.setInt(1, id);
psFunctionality.setString(2, mainFunctionality.getName());
psFunctionality.setString(3, mainFunctionality.getDescription());
psFunctionality.setNull(4, Types.INTEGER);
psFunctionality.setInt(5, 0);
psFunctionality.execute();
id++;
for (Functionality functionality: mainFunctionality.getFunctionalities()){
psFunctionality.setInt(1, id);
psFunctionality.setString(2, functionality.getName());
psFunctionality.setString(3, functionality.getDescription());
psFunctionality.setNull(4, Types.INTEGER);
psFunctionality.setInt(5, 0);
psFunctionality.execute();
for (Service service: functionality.getServices()){
psServices.setInt(1, id);
psServices.setString(2, service.getServiceName());
psServices.setString(3, service.getServiceClass());
psServices.setString(4, "1.00.00");
psServices.execute();
}
for (String portlet: functionality.getPortlets()){
psPortlets.setInt(1, id);
psPortlets.setString(2, portlet);
psPortlets.execute();
}
id++;
}
}
}catch(Exception e){
logger.error("error reading functionalities",e);
throw new GCUBEFault(e,"error reading functionalities");}
}
} }

View File

@ -0,0 +1,37 @@
package org.gcube.vremanagement.vremodeler.impl.resources;
import java.util.ArrayList;
import java.util.List;
public class Functionality {
private String description;
private String name;
private List<Service> services= new ArrayList<Service>();
private List<String> portlets= new ArrayList<String>();
public List<Service> getServices() {
return services;
}
public void setServices(List<Service> services) {
this.services = services;
}
public List<String> getPortlets() {
return portlets;
}
public void setPortlets(List<String> portlets) {
this.portlets = portlets;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,147 @@
package org.gcube.vremanagement.vremodeler.impl.resources;
import org.gcube.common.core.resources.GCUBEResource;
import org.gcube.vremanagement.vremodeler.Body;
public abstract class GCUBEGenericFunctionalityResource extends GCUBEResource{
private Body body;
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}
/**
* The type of the resource.
*/
public static final String TYPE="GenericResource";
//in the following, some of the most common used secondary types
/**
* Secondary type used for transformation programs
*/
public static final String SECONDARYTYPE_TP="TransformationProgram";
/**
* Secondary type used for VREs
*/
public static final String SECONDARYTYPE_VRE="VRE";
/**
* Secondary type used for VOs
*/
public static final String SECONDARYTYPE_VO="VO";
/**
* Secondary type used for INFRASTRUCTUREs
*/
public static final String SECONDARYTYPE_INFRASTRUCTURE="INFRASTRUCTURE";
/**
* Secondary type used for user profiles
*/
public static final String SECONDARYTYPE_USERPROFILE="UserProfile";
/**
* Secondary type used for IndexDefinition
*/
public static final String SECONDARYTYPE_INDEXDEFINITION="IndexDefinition";
/**
* Secondary type used for search configuration
*/
public static final String SECONDARYTYPE_SEARCHCONFIG="SearchConfiguration";
/**
* Secondary type used for portlet configuration
*/
public static final String SECONDARYTYPE_PORTLETCONFIG="PortletConfiguration";
/**
* Secondary type used for grid resources
*/
public static final String SECONDARYTYPE_GRIDRESOURCE="GridResource";
public GCUBEGenericFunctionalityResource() {
this.type = TYPE;
}
private String name;
private String description;
private String secondaryType;
/**
* Sets the sercondary type
* @return the secondaryType
*/
public String getSecondaryType() {
return secondaryType;
}
/**
* Gets the secondary type
* @param secondaryType the secondaryType to set
*/
public void setSecondaryType(String secondaryType) {
this.secondaryType = secondaryType;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
if (!super.equals(obj)) return false;
final GCUBEGenericFunctionalityResource other = (GCUBEGenericFunctionalityResource) obj;
if (body == null) {
if (other.body != null)
return false;
} else if (! body.equals(other.body))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (! name.equals(other.name))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (! description.equals(other.description))
return false;
return true;
}
}

View File

@ -0,0 +1,35 @@
package org.gcube.vremanagement.vremodeler.impl.resources;
import java.util.ArrayList;
import java.util.List;
public class MainFunctionality {
private List<Functionality> functionalities= new ArrayList<Functionality>();
private String description;
private String name;
public List<Functionality> getFunctionalities() {
return functionalities;
}
public void setFunctionalities(List<Functionality> functionalities) {
this.functionalities = functionalities;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,20 @@
package org.gcube.vremanagement.vremodeler.impl.resources;
public class Service {
private String serviceName;
private String serviceClass;
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getServiceClass() {
return serviceClass;
}
public void setServiceClass(String serviceClass) {
this.serviceClass = serviceClass;
}
}

View File

@ -0,0 +1,56 @@
package org.gcube.vremanagement.vremodeler.impl.resources.kxml;
import static org.gcube.common.resources.kxml.KGCUBEResource.NS;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Writer;
import java.text.SimpleDateFormat;
import org.gcube.common.core.resources.GCUBEGenericResource;
import org.gcube.common.core.resources.service.Dependency;
import org.gcube.common.core.resources.service.Dependency.Service;
import org.gcube.common.core.resources.service.Package.ScopeLevel;
import org.gcube.common.resources.kxml.GCUBEResourceImpl;
import org.gcube.common.resources.kxml.KGCUBEResource;
import org.gcube.common.resources.kxml.service.version.VersionSpecificationParser;
import org.gcube.vremanagement.vremodeler.Body;
import org.gcube.vremanagement.vremodeler.impl.resources.MainFunctionality;
import org.kxml2.io.KXmlParser;
import org.kxml2.io.KXmlSerializer;
public class KBody {
public static Body load(KXmlParser parser) throws Exception {
Body d = new Body();
loop: while (true) {
switch (parser.next()){
case KXmlParser.START_TAG :
if (parser.getName().equals("MainFunctionality")) d.getMainFunctionalities().add(KMainFunctionality.load(parser));
break;
case KXmlParser.END_TAG:
if (parser.getName().equals("Body")){
break loop;
}
break;
case KXmlParser.END_DOCUMENT :
throw new Exception("Parsing failed at Body");
}
}
return d;
}
public static void store(Body component, KXmlSerializer serializer) throws Exception {
if (component==null) return;
serializer.startTag(NS,"Body");
if (component.getMainFunctionalities().size()!=0){
serializer.startTag(NS,"MainFunctionalities");
for (MainFunctionality mainFunctionality: component.getMainFunctionalities()) KMainFunctionality.store(mainFunctionality,serializer);
serializer.endTag(NS,"MainFunctionalities");
}
serializer.endTag(NS,"Body");
}
}

View File

@ -0,0 +1,55 @@
package org.gcube.vremanagement.vremodeler.impl.resources.kxml;
import static org.gcube.common.resources.kxml.KGCUBEResource.NS;
import org.gcube.common.core.resources.service.Dependency;
import org.gcube.common.resources.kxml.service.KServiceDependency;
import org.gcube.common.resources.kxml.service.version.VersionSpecificationParser;
import org.gcube.common.resources.kxml.utils.KStringList;
import org.gcube.vremanagement.vremodeler.impl.resources.Functionality;
import org.gcube.vremanagement.vremodeler.impl.resources.Service;
import org.kxml2.io.KXmlParser;
import org.kxml2.io.KXmlSerializer;
public class KFunctionality {
public static Functionality load(KXmlParser parser) throws Exception {
Functionality d = new Functionality();
loop: while (true) {
switch (parser.next()){
case KXmlParser.START_TAG :
if (parser.getName().equals("Name")) d.setName(parser.nextText().trim());
if (parser.getName().equals("Description")) d.setDescription(parser.nextText().trim());
if (parser.getName().equals("Services")) d.getServices().add(KService.load(parser));
if (parser.getName().equals("Portlets")) d.setPortlets((KStringList.load("Portlets", parser)));
break;
case KXmlParser.END_TAG:
if (parser.getName().equals("Functionality")){
break loop;
}
break;
case KXmlParser.END_DOCUMENT :
throw new Exception("Parsing failed at Functionality");
}
}
return d;
}
public static void store(Functionality component, KXmlSerializer serializer) throws Exception {
if (component==null) return;
serializer.startTag(NS,"Functionality");
serializer.startTag(NS, "Name").text(component.getName()).endTag(NS, "Name");
serializer.startTag(NS, "Description").text(component.getDescription()).endTag(NS, "Description");
if (component.getServices().size()!=0) {
serializer.startTag(NS,"Services");
for (Service service: component.getServices()) KService.store(service,serializer);
serializer.endTag(NS,"Services");
}
if (component.getServices().size()!=0)
KStringList.store("Portlets", "Portlet", component.getPortlets(), serializer);
serializer.endTag(NS,"Functionality");
}
}

View File

@ -0,0 +1,70 @@
package org.gcube.vremanagement.vremodeler.impl.resources.kxml;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Writer;
import java.text.SimpleDateFormat;
import org.gcube.common.resources.kxml.GCUBEResourceImpl;
import org.gcube.common.resources.kxml.KGCUBEResource;
import org.gcube.vremanagement.vremodeler.impl.resources.GCUBEGenericFunctionalityResource;
import org.kxml2.io.KXmlParser;
import org.kxml2.io.KXmlSerializer;
import static org.gcube.common.resources.kxml.KGCUBEResource.NS;
public class KGCUBEGenericFunctionalityResource extends GCUBEGenericFunctionalityResource implements GCUBEResourceImpl{
static final SimpleDateFormat dateAndTime=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
public synchronized void load(Reader reader) throws Exception {
KGCUBEResource.load(this,reader);
}
public synchronized void store(Writer writer) throws Exception {
KGCUBEResource.store(this,writer);
}
public InputStream getSchemaResource() throws FileNotFoundException {
return KGCUBEGenericFunctionalityResource.class.getResourceAsStream("/org/gcube/vremanagement/vremodeler/impl/resources/schemas/genericFunctionality.xsd");
}
public void load(KXmlParser parser) throws Exception {
// the top-level implementation object is the only one we do not generate
// hence we need to erase its current state before parsiing.
// single-valued fields will be generated anew, but collection-valued fields
// must be manually cleared before new elements are added to them by parsing
loop: while (true) {
switch (parser.next()){
case KXmlParser.START_TAG :
if (parser.getName().equals("SecondaryType")) this.setSecondaryType(parser.nextText());
if (parser.getName().equals("Description")) this.setDescription(parser.nextText());
if (parser.getName().equals("Name")) this.setName(parser.nextText());
if (parser.getName().equals("Body")) this.setBody(KBody.load(parser));
break;
case KXmlParser.END_TAG:
if (parser.getName().equals("Profile")) break loop;
break;
case KXmlParser.END_DOCUMENT : throw new Exception("Parsing failed at Profile");
}
}
}
public void store(KXmlSerializer serializer) throws Exception {
//when storing we cannot assume that single-valued fields are already initialised
// (e.g. there might not have been a previous load).
serializer.startTag(NS,"Profile");
if (this.getSecondaryType()!=null) serializer.startTag(NS,"SecondaryType").text(this.getSecondaryType()).endTag(NS,"SecondaryType");
if (this.getName()!=null) serializer.startTag(NS,"Name").text(this.getName()).endTag(NS,"Name");
if (this.getDescription()!=null) serializer.startTag(NS,"Description").text(this.getDescription()).endTag(NS,"Description");
if (this.getBody()!= null) KBody.store(this.getBody(), serializer);
serializer.endTag(NS,"Profile");
}
}

View File

@ -0,0 +1,46 @@
package org.gcube.vremanagement.vremodeler.impl.resources.kxml;
import static org.gcube.common.resources.kxml.KGCUBEResource.NS;
import org.gcube.vremanagement.vremodeler.impl.resources.Functionality;
import org.gcube.vremanagement.vremodeler.impl.resources.MainFunctionality;
import org.kxml2.io.KXmlParser;
import org.kxml2.io.KXmlSerializer;
public class KMainFunctionality {
public static MainFunctionality load(KXmlParser parser) throws Exception {
MainFunctionality d = new MainFunctionality();
loop: while (true) {
switch (parser.next()){
case KXmlParser.START_TAG :
if (parser.getName().equals("Name")) d.setName(parser.nextText().trim());
if (parser.getName().equals("Description")) d.setDescription(parser.nextText().trim());
if (parser.getName().equals("Functionality")) d.getFunctionalities().add(KFunctionality.load(parser));
break;
case KXmlParser.END_TAG:
if (parser.getName().equals("MainFunctionality")){
break loop;
}
break;
case KXmlParser.END_DOCUMENT :
throw new Exception("Parsing failed at MainFunctionality");
}
}
return d;
}
public static void store(MainFunctionality component, KXmlSerializer serializer) throws Exception {
if (component==null) return;
serializer.startTag(NS,"MainFunctionality");
serializer.startTag(NS, "Name").text(component.getName()).endTag(NS, "Name");
serializer.startTag(NS, "Description").text(component.getDescription()).endTag(NS, "Description");
if (component.getFunctionalities().size()!=0){
serializer.startTag(NS,"Functionalities");
for (Functionality functionality: component.getFunctionalities()) KFunctionality.store(functionality,serializer);
serializer.endTag(NS,"Functionalities");
}
serializer.endTag(NS,"MainFunctionality");
}
}

View File

@ -0,0 +1,39 @@
package org.gcube.vremanagement.vremodeler.impl.resources.kxml;
import static org.gcube.common.resources.kxml.KGCUBEResource.NS;
import org.gcube.vremanagement.vremodeler.impl.resources.Service;
import org.kxml2.io.KXmlParser;
import org.kxml2.io.KXmlSerializer;
public class KService {
public static Service load(KXmlParser parser) throws Exception {
Service d = new Service();
loop: while (true) {
switch (parser.next()){
case KXmlParser.START_TAG :
if (parser.getName().equals("ServiceName")) d.setServiceName(parser.nextText().trim());
if (parser.getName().equals("ServiceClass")) d.setServiceClass(parser.nextText().trim());
break;
case KXmlParser.END_TAG:
if (parser.getName().equals("Service")){
break loop;
}
break;
case KXmlParser.END_DOCUMENT :
throw new Exception("Parsing failed at Service");
}
}
return d;
}
public static void store(Service component, KXmlSerializer serializer) throws Exception {
if (component==null) return;
serializer.startTag(NS,"Service");
serializer.startTag(NS, "ServiceName").text(component.getServiceName()).endTag(NS, "ServiceName");
serializer.startTag(NS, "ServiceClass").text(component.getServiceClass()).endTag(NS, "ServiceClass");
serializer.endTag(NS,"Service");
}
}

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:annotation>
<xs:documentation xml:lang="en">
XML Schema for GCUBE Generic Resource Version 1.4 Last modified: 29/05/2008 Contact: http://www.gcube-system.org
</xs:documentation>
</xs:annotation>
<xs:redefine schemaLocation="CommonTypeDefinitions.xsd">
<xs:complexType name="ProfileType">
<xs:complexContent>
<xs:restriction base="ProfileType">
<xs:sequence>
<xs:element name="SecondaryType" type="xs:string"/>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Description" type="xs:string"/>
<xs:element name="Body">
<xs:complexType>
<xs:sequence>
<xs:element name="MainFunctionalities" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="MainFunctionality" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Description" type="xs:string"/>
<xs:element name="Functionalities" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element ref="Functionality" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
<xs:element name="Functionality" >
<xs:complexType>
<xs:sequence>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Description" type="xs:string"/>
<xs:element name="Services" minOccurs="0" >
<xs:complexType>
<xs:sequence>
<xs:element ref="Service" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Portlets" minOccurs="0" >
<xs:complexType>
<xs:sequence>
<xs:element name="Portlet" type="xs:string" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Service">
<xs:complexType>
<xs:sequence>
<xs:element name="ServiceName" type="xs:string"/>
<xs:element name="ServiceClass" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--
<xs:element name="Portlet">
<xs:complexType>
<xs:sequence>
<xs:element name="PortletName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
-->
</xs:schema>