You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by js...@apache.org on 2008/08/12 16:51:55 UTC

svn commit: r685172 - in /activemq/camel/trunk: camel-core/src/main/java/org/apache/camel/ camel-core/src/main/java/org/apache/camel/component/bean/ camel-core/src/test/java/org/apache/camel/component/bean/ components/camel-spring/src/test/java/org/apa...

Author: jstrachan
Date: Tue Aug 12 07:51:54 2008
New Revision: 685172

URL: http://svn.apache.org/viewvc?rev=685172&view=rev
Log:
improved version of CAMEL-810 which uses simpler annotations of @InOnly or @InOut based on Claus's great feedback

Added:
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOnly.java   (contents, props changed)
      - copied, changed from r684887, activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/OneWay.java
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOut.java   (with props)
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/Pattern.java   (contents, props changed)
      - copied, changed from r684887, activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/OneWay.java
Removed:
    activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoTestTest.java
Modified:
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
    activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoTest.java
    activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/remoting/IAsyncService.java

Copied: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOnly.java (from r684887, activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/OneWay.java)
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOnly.java?p2=activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOnly.java&p1=activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/OneWay.java&r1=684887&r2=685172&rev=685172&view=diff
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/OneWay.java (original)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOnly.java Tue Aug 12 07:51:54 2008
@@ -22,53 +22,26 @@
 import java.lang.annotation.Target;
 
 /**
- * Marks a method as being a one way asynchronous invocation so that if you are using some kind of
- * <a href="http://activemq.apache.org/camel/spring-remoting.html">Spring Remoting</a> then the method invocation will be asynchronous.
- * <p>
- * You can then either annotate specific methods as being oneway as follows
- *
- * <code><pre> &#64;OneWay
- * public void myMethod() {...}</pre></code>
- *
- * or you can say that all methods are by default asynchronous on an interface by annotating the interface
- *
- * <code><pre> &#64;OneWay
- * public interface Foo {
- *   void methodOne();
- *   void methodTwo();
- * }</pre></code>
- *
- * If you wish to use some other {@link ExchangePattern} than {@link org.apache.camel.ExchangePattern#InOnly} you could use something like
- *
- * <code><pre> &#64;OneWay(ExchangePattern.RobustInOnly)
- * public void myMethod() {...}</pre></code>
- * otherwise the following code would default to using {@link org.apache.camel.ExchangePattern#InOnly}
- * <code><pre> &#64;OneWay
- * public void myMethod() {...}</pre></code>
- *
- * <p>
- * You can also use the annotation on a method to override the annoation on the class as follows...
- * <code><pre> &#64;OneWay
- * public interface Foo {
- *   void methodOne();
- *
- *   &#64;OneWay(ExchangePattern.InOut)
- *   void notOneWayMethod();
- * }</pre></code>
- *
- * Where the <b>notOneWayMethod</b> will not be using one way invocation while all other methods will inherit the InOut exchange pattern
- * @see ExchangePattern
- * @see Exchange#getPattern()
+ * Marks methods as being {@link ExchangePattern#InOnly}
+ * for one way asynchronous invocation when using
+ * <a href="http://activemq.apache.org/camel/bean-integration.html">Bean Integration</a> or
+ * <a href="http://activemq.apache.org/camel/spring-remoting.html">Spring Remoting</a>
+ * to overload the default value which is {@link ExchangePattern#InOut} for request/reply if no annotations are used.
+ *
+ * This annotation can be added to individual methods or added to a class or interface to act as a default for all methods
+ * within the class or interface.
+ *
+ * See the <a href="using-exchange-pattern-annotations.html">using exchange pattern annotations</a>
+ * for more details on how the overloading rules work.
+ *
+ * @see org.apache.camel.ExchangePattern
+ * @see org.apache.camel.Exchange#getPattern()
+ * @see InOut
  *
  * @version $Revision$
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE, ElementType.METHOD})
-public @interface OneWay {
-
-    /**
-     * Allows the exact exchange pattern type to be specified though the default value of
-     * {@link org.apache.camel.ExchangePattern#InOnly} should be fine for most uses
-     */
-    public abstract ExchangePattern value() default ExchangePattern.InOnly;
+@Pattern(ExchangePattern.InOnly)
+public @interface InOnly {
 }
\ No newline at end of file

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOnly.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOnly.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOnly.java
------------------------------------------------------------------------------
    svn:mergeinfo = 

