Merge "Add StatusCode.CREATED"
authorGiovanni Meo <gmeo@cisco.com>
Thu, 5 Dec 2013 15:03:47 +0000 (15:03 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 5 Dec 2013 15:03:47 +0000 (15:03 +0000)
19 files changed:
opendaylight/md-sal/clustered-data-store/integrationtest/pom.xml
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/TransformerGenerator.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/ClassLoaderUtils.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-dom-it/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java [moved from opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java with 100% similarity]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java [moved from opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java with 94% similarity]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java [moved from opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java with 100% similarity]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java [moved from opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java with 100% similarity]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java [moved from opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java with 100% similarity]
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java [moved from opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java with 100% similarity]
opendaylight/md-sal/sal-binding-it/pom.xml
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend

index 968f87a40200c1bbf86ef7a196f92b8d96f9e8f4..176ab6cbe0138a5ae9cecdf4877bb5a4ebeaa5d1 100644 (file)
 
     <artifactId>clustered-datastore.integrationtest</artifactId>
     <version>0.4.0-SNAPSHOT</version>
-    <dependencies>
 
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>xml-apis</groupId>
+                <artifactId>xml-apis</artifactId>
+                <version>1.4.01</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-binding-broker-impl</artifactId>
             <version>1.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>xml-apis</artifactId>
+                    <groupId>xml-apis</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>reflections</artifactId>
+                    <groupId>org.reflections</groupId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>config-netconf-connector</artifactId>
             <version>${netconf.version}</version>
             <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <artifactId>xml-apis</artifactId>
+                    <groupId>xml-apis</groupId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
index 94c31dd0411eb041fc11fd61adcab23dd369a105..0e78598c1137a339c7368be40b0b7a7e39427b9a 100644 (file)
@@ -29,6 +29,7 @@
         <module>sal-binding-broker</module>
 
         <module>sal-binding-util</module>
+        <module>sal-binding-dom-it</module>
 
         <!-- Samples -->
         <module>samples</module>
 
     <dependencyManagement>
         <dependencies>
-
-
-
+            <dependency>
+                <groupId>xml-apis</groupId>
+                <artifactId>xml-apis</artifactId>
+                <version>1.4.01</version>
+            </dependency>
 
             <!-- YANG Tools Dependencies -->
             <dependency>
index 89bb1e8502570ee901d5e0f5f6052ce450140120..ac84aab977783edbebc416d4755379967f70e84c 100644 (file)
                     </execution>
                 </executions>
             </plugin>
+
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
             <groupId>org.reflections</groupId>
             <artifactId>reflections</artifactId>
             <version>0.9.9-RC1</version>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.javassist</groupId>
             <groupId>org.eclipse.xtend</groupId>
             <artifactId>org.eclipse.xtend.lib</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.eclipse.xtend</groupId>
-            <artifactId>org.eclipse.xtend.standalone</artifactId>
-            <version>2.4.3</version>
-            <scope>runtime</scope>
-        </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-binding-config</artifactId>
             <version>1.0-SNAPSHOT</version>
         </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller.model</groupId>
-            <artifactId>model-flow-service</artifactId>
-            <version>1.0-SNAPSHOT</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller.model</groupId>
-            <artifactId>model-flow-management</artifactId>
-            <version>1.0-SNAPSHOT</version>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-data-impl</artifactId>
             <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller.model</groupId>
-            <artifactId>model-flow-statistics</artifactId>
-            <version>1.0-SNAPSHOT</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.reflections</groupId>
-            <artifactId>reflections</artifactId>
-            <version>0.9.9-RC1</version>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
 </project>
index de6836489e6a6b970fb96a409e832876d02e82a7..d33272d6413bfa90628f49a459671eab756ef2d0 100644 (file)
@@ -91,7 +91,7 @@ public class LazyGeneratedCodecRegistry implements //
     Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
 
     @SuppressWarnings("rawtypes")
-    private ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseNodes = new ConcurrentHashMap<>();
+    private ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
 
     private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
 
@@ -136,15 +136,14 @@ public class LazyGeneratedCodecRegistry implements //
         }
         return weakRef.get();
     }
-    
+
     @Override
