qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From oru...@apache.org
Subject svn commit: r1686069 - in /qpid/java/trunk/broker-core/src: main/java/org/apache/qpid/server/logging/ main/java/org/apache/qpid/server/model/ test/java/org/apache/qpid/server/logging/
Date Wed, 17 Jun 2015 16:41:16 GMT
Author: orudyy
Date: Wed Jun 17 16:41:16 2015
New Revision: 1686069

URL: http://svn.apache.org/r1686069
Log:
QPID-6596: [Java Broker] Add ability for virtualhost events to be excluded from the Broker
log

Added:
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilter.java
      - copied, changed from r1686063, qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java
    qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilterTest.java
Modified:
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractBrokerLogger.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractLogger.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractVirtualHostLogger.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/CompositeFilter.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostFileLoggerImpl.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
    qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/CompositeFilterTest.java

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractBrokerLogger.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractBrokerLogger.java?rev=1686069&r1=1686068&r2=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractBrokerLogger.java
(original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractBrokerLogger.java
Wed Jun 17 16:41:16 2015
@@ -26,12 +26,19 @@ import java.util.Map;
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.BrokerLogger;
 import org.apache.qpid.server.model.BrokerLoggerFilter;
+import org.apache.qpid.server.model.ManagedAttributeField;
 
 public abstract class AbstractBrokerLogger<X extends AbstractBrokerLogger<X>>
extends AbstractLogger<X> implements BrokerLogger<X>
 {
+    @ManagedAttributeField
+    private boolean _virtualHostLogEventExcluded;
+    private final CompositeFilter _compositeFilter;
+
     protected AbstractBrokerLogger(Map<String, Object> attributes, Broker<?>
broker)
     {
         super(attributes, broker);
+        _compositeFilter = new CompositeFilter();
+        _compositeFilter.addFilter(new VirtualHostLogEventExcludingFilter(this));
     }
 
     @Override
@@ -40,4 +47,15 @@ public abstract class AbstractBrokerLogg
         return getChildren(BrokerLoggerFilter.class);
     }
 
+    @Override
+    public boolean isVirtualHostLogEventExcluded()
+    {
+        return _virtualHostLogEventExcluded;
+    }
+
+    @Override
+    protected CompositeFilter getCompositeFilter()
+    {
+        return _compositeFilter;
+    }
 }

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractLogger.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractLogger.java?rev=1686069&r1=1686068&r2=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractLogger.java
(original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractLogger.java
Wed Jun 17 16:41:16 2015
@@ -41,16 +41,16 @@ import org.apache.qpid.server.model.Stat
 
 public abstract class AbstractLogger<X extends AbstractLogger<X>> extends AbstractConfiguredObject<X>
 {
-    private final CompositeFilter _compositeFilter = new CompositeFilter();
     private final static ch.qos.logback.classic.Logger ROOT_LOGGER = ((ch.qos.logback.classic.Logger)
LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME));
 
     protected AbstractLogger(Map<String, Object> attributes, ConfiguredObject<?>
parent)
     {
         super(parentsMap(parent), attributes);
-
         addChangeListener(new FilterListener());
     }
 
+    protected abstract CompositeFilter getCompositeFilter();
+
     @Override
     protected void postResolveChildren()
     {
@@ -64,9 +64,9 @@ public abstract class AbstractLogger<X e
 
         for(LoggerFilter filter : getLoggerFilters())
         {
-            _compositeFilter.addFilter(filter);
+            getCompositeFilter().addFilter(filter);
         }
-        appender.addFilter(_compositeFilter);
+        appender.addFilter(getCompositeFilter());
 
         ROOT_LOGGER.addAppender(appender);
         appender.start();
@@ -132,7 +132,7 @@ public abstract class AbstractLogger<X e
         {
             if (child instanceof LoggerFilter)
             {
-                _compositeFilter.addFilter((LoggerFilter) child);
+                getCompositeFilter().addFilter((LoggerFilter) child);
             }
         }
 
@@ -141,7 +141,7 @@ public abstract class AbstractLogger<X e
         {
             if (child instanceof LoggerFilter)
             {
-                _compositeFilter.removeFilter((LoggerFilter) child);
+                getCompositeFilter().removeFilter((LoggerFilter) child);
             }
         }
 

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractVirtualHostLogger.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractVirtualHostLogger.java?rev=1686069&r1=1686068&r2=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractVirtualHostLogger.java
(original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/AbstractVirtualHostLogger.java
Wed Jun 17 16:41:16 2015
@@ -29,10 +29,13 @@ import org.apache.qpid.server.model.Virt
 
 public abstract class AbstractVirtualHostLogger <X extends AbstractVirtualHostLogger<X>>
extends AbstractLogger<X> implements VirtualHostLogger<X>
 {
+    private final CompositeFilter _compositeFilter;
 
     protected AbstractVirtualHostLogger(Map<String, Object> attributes, VirtualHost<?,?,?>
virtualHost)
     {
         super(attributes, virtualHost);
+        _compositeFilter = new CompositeFilter();
+        _compositeFilter.addFilter(new PrincipalLogEventFilter(virtualHost.getPrincipal()));
     }
 
     @Override
@@ -41,4 +44,9 @@ public abstract class AbstractVirtualHos
         return getChildren(VirtualHostLoggerFilter.class);
     }
 
+    @Override
+    protected CompositeFilter getCompositeFilter()
+    {
+        return _compositeFilter;
+    }
 }

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/CompositeFilter.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/CompositeFilter.java?rev=1686069&r1=1686068&r2=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/CompositeFilter.java
(original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/CompositeFilter.java
Wed Jun 17 16:41:16 2015
@@ -20,7 +20,6 @@
  */
 package org.apache.qpid.server.logging;
 
-import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -40,14 +39,6 @@ public class CompositeFilter extends Fil
         _filterList.add(f);
     }
 
-    public void addFilters(Collection<LoggerFilter> filters)
-    {
-        for(LoggerFilter filter : filters)
-        {
-            addFilter(filter);
-        }
-    }
-
     public void removeFilter(LoggerFilter filter)
     {
         Iterator<Filter<ILoggingEvent>> it = _filterList.iterator();

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java?rev=1686069&r1=1686068&r2=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java
(original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java
Wed Jun 17 16:41:16 2015
@@ -30,7 +30,7 @@ import ch.qos.logback.core.filter.Filter
 import ch.qos.logback.core.spi.FilterReply;
 
 
-public class PrincipalLogEventFilter extends Filter<ILoggingEvent>
+public class PrincipalLogEventFilter extends Filter<ILoggingEvent> implements LoggerFilter
 {
     private final Principal _principal;
 
@@ -49,4 +49,16 @@ public class PrincipalLogEventFilter ext
         }
         return FilterReply.DENY;
     }
+
+    @Override
+    public Filter<ILoggingEvent> asFilter()
+    {
+        return this;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "$" + getClass().getName();
+    }
 }

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostFileLoggerImpl.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostFileLoggerImpl.java?rev=1686069&r1=1686068&r2=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostFileLoggerImpl.java
(original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostFileLoggerImpl.java
Wed Jun 17 16:41:16 2015
@@ -26,8 +26,6 @@ import java.util.Map;
 import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.Appender;
 import ch.qos.logback.core.Context;
-import ch.qos.logback.core.filter.Filter;
-import ch.qos.logback.core.rolling.RollingFileAppender;
 
 import org.apache.qpid.server.model.ManagedAttributeField;
 import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
@@ -106,12 +104,7 @@ public class VirtualHostFileLoggerImpl e
     @Override
     protected Appender<ILoggingEvent> createAppenderInstance(Context loggerContext)
     {
-        RollingFileAppender<ILoggingEvent> rollingFileAppender =
-                new RollingFileAppenderFactory().createRollingFileAppender(this, loggerContext);
-
-        Filter<ILoggingEvent> principalFilter = new PrincipalLogEventFilter(_principal);
-        rollingFileAppender.addFilter(principalFilter);
-        return rollingFileAppender;
+        return new RollingFileAppenderFactory().createRollingFileAppender(this, loggerContext);
     }
 
 }

Copied: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilter.java
(from r1686063, qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java)
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilter.java?p2=qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilter.java&p1=qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java&r1=1686063&r2=1686069&rev=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/PrincipalLogEventFilter.java
(original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilter.java
Wed Jun 17 16:41:16 2015
@@ -22,31 +22,64 @@ package org.apache.qpid.server.logging;
 
 import java.security.AccessController;
 import java.security.Principal;
+import java.util.Set;
 
 import javax.security.auth.Subject;
 
 import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.filter.Filter;
 import ch.qos.logback.core.spi.FilterReply;
+import org.apache.qpid.server.model.BrokerLogger;
+import org.apache.qpid.server.virtualhost.VirtualHostPrincipal;
 
-
-public class PrincipalLogEventFilter extends Filter<ILoggingEvent>
+public class VirtualHostLogEventExcludingFilter extends Filter<ILoggingEvent> implements
LoggerFilter
 {
-    private final Principal _principal;
+    private final BrokerLogger<?> _brokerLogger ;
+
+    public VirtualHostLogEventExcludingFilter(BrokerLogger<?> brokerLogger)
+    {
+        super();
+        _brokerLogger = brokerLogger;
+    }
+
+
+    @Override
+    public Filter<ILoggingEvent> asFilter()
+    {
+        return this;
+    }
 
-    public PrincipalLogEventFilter(final Principal principal)
+    @Override
+    public String getName()
     {
-        _principal = principal;
+        return "$" + getClass().getName();
     }
 
     @Override
     public FilterReply decide(ILoggingEvent event)
     {
-        Subject subject = Subject.getSubject(AccessController.getContext());
-        if (subject != null && subject.getPrincipals().contains(_principal))
+        if (!_brokerLogger.isVirtualHostLogEventExcluded()  || !subjectContainsVirtualHostPrincipal())
         {
             return FilterReply.NEUTRAL;
         }
         return FilterReply.DENY;
     }
+
+    private boolean subjectContainsVirtualHostPrincipal()
+    {
+        Subject subject = Subject.getSubject(AccessController.getContext());
+        if (subject != null)
+        {
+            Set<Principal> principals= subject.getPrincipals();
+            for (Principal principal: principals)
+            {
+                if (principal instanceof VirtualHostPrincipal)
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
 }

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java?rev=1686069&r1=1686068&r2=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
(original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerLogger.java
Wed Jun 17 16:41:16 2015
@@ -23,5 +23,8 @@ package org.apache.qpid.server.model;
 @ManagedObject
 public interface BrokerLogger<X extends BrokerLogger<X>> extends ConfiguredObject<X>
 {
+    @ManagedAttribute(defaultValue = "false")
+    boolean isVirtualHostLogEventExcluded();
+
     void stopLogging();
 }

Modified: qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/CompositeFilterTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/CompositeFilterTest.java?rev=1686069&r1=1686068&r2=1686069&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/CompositeFilterTest.java
(original)
+++ qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/CompositeFilterTest.java
Wed Jun 17 16:41:16 2015
@@ -120,24 +120,6 @@ public class CompositeFilterTest extends
         verify(brokerFilter.asFilter()).setName("accept");
     }
 
-    public void testAddFilters()
-    {
-        CompositeFilter compositeFilter = new CompositeFilter();
-
-        LoggerFilter brokerFilterNeutral = createFilter(FilterReply.NEUTRAL, "neutral");
-        LoggerFilter brokerFilterAccept = createFilter(FilterReply.ACCEPT, "accept");
-        LoggerFilter brokerFilterDeny = createFilter(FilterReply.DENY, "deny");
-
-        compositeFilter.addFilters(Arrays.asList(brokerFilterNeutral, brokerFilterAccept,
brokerFilterDeny));
-
-        FilterReply reply = compositeFilter.decide(mock(ILoggingEvent.class));
-        assertEquals("Unexpected reply", FilterReply.ACCEPT, reply);
-
-        verify(brokerFilterNeutral.asFilter()).decide(any(ILoggingEvent.class));
-        verify(brokerFilterAccept.asFilter()).decide(any(ILoggingEvent.class));
-        verify(brokerFilterDeny.asFilter(), never()).decide(any(ILoggingEvent.class));
-    }
-
     private LoggerFilter createFilter(FilterReply decision)
     {
         return createFilter(decision, "UNNAMED");

Added: qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilterTest.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilterTest.java?rev=1686069&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilterTest.java
(added)
+++ qpid/java/trunk/broker-core/src/test/java/org/apache/qpid/server/logging/VirtualHostLogEventExcludingFilterTest.java
Wed Jun 17 16:41:16 2015
@@ -0,0 +1,116 @@
+/*
+ *
+ * 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.qpid.server.logging;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+
+import javax.security.auth.Subject;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.spi.FilterReply;
+import org.apache.qpid.server.model.BrokerLogger;
+import org.apache.qpid.server.virtualhost.VirtualHostPrincipal;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class VirtualHostLogEventExcludingFilterTest extends QpidTestCase
+{
+    private BrokerLogger<?> _brokerLogger;
+    private ILoggingEvent _loggingEvent;
+    private VirtualHostLogEventExcludingFilter _filter;
+
+    public void setUp() throws Exception
+    {
+        super.setUp();
+        _brokerLogger = mock(BrokerLogger.class);
+        _loggingEvent = mock(ILoggingEvent.class);
+        _filter = new VirtualHostLogEventExcludingFilter(_brokerLogger);
+    }
+
+    public void testDecideOnNoVirtualHostPrincipalInSubjectAndVirtualHostLogEventNotExcluded()
throws Exception
+    {
+        Subject subject = new Subject();
+        subject.getPrincipals().add(mock(Principal.class));
+        FilterReply reply = doTestDecide(subject);
+        assertEquals("Unexpected reply for BrokerLogger#virtualHostLogEventExcluded=false
and no VH principal in subject",
+                FilterReply.NEUTRAL, reply);
+    }
+
+    public void testDecideOnNoVirtualHostPrincipalInSubjectAndVirtualHostLogEventExcluded()
throws Exception
+    {
+        when(_brokerLogger.isVirtualHostLogEventExcluded()).thenReturn(true);
+        Subject subject = new Subject();
+        subject.getPrincipals().add(mock(Principal.class));
+        FilterReply reply = doTestDecide(subject);
+        assertEquals("Unexpected reply for BrokerLogger#virtualHostLogEventExcluded=true
and no VH principal in subject",
+                FilterReply.NEUTRAL, reply);
+    }
+
+    public void testDecideOnVirtualHostPrincipalInSubjectAndVirtualHostLogEventNotExcluded()
throws Exception
+    {
+        Subject subject = new Subject();
+        subject.getPrincipals().add(mock(VirtualHostPrincipal.class));
+        FilterReply reply = doTestDecide(subject);
+        assertEquals("Unexpected reply for BrokerLogger#virtualHostLogEventExcluded=false
and VH principal in subject",
+                FilterReply.NEUTRAL, reply);
+    }
+
+    public void testDecideOnVirtualHostPrincipalInSubjectAndVirtualHostLogEventExcluded()
throws Exception
+    {
+        when(_brokerLogger.isVirtualHostLogEventExcluded()).thenReturn(true);
+        Subject subject = new Subject();
+        subject.getPrincipals().add(mock(VirtualHostPrincipal.class));
+        FilterReply reply = doTestDecide(subject);
+        assertEquals("Unexpected reply for BrokerLogger#virtualHostLogEventExcluded=true
and VH principal in subject",
+                FilterReply.DENY, reply);
+    }
+
+    public void testDecideOnVirtualHostLogEventNotExcludedAndNullSubject() throws Exception
+    {
+        FilterReply reply = _filter.decide(_loggingEvent);
+        assertEquals(" BrokerLogger#virtualHostLogEventExcluded=false and subject=null",
FilterReply.NEUTRAL, reply);
+        assertNull("Subject should not be set in test environment", Subject.getSubject(AccessController.getContext()));
+    }
+
+    public void testDecideOnVirtualHostLogEventExcludedAndNullSubject() throws Exception
+    {
+        when(_brokerLogger.isVirtualHostLogEventExcluded()).thenReturn(true);
+        FilterReply reply = _filter.decide(_loggingEvent);
+        assertEquals(" BrokerLogger#virtualHostLogEventExcluded=true and subject=null", FilterReply.NEUTRAL,
reply);
+        assertNull("Subject should not be set in test environment", Subject.getSubject(AccessController.getContext()));
+    }
+
+    private FilterReply doTestDecide(Subject subject)
+    {
+        return  Subject.doAs(subject, new PrivilegedAction<FilterReply>()
+        {
+            @Override
+            public FilterReply run()
+            {
+                return _filter.decide(_loggingEvent);
+            }
+        });
+    }
+}
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


Mime
View raw message