Added: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOut.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOut.java?rev=685172&view=auto
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOut.java (added)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOut.java Tue Aug 12 07:51:54 2008
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a method as being {@link ExchangePattern#InOut} when a class or interface has been annotated with
+ * {@link InOnly} when using
+ * <a href="http://activemq.apache.org/camel/bean-integration.html">Bean Integration</a> or
+ * <a href="http://activemq.apache.org/camel/spring-remoting.html">Spring Remoting</a>.
+ *
+ * This annotation is only intended to be used on methods which the class or interface has been annotated with
+ * a default exchange pattern annotation such as {@link InOnly} or {@link Pattern}
+ *
+ * See the <a href="using-exchange-pattern-annotations.html">using exchange pattern annotations</a>
+ * for more details on how the overloading rules work.
+ *
+ * @see org.apache.camel.ExchangePattern
+ * @see org.apache.camel.Exchange#getPattern()
+ * @see InOut
+ *
+ * @version $Revision: 684887 $
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Pattern(ExchangePattern.InOut)
+public @interface InOut {
+}
\ No newline at end of file

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/InOut.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/Pattern.java (from r684887, activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/OneWay.java)
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/Pattern.java?p2=activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/Pattern.java&p1=activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/OneWay.java&r1=684887&r2=685172&rev=685172&view=diff
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/OneWay.java (original)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/Pattern.java Tue Aug 12 07:51:54 2008
@@ -22,41 +22,24 @@
 import java.lang.annotation.Target;
 
 /**
- * Marks a method as being a one way asynchronous invocation so that if you are using some kind of
- * <a href="http://activemq.apache.org/camel/spring-remoting.html">Spring Remoting</a> then the method invocation will be asynchronous.
- * <p>
- * You can then either annotate specific methods as being oneway as follows
+ * Marks a method as having a specific kind of {@link ExchangePattern} for use with
+ * <a href="http://activemq.apache.org/camel/bean-integration.html">Bean Integration</a> or
+ * <a href="http://activemq.apache.org/camel/spring-remoting.html">Spring Remoting</a>
+ * to overload the default value which is {@link ExchangePattern#InOut} for request/reply if no annotations are used.
+ *
+ * There are abbreviation annotations like {@link InOnly} or {@link InOut} which are typically used for
+ * the common message exchange patterns. You could also add this annotation onto your own custom annotation to default
+ * the message exchange pattern when your own annotation is added to a method
+ * <a href="using-exchange-pattern-annotations.html">as in this example</a>.
  *
- * <code><pre> &#64;OneWay
- * public void myMethod() {...}</pre></code>
+ * This annotation can be added to individual methods or added to a class or interface to act as a default for all methods
+ * within the class or interface.
  *
- * or you can say that all methods are by default asynchronous on an interface by annotating the interface
+ * See the <a href="using-exchange-pattern-annotations.html">using exchange pattern annotations</a>
+ * for more details on how the overloading rules work.
  *
- * <code><pre> &#64;OneWay
- * public interface Foo {
- *   void methodOne();
- *   void methodTwo();
- * }</pre></code>
- *
- * If you wish to use some other {@link ExchangePattern} than {@link org.apache.camel.ExchangePattern#InOnly} you could use something like
- *
- * <code><pre> &#64;OneWay(ExchangePattern.RobustInOnly)
- * public void myMethod() {...}</pre></code>
- * otherwise the following code would default to using {@link org.apache.camel.ExchangePattern#InOnly}
- * <code><pre> &#64;OneWay
- * public void myMethod() {...}</pre></code>
- *
- * <p>
- * You can also use the annotation on a method to override the annoation on the class as follows...
- * <code><pre> &#64;OneWay
- * public interface Foo {
- *   void methodOne();
- *
- *   &#64;OneWay(ExchangePattern.InOut)
- *   void notOneWayMethod();
- * }</pre></code>
- *
- * Where the <b>notOneWayMethod</b> will not be using one way invocation while all other methods will inherit the InOut exchange pattern
+ * @see InOut
+ * @see InOnly
  * @see ExchangePattern
  * @see Exchange#getPattern()
  *
@@ -64,11 +47,10 @@
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE, ElementType.METHOD})
-public @interface OneWay {
+public @interface Pattern {
 
     /**
-     * Allows the exact exchange pattern type to be specified though the default value of
-     * {@link org.apache.camel.ExchangePattern#InOnly} should be fine for most uses
+     * Specifies the exchange pattern to be used for this method
      */
-    public abstract ExchangePattern value() default ExchangePattern.InOnly;
+    public abstract ExchangePattern value();
 }
\ No newline at end of file

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/Pattern.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/Pattern.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/Pattern.java
------------------------------------------------------------------------------
    svn:mergeinfo = 