-    public void putPathToClass(List<QName> names,Class<?> cls) {
+    public void putPathToClass(List<QName> names, Class<?> cls) {
         Type reference = Types.typeForClass(cls);
-        pathToInstantiatedType.put(names, reference );
+        pathToInstantiatedType.put(names, reference);
         bindingClassEncountered(cls);
     }
 
-
     @Override
     public IdentifierCodec<?> getKeyCodecForPath(List<QName> names) {
         @SuppressWarnings("unchecked")
@@ -297,10 +296,12 @@ public class LazyGeneratedCodecRegistry implements //
             return potential;
         }
         ConcreteType typeref = Types.typeForClass(caseClass);
-        ChoiceCaseCodecImpl caseCodec = typeToCaseNodes.get(typeref);
+        ChoiceCaseCodecImpl caseCodec = typeToCaseCodecs.get(typeref);
 
+        checkState(caseCodec != null, "Case Codec was not created proactivelly for %s", caseClass.getName());
+        checkState(caseCodec.getSchema() != null, "Case schema is not available for %s", caseClass.getName());
         @SuppressWarnings("unchecked")
-        Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseCodec.schema);
+        Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseCodec.getSchema());
         BindingCodec newInstance = newInstanceOf(newCodec);
         caseCodec.setDelegate(newInstance);
         caseCodecs.put(caseClass, caseCodec);
@@ -322,17 +323,23 @@ public class LazyGeneratedCodecRegistry implements //
         for (Entry<SchemaPath, GeneratedTypeBuilder> caseNode : cases.entrySet()) {
             ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
                     .getValue().getName());
+
+            LOG.info("Case path: {} Type : {}", caseNode.getKey(), caseNode.getValue().getFullyQualifiedName());
+            pathToType.put(caseNode.getKey(), caseNode.getValue());
+
             ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
+
             if (node == null) {
                 LOG.error("YANGTools Bug: SchemaNode for {}, with path {} was not found in context.",
                         typeref.getFullyQualifiedName(), caseNode.getKey());
+                @SuppressWarnings("rawtypes")
+                ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl();
+                typeToCaseCodecs.putIfAbsent(typeref, value);
                 continue;
             }
-
-            pathToType.put(caseNode.getKey(), caseNode.getValue());
             @SuppressWarnings("rawtypes")
             ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node);
-            typeToCaseNodes.putIfAbsent(typeref, value);
+            typeToCaseCodecs.putIfAbsent(typeref, value);
         }
     }
 
@@ -352,18 +359,24 @@ public class LazyGeneratedCodecRegistry implements //
         choiceCodecs.put(choiceClass, newCodec);
         CodecMapping.setClassToCaseMap(choiceCodec, (Map<Class<?>, BindingCodec<?, ?>>) classToCaseRawCodec);
         CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase());
