Index: src/main/java/org/codehaus/modello/plugin/xsd/XsdGenerator.java
===================================================================
--- src/main/java/org/codehaus/modello/plugin/xsd/XsdGenerator.java (r‚vision 607)
+++ src/main/java/org/codehaus/modello/plugin/xsd/XsdGenerator.java (copie de travail)
@@ -1,7 +1,7 @@
package org.codehaus.modello.plugin.xsd;
/*
- * Copyright (c) 2005, Codehaus.org
+ * Copyright (c) 2004, Codehaus.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@@ -29,6 +29,9 @@
import org.codehaus.modello.model.ModelField;
import org.codehaus.modello.plugin.AbstractModelloGenerator;
import org.codehaus.modello.plugin.model.ModelClassMetadata;
+import org.codehaus.modello.plugin.model.ModelFieldMetadata;
+import org.codehaus.modello.plugins.xml.XmlFieldMetadata;
+import org.codehaus.modello.plugins.xml.XmlModelMetadata;
import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
import org.codehaus.plexus.util.xml.XMLWriter;
@@ -93,9 +96,14 @@
w.startElement( "xs:schema" );
w.addAttribute( "xmlns:xs", "http://www.w3.org/2001/XMLSchema" );
w.addAttribute( "elementFormDefault", "qualified" );
+
+ XmlModelMetadata modelMetadata = (XmlModelMetadata) objectModel.getMetadata( XmlModelMetadata.ID );
+
+ String nameSpace = modelMetadata.getNameSpace() + "/" + getGeneratedVersion();
+
// TODO: make configurable
- w.addAttribute( "targetNamespace", "http://maven.apache.org/POM/4.0.0" );
- w.addAttribute( "xmlns", "http://maven.apache.org/POM/4.0.0" );
+ w.addAttribute( "targetNamespace", nameSpace );
+ w.addAttribute( "xmlns", nameSpace );
ModelClass root = objectModel.getClass( objectModel.getRoot( getGeneratedVersion() ), getGeneratedVersion() );
@@ -165,91 +173,165 @@
writeClassDocumentation( w, modelClass );
- w.startElement( "xs:all" );
+ List fields = getFieldsForClass( objectModel, modelClass );
- List fields = new ArrayList();
- while ( modelClass != null )
+ List attributeFields = getAttributeFieldsForClass( objectModel, modelClass );
+
+ fields.removeAll( attributeFields );
+
+ Set toWrite = new HashSet();
+
+ if ( fields.size() > 0 )
{
- fields.addAll( modelClass.getFields( getGeneratedVersion() ) );
- String superClass = modelClass.getSuperClass();
- if ( superClass != null )
+ /*
+ * If we have any flat association under this element, we have to go
+ * to an xs:sequence instead of an xs:all, since xs:all doesn't allow
+ * for many multiplicity elements.
+ */
+ if ( hasFlatAssociation( objectModel, fields ) )
{
- modelClass = objectModel.getClass( superClass, getGeneratedVersion() );
+ w.startElement( "xs:sequence" );
}
else
{
- modelClass = null;
+ w.startElement( "xs:all" );
}
- }
- Set toWrite = new HashSet();
- for ( Iterator j = fields.iterator(); j.hasNext(); )
- {
- ModelField field = (ModelField) j.next();
+ for ( Iterator j = fields.iterator(); j.hasNext(); )
+ {
+ ModelField field = (ModelField) j.next();
- w.startElement( "xs:element" );
- w.addAttribute( "name", field.getName() );
+ w.startElement( "xs:element" );
- // Usually, would only do this if the field is not "required", but due to inheritence, it may be present,
- // even if not here, so we need to let it slide
- w.addAttribute( "minOccurs", "0" );
+ // Usually, would only do this if the field is not "required", but
+ // due to inheritence, it may be present,
+ // even if not here, so we need to let it slide
+ w.addAttribute( "minOccurs", "0" );
- String xsdType = getXsdType( field.getType() );
- if ( xsdType != null )
- {
- w.addAttribute( "type", xsdType );
+ String xsdType = getXsdType( field.getType() );
- if ( field.getDefaultValue() != null )
+ String tagName = resolveTagName( field );
+
+ if ( field instanceof ModelAssociation )
{
- w.addAttribute( "default", field.getDefaultValue() );
- }
- writeFieldDocumentation( w, field );
- }
- else
- {
- if ( field instanceof ModelAssociation &&
- isClassInModel( ( (ModelAssociation) field ).getTo(), objectModel ) )
- {
- ModelAssociation association = (ModelAssociation) field;
- ModelClass fieldModelClass = objectModel.getClass( association.getTo(), getGeneratedVersion() );
+ ModelAssociation assoc = (ModelAssociation) field;
- toWrite.add( fieldModelClass );
- if ( "*".equals( association.getMultiplicity() ) )
+ boolean wrappedAssociation = isWrappedAssociation( objectModel, field );
+
+ if ( wrappedAssociation )
{
+ w.addAttribute( "name", uncapitalise( assoc.getName() ) );
+
writeFieldDocumentation( w, field );
- writeListElement( w, field, fieldModelClass.getName() );
+
+ ModelClass fieldModelClass = objectModel.getClass( assoc.getTo(), getGeneratedVersion() );
+
+ writeListElement( w, tagName, fieldModelClass.getName() );
+
+ toWrite.add( fieldModelClass );
}
else
{
- w.addAttribute( "type", fieldModelClass.getName() );
+ w.addAttribute( "name", tagName );
+
+ if ( isManyAssociation( objectModel, assoc ) )
+ {
+ w.addAttribute( "maxOccurs", "unbounded" );
+ }
+
+ if ( xsdType != null )
+ {
+ w.addAttribute( "type", xsdType );
+ }
+ else if ( isInnerAssociation( objectModel, assoc ) )
+ {
+ ModelClass fieldModelClass = objectModel.getClass( assoc.getTo(), getGeneratedVersion() );
+
+ w.addAttribute( "type", objectModel.getClass( assoc.getTo(), getGeneratedVersion() )
+ .getName() );
+
+ toWrite.add( fieldModelClass );
+ }
+
writeFieldDocumentation( w, field );
}
}
+
else
{
- if ( List.class.getName().equals( field.getType() ) )
+ w.addAttribute( "name", field.getName() );
+
+ if ( xsdType != null )
{
- writeFieldDocumentation( w, field );
- writeListElement( w, field, getXsdType( "String" ) );
+ w.addAttribute( "type", xsdType );
+
+ if ( field.getDefaultValue() != null )
+ {
+ w.addAttribute( "default", field.getDefaultValue() );
+ }
}
+
+ writeFieldDocumentation( w, field );
+
+ if ( xsdType != null )
+ {
+ }
+ // TODO Is list type really supported????
+ else if ( List.class.getName().equals( field.getType() ) )
+ {
+ writeListElement( w, tagName, getXsdType( "String" ) );
+ }
else if ( Properties.class.getName().equals( field.getType() ) || "DOM".equals( field.getType() ) )
{
- writeFieldDocumentation( w, field );
writePropertiesElement( w );
}
+ // TODO Where is support for the date format?
else
{
- throw new IllegalStateException(
- "Non-association field of a non-primitive type '" + field.getType() + "' for '" + field.getName() + "'" );
+ throw new IllegalStateException( "Non-association field of a non-primitive type '"
+ + field.getType() + "' for '" + field.getName() + "'" );
}
}
+
+ w.endElement();
}
w.endElement();
}
- w.endElement();
+ for ( Iterator j = attributeFields.iterator(); j.hasNext(); )
+ {
+ ModelField field = (ModelField) j.next();
+
+ w.startElement( "xs:attribute" );
+
+ String xsdType = getXsdType( field.getType() );
+
+ String tagName = resolveTagName( field );
+
+ w.addAttribute( "name", tagName );
+
+ if ( xsdType != null )
+ {
+ w.addAttribute( "type", xsdType );
+
+ if ( field.getDefaultValue() != null )
+ {
+ w.addAttribute( "default", field.getDefaultValue() );
+ }
+ }
+ else
+ {
+ throw new IllegalStateException( "Attribute field of a non-primitive type '" + field.getType()
+ + "' for '" + field.getName() + "'" );
+ }
+
+ writeFieldDocumentation( w, field );
+
+ w.endElement();
+ }
+
w.endElement();
for ( Iterator iter = toWrite.iterator(); iter.hasNext(); )
@@ -296,14 +378,14 @@
w.endElement();
}
- private void writeListElement( XMLWriter w, ModelField field, String type )
+ private void writeListElement( XMLWriter w, String tagName, String type )
{
w.startElement( "xs:complexType" );
w.startElement( "xs:sequence" );
w.startElement( "xs:element" );
- w.addAttribute( "name", singular( field.getName() ) );
+ w.addAttribute( "name", tagName );
w.addAttribute( "minOccurs", "0" );
w.addAttribute( "maxOccurs", "unbounded" );
w.addAttribute( "type", type );
@@ -335,4 +417,199 @@
}
}
+ private boolean hasFlatAssociation( Model objectModel, List fields )
+ {
+ boolean flatAssociation = false;
+
+ for ( Iterator i = fields.iterator(); i.hasNext(); )
+ {
+ flatAssociation |= isFlatAssociation( objectModel, (ModelField) i.next() );
+ }
+
+ return flatAssociation;
+ }
+
+ // ------------------------------------------------------------------------
+ // TODO Copied/pasted from XdocGenerator
+ // ------------------------------------------------------------------------
+
+ private List getFieldsForClass( Model objectModel, ModelClass modelClass )
+ {
+ List fields = new ArrayList();
+ while ( modelClass != null )
+ {
+ fields.addAll( modelClass.getFields( getGeneratedVersion() ) );
+ String superClass = modelClass.getSuperClass();
+ if ( superClass != null )
+ {
+ modelClass = objectModel.getClass( superClass, getGeneratedVersion() );
+ }
+ else
+ {
+ modelClass = null;
+ }
+ }
+ return fields;
+ }
+
+ /**
+ * Return the child attribute fields of this class.
+ * @param objectModel global object model
+ * @param modelClass current class
+ * @return the list of attribute fields of this class
+ */
+ private List getAttributeFieldsForClass( Model objectModel, ModelClass modelClass )
+ {
+ List attributeFields = new ArrayList();
+ while ( modelClass != null )
+ {
+ List allFields = modelClass.getFields( getGeneratedVersion() );
+
+ Iterator allFieldsIt = allFields.iterator();
+
+ while ( allFieldsIt.hasNext() )
+ {
+ ModelField field = (ModelField) allFieldsIt.next();
+ XmlFieldMetadata fieldMetadata = (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID );
+ if ( fieldMetadata.isAttribute() )
+ {
+ attributeFields.add( field );
+ }
+ }
+
+ String superClass = modelClass.getSuperClass();
+ if ( superClass != null )
+ {
+ modelClass = objectModel.getClass( superClass, getGeneratedVersion() );
+ }
+ else
+ {
+ modelClass = null;
+ }
+ }
+ return attributeFields;
+ }
+
+ /**
+ * Compute the tagName of a given class, living inside an association.
+ * @param modelClass the class we are looking for the tag name
+ * @param association the association where this class is used
+ * @return the tag name to use
+ */
+ private String resolveTagName( ModelField field )
+ {
+ XmlFieldMetadata metadata = (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID );
+
+ String tagName;
+ if ( metadata == null || metadata.getTagName() == null )
+ {
+ if ( !( field instanceof ModelAssociation ) )
+ {
+ tagName = uncapitalise( field.getName() );
+ }
+ else
+ {
+ ModelAssociation association = (ModelAssociation) field;
+
+ XmlFieldMetadata fieldMetadata = (XmlFieldMetadata) association.getMetadata( XmlFieldMetadata.ID );
+
+ if ( fieldMetadata != null && fieldMetadata.getAssociationTagName() != null )
+ {
+ tagName = fieldMetadata.getAssociationTagName();
+ }
+ else
+ {
+ tagName = association.getName();
+
+ if ( ModelAssociation.MANY_MULTIPLICITY.equals( association.getMultiplicity() ) )
+ {
+ tagName = singular( tagName );
+ }
+ }
+ }
+ }
+ else
+ {
+ tagName = metadata.getTagName();
+ }
+ return tagName;
+ }
+
+ private boolean isInnerAssociation( Model objectModel, ModelField field )
+ {
+ boolean innerAssociation = field instanceof ModelAssociation
+ && isClassInModel( ( (ModelAssociation) field ).getTo(), objectModel );
+
+ return innerAssociation;
+ }
+
+ private boolean isManyAssociation( Model objectModel, ModelField field )
+ {
+ boolean manyAssociation = false;
+
+ if ( isInnerAssociation( objectModel, field ) )
+ {
+ ModelAssociation assoc = (ModelAssociation) field;
+
+ manyAssociation = ModelAssociation.MANY_MULTIPLICITY.equals( assoc.getMultiplicity() );
+ }
+
+ return manyAssociation;
+ }
+
+ private boolean isWrappedAssociation( Model objectModel, ModelField field )
+ {
+
+ boolean wrappedAssociation = false;
+
+ if ( isManyAssociation( objectModel, field ) )
+ {
+
+ XmlFieldMetadata fieldMetadata = (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID );
+
+ wrappedAssociation = XmlFieldMetadata.LIST_STYLE_WRAPPED.equals( fieldMetadata.getListStyle() );
+
+ }
+
+ return wrappedAssociation;
+
+ }
+
+ /**
+ * Wether the given field is an instance of flat association or not.
+ * Also checks that to class is included in model.
+ * @param objectModel the current model
+ * @param field the field to check
+ * @return true if the field is an flat association, false otherwise.
+ */
+ private boolean isFlatAssociation( Model objectModel, ModelField field )
+ {
+
+ boolean flatAssociation = false;
+
+ if ( isManyAssociation( objectModel, field ) )
+ {
+
+ XmlFieldMetadata fieldMetadata = (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID );
+
+ flatAssociation = XmlFieldMetadata.LIST_STYLE_FLAT.equals( fieldMetadata.getListStyle() );
+
+ }
+
+ return flatAssociation;
+
+ }
+
+ private boolean isNonRecursiveAssociation( Model objectModel, ModelClass modelClass, ModelAssociation association )
+ {
+
+ ModelClass fieldModelClass = objectModel.getClass( association.getTo(), getGeneratedVersion() );
+
+ boolean recursiveAssociation = ( modelClass.getName().equals( fieldModelClass.getName() ) )
+ && ( modelClass.getPackageName().equals( fieldModelClass.getPackageName() ) );
+
+ return !( recursiveAssociation );
+
+ }
+
}