Modified: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java?rev=685172&r1=685171&r2=685172&view=diff
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java (original)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java Tue Aug 12 07:51:54 2008
@@ -19,16 +19,20 @@
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.annotation.Annotation;
 import java.util.Arrays;
 import java.util.List;
+import java.util.ArrayList;
 
 import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.Expression;
-import org.apache.camel.OneWay;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Pattern;
 import org.apache.camel.util.ExchangeHelper;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
 /**
  * Information about a method to be used for invocation.
@@ -36,6 +40,8 @@
  * @version $Revision$
  */
 public class MethodInfo {
+    private static final transient Log LOG = LogFactory.getLog(MethodInfo.class);
+
     private Class type;
     private Method method;
     private final List<ParameterInfo> parameters;
@@ -51,7 +57,7 @@
         this.bodyParameters = bodyParameters;
         this.hasCustomAnnotation = hasCustomAnnotation;
         this.parametersExpression = createParametersExpression();
-        OneWay oneway = findOneWayAnnotation(method);
+        Pattern oneway = findOneWayAnnotation(method);
         if (oneway != null) {
             pattern = oneway.value();
         }
@@ -96,7 +102,7 @@
 
     /**
      * Returns the {@link org.apache.camel.ExchangePattern} that should be used when invoking this method. This value
-     * defaults to {@link org.apache.camel.ExchangePattern#InOut} unless some {@link OneWay} annotation is used
+     * defaults to {@link org.apache.camel.ExchangePattern#InOut} unless some {@link org.apache.camel.Pattern} annotation is used
      * to override the message exchange pattern.
      *
      * @return the exchange pattern to use for invoking this method.
@@ -187,8 +193,8 @@
      * @param method the method on which to search
      * @return the first matching annotation or none if it is not available
      */
-    protected OneWay findOneWayAnnotation(Method method) {
-        OneWay answer = method.getAnnotation(OneWay.class);
+    protected Pattern findOneWayAnnotation(Method method) {
+        Pattern answer = getPatternAnnotation(method);
         if (answer == null) {
             Class<?> type = method.getDeclaringClass();
 
@@ -202,7 +208,7 @@
 
             // now lets scan for a type which the current declared class overloads
             answer = findOneWayAnnotationOnMethod(typesToSearch, method);
-            if (answer == null) {
+            if (answer == null ){
                 answer = findOneWayAnnotation(typesToSearch);
             }
         }
@@ -210,6 +216,50 @@
     }
 
     /**
+     * Returns the pattern annotation on the given annotated element; either as a direct annotation or
+     * on an annotation which is also annotated
+     *
+     * @param annotatedElement the element to look for the annotation
+     * @return the first matching annotation or null if none could be found
+     */
+    protected Pattern getPatternAnnotation(AnnotatedElement annotatedElement) {
+        return getPatternAnnotation(annotatedElement, 2);
+    }
+
+    /**
+     * Returns the pattern annotation on the given annotated element; either as a direct annotation or
+     * on an annotation which is also annotated
+     *
+     * @param annotatedElement the element to look for the annotation
+     * @return the first matching annotation or null if none could be found
+     */
+    protected Pattern getPatternAnnotation(AnnotatedElement annotatedElement, int depth) {
+        Pattern answer = annotatedElement.getAnnotation(Pattern.class);
+        int nextDepth = depth - 1;
+
+        if (nextDepth > 0) {
+            // lets look at all the annotations to see if any of those are annotated
+            Annotation[] annotations = annotatedElement.getAnnotations();
+            for (Annotation annotation : annotations) {
+                Class<? extends Annotation> annotationType = annotation.annotationType();
+                if (annotation instanceof Pattern || annotationType.equals(annotatedElement)) {
+                    continue;
+                } else {
+                    Pattern another = getPatternAnnotation(annotationType, nextDepth);
+                    if (pattern != null) {
+                        if (answer == null) {
+                            answer = another;
+                        } else {
+                            LOG.warn("Duplicate pattern annotation: " + another + " found on annotation: " + annotation + " which will be ignored");
+                        }
+                    }
+                }
+            }
+        }
+        return answer;
+    }
+
+    /**
      * Adds the current class and all of its base classes (apart from {@link Object} to the given list
      * @param type
      * @param result
@@ -223,11 +273,11 @@
     /**
      * Finds the first annotation on the base methods defined in the list of classes
      */
-    protected OneWay findOneWayAnnotationOnMethod(List<Class<?>> classes, Method method) {
+    protected Pattern findOneWayAnnotationOnMethod(List<Class<?>> classes, Method method) {
         for (Class<?> type : classes) {
             try {
                 Method definedMethod = type.getMethod(method.getName(), method.getParameterTypes());
-                OneWay answer = definedMethod.getAnnotation(OneWay.class);
+                Pattern answer = getPatternAnnotation(definedMethod);
                 if (answer != null) {
                     return answer;
                 }
@@ -242,9 +292,9 @@
     /**
      * Finds the first annotation on the given list of classes
      */
-    protected OneWay findOneWayAnnotation(List<Class<?>> classes) {
+    protected Pattern findOneWayAnnotation(List<Class<?>> classes) {
         for (Class<?> type : classes) {
-            OneWay answer = type.getAnnotation(OneWay.class);
+            Pattern answer = getPatternAnnotation(type);
             if (answer != null) {
                 return answer;
             }

Modified: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoTest.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoTest.java?rev=685172&r1=685171&r2=685172&view=diff
==============================================================================
--- activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoTest.java (original)
+++ activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/component/bean/BeanInfoTest.java Tue Aug 12 07:51:54 2008
@@ -1,4 +1,5 @@
 /**
+ *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -6,7 +7,7 @@
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,16 +17,14 @@
  */
 package org.apache.camel.component.bean;
 
-import java.lang.reflect.Method;
-
 import junit.framework.TestCase;
-import org.apache.camel.CamelContext;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.OneWay;
+import org.apache.camel.*;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import java.lang.reflect.Method;
+
 /**
  * @version $Revision: 1.1 $
  */
@@ -53,6 +52,7 @@
 
         assertMethodPattern(info, "inOnlyMethod", ExchangePattern.InOnly);
         assertMethodPattern(info, "robustInOnlyMethod", ExchangePattern.RobustInOnly);
+        assertMethodPattern(info, "inOutMethod", ExchangePattern.InOut);
     }
 
     public void testMethodPatternUsingClassAnnotationsButOverloadingOnMethod() throws Exception {
@@ -81,6 +81,7 @@
 
         assertMethodPattern(info, "inOnlyMethod", ExchangePattern.InOnly);
         assertMethodPattern(info, "robustInOnlyMethod", ExchangePattern.RobustInOnly);
+        assertMethodPattern(info, "inOutMethod", ExchangePattern.InOut);
     }
 
     protected BeanInfo createBeanInfo(Class type) {
@@ -103,26 +104,29 @@
     }
 
     public interface Foo {
-        void inOutMethod();
+        public void inOutMethod();
 
-        @OneWay
-        void inOnlyMethod();
+        @Pattern(ExchangePattern.InOnly)
+        public void inOnlyMethod();
 
-        @OneWay(ExchangePattern.RobustInOnly)
-        void robustInOnlyMethod();
+        @Pattern(ExchangePattern.RobustInOnly)
+        public void robustInOnlyMethod();
     }
 
-    @OneWay
+    @InOnly
     public interface MyOneWayInterface {
-        void inOnlyMethod();
+        public void inOnlyMethod();
     }
 
-    @OneWay
+    @InOnly
     public interface MyOneWayInterfaceWithOverloadedMethod {
-        void inOnlyMethod();
+        public void inOnlyMethod();
+
+        @Pattern(ExchangePattern.RobustInOnly)
+        public void robustInOnlyMethod();
 
-        @OneWay(ExchangePattern.RobustInOnly)
-        void robustInOnlyMethod();
+        @InOut
+        public Object inOutMethod();
     }
 
     public static class OverloadOnMethod implements MyOneWayInterface {
@@ -130,7 +134,7 @@
         public void inOnlyMethod() {
         }
 
-        @OneWay(ExchangePattern.RobustInOnly)
+        @Pattern(ExchangePattern.RobustInOnly)
         public void robustInOnlyMethod() {
         }
     }
@@ -147,6 +151,10 @@
 
         public void robustInOnlyMethod() {
         }
+
+        public Object inOutMethod() {
+            return null;
+        }
     }
 
 }

Modified: activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/remoting/IAsyncService.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/remoting/IAsyncService.java?rev=685172&r1=685171&r2=685172&view=diff
==============================================================================
--- activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/remoting/IAsyncService.java (original)
+++ activemq/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/remoting/IAsyncService.java Tue Aug 12 07:51:54 2008
@@ -16,12 +16,12 @@
  */
 package org.apache.camel.spring.remoting;
 
-import org.apache.camel.OneWay;
+import org.apache.camel.InOnly;
 
 /**
- * A dummy interface which has a oneway method via the {@link org.apache.camel.OneWay} annotation
+ * A dummy interface which has a oneway method via the {@link InOnly} annotation
  */
 public interface IAsyncService {
-    @OneWay
+    @InOnly
     void doSomethingAsync(String body);
 }
\ No newline at end of file