-        
+
         tryToCreateCasesCodecs(schema);
 
     }
 
     private void tryToCreateCasesCodecs(ChoiceNode schema) {
-        for(ChoiceCaseNode caseNode : schema.getCases()) {
+        for (ChoiceCaseNode caseNode : schema.getCases()) {
             SchemaPath path = caseNode.getPath();
             GeneratedTypeBuilder type;
-            if(path != null && (type = pathToType.get(path)) != null) {
+            if (path != null && (type = pathToType.get(path)) != null) {
+                ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+                ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref);
+                if(partialCodec.getSchema() == null ) {
+                    partialCodec.setSchema(caseNode);
+                }
+                
                 Class<?> caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName());
-                if(caseClass != null) {
+                if (caseClass != null) {
                     getCaseCodecFor(caseClass);
                 }
             }
@@ -381,8 +394,7 @@ public class LazyGeneratedCodecRegistry implements //
     }
 
     @Override
-    public void onDataContainerCodecCreated(Class<?> dataClass,
-            Class<? extends BindingCodec<?,?>> dataCodec) {
+    public void onDataContainerCodecCreated(Class<?> dataClass, Class<? extends BindingCodec<?, ?>> dataCodec) {
         if (Augmentable.class.isAssignableFrom(dataClass)) {
             AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass);
             CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec);
@@ -471,15 +483,15 @@ public class LazyGeneratedCodecRegistry implements //
     @SuppressWarnings("rawtypes")
     private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
             Delegator<BindingCodec> {
-        private final boolean augmenting;
+        private boolean augmenting;
         private BindingCodec delegate;
 
-        private final Set<String> validNames;
-        private final Set<QName> validQNames;
+        private Set<String> validNames;
+        private Set<QName> validQNames;
         private ChoiceCaseNode schema;
 
-        public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) {
-            this.delegate = NOT_READY_CODEC;
+        public void setSchema(ChoiceCaseNode caseNode) {
+            this.schema = schema;
             this.schema = caseNode;
             validNames = new HashSet<>();
             validQNames = new HashSet<>();
@@ -491,6 +503,15 @@ public class LazyGeneratedCodecRegistry implements //
             augmenting = caseNode.isAugmenting();
         }
 
+        public ChoiceCaseCodecImpl() {
+            this.delegate = NOT_READY_CODEC;
+        }
+
+        public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) {
+            this.delegate = NOT_READY_CODEC;
+            setSchema(caseNode);
+        }
+
         @Override
         public ValueWithQName<T> deserialize(Node<?> input) {
             throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
index 7eb473ce3401a6774ed31f9690db658f24e4a576..cb25f4da8bb9247845c251ed95b67ee6ffeca4d5 100644 (file)
@@ -78,7 +78,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
         for (entry : newBinding.moduleContexts.entrySet) {
 
             registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
-
+            binding.pathToType.putAll(entry.value.childNodes)
             //val module = entry.key;
             val context = entry.value;
             updateBindingFor(context.childNodes, schemaContext);
@@ -174,16 +174,18 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer
     }
 
     private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
+        
         for (entry : map.entrySet) {
             val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
 
             //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
+            val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name)
+            typeToDefinition.put(typeRef, entry.value);
             if (schemaNode != null) {
-                val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name)
                 typeToSchemaNode.put(typeRef, schemaNode);
-                typeToDefinition.put(typeRef, entry.value);
                 updatePromisedSchemas(typeRef, schemaNode);
             }
+            
         }
     }
 
index a732f152b25675612a21a3a6aad503c5971dbdaa..0316614aa1269a93eb8d6aa3f7d2e3fd2a4438a7 100644 (file)
@@ -49,6 +49,8 @@ import static extension org.opendaylight.controller.sal.binding.impl.util.YangSc
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
 import org.opendaylight.yangtools.yang.model.util.ExtendedType
 import org.opendaylight.yangtools.yang.model.util.EnumerationType
+import static com.google.common.base.Preconditions.*
+import org.opendaylight.yangtools.yang.model.api.SchemaPath
 
 class TransformerGenerator {
 
@@ -78,6 +80,9 @@ class TransformerGenerator {
     @Property
     var Map<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
 
+    @Property
+    var Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap();
+
     @Property
     var Map<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
 
@@ -105,6 +110,27 @@ class TransformerGenerator {
             val ref = Types.typeForClass(inputType)
             val node = typeToSchemaNode.get(ref)
             val typeSpecBuilder = typeToDefinition.get(ref)
+            checkState(typeSpecBuilder !== null, "Could not find typedefinition for %s", inputType.name);
+            val typeSpec = typeSpecBuilder.toInstance();
+            val newret = generateTransformerFor(inputType, typeSpec, node);
+            listener.onClassProcessed(inputType);
+            return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+        ]
+    }
+
+    def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType, DataSchemaNode node) {
+        return withClassLoaderAndLock(inputType.classLoader, lock) [ |
+            val ret = getGeneratedClass(inputType)
+            if (ret !== null) {
+                listener.onClassProcessed(inputType);
+                return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
+            }
+            val ref = Types.typeForClass(inputType)
+            var typeSpecBuilder = typeToDefinition.get(ref)
+            if (typeSpecBuilder == null) {
+                typeSpecBuilder = pathToType.get(node.path);
+            }
+            checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node);
             val typeSpec = typeSpecBuilder.toInstance();
             val newret = generateTransformerFor(inputType, typeSpec, node);
             listener.onClassProcessed(inputType);
@@ -205,11 +231,9 @@ class TransformerGenerator {
         keyTransformerFor(cls, type, node);
     }
 
-    private def serializer(Type type) {
+    private def serializer(Type type, DataSchemaNode node) {
         val cls = loadClassWithTCCL(type.resolvedName);
-
-        transformerFor(cls);
-
+        transformerFor(cls, node);
     }
 
     private def Class<?> getValueSerializer(GeneratedTransferObject type) {
@@ -367,7 +391,7 @@ class TransformerGenerator {
             ]
 
             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)  as Class<? extends BindingCodec<Object, Object>>
-            listener?.onDataContainerCodecCreated(inputType,ret);
+            listener?.onDataContainerCodecCreated(inputType, ret);
             log.info("DOM Codec for {} was generated {}", inputType, ret)
             return ret;
         } catch (Exception e) {
@@ -710,7 +734,7 @@ class TransformerGenerator {
                 Object _listItem = _iterator.next();
                 _is_empty = false;
                 //System.out.println("  item" + _listItem);
-                Object _value = Â«type.actualTypeArguments.get(0).serializer.resolvedName».fromDomStatic(_localQName,_listItem);
+                Object _value = Â«type.actualTypeArguments.get(0).serializer(schema).resolvedName».fromDomStatic(_localQName,_listItem);
                 //System.out.println("  value" + _value);
                 Â«propertyName».add(_value);
                 _hasNext = _iterator.hasNext();
@@ -762,12 +786,12 @@ class TransformerGenerator {
         if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
             _is_empty = false;
             java.util.Map _dom_«propertyName» = (java.util.Map) _dom_«propertyName»_list.get(0);
-            Â«propertyName» =  Â«type.serializer.resolvedName».fromDomStatic(_localQName,_dom_«propertyName»);
+            Â«propertyName» =  Â«type.serializer(schema).resolvedName».fromDomStatic(_localQName,_dom_«propertyName»);
         }
     '''
 
     private def dispatch CharSequence deserializeProperty(ChoiceNode schema, Type type, String propertyName) '''
-        Â«type.resolvedName» Â«propertyName» = Â«type.serializer.resolvedName».fromDomStatic(_localQName,_compositeNode);
+        Â«type.resolvedName» Â«propertyName» = Â«type.serializer(schema).resolvedName».fromDomStatic(_localQName,_compositeNode);
         if(«propertyName» != null) {
             _is_empty = false;
         }
@@ -1140,7 +1164,7 @@ class TransformerGenerator {
             boolean _hasNext = _iterator.hasNext();
             while(_hasNext) {
                 Object _listItem = _iterator.next();
-                Object _domValue = Â«type.actualTypeArguments.get(0).serializer.resolvedName».toDomStatic(_resultName,_listItem);
+                Object _domValue = Â«type.actualTypeArguments.get(0).serializer(schema).resolvedName».toDomStatic(_resultName,_listItem);
                 _childNodes.add(_domValue);
                 _hasNext = _iterator.hasNext();
             }
@@ -1193,7 +1217,7 @@ class TransformerGenerator {
         String propertyName) '''
         Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
         if(«propertyName» != null) {
-            java.util.List domValue = Â«type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»);
+            java.util.List domValue = Â«type.serializer(container).resolvedName».toDomStatic(_resultName,«propertyName»);
             _childNodes.addAll(domValue);
         }
     '''
@@ -1219,7 +1243,7 @@ class TransformerGenerator {
         String propertyName) '''
         Â«type.resolvedName» Â«propertyName» = value.«propertyName»();
         if(«propertyName» != null) {
-            Object domValue = Â«type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»);
+            Object domValue = Â«type.serializer(container).resolvedName».toDomStatic(_resultName,«propertyName»);
             _childNodes.add(domValue);
         }
     '''
index 596329e07b1cdb23b2642d3f97e943aebcbf579a..d230fd17f9475c24bd920094a233734291593901 100644 (file)
@@ -7,9 +7,10 @@ import static com.google.common.base.Preconditions.*;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
+import com.google.common.base.Joiner;
 import com.google.common.base.Optional;
 
 public final class ClassLoaderUtils {
@@ -56,15 +57,28 @@ public final class ClassLoaderUtils {
         if ("byte[]".equals(name)) {
             return byte[].class;
         }
-
-        return Thread.currentThread().getContextClassLoader().loadClass(name);
+        try {
+            return Thread.currentThread().getContextClassLoader().loadClass(name);
+        } catch (ClassNotFoundException e) {
+            String[] components = name.split("\\.");
+            String potentialOuter;
+            int length = components.length;
+            if (length > 2 && (potentialOuter = components[length - 2]) != null && Character.isUpperCase(potentialOuter.charAt(0))) {
+                
+                    String outerName = Joiner.on(".").join(Arrays.asList(components).subList(0, length - 1));
+                    String innerName = outerName + "$" + components[length-1];
+                    return Thread.currentThread().getContextClassLoader().loadClass(innerName);
+            } else {
+                throw e;
+            }
+        }
     }
 
     public static Class<?> tryToLoadClassWithTCCL(String fullyQualifiedName) {
         try {
             return loadClassWithTCCL(fullyQualifiedName);
         } catch (ClassNotFoundException e) {
-            
+
         }
         return null;
     }
index c67a0176d2de550ed6287607b14b546df64d71f7..a7a70c2839ca848bae7a0e45adc702c620ec4bcb 100644 (file)
@@ -14,6 +14,8 @@ import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
+import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
+import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
 import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.core.api.data.DataStore;
@@ -37,117 +39,34 @@ public abstract class AbstractDataServiceTest {
 
     protected org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
     protected DataProviderService baDataService;
-
-    /**
-     * Workaround for JUNIT sharing classloaders
-     * 
-     */
-    protected static final ClassPool POOL = new ClassPool();
-
-    protected RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
     protected BindingIndependentMappingService mappingService;
-    protected DataBrokerImpl baDataImpl;
-    protected org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
-    protected ListeningExecutorService executor;
-    protected BindingIndependentDataServiceConnector connectorServiceImpl;
-    protected HashMapDataStore rawDataStore;
-    protected SchemaAwareDataStoreAdapter schemaAwareDataStore;
     private DataStoreStatsWrapper dataStoreStats;
-
     protected DataStore dataStore;
+    protected BindingTestContext testContext;
 
     @Before
     public void setUp() {
-        executor = MoreExecutors.sameThreadExecutor();
-        baDataImpl = new DataBrokerImpl();
-        baDataService = baDataImpl;
-        baDataImpl.setExecutor(executor);
-
-        biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
-        biDataService = biDataImpl;
-        biDataImpl.setExecutor(executor);
-
-        rawDataStore = new HashMapDataStore();
-        schemaAwareDataStore = new SchemaAwareDataStoreAdapter();
-        schemaAwareDataStore.changeDelegate(rawDataStore);
-        dataStoreStats = new DataStoreStatsWrapper(schemaAwareDataStore);
-        dataStore = dataStoreStats;
-
-        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-                .builder().toInstance();
-        biDataImpl.registerConfigurationReader(treeRoot, dataStore);
-        biDataImpl.registerOperationalReader(treeRoot, dataStore);
-        biDataImpl.registerCommitHandler(treeRoot, dataStore);
-
-        mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl();
-        mappingServiceImpl.setPool(POOL);
-        mappingService = mappingServiceImpl;
-        File pathname = new File("target/gen-classes-debug");
-        // System.out.println("Generated classes are captured in " +
-        // pathname.getAbsolutePath());
-        mappingServiceImpl.start(null);
-        // mappingServiceImpl.getBinding().setClassFileCapturePath(pathname);
-
-        connectorServiceImpl = new BindingIndependentDataServiceConnector();
-        connectorServiceImpl.setBaDataService(baDataService);
-        connectorServiceImpl.setBiDataService(biDataService);
-        connectorServiceImpl.setMappingService(mappingServiceImpl);
-        connectorServiceImpl.start();
-
-        String[] yangFiles = getModelFilenames();
-        if (yangFiles != null && yangFiles.length > 0) {
-            SchemaContext context = getContext(yangFiles);
-            mappingServiceImpl.onGlobalContextUpdated(context);
-            schemaAwareDataStore.onGlobalContextUpdated(context);
-        }
+        ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
+        BindingBrokerTestFactory factory = new BindingBrokerTestFactory();
+        factory.setExecutor(executor);
+        factory.setStartWithParsedSchema(getStartWithSchema());
+        testContext = factory.getTestContext();
+        testContext.start();
+        
+        baDataService = testContext.getBindingDataBroker();
+        biDataService = testContext.getDomDataBroker();
+        dataStore = testContext.getDomDataStore();
+        mappingService = testContext.getBindingToDomMappingService();
     }
 
-    protected String[] getModelFilenames() {
-        return getAllModelFilenames();
-    }
-
-    public static String[] getAllModelFilenames() {
-        Predicate<String> predicate = new Predicate<String>() {
-            @Override
-            public boolean apply(String input) {
-                return input.endsWith(".yang");
-            }
-        };
-        Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner());
-        Set<String> result = reflection.getResources(predicate);
-        return (String[]) result.toArray(new String[result.size()]);
-    }
-
-    public static SchemaContext getContext(String[] yangFiles) {
-
-        ClassLoader loader = AbstractDataServiceTest.class.getClassLoader();
-
-        List<InputStream> streams = new ArrayList<>();
-        for (String string : yangFiles) {
-            InputStream stream = loader.getResourceAsStream(string);
-            streams.add(stream);
-
-        }
-        YangParserImpl parser = new YangParserImpl();
-
-        Set<Module> modules = parser.parseYangModelsFromStreams(streams);
-        return parser.resolveSchemaContext(modules);
+    protected boolean getStartWithSchema() {
+        return true;
     }
 
     @After
     public void afterTest() {
 
-        log.info("BIDataStore Statistics: Configuration Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
-                dataStoreStats.getConfigurationReadCount(), dataStoreStats.getConfigurationReadTotalTime(),
-                dataStoreStats.getConfigurationReadAverageTime());
-
-        log.info("BIDataStore Statistics: Operational Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
-                dataStoreStats.getOperationalReadCount(), dataStoreStats.getOperationalReadTotalTime(),
-                dataStoreStats.getOperationalReadAverageTime());
-
-        log.info("BIDataStore Statistics: Request Commit Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
-                dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
-                dataStoreStats.getRequestCommitAverageTime());
+        testContext.logDataStoreStatistics();
 
     }
 }
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java
new file mode 100644 (file)
index 0000000..bad485e
--- /dev/null
@@ -0,0 +1,59 @@
+package org.opendaylight.controller.sal.binding.test.util;
+
+import java.util.concurrent.ExecutorService;
+
+import javassist.ClassPool;
+
+import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
+import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class BindingBrokerTestFactory {
+
+    private static final ClassPool CLASS_POOL = new ClassPool();
+    private boolean startWithParsedSchema = true;
+    private ExecutorService executor;
+    private ClassPool classPool;
+
+    
+    public boolean isStartWithParsedSchema() {
+        return startWithParsedSchema;
+    }
+
+    public void setStartWithParsedSchema(boolean startWithParsedSchema) {
+        this.startWithParsedSchema = startWithParsedSchema;
+    }
+
+    public ExecutorService getExecutor() {
+        return executor;
+    }
+
+    public void setExecutor(ExecutorService executor) {
+        this.executor = executor;
+    }
+
+
+    public BindingTestContext getTestContext() {
+        Preconditions.checkState(executor != null, "Executor is not set.");
+        ListeningExecutorService listenableExecutor = MoreExecutors.listeningDecorator(executor);
+        return new BindingTestContext(listenableExecutor, getClassPool(),startWithParsedSchema);
+    }
+
+    public ClassPool getClassPool() {
+        if(classPool == null) {
+            return CLASS_POOL;
+        }
+        
+        return classPool;
+    }
+
+    public void setClassPool(ClassPool classPool) {
+        this.classPool = classPool;
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java
new file mode 100644 (file)
index 0000000..4e611c5
--- /dev/null
@@ -0,0 +1,199 @@
+package org.opendaylight.controller.sal.binding.test.util;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javassist.ClassPool;
+
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
+import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.reflections.Reflections;
+import org.reflections.scanners.ResourcesScanner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import static com.google.common.base.Preconditions.*;
+
+public class BindingTestContext {
+    
+    
+    public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+            .builder().toInstance();
+
+    private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class);
+    
+    private RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
+    private DataBrokerImpl baDataImpl;
+    private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
+    
+    private BindingIndependentDataServiceConnector connectorServiceImpl;
+    private HashMapDataStore rawDataStore;
+    private SchemaAwareDataStoreAdapter schemaAwareDataStore;
+    private DataStoreStatsWrapper dataStoreStats;
+    private DataStore dataStore;
+
+    
+    private boolean dataStoreStatisticsEnabled = false;
+    
+    private final ListeningExecutorService executor;
+    private final ClassPool classPool;
+
+    private final boolean startWithSchema;
+    
+    protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) {
+        this.executor = executor;
+        this.classPool = classPool;
+        this.startWithSchema = startWithSchema;
+    }
+
+    public void startDomDataStore() {
+        checkState(dataStore == null, "DataStore already started.");
+        checkState(biDataImpl != null, "Dom Data Broker not present");
+        rawDataStore = new HashMapDataStore();
+        schemaAwareDataStore = new SchemaAwareDataStoreAdapter();
+        schemaAwareDataStore.changeDelegate(rawDataStore);
+        if(dataStoreStatisticsEnabled) {
+        dataStoreStats = new DataStoreStatsWrapper(schemaAwareDataStore);
+        dataStore = dataStoreStats;
+        } else {
+            dataStore = schemaAwareDataStore;
+        }
+        
+        biDataImpl.registerConfigurationReader(TREE_ROOT, dataStore);
+        biDataImpl.registerOperationalReader(TREE_ROOT, dataStore);
+        biDataImpl.registerCommitHandler(TREE_ROOT, dataStore);
+    }
+    
+    public void startDomDataBroker() {
+        checkState(executor != null,"Executor needs to be set");
+        biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
+        biDataImpl.setExecutor(executor);
+    }
+    
+    public void startBindingDataBroker() {
+        checkState(executor != null,"Executor needs to be set");
+        baDataImpl = new DataBrokerImpl();
+        baDataImpl.setExecutor(executor);
+    }
+    
+    public void startBindingToDomDataConnector() {
+        checkState(baDataImpl != null,"Binding Data Broker needs to be started");
+        checkState(biDataImpl != null,"DOM Data Broker needs to be started.");
+        checkState(mappingServiceImpl != null,"DOM Mapping Service needs to be started.");
+        connectorServiceImpl = new BindingIndependentDataServiceConnector();
+        connectorServiceImpl.setBaDataService(baDataImpl);
+        connectorServiceImpl.setBiDataService(biDataImpl);
+        connectorServiceImpl.setMappingService(mappingServiceImpl);
+        connectorServiceImpl.start();
+    }
+    
+    public void startBindingToDomMappingService() {
+        checkState(classPool != null,"ClassPool needs to be present");
+        mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl();
+        mappingServiceImpl.setPool(classPool);
+        mappingServiceImpl.start(null);
+    }
+    
+    
+    public void updateYangSchema(String[] files) {
+        SchemaContext context = getContext(files);
+        if(schemaAwareDataStore != null) {
+            schemaAwareDataStore.onGlobalContextUpdated(context);
+        }
+        if(mappingServiceImpl != null) {
+            mappingServiceImpl.onGlobalContextUpdated(context);
+        }
+    }
+    
+    
+    public static String[] getAllYangFilesOnClasspath() {
+        Predicate<String> predicate = new Predicate<String>() {
+            @Override
+            public boolean apply(String input) {
+                return input.endsWith(".yang");
+            }
+        };
+        Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner());
+        Set<String> result = reflection.getResources(predicate);
+        return (String[]) result.toArray(new String[result.size()]);
+    }
+    
+    private static SchemaContext getContext(String[] yangFiles) {
+        ClassLoader loader = BindingTestContext.class.getClassLoader();
+        List<InputStream> streams = new ArrayList<>();
+        for (String string : yangFiles) {
+            InputStream stream = loader.getResourceAsStream(string);
+            streams.add(stream);
+        }
+        YangParserImpl parser = new YangParserImpl();
+        Set<Module> modules = parser.parseYangModelsFromStreams(streams);
+        return parser.resolveSchemaContext(modules);
+    }
+    
+    public void start() {
+        startBindingDataBroker();
+        startDomDataBroker();
+        startDomDataStore();
+        startBindingToDomMappingService();
+        startBindingToDomDataConnector();
+        if(startWithSchema) {
+            loadYangSchemaFromClasspath();
+        }
+    }
+
+    public void loadYangSchemaFromClasspath() {
+        String[] files = getAllYangFilesOnClasspath();
+        updateYangSchema(files);
+    }
+
+    public DataProviderService getBindingDataBroker() {
+        return baDataImpl;
+    }
+
+    public org.opendaylight.controller.sal.core.api.data.DataProviderService getDomDataBroker() {
+        return biDataImpl;
+    }
+
+    public DataStore getDomDataStore() {
+        return dataStore;
+    }
+
+    public BindingIndependentMappingService getBindingToDomMappingService() {
+        return mappingServiceImpl;
+    }
+
+    public void logDataStoreStatistics() {
+        if(dataStoreStats == null) {
+            return;
+        }
+        
+        LOG.info("BIDataStore Statistics: Configuration Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
+                dataStoreStats.getConfigurationReadCount(), dataStoreStats.getConfigurationReadTotalTime(),
+                dataStoreStats.getConfigurationReadAverageTime());
+
+        LOG.info("BIDataStore Statistics: Operational Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
+                dataStoreStats.getOperationalReadCount(), dataStoreStats.getOperationalReadTotalTime(),
+                dataStoreStats.getOperationalReadAverageTime());
+
+        LOG.info("BIDataStore Statistics: Request Commit Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
+                dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
+                dataStoreStats.getRequestCommitAverageTime());
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-dom-it/pom.xml b/opendaylight/md-sal/sal-binding-dom-it/pom.xml
new file mode 100644 (file)
index 0000000..9a143d3
--- /dev/null
@@ -0,0 +1,82 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-parent</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>sal-binding-dom-it</artifactId>
+    <packaging>bundle</packaging>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+    </scm>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.eclipse.xtend</groupId>
+                <artifactId>xtend-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <configuration>
+                    <includes>org.opendaylight.controller.*</includes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>pre-test</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>post-test</id>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+    <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-broker-impl</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-broker-impl</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-flow-service</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-flow-management</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+    </dependencies>
+</project>
@@ -53,11 +53,6 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
             .toInstance();
     private static final NodeRef NODE_REF = new NodeRef(NODE_INSTANCE_ID_BA);
 
-    @Override
-    protected String[] getModelFilenames() {
-        return null;
-    }
-
     /**
      * 
      * 
@@ -79,9 +74,7 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
             }
         });
         
-        SchemaContext ctx = getContext(getAllModelFilenames());
-        schemaAwareDataStore.onGlobalContextUpdated(ctx);
-        mappingServiceImpl.onGlobalContextUpdated(ctx);
+        testContext.loadYangSchemaFromClasspath();
         RpcResult<TransactionStatus> result = future.get().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
         
@@ -95,5 +88,10 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
         return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
 
     }
+    
+    @Override
+    protected boolean getStartWithSchema() {
+        return false;
+    }
 
 }
index 27d426791f5c65f6fe01aac0a5e51fb2228b1032..6a994dbd07c6295d9284bfae5bf270523c4e8785 100644 (file)
         </pluginManagement>
     </build>
 
+
     <dependencies>
         <dependency>
             <groupId>org.opendaylight.yangtools.thirdparty</groupId>
index da47438a6bb4a282045bb3fe44cd15863b9c3b03..32e59b869e20de484e4f1c27028698e1d8b05a49 100644 (file)
@@ -345,10 +345,19 @@ public abstract class AbstractDataTransaction<P extends Path<P>, D> extends Abst
     }\r
 \r
     override readConfigurationData(P path) {\r
+        val local = this.updatedConfigurationData.get(path);\r
+        if(local != null) {\r
+            return local;\r
+        }\r
+        \r
         return broker.readConfigurationData(path);\r
     }\r
 \r
     override readOperationalData(P path) {\r
+        val local = this.updatedOperationalData.get(path);\r
+        if(local != null) {\r
+            return local;\r
+        }\r
         return broker.readOperationalData(path);\r
     }\r
 \r