logging-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rgo...@apache.org
Subject svn commit: r1504620 - in /logging/log4j/log4j2/trunk: core/src/main/java/org/apache/logging/log4j/core/lookup/ core/src/test/java/org/apache/logging/log4j/core/appender/routing/ core/src/test/java/org/apache/logging/log4j/core/lookup/ core/src/test/re...
Date Thu, 18 Jul 2013 19:47:20 GMT
Author: rgoers
Date: Thu Jul 18 19:47:20 2013
New Revision: 1504620

URL: http://svn.apache.org/r1504620
Log:
LOG4J2-313 - Add JNDILookup

Added:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j-routing-by-jndi.xml
Modified:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml
    logging/log4j/log4j2/trunk/src/site/site.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/lookups.xml

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java?rev=1504620&r1=1504619&r2=1504620&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
(original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java
Thu Jul 18 19:47:20 2013
@@ -63,6 +63,7 @@ public class Interpolator implements Str
         this.defaultLookup = new MapLookup(new HashMap<String, String>());
         lookups.put("sys", new SystemPropertiesLookup());
         lookups.put("env", new EnvironmentLookup());
+        lookups.put("jndi", new JndiLookup());
     }
 
      /**

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java?rev=1504620&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java
(added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/lookup/JndiLookup.java
Thu Jul 18 19:47:20 2013
@@ -0,0 +1,78 @@
+/*
+ * 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.logging.log4j.core.lookup;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+
+/**
+ * Looks up keys from JNDI resources.
+ */
+@Plugin(name = "jndi", category = "Lookup")
+public class JndiLookup implements StrLookup {
+
+    /** JNDI resourcce path prefix used in a J2EE container */
+    static final String CONTAINER_JNDI_RESOURCE_PATH_PREFIX = "java:comp/env/";
+
+    /**
+     * Get the value of the JNDI resource.
+     * @param key  the JNDI resource name to be looked up, may be null
+     * @return The value of the JNDI resource.
+     */
+    @Override
+    public String lookup(final String key) {
+        return lookup(null, key);
+    }
+
+    /**
+     * Get the value of the JNDI resource.
+     * @param event The current LogEvent (is ignored by this StrLookup).
+     * @param key  the JNDI resource name to be looked up, may be null
+     * @return The value of the JNDI resource.
+     */
+    @Override
+    public String lookup(final LogEvent event, final String key) {
+        if (key == null) {
+            return null;
+        }
+
+        try {
+            InitialContext ctx = new InitialContext();
+            return (String) ctx.lookup(convertJndiName(key));
+        } catch (NamingException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Convert the given JNDI name to the actual JNDI name to use.
+     * Default implementation applies the "java:comp/env/" prefix
+     * unless other scheme like "java:" is given.
+     * @param jndiName The name of the resource.
+     * @return The fully qualified name to look up.
+     */
+    private String convertJndiName(String jndiName) {
+        if (!jndiName.startsWith(CONTAINER_JNDI_RESOURCE_PATH_PREFIX) && jndiName.indexOf(':')
== -1) {
+            jndiName = CONTAINER_JNDI_RESOURCE_PATH_PREFIX + jndiName;
+        }
+
+        return jndiName;
+    }
+}

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java?rev=1504620&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
(added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutingAppenderWithJndiTest.java
Thu Jul 18 19:47:20 2013
@@ -0,0 +1,122 @@
+/*
+ * 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.logging.log4j.core.appender.routing;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.Map;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.EventLogger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
+import org.apache.logging.log4j.message.StructuredDataMessage;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockejb.jndi.MockContextFactory;
+
+/**
+ * RoutingAppenderWithJndiTest
+ */
+public class RoutingAppenderWithJndiTest {
+
+    private static final String CONFIG = "log4j-routing-by-jndi.xml";
+    private static Configuration config;
+    private static ListAppender<LogEvent> listAppender1;
+    private static ListAppender<LogEvent> listAppender2;
+    private static LoggerContext ctx;
+
+    @BeforeClass
+    @SuppressWarnings("unchecked")
+    public static void setupClass() {
+        System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
+        ctx = (LoggerContext) LogManager.getContext(false);
+        config = ctx.getConfiguration();
+        for (final Map.Entry<String, Appender<?>> entry : config.getAppenders().entrySet())
{
+            if (entry.getKey().equals("List1")) {
+                listAppender1 = (ListAppender<LogEvent>) entry.getValue();
+            }
+            if (entry.getKey().equals("List2")) {
+                listAppender2 = (ListAppender<LogEvent>) entry.getValue();
+            }
+        }
+    }
+
+    @Before
+    public void before() throws NamingException {
+        MockContextFactory.setAsInitial();
+    }
+
+    @After
+    public void after() {
+        MockContextFactory.revertSetAsInitial();
+    }
+
+    @AfterClass
+    public static void cleanupClass() {
+        System.clearProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
+        ctx.reconfigure();
+        StatusLogger.getLogger().reset();
+    }
+
+    @Test
+    public void routingTest() throws NamingException {
+        // default route when there's no jndi resource
+        StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a message
from unknown context", "Context");
+        EventLogger.logEvent(msg);
+        File defaultLogFile = new File("target/routingbyjndi/routingbyjnditest-default.log");
+        assertTrue("The default log file was not created", defaultLogFile.exists());
+
+        // now set jndi resource to Application1
+        Context context = new InitialContext();
+        context.bind("java:comp/env/logging/context-name", "Application1");
+
+        msg = new StructuredDataMessage("Test", "This is a message from Application1", "Context");
+        EventLogger.logEvent(msg);
+        assertNotNull("No events generated", listAppender1.getEvents());
+        assertTrue("Incorrect number of events. Expected 1, got " + listAppender1.getEvents().size(),
listAppender1.getEvents().size() == 1);
+
+        // now set jndi resource to Application2
+        context.rebind("java:comp/env/logging/context-name", "Application2");
+
+        msg = new StructuredDataMessage("Test", "This is a message from Application2", "Context");
+        EventLogger.logEvent(msg);
+        assertNotNull("No events generated", listAppender2.getEvents());
+        assertTrue("Incorrect number of events. Expected 1, got " + listAppender2.getEvents().size(),
listAppender2.getEvents().size() == 1);
+        assertTrue("Incorrect number of events. Expected 1, got " + listAppender1.getEvents().size(),
listAppender1.getEvents().size() == 1);
+
+        msg = new StructuredDataMessage("Test", "This is another message from Application2",
"Context");
+        EventLogger.logEvent(msg);
+        assertNotNull("No events generated", listAppender2.getEvents());
+        assertTrue("Incorrect number of events. Expected 2, got " + listAppender2.getEvents().size(),
listAppender2.getEvents().size() == 2);
+        assertTrue("Incorrect number of events. Expected 1, got " + listAppender1.getEvents().size(),
listAppender1.getEvents().size() == 1);
+    }
+}

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java?rev=1504620&r1=1504619&r2=1504620&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
(original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/InterpolatorTest.java
Thu Jul 18 19:47:20 2013
@@ -16,16 +16,22 @@
  */
 package org.apache.logging.log4j.core.lookup;
 
-import org.apache.logging.log4j.ThreadContext;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.logging.log4j.ThreadContext;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockejb.jndi.MockContextFactory;
 
 /**
  *
@@ -35,18 +41,25 @@ public class InterpolatorTest {
     private static final String TESTKEY = "TestKey";
     private static final String TESTVAL = "TestValue";
 
+    private static final String TEST_CONTEXT_RESOURCE_NAME = "logging/context-name";
+    private static final String TEST_CONTEXT_NAME = "app-1";
 
     @BeforeClass
-    public static void before() {
+    public static void before() throws NamingException {
         System.setProperty(TESTKEY, TESTVAL);
+
+        MockContextFactory.setAsInitial();
+        Context context = new InitialContext();
+        context.bind(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME,
TEST_CONTEXT_NAME);
     }
 
     @AfterClass
     public static void after() {
+        MockContextFactory.revertSetAsInitial();
+
         System.clearProperty(TESTKEY);
     }
 
-
     @Test
     public void testLookup() {
         final Map<String, String> map = new HashMap<String, String>();
@@ -64,5 +77,18 @@ public class InterpolatorTest {
         ThreadContext.clear();
         value = lookup.lookup("ctx:" + TESTKEY);
         assertEquals(TESTVAL, value);
+        value = lookup.lookup("jndi:" + TEST_CONTEXT_RESOURCE_NAME);
+        assertEquals(TEST_CONTEXT_NAME, value);
+    }
+
+    @Test
+    public void testLookupWithDefaultInterpolator() {
+        final StrLookup lookup = new Interpolator();
+        String value = lookup.lookup("sys:" + TESTKEY);
+        assertEquals(TESTVAL, value);
+        value = lookup.lookup("env:PATH");
+        assertNotNull(value);
+        value = lookup.lookup("jndi:" + TEST_CONTEXT_RESOURCE_NAME);
+        assertEquals(TEST_CONTEXT_NAME, value);
     }
 }

Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java?rev=1504620&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java
(added)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/lookup/JndiLookupTest.java
Thu Jul 18 19:47:20 2013
@@ -0,0 +1,64 @@
+/*
+ * 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.logging.log4j.core.lookup;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockejb.jndi.MockContextFactory;
+
+/**
+ * JndiLookupTest
+ */
+public class JndiLookupTest {
+
+    private static final String TEST_CONTEXT_RESOURCE_NAME = "logging/context-name";
+    private static final String TEST_CONTEXT_NAME = "app-1";
+
+    @Before
+    public void before() throws NamingException {
+        MockContextFactory.setAsInitial();
+        Context context = new InitialContext();
+        context.bind(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME,
TEST_CONTEXT_NAME);
+    }
+
+    @After
+    public void after() {
+        MockContextFactory.revertSetAsInitial();
+    }
+
+    @Test
+    public void testLookup() {
+        final StrLookup lookup = new JndiLookup();
+
+        String contextName = lookup.lookup(TEST_CONTEXT_RESOURCE_NAME);
+        assertEquals(TEST_CONTEXT_NAME, contextName);
+
+        contextName = lookup.lookup(JndiLookup.CONTAINER_JNDI_RESOURCE_PATH_PREFIX + TEST_CONTEXT_RESOURCE_NAME);
+        assertEquals(TEST_CONTEXT_NAME, contextName);
+
+        String nonExistingResource = lookup.lookup("logging/non-existing-resource");
+        assertNull(nonExistingResource);
+    }
+}

Added: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-routing-by-jndi.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-routing-by-jndi.xml?rev=1504620&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-routing-by-jndi.xml (added)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-routing-by-jndi.xml Thu Jul 18
19:47:20 2013
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+<configuration status="debug" name="RoutingByJndiTest" packages="org.apache.logging.log4j.test">
+
+  <ThresholdFilter level="debug"/>
+
+  <appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+    <List name="List1">
+      <ThresholdFilter level="debug"/>
+    </List>
+    <List name="List2">
+      <ThresholdFilter level="debug"/>
+    </List>
+    <Routing name="Routing">
+      <Routes pattern="$${jndi:logging/context-name}">
+        <!-- Default route -->
+        <Route>
+          <File name="DefaultApplicationLogFile" fileName="target/routingbyjndi/routingbyjnditest-default.log"
append="false">
+            <PatternLayout>
+              <pattern>%d %p %C{1.} [%t] %m%n</pattern>
+            </PatternLayout>
+          </File>
+        </Route>
+        <Route ref="List1" key="Application1"/>
+        <Route ref="List2" key="Application2"/>
+      </Routes>
+    </Routing>
+  </appenders>
+
+  <loggers>
+    <logger name="EventLogger" level="info" additivity="false">
+      <appender-ref ref="Routing"/>
+      <appender-ref ref="STDOUT"/>
+    </logger>
+
+    <root level="error">
+      <appender-ref ref="STDOUT"/>
+    </root>
+  </loggers>
+
+</configuration>
\ No newline at end of file

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1504620&r1=1504619&r2=1504620&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Thu Jul 18 19:47:20 2013
@@ -21,6 +21,9 @@
   </properties>
   <body>
     <release version="2.0-beta9" date="soon, very soon" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-313" dev="rgoers" type="add" due-to="Woonsan Ko">
+        Add JNDILookup plugin.
+      </action>
       <action issue="LOG4J2-299" dev="rgoers" type="fix">
         Add getThrowable method to ThrowableProxy.
       </action>

Modified: logging/log4j/log4j2/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/site.xml?rev=1504620&r1=1504619&r2=1504620&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/site.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/site.xml Thu Jul 18 19:47:20 2013
@@ -76,6 +76,7 @@
         <item name="ContextMap" href="/manual/lookups.html#ContextMapLookup"/>
         <item name="Date" href="/manual/lookups.html#DateLookcup"/>
         <item name="Environment" href="/manual/lookups.html#EnvironmentLookup"/>
+        <item name="JNDI" href="/manual/lookups.html#JNDILookup"/>
         <item name="Map" href="/manual/lookups.html#MapLookup"/>
         <item name="StructuredData" href="/manual/lookups.html#StructuredDataLookup"/>
         <item name="SystemProperties" href="/manual/lookups.html#SystemPropertiesLookup"/>

Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/lookups.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/lookups.xml?rev=1504620&r1=1504619&r2=1504620&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/lookups.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/lookups.xml Thu Jul 18 19:47:20 2013
@@ -80,6 +80,19 @@
   </PatternLayout>
 </File>]]></pre>
         </subsection>
+        <a name="JNDILookup"/>
+        <subsection name="JNDILookup">
+          <p>
+            The JNDILookup allows variables to be retrieved via JNDI. By default the key
will be prefixed with
+            java:comp/env/, however if the key contains a ":" no prefix will be added.
+          </p>
+          <pre class="prettyprint linenums"><![CDATA[
+<File name="Application" fileName="application.log">
+  <PatternLayout>
+    <pattern>%d %p %c{1.} [%t] $${jndi:logging/context-name} %m%n</pattern>
+  </PatternLayout>
+</File>]]></pre>
+        </subsection>
         <a name="MapLookup"/>
         <subsection name="MapLookup">
           <p>



Mime
View raw message