hivemind-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ahue...@apache.org
Subject svn commit: r513812 - in /hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations: definition/impl/ definition/processors/ internal/
Date Fri, 02 Mar 2007 15:32:10 GMT
Author: ahuegen
Date: Fri Mar  2 07:32:09 2007
New Revision: 513812

URL: http://svn.apache.org/viewvc?view=rev&rev=513812
Log:
Annotation processing factored out for easy support of custom annotations

Added:
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/impl/
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/impl/AnnotatedModuleDefinitionImpl.java
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessingContext.java
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessor.java
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/ServiceProcessor.java
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessingContextImpl.java
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessorRegistry.java
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/CheckTools.java
Modified:
    hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotatedModuleProcessor.java

Added: hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/impl/AnnotatedModuleDefinitionImpl.java
URL: http://svn.apache.org/viewvc/hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/impl/AnnotatedModuleDefinitionImpl.java?view=auto&rev=513812
==============================================================================
--- hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/impl/AnnotatedModuleDefinitionImpl.java
(added)
+++ hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/impl/AnnotatedModuleDefinitionImpl.java
Fri Mar  2 07:32:09 2007
@@ -0,0 +1,20 @@
+package org.apache.hivemind.annotations.definition.impl;
+
+import org.apache.hivemind.ClassResolver;
+import org.apache.hivemind.Location;
+import org.apache.hivemind.definition.impl.ModuleDefinitionImpl;
+
+public class AnnotatedModuleDefinitionImpl extends ModuleDefinitionImpl
+{
+
+    public AnnotatedModuleDefinitionImpl(String id, Location location, ClassResolver resolver,
String packageName)
+    {
+        super(id, location, resolver, packageName);
+    }
+
+    public AnnotatedModuleDefinitionImpl(String id, Location location)
+    {
+        super(id, location);
+    }
+
+}

Added: hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessingContext.java
URL: http://svn.apache.org/viewvc/hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessingContext.java?view=auto&rev=513812
==============================================================================
--- hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessingContext.java
(added)
+++ hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessingContext.java
Fri Mar  2 07:32:09 2007
@@ -0,0 +1,18 @@
+package org.apache.hivemind.annotations.definition.processors;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+
+import org.apache.hivemind.Location;
+import org.apache.hivemind.annotations.definition.impl.AnnotatedModuleDefinitionImpl;
+import org.apache.hivemind.annotations.internal.ModuleInstanceProvider;
+
+public interface AnnotationProcessingContext
+{
+    public AnnotatedElement getAnnotatedElement();
+    public Annotation getTargetAnnotation();
+    public Annotation[] getAllAnnotations();
+    public Location getLocation();
+    public AnnotatedModuleDefinitionImpl getModule(); 
+    public ModuleInstanceProvider getModuleInstanceProvider();
+}

Added: hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessor.java
URL: http://svn.apache.org/viewvc/hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessor.java?view=auto&rev=513812
==============================================================================
--- hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessor.java
(added)
+++ hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/AnnotationProcessor.java
Fri Mar  2 07:32:09 2007
@@ -0,0 +1,13 @@
+package org.apache.hivemind.annotations.definition.processors;
+
+import org.apache.hivemind.ApplicationRuntimeException;
+
+public interface AnnotationProcessor
+{
+    /**
+     * @param context
+     * @return true if annotation has been processed. Used for chaining.
+     * @throws ApplicationRuntimeException  if annotation can not be processed due to inconsistent
data. 
+     */
+    public boolean processAnnotation(AnnotationProcessingContext context) throws ApplicationRuntimeException;
+}

