Merge "BUG-2470: add trace of failed modification"
[controller.git] / opendaylight / config / yang-jmx-generator-plugin / src / main / java / org / opendaylight / controller / config / yangjmxgenerator / plugin / ftl / TemplateFactory.java
index 28e0256c05b0cbd055636aa8cf391be97fba6d21..53ab4ef335973029568f0820968c830d59112f17 100644 (file)
@@ -7,11 +7,19 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl;
 
-import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.management.openmbean.SimpleType;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.IdentityAttributeRef;
 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
 import org.opendaylight.controller.config.api.runtime.RuntimeBean;
@@ -26,6 +34,7 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIf
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
@@ -34,6 +43,7 @@ import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Anno
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Constructor;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Header;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.IdentityRefModuleField;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDeclaration;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDefinition;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
@@ -42,61 +52,8 @@ import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 
-import javax.management.openmbean.SimpleType;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
 public class TemplateFactory {
 
-    public static Map<String, FtlTemplate> getFtlTemplates(
-            ModuleMXBeanEntry entry) {
-        Map<String, FtlTemplate> result = new HashMap<>();
-
-        result.putAll(TemplateFactory.tOsFromMbe(entry));
-
-        // IFC
-        result.put(entry.getMXBeanInterfaceName() + ".java",
-                TemplateFactory.mXBeanInterfaceTemplateFromMbe(entry));
-
-        // ABS fact
-        result.put(entry.getAbstractFactoryName() + ".java",
-                TemplateFactory.abstractFactoryTemplateFromMbe(entry));
-
-        // ABS module
-        result.put(entry.getAbstractModuleName() + ".java",
-                TemplateFactory.abstractModuleTemplateFromMbe(entry));
-
-        return result;
-    }
-
-    public static Map<String, FtlTemplate> getFtlStubTemplates(
-            ModuleMXBeanEntry entry) {
-        Map<String, FtlTemplate> result = new HashMap<>();
-        // STUB fact
-        result.put(entry.getStubFactoryName() + ".java",
-                TemplateFactory.stubFactoryTemplateFromMbe(entry));
-
-        result.put(entry.getStubModuleName() + ".java",
-                TemplateFactory.stubModuleTemplateFromMbe(entry));
-        return result;
-    }
-
-    public static Map<String, FtlTemplate> getFtlTemplates(
-            ServiceInterfaceEntry entry) {
-
-        Map<String, FtlTemplate> result = new HashMap<>();
-        result.put(entry.getTypeName() + ".java",
-                TemplateFactory.serviceInterfaceFromSie(entry));
-
-        return result;
-    }
-
     /**
      * Get map of file name as key, FtlFile instance representing runtime mx
      * bean as value that should be persisted from this instance.
@@ -152,12 +109,12 @@ public class TemplateFactory {
     }
 
     // FIXME: put into Type.toString
-    static String serializeType(Type type) {
+    static String serializeType(Type type, boolean addWildcards) {
         if (type instanceof ParameterizedType){
             ParameterizedType parameterizedType = (ParameterizedType) type;
-            StringBuffer sb = new StringBuffer();
+            StringBuilder sb = new StringBuilder();
             sb.append(parameterizedType.getRawType().getFullyQualifiedName());
-            sb.append("<");
+            sb.append(addWildcards ? "<? extends " : "<");
             boolean first = true;
             for(Type parameter: parameterizedType.getActualTypeArguments()) {
                 if (first) {
@@ -174,6 +131,9 @@ public class TemplateFactory {
         }
     }
 
+    static String serializeType(Type type) {
+        return serializeType(type, false);
+    }
 
     private static String getReturnType(AttributeIfc attributeIfc) {
         String returnType;
@@ -206,10 +166,11 @@ public class TemplateFactory {
                 Lists.<MethodDeclaration> newArrayList());
         sieTemplate.setJavadoc(sie.getNullableDescription());
 
-        if (sie.getNullableDescription() != null)
+        if (sie.getNullableDescription() != null) {
             sieTemplate.getAnnotations().add(
                     Annotation.createDescriptionAnnotation(sie
                             .getNullableDescription()));
+        }
         sieTemplate.getAnnotations().addAll(Annotation.createSieAnnotations(sie));
 
         return sieTemplate;
@@ -221,28 +182,17 @@ public class TemplateFactory {
         attrProcessor.processAttributes(mbe.getAttributes(),
                 mbe.getPackageName());
 
-        Collection<String> transformed = Collections2.transform(mbe
-                .getProvidedServices().keySet(),
-                new Function<String, String>() {
 
-                    @Override
-                    public String apply(String input) {
-                        return input + ".class";
-                    }
-                });
 
         return new AbstractFactoryTemplate(getHeaderFromEntry(mbe),
                 mbe.getPackageName(), mbe.getAbstractFactoryName(),
-                mbe.getGloballyUniqueName(), mbe.getFullyQualifiedName(mbe
-                        .getStubModuleName()), attrProcessor.getFields(),
-                Lists.newArrayList(transformed), mbe);
+                attrProcessor.getFields()
+        );
     }
 
     public static AbstractModuleTemplate abstractModuleTemplateFromMbe(
             ModuleMXBeanEntry mbe) {
-        AbstractModuleAttributesProcessor attrProcessor = new AbstractModuleAttributesProcessor();
-        attrProcessor.processAttributes(mbe.getAttributes(),
-                mbe.getPackageName());
+        AbstractModuleAttributesProcessor attrProcessor = new AbstractModuleAttributesProcessor(mbe.getAttributes());
 
         List<ModuleField> moduleFields = attrProcessor.getModuleFields();
         List<String> implementedIfcs = Lists.newArrayList(
@@ -274,10 +224,11 @@ public class TemplateFactory {
                 attrProcessor.getMethods(), generateRuntime,
                 registratorFullyQualifiedName);
 
-        if (mbe.getNullableDescription() != null)
+        if (mbe.getNullableDescription() != null) {
             abstractModuleTemplate.getAnnotations().add(
                     Annotation.createDescriptionAnnotation(mbe
                             .getNullableDescription()));
+        }
         return abstractModuleTemplate;
     }
 
@@ -285,15 +236,8 @@ public class TemplateFactory {
             ModuleMXBeanEntry mbe) {
         return new StubFactoryTemplate(getHeaderFromEntry(mbe),
                 mbe.getPackageName(), mbe.getStubFactoryName(),
-                mbe.getFullyQualifiedName(mbe.getAbstractFactoryName()),
-                mbe.getStubModuleName());
-    }
-
-    public static StubModuleTemplate stubModuleTemplateFromMbe(
-            ModuleMXBeanEntry mbe) {
-        return new StubModuleTemplate(getHeaderFromEntry(mbe),
-                mbe.getPackageName(), mbe.getStubModuleName(),
-                mbe.getFullyQualifiedName(mbe.getAbstractModuleName()));
+                mbe.getFullyQualifiedName(mbe.getAbstractFactoryName())
+        );
     }
 
     public static GeneralInterfaceTemplate mXBeanInterfaceTemplateFromMbe(
@@ -339,12 +283,15 @@ public class TemplateFactory {
         for (Rpc rpc : rbe.getRpcs()) {
             AttributeIfc returnType = rpc.getReturnType();
 
-            if (returnType == VoidAttribute.getInstance())
+            if (returnType == VoidAttribute.getInstance()) {
                 continue;
-            if (returnType instanceof JavaAttribute)
+            }
+            if (returnType instanceof JavaAttribute) {
                 continue;
-            if (returnType instanceof ListAttribute && returnType.getOpenType() instanceof SimpleType)
+            }
+            if (returnType instanceof ListAttribute && returnType.getOpenType() instanceof SimpleType) {
                 continue;
+            }
 
             Preconditions.checkState(yangPropertiesToTypesMap.containsKey(returnType.getAttributeYangName()) == false,
                     "Duplicate TO %s for %s", returnType.getAttributeYangName(), rbe);
@@ -423,10 +370,19 @@ public class TemplateFactory {
                 processAttrs(attrs, packageName);
             }
 
+            private final static String dependencyResolverVarName = "dependencyResolver";
+            private final static String dependencyResolverInjectMethodName = "injectDependencyResolver";
+
             private void processAttrs(Map<String, AttributeIfc> attrs, String packageName) {
                 fields = Lists.newArrayList();
                 methods = Lists.newArrayList();
 
+                // FIXME conflict if "dependencyResolver" field from yang
+                Field depRes = new Field(DependencyResolver.class.getName(), dependencyResolverVarName);
+                fields.add(depRes);
+                methods.add(new MethodDefinition("void", dependencyResolverInjectMethodName, Lists.newArrayList(depRes),
+                        "this." + dependencyResolverVarName + " = " + dependencyResolverVarName + ";"));
+
                 for (Entry<String, AttributeIfc> attrEntry : attrs.entrySet()) {
                     String innerName = attrEntry.getKey();
                     String varName = BindingGeneratorUtil
@@ -435,15 +391,23 @@ public class TemplateFactory {
                     String fullyQualifiedName, nullableDefault = null;
                     if (attrEntry.getValue() instanceof TypedAttribute) {
                         Type type = ((TypedAttribute) attrEntry.getValue()).getType();
-                        fullyQualifiedName = serializeType(type);
                         if(attrEntry.getValue() instanceof JavaAttribute) {
                             nullableDefault = ((JavaAttribute)attrEntry.getValue()).getNullableDefaultWrappedForCode();
+                            if(((JavaAttribute)attrEntry.getValue()).isIdentityRef()) {
+
+                                String fieldType = serializeType(type, true);
+                                String innerType = getInnerTypeFromIdentity(type);
+                                methods.add(new MethodDefinition(fieldType, "resolve" + attrEntry.getKey(), Collections.<Field>emptyList(),
+                                        "return " + varName + ".resolveIdentity(" + dependencyResolverVarName + "," +  innerType + ".class);"));
+                                type = identityRefType;
+                            }
                         }
+                        fullyQualifiedName = serializeType(type);
                     } else {
                         fullyQualifiedName = FullyQualifiedNameHelper
                                 .getFullyQualifiedName(packageName, attrEntry.getValue().getUpperCaseCammelCase());
                     }
-                    fields.add(new Field(fullyQualifiedName, varName, nullableDefault));
+                    fields.add(new Field(fullyQualifiedName, varName, nullableDefault, needsDepResolver(attrEntry.getValue())));
 
                     String getterName = "get" + innerName;
                     MethodDefinition getter = new MethodDefinition(
@@ -480,6 +444,7 @@ public class TemplateFactory {
         }
     }
 
+
     private static class MXBeanInterfaceAttributesProcessor {
         private final List<MethodDeclaration> methods = Lists.newArrayList();
 
@@ -491,6 +456,11 @@ public class TemplateFactory {
                 if (attributeIfc instanceof TypedAttribute) {
                     TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
                     returnType = serializeType(typedAttribute.getType());
+
+                    if (attributeIfc instanceof JavaAttribute && ((JavaAttribute)attrEntry.getValue()).isIdentityRef()) {
+                        returnType = serializeType(identityRefType);
+                    }
+
                 } else {
                     throw new UnsupportedOperationException(
                             "Attribute not supported: "
@@ -509,6 +479,7 @@ public class TemplateFactory {
                 MethodDeclaration setter = new MethodDeclaration("void",
                         setterName, Lists.newArrayList(new Field(returnType,
                                 varName)));
+
                 methods.add(getter);
                 methods.add(setter);
 
@@ -524,10 +495,28 @@ public class TemplateFactory {
         }
     }
 
+    private static final Type identityRefType = new Type() {
+        public final Class<IdentityAttributeRef> IDENTITY_ATTRIBUTE_REF_CLASS = IdentityAttributeRef.class;
+
+        @Override
+        public String getPackageName() {
+            return IDENTITY_ATTRIBUTE_REF_CLASS.getPackage().getName();
+        }
+
+        @Override
+        public String getName() {
+            return IDENTITY_ATTRIBUTE_REF_CLASS.getSimpleName();
+        }
+
+        @Override
+        public String getFullyQualifiedName() {
+            return IDENTITY_ATTRIBUTE_REF_CLASS.getName();
+        }
+    };
+
     private static class AbstractFactoryAttributesProcessor {
 
         private final List<Field> fields = Lists.newArrayList();
-        private static final String STRING_FULLY_QUALIFIED_NAME = "java.util.List";
 
         void processAttributes(Map<String, AttributeIfc> attributes,
                 String packageName) {
@@ -539,27 +528,6 @@ public class TemplateFactory {
                 if (attributeIfc instanceof TypedAttribute) {
                     TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
                     type = serializeType(typedAttribute.getType());
-                } else if (attributeIfc instanceof TOAttribute) {
-                    String fullyQualifiedName = FullyQualifiedNameHelper
-                            .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
-
-                    type = fullyQualifiedName;
-                } else if (attributeIfc instanceof ListAttribute) {  //FIXME: listAttribute might extend TypedAttribute
-                    String fullyQualifiedName = null;
-                    AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
-                            .getInnerAttribute();
-                    if (innerAttr instanceof JavaAttribute) {
-                        fullyQualifiedName = ((JavaAttribute) innerAttr)
-                                .getType().getFullyQualifiedName();
-                        nullableDefaultWrapped = ((JavaAttribute) innerAttr).getNullableDefaultWrappedForCode();
-                    } else if (innerAttr instanceof TOAttribute) {
-                        fullyQualifiedName = FullyQualifiedNameHelper
-                                .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
-                    }
-
-                    type = STRING_FULLY_QUALIFIED_NAME.concat("<")
-                            .concat(fullyQualifiedName).concat(">");
-
                 } else {
                     throw new UnsupportedOperationException(
                             "Attribute not supported: "
@@ -577,45 +545,42 @@ public class TemplateFactory {
     }
 
     private static class AbstractModuleAttributesProcessor {
+        private static class Holder {
+            private final List<ModuleField> moduleFields;
+            private final List<MethodDefinition> methods;
 
-        private static final String STRING_FULLY_QUALIFIED_NAME = "java.util.List";
+            private Holder(List<ModuleField> moduleFields, List<MethodDefinition> methods) {
+                this.moduleFields = Collections.unmodifiableList(moduleFields);
+                this.methods = Collections.unmodifiableList(methods);
+            }
+        }
 
-        private final List<ModuleField> moduleFields = Lists.newArrayList();
-        private final List<MethodDefinition> methods = Lists.newArrayList();
+        private final Holder holder;
 
-        void processAttributes(Map<String, AttributeIfc> attributes,
-                String packageName) {
+
+        private AbstractModuleAttributesProcessor(Map<String, AttributeIfc> attributes) {
+            this.holder = processAttributes(attributes);
+        }
+
+        private static Holder processAttributes(Map<String, AttributeIfc> attributes) {
+            List<ModuleField> moduleFields = new ArrayList<>();
+            List<MethodDefinition> methods = new ArrayList<>();
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 String type, nullableDefaultWrapped = null;
                 AttributeIfc attributeIfc = attrEntry.getValue();
+                boolean isIdentity = false;
+                boolean needsDepResolver = needsDepResolver(attrEntry.getValue());
 
                 if (attributeIfc instanceof TypedAttribute) {
                     TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
                     type = serializeType(typedAttribute.getType());
                     if (attributeIfc instanceof JavaAttribute) {
                         nullableDefaultWrapped = ((JavaAttribute) attributeIfc).getNullableDefaultWrappedForCode();
+                        if(((JavaAttribute)attrEntry.getValue()).isIdentityRef()) {
+                            isIdentity = true;
+                            type = serializeType(typedAttribute.getType(), true);
+                        }
                     }
-
-                } else if (attributeIfc instanceof TOAttribute) {
-                    String fullyQualifiedName = FullyQualifiedNameHelper
-                            .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
-
-                    type = fullyQualifiedName;
-                } else if (attributeIfc instanceof ListAttribute) {
-                    String fullyQualifiedName = null;
-                    AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
-                            .getInnerAttribute();
-                    if (innerAttr instanceof JavaAttribute) {
-                        fullyQualifiedName = ((JavaAttribute) innerAttr)
-                                .getType().getFullyQualifiedName();
-                        nullableDefaultWrapped = ((JavaAttribute) innerAttr).getNullableDefaultWrappedForCode();
-                    } else if (innerAttr instanceof TOAttribute) {
-                        fullyQualifiedName = FullyQualifiedNameHelper
-                                .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
-                    }
-
-                    type = STRING_FULLY_QUALIFIED_NAME.concat("<")
-                            .concat(fullyQualifiedName).concat(">");
                 } else {
                     throw new UnsupportedOperationException(
                             "Attribute not supported: "
@@ -623,6 +588,7 @@ public class TemplateFactory {
                 }
 
                 boolean isDependency = false;
+                boolean isListOfDependencies = false;
                 Dependency dependency = null;
                 Annotation overrideAnnotation = new Annotation("Override",
                         Collections.<Parameter> emptyList());
@@ -635,19 +601,56 @@ public class TemplateFactory {
                             .getDependency();
                     annotations.add(Annotation
                             .createRequireIfcAnnotation(dependency.getSie()));
+                    if (attributeIfc instanceof ListDependenciesAttribute) {
+                        isListOfDependencies = true;
+                    }
                 }
 
                 String varName = BindingGeneratorUtil
                         .parseToValidParamName(attrEntry.getKey());
-                moduleFields.add(new ModuleField(type, varName, attributeIfc
-                        .getUpperCaseCammelCase(), nullableDefaultWrapped, isDependency, dependency));
+
+                ModuleField field;
+                if (isIdentity) {
+                    String identityBaseClass = getInnerTypeFromIdentity(((TypedAttribute) attributeIfc).getType());
+                    IdentityRefModuleField identityField = new IdentityRefModuleField(type, varName,
+                            attributeIfc.getUpperCaseCammelCase(), identityBaseClass);
+
+                    String getterName = "get"
+                            + attributeIfc.getUpperCaseCammelCase() + "Identity";
+                    MethodDefinition additionalGetter = new MethodDefinition(type, getterName, Collections.<Field> emptyList(),
+                            Collections.<Annotation> emptyList(), "return " + identityField.getIdentityClassName()
+                                    + ";");
+                    methods.add(additionalGetter);
+
+                    String setterName = "set"
+                            + attributeIfc.getUpperCaseCammelCase();
+
+                    String setterBody = "this." + identityField.getIdentityClassName() + " = " + identityField.getIdentityClassName() + ";";
+                    MethodDefinition additionalSetter = new MethodDefinition("void",
+                            setterName,
+                            Lists.newArrayList(new Field(type, identityField.getIdentityClassName())),
+                            Collections.<Annotation> emptyList(), setterBody);
+                    additionalSetter.setJavadoc(attributeIfc.getNullableDescription());
+
+                    methods.add(additionalSetter);
+
+                    type = serializeType(identityRefType);
+                    field = identityField;
+                } else {
+                    field = new ModuleField(type, varName, attributeIfc.getUpperCaseCammelCase(),
+                            nullableDefaultWrapped, isDependency, dependency, isListOfDependencies, needsDepResolver);
+                }
+                moduleFields.add(field);
+
 
                 String getterName = "get"
                         + attributeIfc.getUpperCaseCammelCase();
                 MethodDefinition getter = new MethodDefinition(type,
                         getterName, Collections.<Field> emptyList(),
                         Lists.newArrayList(overrideAnnotation), "return "
-                                + varName + ";");
+                        + varName + ";");
+
+                methods.add(getter);
 
                 String setterName = "set"
                         + attributeIfc.getUpperCaseCammelCase();
@@ -657,25 +660,50 @@ public class TemplateFactory {
                             .createDescriptionAnnotation(attributeIfc.getNullableDescription()));
                 }
 
+                String setterBody = "this." + varName + " = " + varName + ";";
+                if (isListOfDependencies) {
+                    String nullCheck = String.format("if (%s == null) throw new IllegalArgumentException(\"Null not supported\");%n",
+                            varName);
+                    setterBody = nullCheck + setterBody;
+                }
                 MethodDefinition setter = new MethodDefinition("void",
                         setterName,
                         Lists.newArrayList(new Field(type, varName)),
-                        annotations, "this." + varName + " = " + varName + ";");
+                        annotations, setterBody);
                 setter.setJavadoc(attributeIfc.getNullableDescription());
 
-                methods.add(getter);
                 methods.add(setter);
             }
+            return new Holder(moduleFields, methods);
         }
 
         List<ModuleField> getModuleFields() {
-            return moduleFields;
+            return holder.moduleFields;
         }
 
         List<MethodDefinition> getMethods() {
-            return methods;
+            return holder.methods;
         }
 
     }
 
+
+    private static boolean needsDepResolver(AttributeIfc value) {
+        if(value instanceof TOAttribute) {
+            return true;
+        }
+        if(value instanceof ListAttribute) {
+            AttributeIfc innerAttribute = ((ListAttribute) value).getInnerAttribute();
+            return needsDepResolver(innerAttribute);
+        }
+
+        return false;
+    }
+
+    private static String getInnerTypeFromIdentity(Type type) {
+        Preconditions.checkArgument(type instanceof ParameterizedType);
+        Type[] args = ((ParameterizedType) type).getActualTypeArguments();
+        Preconditions.checkArgument(args.length ==1);
+        return serializeType(args[0]);
+    }
 }