From 6521fd3836b02f0461e72a546ec52da40b5a672d Mon Sep 17 00:00:00 2001 From: "David M. Lloyd" Date: Tue, 25 Sep 2012 00:18:38 -0500 Subject: [PATCH] almost looks like progress, but not really --- api/pom.xml | 7 + .../java/org/jboss/mgmt/AbstractResource.java | 6 +- ...lder.java => AbstractResourceBuilder.java} | 13 +- ...uilderFactory.java => BuilderFactory.java} | 2 +- ...ilderCollectionBuilder.java => Entry.java} | 26 +- .../jboss/mgmt/{model => }/ResourceNode.java | 42 ++- .../jboss/mgmt/SimpleCollectionBuilder.java | 30 -- .../java/org/jboss/mgmt/SimpleMapBuilder.java | 30 -- .../main/java/example1/DomainResource.java | 3 +- .../example1/LoggingSubsystemResource.java | 3 +- .../example1/StandaloneServerResource.java | 12 +- pom.xml | 18 +- tool/pom.xml | 8 +- .../jboss/mgmt/annotation/AttributeType.java | 2 + .../jboss/mgmt/annotation/Description.java | 39 -- .../jboss/mgmt/annotation/RootResource.java | 7 + .../{Gen.java => xml/XmlTypeName.java} | 15 +- .../generator/AbstractClassGenerator.java | 2 +- .../jboss/mgmt/generator/AnnotationUtils.java | 149 ++++++++ .../generator/AttributeGroupBuilderImpl.java | 2 +- .../jboss/mgmt/generator/CodeModelUtils.java | 3 +- .../jboss/mgmt/generator/FilerCodeWriter.java | 2 +- .../org/jboss/mgmt/generator/Generator.java | 334 ++++++++++-------- .../org/jboss/mgmt/generator/Processor.java | 13 +- .../ResourceBuilderInterfaceGenerator.java | 2 +- 25 files changed, 482 insertions(+), 288 deletions(-) rename api/src/main/java/org/jboss/mgmt/{BuilderMapBuilder.java => AbstractResourceBuilder.java} (71%) rename api/src/main/java/org/jboss/mgmt/{ResourceBuilderFactory.java => BuilderFactory.java} (94%) rename api/src/main/java/org/jboss/mgmt/{BuilderCollectionBuilder.java => Entry.java} (69%) rename api/src/main/java/org/jboss/mgmt/{model => }/ResourceNode.java (74%) delete mode 100644 api/src/main/java/org/jboss/mgmt/SimpleCollectionBuilder.java delete mode 100644 api/src/main/java/org/jboss/mgmt/SimpleMapBuilder.java delete mode 100644 tool/src/main/java/org/jboss/mgmt/annotation/Description.java rename tool/src/main/java/org/jboss/mgmt/annotation/{Gen.java => xml/XmlTypeName.java} (79%) create mode 100644 tool/src/main/java/org/jboss/mgmt/generator/AnnotationUtils.java diff --git a/api/pom.xml b/api/pom.xml index 8326c59..e0a8479 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -11,4 +11,11 @@ jboss-mgmt-api + + + + org.jboss.msc + jboss-msc2 + + \ No newline at end of file diff --git a/api/src/main/java/org/jboss/mgmt/AbstractResource.java b/api/src/main/java/org/jboss/mgmt/AbstractResource.java index 8e33378..168fbbe 100644 --- a/api/src/main/java/org/jboss/mgmt/AbstractResource.java +++ b/api/src/main/java/org/jboss/mgmt/AbstractResource.java @@ -23,15 +23,17 @@ package org.jboss.mgmt; /** + * Base class for resource data objects. + * * @author David M. Lloyd */ public abstract class AbstractResource implements Resource { private final String preComment; private final String postComment; private final String name; - private final Resource parent; + private final ResourceNode parent; - protected AbstractResource(final String preComment, final String postComment, final String name, final Resource parent) { + protected AbstractResource(final String preComment, final String postComment, final String name, final ResourceNode parent) { this.preComment = preComment; this.postComment = postComment; this.name = name; diff --git a/api/src/main/java/org/jboss/mgmt/BuilderMapBuilder.java b/api/src/main/java/org/jboss/mgmt/AbstractResourceBuilder.java similarity index 71% rename from api/src/main/java/org/jboss/mgmt/BuilderMapBuilder.java rename to api/src/main/java/org/jboss/mgmt/AbstractResourceBuilder.java index f983440..d6890df 100644 --- a/api/src/main/java/org/jboss/mgmt/BuilderMapBuilder.java +++ b/api/src/main/java/org/jboss/mgmt/AbstractResourceBuilder.java @@ -23,12 +23,17 @@ package org.jboss.mgmt; /** - * A builder for attributes of a map type whose values are complex. + * Infrastructure class used by generated resource implementations. * * @author David M. Lloyd */ -public interface BuilderMapBuilder>> extends NestedBuilder

{ - V put(K key); +public abstract class AbstractResourceBuilder, THIS extends AbstractResourceBuilder> implements NestedBuilder

{ + protected final ResourceNode construct(ResourceNode parentNode) { + return null; + } - BuilderMapBuilder remove(K key); + @SuppressWarnings("unchecked") + protected final THIS _this() { + return (THIS) this; + } } diff --git a/api/src/main/java/org/jboss/mgmt/ResourceBuilderFactory.java b/api/src/main/java/org/jboss/mgmt/BuilderFactory.java similarity index 94% rename from api/src/main/java/org/jboss/mgmt/ResourceBuilderFactory.java rename to api/src/main/java/org/jboss/mgmt/BuilderFactory.java index e0a17eb..9737346 100644 --- a/api/src/main/java/org/jboss/mgmt/ResourceBuilderFactory.java +++ b/api/src/main/java/org/jboss/mgmt/BuilderFactory.java @@ -27,6 +27,6 @@ * * @author David M. Lloyd */ -public interface ResourceBuilderFactory> { +public interface BuilderFactory> { B construct(P parent); } diff --git a/api/src/main/java/org/jboss/mgmt/BuilderCollectionBuilder.java b/api/src/main/java/org/jboss/mgmt/Entry.java similarity index 69% rename from api/src/main/java/org/jboss/mgmt/BuilderCollectionBuilder.java rename to api/src/main/java/org/jboss/mgmt/Entry.java index 1cf753d..1b40d3a 100644 --- a/api/src/main/java/org/jboss/mgmt/BuilderCollectionBuilder.java +++ b/api/src/main/java/org/jboss/mgmt/Entry.java @@ -22,9 +22,31 @@ package org.jboss.mgmt; +import java.util.Map; + /** + * An immutable map entry, used by builder classes. + * * @author David M. Lloyd */ -public interface BuilderCollectionBuilder>> extends NestedBuilder

{ - E add(); +public final class Entry implements Map.Entry { + private final K key; + private final V value; + + Entry(final K key, final V value) { + this.value = value; + this.key = key; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public V setValue(final V value) { + throw new UnsupportedOperationException(); + } } diff --git a/api/src/main/java/org/jboss/mgmt/model/ResourceNode.java b/api/src/main/java/org/jboss/mgmt/ResourceNode.java similarity index 74% rename from api/src/main/java/org/jboss/mgmt/model/ResourceNode.java rename to api/src/main/java/org/jboss/mgmt/ResourceNode.java index a44baf3..fd8bba5 100644 --- a/api/src/main/java/org/jboss/mgmt/model/ResourceNode.java +++ b/api/src/main/java/org/jboss/mgmt/ResourceNode.java @@ -20,19 +20,24 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.jboss.mgmt.model; +package org.jboss.mgmt; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import org.jboss.msc.txn.WorkContext; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; /** * @author David M. Lloyd */ -public abstract class ResourceNode { +public abstract class ResourceNode implements Resource { private volatile int state; private volatile R current; private volatile Object owningTxn; private volatile Thread waiter; + private final ResourceNode parent; private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(ResourceNode.class, "state"); private static final AtomicReferenceFieldUpdater currentUpdater = AtomicReferenceFieldUpdater.newUpdater(ResourceNode.class, Object.class, "current"); @@ -43,6 +48,10 @@ public abstract class ResourceNode { private static final int INTENT_WRITE_LOCK = (1 << 30); private static final int READERS = INTENT_WRITE_LOCK - 1; + protected ResourceNode(final ResourceNode parent) { + this.parent = parent; + } + private static Object currentTransaction() { return null; // todo once msc-2 stabilizes... } @@ -69,4 +78,33 @@ private void lockRead(final Object txn) { private void lockWrite(final Object txn) { // set write flag or block with txn } + + public String getPreComment() { + return current.getPreComment(); + } + + public String getPostComment() { + return current.getPostComment(); + } + + public String getName() { + return current.getName(); + } + + public Resource getParent() { + return parent; + } + + public Resource navigate(final String key, final String value) { + return null; + } + + protected abstract R writeAttribute(WorkContext workContext, String name, Object value); + + protected abstract void persist(XMLStreamWriter writer) throws XMLStreamException; + + @SuppressWarnings("unchecked") + R asResource() { + return (R) this; + } } diff --git a/api/src/main/java/org/jboss/mgmt/SimpleCollectionBuilder.java b/api/src/main/java/org/jboss/mgmt/SimpleCollectionBuilder.java deleted file mode 100644 index 4fe637a..0000000 --- a/api/src/main/java/org/jboss/mgmt/SimpleCollectionBuilder.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * JBoss, Home of Professional Open Source. - * Copyright 2012, Red Hat, Inc., and individual contributors - * as indicated by the @author tags. See the copyright.txt file in the - * distribution for a full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.jboss.mgmt; - -/** - * @author David M. Lloyd - */ -public interface SimpleCollectionBuilder extends NestedBuilder

{ - SimpleCollectionBuilder add(E value); -} diff --git a/api/src/main/java/org/jboss/mgmt/SimpleMapBuilder.java b/api/src/main/java/org/jboss/mgmt/SimpleMapBuilder.java deleted file mode 100644 index 7fec541..0000000 --- a/api/src/main/java/org/jboss/mgmt/SimpleMapBuilder.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * JBoss, Home of Professional Open Source. - * Copyright 2012, Red Hat, Inc., and individual contributors - * as indicated by the @author tags. See the copyright.txt file in the - * distribution for a full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.jboss.mgmt; - -/** - * @author David M. Lloyd - */ -public interface SimpleMapBuilder extends NestedBuilder

{ - SimpleMapBuilder put(K key, V value); -} diff --git a/example/src/main/java/example1/DomainResource.java b/example/src/main/java/example1/DomainResource.java index f631272..aa6af70 100644 --- a/example/src/main/java/example1/DomainResource.java +++ b/example/src/main/java/example1/DomainResource.java @@ -35,8 +35,9 @@ @RootResource( type = "top", namespace = "jboss", - version = "1.0", + version = "8.0", kind = RootResource.Kind.SYSTEM, + schemaLocation = "http://www.jboss.org/schema/jbossas/jboss_8_0.xsd", compatibilityNamespaces = { "urn:jboss:domain:1.0" } ) public interface DomainResource extends Resource { diff --git a/example/src/main/java/example1/LoggingSubsystemResource.java b/example/src/main/java/example1/LoggingSubsystemResource.java index cb4fbb5..057e7da 100644 --- a/example/src/main/java/example1/LoggingSubsystemResource.java +++ b/example/src/main/java/example1/LoggingSubsystemResource.java @@ -37,7 +37,8 @@ type = "subsystem", name = "logging", namespace = "core.logging", - version = "1.0" + schemaLocation = "http://www.jboss.org/schema/jbossas/jboss-core-logging_8_0.xsd", + version = "8.0" ) @XmlName("subsystem") public interface LoggingSubsystemResource extends Resource { diff --git a/example/src/main/java/example1/StandaloneServerResource.java b/example/src/main/java/example1/StandaloneServerResource.java index bbb9d1c..d5c954f 100644 --- a/example/src/main/java/example1/StandaloneServerResource.java +++ b/example/src/main/java/example1/StandaloneServerResource.java @@ -24,13 +24,19 @@ import org.jboss.mgmt.annotation.AttributeGroup; import org.jboss.mgmt.annotation.RootResource; -import org.jboss.mgmt.annotation.xml.XmlName; /** * @author David M. Lloyd */ -@RootResource(type = "model", kind = RootResource.Kind.SYSTEM, name = "standalone", version = "1.0", namespace = "jboss") -@XmlName("standalone") +@RootResource( + name = "server", + type = "top", + namespace = "jboss", + version = "8.0", + kind = RootResource.Kind.SYSTEM, + schemaLocation = "http://www.jboss.org/schema/jbossas/jboss_8_0.xsd", + compatibilityNamespaces = { "urn:jboss:domain:1.0" } +) public interface StandaloneServerResource extends ServerResource { @AttributeGroup diff --git a/pom.xml b/pom.xml index a3628c0..d360a45 100644 --- a/pom.xml +++ b/pom.xml @@ -39,8 +39,8 @@ 2.5.1 - 1.7 - 1.7 + 1.6 + 1.6 @@ -57,8 +57,8 @@ ${version.compiler.plugin} - - + + @@ -76,11 +76,11 @@ jboss-mgmt-tool ${project.version} - - - - - + + org.jboss.msc + jboss-msc2 + 2.0.0.Beta1-SNAPSHOT + xom xom diff --git a/tool/pom.xml b/tool/pom.xml index 6c6a646..65058f6 100644 --- a/tool/pom.xml +++ b/tool/pom.xml @@ -29,10 +29,10 @@ org.jboss.mgmt jboss-mgmt-api - - - - + + org.jboss.msc + jboss-msc2 + com.sun.codemodel codemodel diff --git a/tool/src/main/java/org/jboss/mgmt/annotation/AttributeType.java b/tool/src/main/java/org/jboss/mgmt/annotation/AttributeType.java index b4f2480..607d4f3 100644 --- a/tool/src/main/java/org/jboss/mgmt/annotation/AttributeType.java +++ b/tool/src/main/java/org/jboss/mgmt/annotation/AttributeType.java @@ -29,6 +29,8 @@ import static java.lang.annotation.RetentionPolicy.CLASS; /** + * Declare a class to be an attribute type. Attribute types are read and written as one attribute. + * * @author David M. Lloyd */ @Retention(CLASS) diff --git a/tool/src/main/java/org/jboss/mgmt/annotation/Description.java b/tool/src/main/java/org/jboss/mgmt/annotation/Description.java deleted file mode 100644 index c9287d5..0000000 --- a/tool/src/main/java/org/jboss/mgmt/annotation/Description.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * Copyright 2008, JBoss Inc., and individual contributors as indicated - * by the @authors tag. See the copyright.txt in the distribution for a - * full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -package org.jboss.mgmt.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -/** - * A description for a resource or attribute. - */ -@Target({TYPE, METHOD}) -@Retention(SOURCE) -public @interface Description { - String value(); -} diff --git a/tool/src/main/java/org/jboss/mgmt/annotation/RootResource.java b/tool/src/main/java/org/jboss/mgmt/annotation/RootResource.java index 1015efc..e881cf8 100644 --- a/tool/src/main/java/org/jboss/mgmt/annotation/RootResource.java +++ b/tool/src/main/java/org/jboss/mgmt/annotation/RootResource.java @@ -71,6 +71,13 @@ */ String namespace(); + /** + * The schema location. This URL string will be used to determine the target filename of the generated schema. + * + * @return the URL + */ + String schemaLocation(); + /** * Compatibility namespaces that should also be recognized (but not generated). * diff --git a/tool/src/main/java/org/jboss/mgmt/annotation/Gen.java b/tool/src/main/java/org/jboss/mgmt/annotation/xml/XmlTypeName.java similarity index 79% rename from tool/src/main/java/org/jboss/mgmt/annotation/Gen.java rename to tool/src/main/java/org/jboss/mgmt/annotation/xml/XmlTypeName.java index 4bd9954..b74f5ef 100644 --- a/tool/src/main/java/org/jboss/mgmt/annotation/Gen.java +++ b/tool/src/main/java/org/jboss/mgmt/annotation/xml/XmlTypeName.java @@ -20,21 +20,20 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.jboss.mgmt.annotation; +package org.jboss.mgmt.annotation.xml; import java.lang.annotation.Retention; import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static java.lang.annotation.RetentionPolicy.CLASS; /** - * Indicates that this class was generated by the given version of the generation tool. - * - * @author David M. Lloyd + * The name of the XML type to assign to a resource, attribute type, or attribute group. */ -@Target(TYPE) -@Retention(RUNTIME) -public @interface Gen { +@Target({TYPE, METHOD}) +@Retention(CLASS) +public @interface XmlTypeName { String value(); } diff --git a/tool/src/main/java/org/jboss/mgmt/generator/AbstractClassGenerator.java b/tool/src/main/java/org/jboss/mgmt/generator/AbstractClassGenerator.java index 07d5bdc..762cb62 100644 --- a/tool/src/main/java/org/jboss/mgmt/generator/AbstractClassGenerator.java +++ b/tool/src/main/java/org/jboss/mgmt/generator/AbstractClassGenerator.java @@ -36,7 +36,7 @@ /** * @author David M. Lloyd */ -public abstract class AbstractClassGenerator { +abstract class AbstractClassGenerator { private final JCodeModel codeModel; private final Messager messager; private final String packageName; diff --git a/tool/src/main/java/org/jboss/mgmt/generator/AnnotationUtils.java b/tool/src/main/java/org/jboss/mgmt/generator/AnnotationUtils.java new file mode 100644 index 0000000..b0c4c5c --- /dev/null +++ b/tool/src/main/java/org/jboss/mgmt/generator/AnnotationUtils.java @@ -0,0 +1,149 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2012, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.jboss.mgmt.generator; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; + +/** + * @author David M. Lloyd + */ +final class AnnotationUtils { + + private AnnotationUtils() { + } + + public static AnnotationMirror getAnnotation(Elements elements, Element annotatedElement, String annotationName) { + for (AnnotationMirror mirror : elements.getAllAnnotationMirrors(annotatedElement)) { + if (mirror.getAnnotationType().asElement().getSimpleName().toString().equals(annotationName)) { + return mirror; + } + } + return null; + } + + public static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) { + final Set> entries = mirror.getElementValues().entrySet(); + for (Map.Entry entry : entries) { + if (entry.getKey().getSimpleName().toString().equals(name)) { + return entry.getValue(); + } + } + return null; + } + + public static String getAnnotationValueString(AnnotationMirror mirror, String name) { + return stringValue(getAnnotationValue(mirror, name)); + } + + public static String getAnnotationValueClassName(AnnotationMirror mirror, String name) { + return classNameValue(getAnnotationValue(mirror, name)); + } + + public static String stringValue(AnnotationValue value) { + if (value == null) return null; + return (String) value.getValue(); + } + + public static TypeMirror classValue(AnnotationValue value) { + if (value == null) return null; + return (TypeMirror) value.getValue(); + } + + public static String classNameValue(AnnotationValue value) { + if (value == null) return null; + final TypeMirror typeMirror = classValue(value); + return typeMirror instanceof PrimitiveType ? ((PrimitiveType)typeMirror).getKind().toString().toLowerCase(Locale.ENGLISH) : ((DeclaredType)typeMirror).asElement().getSimpleName().toString(); + } + + public static VariableElement enumValue(AnnotationValue value) { + return (VariableElement) value; + } + + public static String enumNameValue(AnnotationValue value) { + final VariableElement element = enumValue(value); + return element.getSimpleName().toString(); + } + + public static > E enumConstValue(Class type, AnnotationValue value) { + return Enum.valueOf(type, enumNameValue(value)); + } + + public static boolean booleanValue(AnnotationValue value, boolean defVal) { + if (value == null) return defVal; + return ((Boolean) value.getValue()).booleanValue(); + } + + public static int intValue(AnnotationValue value, int defVal) { + if (value == null) return defVal; + return ((Integer) value.getValue()).intValue(); + } + + public static String[] stringArrayValue(AnnotationValue value) { + if (value == null) return null; + @SuppressWarnings("unchecked") + final List list = (List) value.getValue(); + final String[] array = new String[list.size()]; + int i = 0; + for (AnnotationValue annotationValue : list) { + array[i++] = stringValue(annotationValue); + } + return array; + } + + public static TypeMirror[] classArrayValue(AnnotationValue value) { + if (value == null) return null; + @SuppressWarnings("unchecked") + final List list = (List) value.getValue(); + final TypeMirror[] array = new TypeMirror[list.size()]; + int i = 0; + for (AnnotationValue annotationValue : list) { + array[i++] = classValue(annotationValue); + } + return array; + } + + public static String[] classNameArrayValue(AnnotationValue value) { + if (value == null) return null; + @SuppressWarnings("unchecked") + final List list = (List) value.getValue(); + final String[] array = new String[list.size()]; + int i = 0; + for (AnnotationValue annotationValue : list) { + array[i++] = classNameValue(annotationValue); + } + return array; + } +} diff --git a/tool/src/main/java/org/jboss/mgmt/generator/AttributeGroupBuilderImpl.java b/tool/src/main/java/org/jboss/mgmt/generator/AttributeGroupBuilderImpl.java index aa7546e..d6228eb 100644 --- a/tool/src/main/java/org/jboss/mgmt/generator/AttributeGroupBuilderImpl.java +++ b/tool/src/main/java/org/jboss/mgmt/generator/AttributeGroupBuilderImpl.java @@ -30,7 +30,7 @@ /** * @author David M. Lloyd */ -public final class AttributeGroupBuilderImpl

implements AttributeGroupBuilder

{ +final class AttributeGroupBuilderImpl

implements AttributeGroupBuilder

{ private final P parent; private final String name; private final DeclaredType type; diff --git a/tool/src/main/java/org/jboss/mgmt/generator/CodeModelUtils.java b/tool/src/main/java/org/jboss/mgmt/generator/CodeModelUtils.java index 9b8b7b7..45145f1 100644 --- a/tool/src/main/java/org/jboss/mgmt/generator/CodeModelUtils.java +++ b/tool/src/main/java/org/jboss/mgmt/generator/CodeModelUtils.java @@ -57,7 +57,7 @@ /** * @author David M. Lloyd */ -public final class CodeModelUtils { +final class CodeModelUtils { private CodeModelUtils() { } @@ -160,7 +160,6 @@ private static JDefinedClass mirror(ProcessingEnvironment env, JCodeModel codeMo definedClass.hide(); // clone type parameters final List typeParameters = element.getTypeParameters(); - System.out.println("" + element + " has " + typeParameters.size() + " params: " + typeParameters); for (TypeParameterElement typeParameter : typeParameters) { final String paramName = typeParameter.getSimpleName().toString(); final List bounds = typeParameter.getBounds(); diff --git a/tool/src/main/java/org/jboss/mgmt/generator/FilerCodeWriter.java b/tool/src/main/java/org/jboss/mgmt/generator/FilerCodeWriter.java index 2094475..a1ad4d7 100644 --- a/tool/src/main/java/org/jboss/mgmt/generator/FilerCodeWriter.java +++ b/tool/src/main/java/org/jboss/mgmt/generator/FilerCodeWriter.java @@ -38,7 +38,7 @@ * * @author David M. Lloyd */ -public class FilerCodeWriter extends CodeWriter { +class FilerCodeWriter extends CodeWriter { private final Filer filer; diff --git a/tool/src/main/java/org/jboss/mgmt/generator/Generator.java b/tool/src/main/java/org/jboss/mgmt/generator/Generator.java index 8dd6a70..71341e6 100644 --- a/tool/src/main/java/org/jboss/mgmt/generator/Generator.java +++ b/tool/src/main/java/org/jboss/mgmt/generator/Generator.java @@ -24,32 +24,35 @@ import java.io.IOException; import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import nu.xom.Attribute; +import nu.xom.Comment; import nu.xom.Document; import nu.xom.Element; import nu.xom.Serializer; import org.jboss.mgmt.AbstractResource; -import org.jboss.mgmt.AttributeValidator; -import org.jboss.mgmt.BuilderCollectionBuilder; -import org.jboss.mgmt.BuilderMapBuilder; +import org.jboss.mgmt.BuilderFactory; +import org.jboss.mgmt.Entry; import org.jboss.mgmt.ExceptionThrowingValidationContext; import org.jboss.mgmt.ModelNodeDeparser; import org.jboss.mgmt.ModelNodeParser; import org.jboss.mgmt.NestedBuilder; import org.jboss.mgmt.Resource; -import org.jboss.mgmt.ResourceBuilderFactory; -import org.jboss.mgmt.SimpleCollectionBuilder; -import org.jboss.mgmt.SimpleMapBuilder; import org.jboss.mgmt.VirtualAttribute; import org.jboss.mgmt.annotation.Access; -import org.jboss.mgmt.annotation.Gen; import org.jboss.mgmt.annotation.RootResource; import org.jboss.mgmt.annotation.xml.XmlRender; -import org.jboss.mgmt.model.ResourceNode; +import org.jboss.mgmt.ResourceNode; +import com.sun.codemodel.JArray; import com.sun.codemodel.JBlock; import com.sun.codemodel.JClass; import com.sun.codemodel.JClassAlreadyExistsException; @@ -69,6 +72,7 @@ import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; +import javax.annotation.Generated; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; @@ -100,6 +104,7 @@ final class Generator { private static final String GENERATOR_VERSION = "1.0"; private final ProcessingEnvironment env; + private final RoundEnvironment roundEnv; private final Filer filer; private final Messager messager; private final Types types; @@ -108,33 +113,23 @@ final class Generator { private final JCodeModel codeModel = new JCodeModel(); // -------------------------------------------------- - // Common types + // Accumulated output // -------------------------------------------------- - private final JClass modelNodeParser = codeModel.ref(ModelNodeParser.class).erasure(); - private final JClass modelNodeDeparser = codeModel.ref(ModelNodeDeparser.class).erasure(); - private final JClass xmlStreamReader = codeModel.ref(XMLStreamReader.class); - private final JClass xmlStreamWriter = codeModel.ref(XMLStreamWriter.class); - private final JClass xmlStreamException = codeModel.ref(XMLStreamException.class); - private final JClass exceptionThrowingValidationContext = codeModel.ref(ExceptionThrowingValidationContext.class); - private final JClass attributeValidator = codeModel.ref(AttributeValidator.class); - private final JClass resourceJClass = codeModel.ref(Resource.class); - private final JClass abstractResource = codeModel.ref(AbstractResource.class); - private final JClass string = codeModel.ref(String.class); - private final JClass virtualAttribute = codeModel.ref(VirtualAttribute.class).erasure(); - private final JClass resourceNode = codeModel.ref(ResourceNode.class).erasure(); - private final JClass resourceBuilderFactory = codeModel.ref(ResourceBuilderFactory.class).erasure(); - private final JClass nestedBuilder = codeModel.ref(NestedBuilder.class).erasure(); - private final JClass simpleMapBuilder = codeModel.ref(SimpleMapBuilder.class).erasure(); - private final JClass simpleCollectionBuilder = codeModel.ref(SimpleCollectionBuilder.class).erasure(); - private final JClass builderMapBuilder = codeModel.ref(BuilderMapBuilder.class).erasure(); - private final JClass builderCollectionBuilder = codeModel.ref(BuilderCollectionBuilder.class).erasure(); - - - private final Map namespaceDocuments = new HashMap(); - private final Map namespaceSchemas = new HashMap(); - private final Map namespaceSchemaLocations = new HashMap(); - private final RoundEnvironment roundEnv; + static class DocInfo { + final Map typeDecls = new TreeMap(); + final Map rootElementDecls = new TreeMap(); + final Set altXmlNamespaces = new HashSet(); + String schemaLocation; + RootResource.Kind resourceNamespaceKind = RootResource.Kind.EXTENSION; + String version; + String namespace; // just the module part + } + + private final Map namespaceSchemas = new HashMap(); + private final Set generatedResourceTypes = new HashSet(); + private final Set generatedAttributeTypes = new HashSet(); + private final Set generatedAttributeGroups = new HashSet(); Generator(final ProcessingEnvironment env, final RoundEnvironment roundEnv, final SessionImpl session) { this.roundEnv = roundEnv; @@ -147,7 +142,6 @@ final class Generator { } void generate() { - final List resources = session.getResources(); for (RootResourceBuilderImpl resource : resources) { @@ -158,70 +152,102 @@ void generate() { final String version = def(resource.getVersion(), "1.0"); final String namespace = def(resource.getNamespace(), "unspecified"); - final String schemaLocation = def(resource.getSchemaLocation(), "http://nowhere.com/"); + final String schemaLocation = resource.getSchemaLocation(); final RootResource.Kind resourceNamespaceKind = def(resource.getKind(), RootResource.Kind.EXTENSION); final String xmlNamespace = buildNamespace(resourceNamespaceKind, namespace, version); - Element schemaElement; + final DocInfo docInfo; if (! namespaceSchemas.containsKey(xmlNamespace)) { - final Document schemaDocument; - - schemaElement = new Element("xs:schema", XSD); - schemaElement.addNamespaceDeclaration("", xmlNamespace); - schemaElement.addNamespaceDeclaration("xs", XSD); - schemaDocument = new Document(schemaElement); - - schemaElement.addAttribute(new Attribute("targetNamespace", xmlNamespace)); - schemaElement.addAttribute(new Attribute("elementFormDefault", "qualified")); - schemaElement.addAttribute(new Attribute("attributeFormDefault", "unqualified")); - - namespaceDocuments.put(xmlNamespace, schemaDocument); - namespaceSchemas.put(xmlNamespace, schemaElement); - namespaceSchemaLocations.put(xmlNamespace, schemaLocation); + docInfo = new DocInfo(); + docInfo.schemaLocation = schemaLocation; + docInfo.namespace = namespace; + docInfo.resourceNamespaceKind = resourceNamespaceKind; + docInfo.version = version; + namespaceSchemas.put(xmlNamespace, docInfo); } else { - schemaElement = namespaceSchemas.get(xmlNamespace); - if (! schemaLocation.equals(namespaceSchemaLocations.get(xmlNamespace))) { + docInfo = namespaceSchemas.get(xmlNamespace); + if (! schemaLocation.equals(docInfo.schemaLocation)) { messager.printMessage(WARNING, "Namespace '" + xmlNamespace + "' declared with conflicting schema locations"); } } // Root resources declare elements in the root schema. - new ResourceWriter(resource, schemaElement, schemaElement, xmlNamespace, true).generate(); + new ResourceWriter(resource, docInfo, xmlNamespace, null).generate(); } // -------------------------------------------------- // Emit results (if no error) // -------------------------------------------------- - if (roundEnv.errorRaised()) { - return; - } + for (Map.Entry entry : namespaceSchemas.entrySet()) { + final Element schemaElement = new Element("xs:schema", XSD); + final Document document = new Document(schemaElement); + final String xmlNamespace = entry.getKey(); + final DocInfo docInfo = entry.getValue(); + + schemaElement.addNamespaceDeclaration("", xmlNamespace); + schemaElement.addNamespaceDeclaration("xs", XSD); + + schemaElement.addAttribute(new Attribute("targetNamespace", xmlNamespace)); + schemaElement.addAttribute(new Attribute("elementFormDefault", "qualified")); + schemaElement.addAttribute(new Attribute("attributeFormDefault", "unqualified")); - for (Map.Entry entry : namespaceDocuments.entrySet()) { - final String namespace = entry.getKey().replaceAll(":","-"); - final Document document = entry.getValue(); - final Serializer serializer; - final OutputStream stream; + schemaElement.appendChild("\n"); + schemaElement.appendChild(new Comment("Root elements")); + schemaElement.appendChild("\n"); + for (Map.Entry elementEntry : docInfo.rootElementDecls.entrySet()) { + schemaElement.appendChild(elementEntry.getValue()); + } + schemaElement.appendChild("\n"); + schemaElement.appendChild(new Comment("Element types")); + schemaElement.appendChild("\n"); + for (Map.Entry elementEntry : docInfo.typeDecls.entrySet()) { + schemaElement.appendChild(elementEntry.getValue()); + } + if (docInfo.schemaLocation == null) { + messager.printMessage(ERROR, "No namespace location for schema " + xmlNamespace); + continue; + } + final URI uri; try { - stream = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "META-INF/" + namespace + ".xsd").openOutputStream(); + uri = new URI(docInfo.schemaLocation); + } catch (URISyntaxException e) { + messager.printMessage(ERROR, "Namespace schema location '" + docInfo.schemaLocation + "' is not valid for " + xmlNamespace); + continue; + } + final String path = uri.getPath(); + if (path == null) { + messager.printMessage(ERROR, "Namespace schema location '" + docInfo.schemaLocation + "' does not have a path component for " + xmlNamespace); + continue; + } + final String fileName = path.substring(path.lastIndexOf('/') + 1); + if (! fileName.endsWith(".xsd")) { + messager.printMessage(WARNING, "Namespace schema location '" + docInfo.schemaLocation + "' should specify a file name ending in \".xsd\""); + } + if (! roundEnv.errorRaised()) { + final Serializer serializer; + final OutputStream stream; try { - serializer = new Serializer(stream); - serializer.setIndent(4); - serializer.setLineSeparator("\n"); - serializer.write(document); - serializer.flush(); - } finally { + stream = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "META-INF/" + fileName).openOutputStream(); try { - stream.close(); - } catch (IOException e) { - messager.printMessage(ERROR, "Failed to close XSD stream: " + e); + serializer = new Serializer(stream); + serializer.setIndent(4); + serializer.setLineSeparator("\n"); + serializer.write(document); + serializer.flush(); + } finally { + try { + stream.close(); + } catch (IOException e) { + messager.printMessage(ERROR, "Failed to close XSD stream for '" + docInfo.schemaLocation + "' of " + xmlNamespace + ": " + e); + } } + } catch (IOException e) { + messager.printMessage(ERROR, "Failed to write XSD for '" + docInfo.schemaLocation + "' of " + xmlNamespace + ": " + e); } - } catch (IOException e) { - messager.printMessage(ERROR, "Failed to write XSD: " + e); } } - try { + if (! roundEnv.errorRaised()) try { codeModel.build(new FilerCodeWriter(filer)); } catch (IOException e) { messager.printMessage(ERROR, "Failed to write source files: " + e); @@ -230,17 +256,15 @@ void generate() { class ResourceWriter { private final GeneralResourceBuilderImpl resource; - private final Element schemaElement; - private final Element parentElement; + private final DocInfo docInfo; private final String xmlNamespace; - private final boolean root; + private final Element parentType; - ResourceWriter(final GeneralResourceBuilderImpl resource, final Element schemaElement, final Element parentElement, final String xmlNamespace, final boolean root) { + ResourceWriter(final GeneralResourceBuilderImpl resource, final DocInfo docInfo, final String xmlNamespace, final Element parentType) { this.resource = resource; - this.schemaElement = schemaElement; - this.parentElement = parentElement; + this.docInfo = docInfo; this.xmlNamespace = xmlNamespace; - this.root = root; + this.parentType = parentType; } void generate() { @@ -261,6 +285,29 @@ void generate() { final String scn = resourceScn.substring(0, resourceScn.length() - 8); final String xmlName = def(resource.getXmlName(), xmlify(scn)); + // -------------------------------------------------- + // Schema root element for root resource + // -------------------------------------------------- + + final Element elementElement = new Element("xs:element", XSD); + elementElement.addAttribute(new Attribute("name", xmlName)); + + final Element typeElement = new Element("xs:complexType", XSD); + if (parentType == null) { + elementElement.appendChild(typeElement); + docInfo.rootElementDecls.put(xmlName, elementElement); + } else { + parentType.appendChild(elementElement); + elementElement.addAttribute(new Attribute("type", xmlName)); + typeElement.addAttribute(new Attribute("name", xmlName)); + docInfo.typeDecls.put(xmlName, typeElement); + } + + final Element typeSeqElement = new Element("xs:sequence", XSD); + typeElement.appendChild(typeSeqElement); + + addDocumentation(elementElement, "RESOURCE DESCRIPTION"); + // -------------------------------------------------- // Code model class instances // -------------------------------------------------- @@ -283,69 +330,51 @@ void generate() { builderClass = codeModel._class(PUBLIC | FINAL, fqcn + "BuilderImpl", CLASS); implementationClass = codeModel._class(PUBLIC | FINAL, fqcn + "ResourceImpl", CLASS); resourceNodeClass = codeModel._class(PUBLIC | FINAL, fqcn + "NodeImpl", CLASS); - coreClass = root ? codeModel._class(PUBLIC | FINAL, fqcn, CLASS) : null; + coreClass = parentType == null ? codeModel._class(PUBLIC | FINAL, fqcn, CLASS) : null; builderFactoryClass = codeModel._class(PUBLIC | FINAL, fqcn + "BuilderFactory", CLASS); } catch (JClassAlreadyExistsException e) { messager.printMessage(ERROR, "Duplicate class generation for " + fqcn); return; } - // -------------------------------------------------- - // Schema root element for root resource - // -------------------------------------------------- - - final Element elementElement = new Element("xs:element", XSD); - parentElement.appendChild(elementElement); - elementElement.addAttribute(new Attribute("name", xmlName)); - elementElement.addAttribute(new Attribute("type", xmlName)); - - final Element typeElement = new Element("xs:complexType", XSD); - schemaElement.appendChild(typeElement); - typeElement.addAttribute(new Attribute("name", xmlName)); - - final Element typeSeqElement = new Element("xs:sequence", XSD); - typeElement.appendChild(typeSeqElement); - - addDocumentation(elementElement, "RESOURCE DESCRIPTION"); - // -------------------------------------------------- // Class headers, extends/implements // -------------------------------------------------- - parserClass.annotate(Gen.class).param("value", GENERATOR_VERSION); - deparserClass.annotate(Gen.class).param("value", GENERATOR_VERSION); - builderInterface.annotate(Gen.class).param("value", GENERATOR_VERSION); - builderClass.annotate(Gen.class).param("value", GENERATOR_VERSION); - implementationClass.annotate(Gen.class).param("value", GENERATOR_VERSION); - resourceNodeClass.annotate(Gen.class).param("value", GENERATOR_VERSION); - if (root) coreClass.annotate(Gen.class).param("value", GENERATOR_VERSION); + parserClass.annotate(Generated.class).paramArray("value").param(Generator.class.getName()).param(GENERATOR_VERSION); + deparserClass.annotate(Generated.class).paramArray("value").param(Generator.class.getName()).param(GENERATOR_VERSION); + builderInterface.annotate(Generated.class).paramArray("value").param(Generator.class.getName()).param(GENERATOR_VERSION); + builderClass.annotate(Generated.class).paramArray("value").param(Generator.class.getName()).param(GENERATOR_VERSION); + implementationClass.annotate(Generated.class).paramArray("value").param(Generator.class.getName()).param(GENERATOR_VERSION); + resourceNodeClass.annotate(Generated.class).paramArray("value").param(Generator.class.getName()).param(GENERATOR_VERSION); + if (parentType == null) coreClass.annotate(Generated.class).paramArray("value").param(Generator.class.getName()).param(GENERATOR_VERSION); final JTypeVar builderInterfaceP = builderInterface.generify("P"); - builderInterface._extends(nestedBuilder.erasure().narrow(builderInterfaceP)); + builderInterface._extends(codeModel.ref(NestedBuilder.class).erasure().erasure().narrow(builderInterfaceP)); builderInterface.javadoc().add("A builder for " + resource.getName() + " resources. This interface was automatically generated."); final JTypeVar builderClassP = builderClass.generify("P"); builderClass._implements(builderInterface.narrow(builderClassP)); - parserClass._implements(modelNodeParser.narrow(builderInterface.narrow(codeModel.wildcard()))); - deparserClass._implements(modelNodeDeparser.narrow(resourceInterface)); + parserClass._implements(codeModel.ref(ModelNodeParser.class).erasure().narrow(builderInterface.narrow(codeModel.wildcard()))); + deparserClass._implements(codeModel.ref(ModelNodeDeparser.class).erasure().narrow(resourceInterface)); - implementationClass._extends(abstractResource); + implementationClass._extends(codeModel.ref(AbstractResource.class)); implementationClass._implements(resourceInterface); - resourceNodeClass._extends(resourceNode.narrow(resourceInterface)); + resourceNodeClass._extends(codeModel.ref(ResourceNode.class).erasure().narrow(resourceInterface)); final JTypeVar builderFactoryP = builderFactoryClass.generify("P"); - builderFactoryClass._implements(resourceBuilderFactory.narrow(builderFactoryP, builderInterface.erasure().narrow(builderFactoryP))); + builderFactoryClass._implements(codeModel.ref(BuilderFactory.class).erasure().narrow(builderFactoryP, builderInterface.erasure().narrow(builderFactoryP))); final JMethod implConstructor = implementationClass.constructor(PUBLIC); final JBlock implConstructorBody = implConstructor.body(); final JInvocation implConstructorSuperCall = implConstructorBody.invoke("super"); - implConstructorSuperCall.arg(implConstructor.param(FINAL, string, "preComment")); - implConstructorSuperCall.arg(implConstructor.param(FINAL, string, "postComment")); - implConstructorSuperCall.arg(implConstructor.param(FINAL, string, "name")); - implConstructorSuperCall.arg(implConstructor.param(FINAL, resourceJClass, "parent")); + implConstructorSuperCall.arg(implConstructor.param(FINAL, codeModel.ref(String.class), "preComment")); + implConstructorSuperCall.arg(implConstructor.param(FINAL, codeModel.ref(String.class), "postComment")); + implConstructorSuperCall.arg(implConstructor.param(FINAL, codeModel.ref(String.class), "name")); + implConstructorSuperCall.arg(implConstructor.param(FINAL, codeModel.ref(Resource.class), "parent")); // The core class is not instantiatable coreClass.constructor(PRIVATE); @@ -372,7 +401,7 @@ void generate() { final JMethod builderFactoryConstructMethod = builderFactoryClass.method(PUBLIC, builderClass.narrow(builderFactoryP), "construct"); builderFactoryConstructMethod.body()._return(JExpr._new(builderClass.narrow(builderFactoryP)).arg(builderFactoryConstructMethod.param(FINAL, builderFactoryP, "parent"))); - if (root) { + if (parentType == null) { final JMethod coreBuildMethod = coreClass.method(PUBLIC | STATIC, builderFactoryClass, "build"); coreBuildMethod.javadoc().add("Introduce this resource type into a builder which supports nested polymorphic types."); coreBuildMethod.javadoc().add("Normally this method should not be directly invoked, but rather as part of a builder invocation chain."); @@ -387,18 +416,18 @@ void generate() { // -------------------------------------------------- final JMethod parseMethod = parserClass.method(PUBLIC, codeModel.VOID, "parse"); - parseMethod._throws(xmlStreamException); - final JVar parseMethodStreamReader = parseMethod.param(xmlStreamReader, "streamReader"); + parseMethod._throws(codeModel.ref(XMLStreamException.class)); + final JVar parseMethodStreamReader = parseMethod.param(codeModel.ref(XMLStreamReader.class), "streamReader"); final JVar parseMethodBuilder = parseMethod.param(builderInterface.narrow(codeModel.wildcard()), "builder"); final JBlock parseMethodBody = parseMethod.body(); final JMethod deparseMethod = deparserClass.method(PUBLIC, codeModel.VOID, "deparse"); - deparseMethod._throws(xmlStreamException); - final JVar deparseMethodStreamWriter = deparseMethod.param(xmlStreamWriter, "streamWriter"); + deparseMethod._throws(codeModel.ref(XMLStreamException.class)); + final JVar deparseMethodStreamWriter = deparseMethod.param(codeModel.ref(XMLStreamWriter.class), "streamWriter"); final JVar deparseMethodResource = deparseMethod.param(resourceInterface, "resource"); final JBlock deparseMethodBody = deparseMethod.body(); - final JVar deparsePreComment = deparseMethodBody.decl(FINAL, string, "preComment", JExpr.invoke(deparseMethodResource, "getPreComment")); - final JVar deparsePostComment = deparseMethodBody.decl(FINAL, string, "postComment", JExpr.invoke(deparseMethodResource, "getPostComment")); + final JVar deparsePreComment = deparseMethodBody.decl(FINAL, codeModel.ref(String.class), "preComment", JExpr.invoke(deparseMethodResource, "getPreComment")); + final JVar deparsePostComment = deparseMethodBody.decl(FINAL, codeModel.ref(String.class), "postComment", JExpr.invoke(deparseMethodResource, "getPostComment")); deparseMethodBody._if(deparsePreComment.ne(JExpr._null()))._then().invoke(deparseMethodStreamWriter, "writeComment").arg(deparsePreComment); deparseMethodBody.invoke(deparseMethodStreamWriter, "writeStartElement").arg(xmlNamespace).arg(xmlName); final JBlock deparseMethodAttributesBlock = deparseMethodBody.block(); @@ -411,7 +440,7 @@ void generate() { // -------------------------------------------------- for (SubResourceBuilderImpl resourceBuilder : resource.getSubResources()) { - new ResourceWriter(resourceBuilder, schemaElement, parentElement, xmlNamespace, false).generate(); + new ResourceWriter(resourceBuilder, docInfo, xmlNamespace, typeElement).generate(); } // -------------------------------------------------- @@ -480,7 +509,7 @@ void generate() { // Parser / Deparser // -------------------------------------------------- - if (virtualAttribute == null) { + if (codeModel.ref(VirtualAttribute.class).erasure() == null) { // ---------------------------------------------- // Deparser // ---------------------------------------------- @@ -508,14 +537,14 @@ void generate() { if (access.isReadable()) { if (virtual != null) { // todo - cache virtual instances - getterMethodBody._return(JExpr.invoke(JExpr._new(virtualAttribute.narrow(attributeJType)), "getValue")); + getterMethodBody._return(JExpr.invoke(JExpr._new(codeModel.ref(VirtualAttribute.class).erasure().narrow(attributeJType)), "getValue")); } else { final JFieldVar field = implementationClass.field(PRIVATE | FINAL, attributeJType, attrVarName); implConstructorBody.assign(JExpr._this().ref(field), implConstructor.param(FINAL, attributeJType, attrVarName)); getterMethodBody._return(field); } } else { - getterMethodBody._throw(abstractResource.staticInvoke("notReadable")); + getterMethodBody._throw(codeModel.ref(AbstractResource.class).staticInvoke("notReadable")); } // -------------------------------------------------- @@ -542,24 +571,43 @@ void generate() { // value is a simple type - JClass[] typeParams = { - builderInterface.narrow(builderInterfaceP), - keyType, - valueType, - }; + final JClass listType = codeModel.ref(ArrayList.class).narrow(codeModel.ref(Entry.class).narrow(keyType, valueType)); + final JFieldVar attributeField = builderClass.field(PRIVATE | FINAL, listType, attrVarName); + attributeField.init(JExpr._new(listType)); + + builderInterfaceSetMethod = builderInterface.method(NONE, builderInterface.narrow(builderInterfaceP), "add" + name); + builderInterfaceSetMethod.param(keyType, "key"); + builderInterfaceSetMethod.param(valueType, "value"); + builderClassSetMethod = builderClass.method(NONE, builderInterface.narrow(builderInterfaceP), "add" + name); + final JVar keyParam = builderClassSetMethod.param(FINAL, keyType, "key"); + final JVar valueParam = builderClassSetMethod.param(FINAL, valueType, "value"); + final JBlock body = builderClassSetMethod.body(); + attributeField.invoke("add").arg(JExpr._new(codeModel.ref(Entry.class).narrow(keyType, valueType)).arg(keyParam).arg(valueParam)); + body._return(JExpr._this()); + } else { + // value is a complex (resource) type - final JFieldVar attributeField = builderClass.field(PRIVATE | FINAL, simpleMapBuilder.narrow(typeParams), attrVarName); - if (defaultValueExpr != null) { - attributeField.assign(defaultValueExpr); + final String nestedBuilderTypeName = valueType.fullName() + "BuilderImpl"; + final JClass nestedBuilderType = codeModel._getClass(nestedBuilderTypeName); + if (nestedBuilderType == null) { + messager.printMessage(ERROR, "No builder was generated for non-simple attribute type " + nestedBuilderTypeName); + return; } - attributeField.init(JExpr._null()); // todo fixed builder instance - builderInterfaceSetMethod = builderInterface.method(NONE, simpleMapBuilder.narrow(typeParams), attrVarName); - builderClassSetMethod = builderClass.method(PUBLIC, simpleMapBuilder.narrow(typeParams), attrVarName); - builderClassSetMethod.body()._return(attributeField); - } else { - // value is a complex (resource) type + final JClass listType = codeModel.ref(ArrayList.class).narrow(codeModel.ref(Entry.class).narrow(keyType, nestedBuilderType)); + final JFieldVar attributeField = builderClass.field(PRIVATE | FINAL, listType, attrVarName); + attributeField.init(JExpr._new(listType)); + + final JClass narrowedBuilderType = nestedBuilderType.narrow(builderInterface.narrow(builderInterfaceP)); + builderInterfaceSetMethod = builderInterface.method(NONE, narrowedBuilderType, "add" + name); + builderInterfaceSetMethod.param(keyType, "key"); + builderClassSetMethod = builderClass.method(NONE, narrowedBuilderType, "add" + name); + final JVar keyParam = builderClassSetMethod.param(FINAL, keyType, "key"); + final JBlock body = builderClassSetMethod.body(); + final JVar valueVar = body.decl(nestedBuilderType, "_builder", JExpr._new(narrowedBuilderType).arg(JExpr._this())); + attributeField.invoke("add").arg(JExpr._new(codeModel.ref(Entry.class).narrow(keyType, valueType)).arg(keyParam).arg(valueVar)); + body._return(valueVar); } } else { // value is a simple type... @@ -598,7 +646,7 @@ void generate() { // Emit validation block // -------------------------------------------------- - final JVar context = body.decl(FINAL, exceptionThrowingValidationContext, "_context", JExpr._new(exceptionThrowingValidationContext)); + final JVar context = body.decl(FINAL, codeModel.ref(ExceptionThrowingValidationContext.class), "_context", JExpr._new(codeModel.ref(ExceptionThrowingValidationContext.class))); for (DeclaredType validator : validators) { final JClass validatorType = (JClass) CodeModelUtils.typeFor(env, codeModel, validator); // todo - cache validator instances diff --git a/tool/src/main/java/org/jboss/mgmt/generator/Processor.java b/tool/src/main/java/org/jboss/mgmt/generator/Processor.java index 68de53f..5d04da4 100644 --- a/tool/src/main/java/org/jboss/mgmt/generator/Processor.java +++ b/tool/src/main/java/org/jboss/mgmt/generator/Processor.java @@ -32,6 +32,7 @@ import org.jboss.mgmt.Resource; import org.jboss.mgmt.annotation.Access; import org.jboss.mgmt.annotation.Attribute; +import org.jboss.mgmt.annotation.AttributeGroup; import org.jboss.mgmt.annotation.AttributeType; import org.jboss.mgmt.annotation.Provides; import org.jboss.mgmt.annotation.ResourceType; @@ -67,9 +68,10 @@ public Set getSupportedOptions() { public Set getSupportedAnnotationTypes() { return new HashSet(Arrays.asList( - AttributeType.class.getName(), - ResourceType.class.getName(), - RootResource.class.getName() + AttributeType.class.getName(), + ResourceType.class.getName(), + RootResource.class.getName(), + AttributeGroup.class.getName() )); } @@ -101,6 +103,7 @@ public boolean process(final Set annotations, final Round String resourceType = null; String resourceModelName = null; String resourceNamespace = null; + String schemaLocation = null; String[] resourceCompatNamespaces = null; RootResource.Kind resourceKind = RootResource.Kind.EXTENSION; final Map mirrorMap = mirrorListToMap(mirrors); @@ -116,6 +119,7 @@ public boolean process(final Set annotations, final Round if (valueMap.containsKey("kind")) resourceKind = getAnnotationValue(RootResource.Kind.class, valueMap.get("kind")); if (valueMap.containsKey("namespace")) resourceNamespace = valueMap.get("namespace").getValue().toString(); if (valueMap.containsKey("compatibilityNamespaces")) resourceCompatNamespaces = getStringArrayAnnotationValue(valueMap.get("compatibilityNamespaces")); + if (valueMap.containsKey("schemaLocation")) schemaLocation = valueMap.get("schemaLocation").getValue().toString(); } else if (annotationName.equals(XmlName.class.getName())) { xmlName = valueMap.get("value").getValue().toString(); } else if (annotationName.equals(Provides.class.getName())) { @@ -146,6 +150,9 @@ public boolean process(final Set annotations, final Round if (resourceKind != null) { resourceBuilder.kind(resourceKind); } + if (schemaLocation != null) { + resourceBuilder.schemaLocation(schemaLocation); + } for (ExecutableElement enclosedElement : ElementFilter.methodsIn(element.getEnclosedElements())) { final String methodName = enclosedElement.getSimpleName().toString(); diff --git a/tool/src/main/java/org/jboss/mgmt/generator/ResourceBuilderInterfaceGenerator.java b/tool/src/main/java/org/jboss/mgmt/generator/ResourceBuilderInterfaceGenerator.java index b15fc8c..195148e 100644 --- a/tool/src/main/java/org/jboss/mgmt/generator/ResourceBuilderInterfaceGenerator.java +++ b/tool/src/main/java/org/jboss/mgmt/generator/ResourceBuilderInterfaceGenerator.java @@ -40,7 +40,7 @@ /** * @author David M. Lloyd */ -public final class ResourceBuilderInterfaceGenerator extends AbstractClassGenerator { +final class ResourceBuilderInterfaceGenerator extends AbstractClassGenerator { private final GeneralResourceBuilderImpl resourceBuilder; public ResourceBuilderInterfaceGenerator(final JCodeModel codeModel, final Messager messager, final String className, final String packageName, final GeneralResourceBuilderImpl builder) {