Added: hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/ServiceProcessor.java
URL: http://svn.apache.org/viewvc/hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/ServiceProcessor.java?view=auto&rev=513812
==============================================================================
--- hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/ServiceProcessor.java
(added)
+++ hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/definition/processors/ServiceProcessor.java
Fri Mar  2 07:32:09 2007
@@ -0,0 +1,59 @@
+package org.apache.hivemind.annotations.definition.processors;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hivemind.Location;
+import org.apache.hivemind.annotations.definition.Service;
+import org.apache.hivemind.annotations.definition.impl.AnnotatedModuleDefinitionImpl;
+import org.apache.hivemind.annotations.internal.AnnotatedModuleLocation;
+import org.apache.hivemind.annotations.internal.CheckTools;
+import org.apache.hivemind.annotations.internal.MethodCallImplementationConstructor;
+import org.apache.hivemind.definition.ImplementationConstructor;
+import org.apache.hivemind.definition.ImplementationDefinition;
+import org.apache.hivemind.definition.Visibility;
+import org.apache.hivemind.definition.impl.ImplementationDefinitionImpl;
+import org.apache.hivemind.definition.impl.ServicePointDefinitionImpl;
+
+public class ServiceProcessor implements AnnotationProcessor
+{
+    private static final Log _log = LogFactory.getLog(ServiceProcessor.class);
+
+    /**
+     * @see org.apache.hivemind.annotations.definition.processors.AnnotationProcessor#processAnnotation(org.apache.hivemind.annotations.definition.processors.AnnotationProcessingContext)
+     */
+    public boolean processAnnotation(AnnotationProcessingContext context)
+    {
+        Method method = (Method) context.getAnnotatedElement();
+        AnnotatedModuleDefinitionImpl module = context.getModule();
+        Service serviceAnnotation = (Service) context.getTargetAnnotation(); 
+        
+        CheckTools.checkMethodModifiers(method, 0, "service point");
+        
+        if (_log.isDebugEnabled())
+        {
+            _log.debug("Method " + method.getName() + "classified as service point.");
+        }
+        
+        Visibility visibility = Visibility.PUBLIC;
+        if (Modifier.isProtected(method.getModifiers())) {
+            visibility = Visibility.PRIVATE;
+        }
+        ServicePointDefinitionImpl spd = new ServicePointDefinitionImpl(module, serviceAnnotation.id(),
context.getLocation(), 
+                visibility, method.getReturnType().getName());
+        module.addServicePoint(spd);
+
+        ImplementationConstructor constructor = new MethodCallImplementationConstructor(context.getLocation(),

+                method, context.getModuleInstanceProvider());
+
+        ImplementationDefinition sid = new ImplementationDefinitionImpl(module, context.getLocation(),

+                constructor, serviceAnnotation.serviceModel(), true);
+
+        spd.addImplementation(sid);
+
+        return true;
+    }
+
+}

Modified: hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotatedModuleProcessor.java
URL: http://svn.apache.org/viewvc/hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotatedModuleProcessor.java?view=diff&rev=513812&r1=513811&r2=513812
==============================================================================
--- hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotatedModuleProcessor.java
(original)
+++ hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotatedModuleProcessor.java
Fri Mar  2 07:32:09 2007
@@ -17,6 +17,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -30,6 +31,10 @@
 import org.apache.hivemind.annotations.definition.Module;
 import org.apache.hivemind.annotations.definition.Service;
 import org.apache.hivemind.annotations.definition.Submodule;
+import org.apache.hivemind.annotations.definition.impl.AnnotatedModuleDefinitionImpl;
+import org.apache.hivemind.annotations.definition.processors.AnnotationProcessingContext;
+import org.apache.hivemind.annotations.definition.processors.AnnotationProcessor;
+import org.apache.hivemind.annotations.definition.processors.ServiceProcessor;
 import org.apache.hivemind.definition.Contribution;
 import org.apache.hivemind.definition.ImplementationConstructor;
 import org.apache.hivemind.definition.ImplementationDefinition;
@@ -38,7 +43,6 @@
 import org.apache.hivemind.definition.Visibility;
 import org.apache.hivemind.definition.impl.ConfigurationPointDefinitionImpl;
 import org.apache.hivemind.definition.impl.ContributionDefinitionImpl;
-import org.apache.hivemind.definition.impl.ModuleDefinitionImpl;
 import org.apache.hivemind.definition.impl.ImplementationDefinitionImpl;
 import org.apache.hivemind.definition.impl.ServicePointDefinitionImpl;
 import org.apache.hivemind.util.ClasspathResource;
@@ -63,6 +67,8 @@
     private ErrorHandler _errorHandler;
 
     private RegistryDefinition _registryDefinition;
+    
+    private AnnotationProcessorRegistry _annotationProcessorRegistry;
 
     public AnnotatedModuleProcessor(RegistryDefinition registryDefinition,
             ClassResolver classResolver, ErrorHandler errorHandler)
@@ -70,6 +76,7 @@
         _registryDefinition = registryDefinition;
         _classResolver = classResolver;
         _errorHandler = errorHandler;
+        _annotationProcessorRegistry = createAnnotationProcessorRegistry();
     }
     
     public void processModule(Class moduleClass)
@@ -87,7 +94,7 @@
     {
         checkModuleClassPrerequisites(moduleClass);
         
-        ModuleDefinitionImpl module = new ModuleDefinitionImpl(moduleId,
+        AnnotatedModuleDefinitionImpl module = new AnnotatedModuleDefinitionImpl(moduleId,
                 createModuleLocation(moduleClass), _classResolver, moduleClass.getPackage().getName());
 
         // processServices(moduleClass);
@@ -103,6 +110,13 @@
 
     }
     
+    private AnnotationProcessorRegistry createAnnotationProcessorRegistry()
+    {
+        AnnotationProcessorRegistry result = new AnnotationProcessorRegistry();
+        result.registerProcessor(Service.class, new ServiceProcessor());
+        return result;
+    }
+    
     /**
      * Ensures that a module class fulfills all prerequisites.
      * 
@@ -124,7 +138,7 @@
         }
     }
 
-    private void processModuleMethods(Class moduleClass, ModuleDefinitionImpl module,
+    private void processModuleMethods(Class moduleClass, AnnotatedModuleDefinitionImpl module,
             ModuleInstanceProvider instanceProvider)
     {
         // We need access to protected methods via getDeclaredMethods
@@ -142,7 +156,7 @@
         }
     }
 
-    private void processMethod(Method method, ModuleDefinitionImpl module,
+    private void processMethod(Method method, AnnotatedModuleDefinitionImpl module,
             ModuleInstanceProvider instanceProvider)
     {
         if (_log.isDebugEnabled())
@@ -154,7 +168,21 @@
         for (int j = 0; j < annotations.length; j++)
         {
             Annotation annotation = annotations[j];
-
+            
+            Location location = new AnnotatedModuleLocation(module.getLocation().getResource(),

+                    method.getDeclaringClass(), method);
+
+            AnnotationProcessingContext context = new AnnotationProcessingContextImpl(module,
+                    annotation, method, location, instanceProvider);
+            
+            List<AnnotationProcessor> processors = _annotationProcessorRegistry.getProcessors(annotation.getClass());
+            if (processors != null) {
+                for (AnnotationProcessor processor : processors)
+                {
+                    processor.processAnnotation(null);
+                }
+            }
+            
             if (Service.class.equals(annotation.annotationType()))
             {
                 processAnnotatedServiceMethod(
@@ -191,43 +219,11 @@
 
     }
     
-    /**
-     * Ensures that an annotated method has only allowed modifiers.
-     * By default Modifier.PUBLIC and Modifier.PROTECTED are allowed.
-     * @param method  the method
-     * @param allowedModifiers  allowed {@link Modifier modifiers}. 
-     * @param methodType  used in error messages to describe what the method is used for
-     */
-    protected void checkMethodModifiers(Method method, int allowedModifiers, String methodType)
-    {
-        // These modifiers are allowed
-        final int validModifiers = Modifier.PUBLIC | Modifier.PROTECTED | allowedModifiers;
-        
-        int invalidModifiers = method.getModifiers() & ~validModifiers;
-        if (invalidModifiers > 0) {
-            throw new ApplicationRuntimeException(AnnotationsMessages.annotatedMethodHasInvalidModifiers(method,
methodType, invalidModifiers));
-        }
-
-        // TODO: Check for package access
-        
-        // Check for setAccessible-Errors when Modifier.PROTECTED is used
-        if (Modifier.isProtected(method.getModifiers())) {
-            // Try to set method accessible
-            try
-            {
-                method.setAccessible(true);
-            }
-            catch (SecurityException e)
-            {
-                throw new ApplicationRuntimeException(AnnotationsMessages.annotatedMethodIsProtectedAndNotAccessible(method,
methodType));
-            }
-        }
-    }
 
     private void processAnnotatedServiceMethod(Method method, Service service,
-            ModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
+            AnnotatedModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
     {
-        checkMethodModifiers(method, 0, "service point");
+        CheckTools.checkMethodModifiers(method, 0, "service point");
         
         if (_log.isDebugEnabled())
         {
@@ -255,9 +251,10 @@
 
     }
 
-    private void processAnnotatedConfigurationMethod(Method method, Configuration configuration,
ModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
+    private void processAnnotatedConfigurationMethod(Method method, Configuration configuration,

+            AnnotatedModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
     {
-        checkMethodModifiers(method, 0, "configuration point");
+        CheckTools.checkMethodModifiers(method, 0, "configuration point");
 
         if (_log.isDebugEnabled())
         {
@@ -283,9 +280,10 @@
         cpd.addContribution(cd);
     }
 
-    private void processAnnotatedContributionMethod(Method method, org.apache.hivemind.annotations.definition.Contribution
contribution, ModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
+    private void processAnnotatedContributionMethod(Method method, org.apache.hivemind.annotations.definition.Contribution
contribution, 
+            AnnotatedModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
     {
-        checkMethodModifiers(method, 0, "contribution");
+        CheckTools.checkMethodModifiers(method, 0, "contribution");
 
         if (_log.isDebugEnabled())
         {
@@ -309,9 +307,10 @@
     /**
      * Processes a method that is marked as submodule definition.
      */
-    private void processAnnotatedSubmoduleMethod(Method method, Submodule submodule, ModuleDefinitionImpl
module, ModuleInstanceProvider instanceProvider)
+    private void processAnnotatedSubmoduleMethod(Method method, Submodule submodule, 
+            AnnotatedModuleDefinitionImpl module, ModuleInstanceProvider instanceProvider)
     {
-        checkMethodModifiers(method, 0, "submodule");
+        CheckTools.checkMethodModifiers(method, 0, "submodule");
 
         if (_log.isDebugEnabled())
         {

Added: hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessingContextImpl.java
URL: http://svn.apache.org/viewvc/hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessingContextImpl.java?view=auto&rev=513812
==============================================================================
--- hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessingContextImpl.java
(added)
+++ hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessingContextImpl.java
Fri Mar  2 07:32:09 2007
@@ -0,0 +1,58 @@
+package org.apache.hivemind.annotations.internal;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+
+import org.apache.hivemind.Location;
+import org.apache.hivemind.annotations.definition.impl.AnnotatedModuleDefinitionImpl;
+import org.apache.hivemind.annotations.definition.processors.AnnotationProcessingContext;
+
+public class AnnotationProcessingContextImpl implements AnnotationProcessingContext
+{
+    private AnnotatedElement _annotatedElement;
+    private Location _location;
+    private AnnotatedModuleDefinitionImpl _module;
+    private ModuleInstanceProvider _moduleInstanceProvider;
+    private Annotation _targetAnnotation;
+
+    public AnnotationProcessingContextImpl(AnnotatedModuleDefinitionImpl module, Annotation
targetAnnotation, AnnotatedElement annotatedElement, Location location, ModuleInstanceProvider
moduleInstanceProvider)
+    {
+        super();
+        _module = module;
+        _targetAnnotation = targetAnnotation;
+        _annotatedElement = annotatedElement;
+        _location = location;
+        _moduleInstanceProvider = moduleInstanceProvider;
+    }
+
+    public Annotation[] getAllAnnotations()
+    {
+        return _annotatedElement.getAnnotations();
+    }
+
+    public AnnotatedElement getAnnotatedElement()
+    {
+        return _annotatedElement;
+    }
+
+    public Location getLocation()
+    {
+        return _location;
+    }
+
+    public AnnotatedModuleDefinitionImpl getModule()
+    {
+        return _module;
+    }
+
+    public ModuleInstanceProvider getModuleInstanceProvider()
+    {
+        return _moduleInstanceProvider;
+    }
+
+    public Annotation getTargetAnnotation()
+    {
+        return _targetAnnotation;
+    }
+
+}

Added: hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessorRegistry.java
URL: http://svn.apache.org/viewvc/hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessorRegistry.java?view=auto&rev=513812
==============================================================================
--- hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessorRegistry.java
(added)
+++ hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/AnnotationProcessorRegistry.java
Fri Mar  2 07:32:09 2007
@@ -0,0 +1,30 @@
+package org.apache.hivemind.annotations.internal;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.hivemind.annotations.definition.processors.AnnotationProcessor;
+
+public class AnnotationProcessorRegistry
+{
+    private Map<Class<? extends Annotation>, List<AnnotationProcessor>>
processorLists = new HashMap<Class<? extends Annotation>, List<AnnotationProcessor>>();
+
+    public List<AnnotationProcessor> getProcessors(Class<? extends Annotation>
annotationClass)
+    {
+        return processorLists.get(annotationClass);
+    }
+
+    public void registerProcessor(Class<? extends Annotation> annotationClass, AnnotationProcessor
processor)
+    {
+        List<AnnotationProcessor> processorList = getProcessors(annotationClass);
+        if (processorList == null) {
+            processorList = new ArrayList<AnnotationProcessor>();
+            processorLists.put(annotationClass, processorList);
+        }
+        processorList.add(processor);
+    }
+}
+

Added: hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/CheckTools.java
URL: http://svn.apache.org/viewvc/hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/CheckTools.java?view=auto&rev=513812
==============================================================================
--- hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/CheckTools.java
(added)
+++ hivemind/hivemind2/trunk/annotations/src/java/org/apache/hivemind/annotations/internal/CheckTools.java
Fri Mar  2 07:32:09 2007
@@ -0,0 +1,43 @@
+package org.apache.hivemind.annotations.internal;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.apache.hivemind.ApplicationRuntimeException;
+import org.apache.hivemind.annotations.AnnotationsMessages;
+
+public class CheckTools
+{
+    /**
+     * Ensures that an annotated method has only allowed modifiers.
+     * By default Modifier.PUBLIC and Modifier.PROTECTED are allowed.
+     * @param method  the method
+     * @param allowedModifiers  allowed {@link Modifier modifiers}. 
+     * @param methodType  used in error messages to describe what the method is used for
+     */
+    public static void checkMethodModifiers(Method method, int allowedModifiers, String methodType)
+    {
+        // These modifiers are allowed
+        final int validModifiers = Modifier.PUBLIC | Modifier.PROTECTED | allowedModifiers;
+        
+        int invalidModifiers = method.getModifiers() & ~validModifiers;
+        if (invalidModifiers > 0) {
+            throw new ApplicationRuntimeException(AnnotationsMessages.annotatedMethodHasInvalidModifiers(method,
methodType, invalidModifiers));
+        }
+
+        // TODO: Check for package access
+        
+        // Check for setAccessible-Errors when Modifier.PROTECTED is used
+        if (Modifier.isProtected(method.getModifiers())) {
+            // Try to set method accessible
+            try
+            {
+                method.setAccessible(true);
+            }
+            catch (SecurityException e)
+            {
+                throw new ApplicationRuntimeException(AnnotationsMessages.annotatedMethodIsProtectedAndNotAccessible(method,
methodType));
+            }
+        }
+    }
+}



Mime
View raw message