logging-log4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Matt Sicker <boa...@gmail.com>
Subject Re: [02/29] Split out JMS appender and receiver into new log4j module.
Date Thu, 11 Sep 2014 19:04:05 GMT
Plus the LMAX library for AsyncLogger (which I find to be a rather killer
feature) makes it somewhat awkward to truly enforce that policy.


On 11 September 2014 08:47, Gary Gregory <garydgregory@gmail.com> wrote:

> I think the API module should have 0-deps, ideally, which we do. The OSGi
> dep is "provided" so that's an exception.
>
> For Core, I do not think we've ever settled on a policy. The policy could
> be: if you have a runtime dep (test only deps are OK), then you cannot live
> in Core. But that breaks right away since we bring in lots of deps just to
> do XML and JSON IO. So that would have to be moved out. Bleh, seems like a
> big mess.
>
> Gary
>
> On Thu, Sep 11, 2014 at 9:29 AM, Matt Sicker <boards@gmail.com> wrote:
>
>> Well, I wouldn't mind putting it back in log4j-core. I mean, the JPA
>> appender is in there, and it would be weird to split that out from the JDBC
>> ones even though only JDBC is in the JDK. Other than the JPA appender, what
>> other appenders are in core that require optional dependencies? I think the
>> SMTP appender requires JavaMail, so there's one more.
>>
>> On 11 September 2014 07:39, Ralph Goers <rgoers@apache.org> wrote:
>>
>>> It sounds like you and I have a similar point of view. If I had to vote
>>> it would be something like -0.5 - not a veto but really don't see why this
>>> is better.
>>>
>>> Sent from my iPad
>>>
>>> On Sep 11, 2014, at 4:30 AM, Gary Gregory <garydgregory@gmail.com>
>>> wrote:
>>>
>>> So... do we have consensus here?
>>>
>>> Right now we have a "Apache Log4j JMS Appenders" module. Shouldn't that
>>> be renamed to "Appender" singular?
>>>
>>> The only advantage I see is not dragging in the JMS API jar...
>>>
>>> Gary
>>>
>>>
>>> On Sat, Sep 6, 2014 at 5:47 PM, Matt Sicker <boards@gmail.com> wrote:
>>>
>>>> Honestly, I'd be more likely to use Log4j to log my JMS server rather
>>>> than the other way around. Plus, Flume is really awesome for distributed
>>>> logging without the hassle of setting up a network of brokers and other
>>>> configuration fun when dealing with JMS on a large scale.
>>>>
>>>>
>>>> On 6 September 2014 16:20, Ralph Goers <ralph.goers@dslextreme.com>
>>>> wrote:
>>>>
>>>>> I guess I prefer to follow the 80/20 rule - core should have all the
>>>>> functionality that 80% of the users will use.  The other 20% - which
>>>>> necessarily require their own dependencies - can be found in outside jars.
>>>>>  I don’t mind telling a user that core has a few optional dependencies for
>>>>> a few optional features. But there should only be a handful of those.
>>>>>
>>>>> JMS might fit into the same bucket as Flume but it could also be
>>>>> argued that it is similar to JDBC, so I’m on the fence as to whether moving
>>>>> it out is the right thing to do.
>>>>>
>>>>> Ralph
>>>>>
>>>>> On Sep 6, 2014, at 11:56 AM, Gary Gregory <garydgregory@gmail.com>
>>>>> wrote:
>>>>>
>>>>> I agree with most of that but the flip side for logging is that we
>>>>> deliver all of log4j because it is the users of our products that decide
>>>>> how to integrate with our products and how logging is done is all up to the
>>>>> users. So our use case is give users all of log4j and let them configure it
>>>>> as they see fit. Which is why I want a all - in - one module where core is
>>>>> the impl.
>>>>>
>>>>> Gary
>>>>>
>>>>>
>>>>> -------- Original message --------
>>>>> From: Matt Sicker
>>>>> Date:09/06/2014 14:15 (GMT-05:00)
>>>>> To: Log4J Developers List
>>>>> Cc: Ralph Goers
>>>>> Subject: Re: [02/29] Split out JMS appender and receiver into new
>>>>> log4j module.
>>>>>
>>>>> The basic idea is that instead of so many optional dependencies (which
>>>>> still need to be specified in your build script or included as additional
>>>>> JARs), we can break out non-essential pieces with said dependencies into
>>>>> more easily used components. Most of log4j-core doesn't require outside
>>>>> dependencies, so that's a good thing! Sure, in a sense it could be broken
>>>>> up into tons of little modules, but besides the mass of JARs you get from
>>>>> that, I've found that most projects that are so finely split up like that
>>>>> have next to no documentation outside the core modules. Then again, that
>>>>> could be the same with monolithic projects, too. In that regard, I think
>>>>> Log4j is more like Spring where the entire project is rather well
>>>>> documented; however, the javadoc side of things is still lacking (which is
>>>>> understandable).
>>>>>
>>>>> Basically, clear, concise documentation relevant to users and
>>>>> developers alike is key to having a bunch of features (or modules). There
>>>>> are projects like Apache Karaf which have like a bazillion features but
>>>>> tons of them are either undocumented or exist on entirely different
>>>>> projects (like ops4j, Felix, Aries, Geronimo, OpenEJB, OpenWebBeans, Weld,
>>>>> the list goes on and on). The documentation is the code so to say, and when
>>>>> that's split up into dozens of modules, good luck finding anything!
>>>>>
>>>>> I also think that encouraging users to use build systems like Maven or
>>>>> Gradle instead of relying on IDE builds should be encouraged. However, yes,
>>>>> it is important to document how to properly pull all the necessary
>>>>> libraries together manually. I know we've still got various Ant-based
>>>>> builds at my work that require a lot of work to get new libraries added
>>>>> (like Camel, CXF, etc.), and as a user, that's a huge pain. However, I
>>>>> think Log4j is a bit different than projects like Spring/CXF/Camel/Mule as
>>>>> with those projects, you tend to bring in tons of their modules (if not
>>>>> most of them); in Log4j, you only need the modules that correspond to the
>>>>> features you're using (which is probably in log4j-core most of the time;
>>>>> people still prefer logging to files). So instead of having a long chain of
>>>>> dependencies within our own project, anything outside log4j-core would only
>>>>> need third party dependencies/APIs rather than trying to figure out which
>>>>> set of Log4j dependencies are required for yet another Log4j dependency.
>>>>> That would be a much more modular system than the sort of modules we get
>>>>> from monoliths like Spring. (Speaking of Spring, to see just how ridiculous
>>>>> transitive dependencies have gotten, take a look at the Spring IO Platform
>>>>> project: <
>>>>> http://docs.spring.io/platform/docs/1.0.2.RELEASE/reference/htmlsingle/
>>>>> >)
>>>>>
>>>>> I also find that it helps testability when you separate things out a
>>>>> bit more. It can help identify weak areas that don't have many tests that
>>>>> would otherwise go unnoticed (without test coverage tools). It can help
>>>>> identify documentation gaps, too. A monolithic application can mask its
>>>>> lack of manuals or stability just out of its sheer size! I feel that way
>>>>> every time I work with a Java EE server (even though they all use OSGi
>>>>> nowadays) or proprietary libraries with even less documentation than your
>>>>> typical Incubator project. Plus, when things are modularised in a nice
>>>>> fashion (and not ad hoc), then it makes it that much easier for outside
>>>>> contributors to provide changes. Of course, that's more related to high
>>>>> cohesion and loose coupling, but having a module system helps enforce those
>>>>> goals.
>>>>>
>>>>>
>>>>> On 6 September 2014 12:22, Gary Gregory <garydgregory@gmail.com>
>>>>> wrote:
>>>>>
>>>>>> Hi Matt,
>>>>>>
>>>>>> Feel free to document your thinking process on the ML since we can't
>>>>>> banter around a water cooler...
>>>>>>
>>>>>> I'm all for packaging log4j in a way to make it appealing to the
>>>>>> widest audience. I am not fond personally of lots of little jars but it
>>>>>> seems to be what OSGi wants. It's that correct?
>>>>>>
>>>>>> Gary
>>>>>>
>>>>>>
>>>>>> -------- Original message --------
>>>>>> From: Matt Sicker
>>>>>> Date:09/06/2014 12:08 (GMT-05:00)
>>>>>> To: Log4J Developers List
>>>>>> Cc: Ralph Goers
>>>>>> Subject: Re: [02/29] Split out JMS appender and receiver into new
>>>>>> log4j module.
>>>>>>
>>>>>> The nice thing about it being separate from core is that you no
>>>>>> longer have
>>>>>> to make the JMS API optional, so this helps transitive dependency
>>>>>> resolution. I already fixed the OSGi problem while it was in core
>>>>>> (just had
>>>>>> to make it optional as well as provided). Was it part of log4j 1.2?
>>>>>>
>>>>>> http://activemq.apache.org/how-do-i-use-log4j-jms-appender-with-activemq.html
>>>>>>
>>>>>> Plus, log4j-web is split out, too, though now I'm starting to
>>>>>> reconsider
>>>>>> that.
>>>>>>
>>>>>>
>>>>>> On 6 September 2014 10:54, Gary Gregory <garydgregory@gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>> > Unless you count the JMS API jar which is not part of the JRE...
>>>>>> but is
>>>>>> > that reason enough to have a new module?
>>>>>> >
>>>>>> > Gary
>>>>>> >
>>>>>> >
>>>>>> > -------- Original message --------
>>>>>> > From: Ralph Goers
>>>>>> > Date:09/06/2014 09:17 (GMT-05:00)
>>>>>> > To: Log4J Developers List
>>>>>> > Subject: Re: [02/29] Split out JMS appender and receiver into new
>>>>>> log4j
>>>>>> > module.
>>>>>> >
>>>>>> > I think he is doing it for OSGi. But if it has no third party
>>>>>> dependencies
>>>>>> > I am not sure why it is necessary.
>>>>>> >
>>>>>> > Sent from my iPad
>>>>>> >
>>>>>> > > On Sep 6, 2014, at 5:14 AM, Gary Gregory <garydgregory@gmail.com>
>>>>>> wrote:
>>>>>> > >
>>>>>> > > What is the thought behind splitting JMS out of core?
>>>>>> > >
>>>>>> > > Gary
>>>>>> > >
>>>>>> > >
>>>>>> > > -------- Original message --------
>>>>>> > > From: mattsicker@apache.org
>>>>>> > > Date:09/06/2014 00:58 (GMT-05:00)
>>>>>> > > To: commits@logging.apache.org
>>>>>> > > Subject: [02/29] Split out JMS appender and receiver into new
>>>>>> log4j
>>>>>> > module.
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/pom.xml
>>>>>> > >
>>>>>> ----------------------------------------------------------------------
>>>>>> > > diff --git a/log4j-mom/pom.xml b/log4j-mom/pom.xml
>>>>>> > > new file mode 100644
>>>>>> > > index 0000000..6c3f760
>>>>>> > > --- /dev/null
>>>>>> > > +++ b/log4j-mom/pom.xml
>>>>>> > > @@ -0,0 +1,53 @@
>>>>>> > > +<?xml version="1.0" encoding="UTF-8"?>
>>>>>> > > +<project xmlns="http://maven.apache.org/POM/4.0.0"
>>>>>> > > +         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>>>>>> > > +         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
>>>>>> > http://maven.apache.org/xsd/maven-4.0.0.xsd">
>>>>>> > > +  <parent>
>>>>>> > > +    <artifactId>log4j</artifactId>
>>>>>> > > +    <groupId>org.apache.logging.log4j</groupId>
>>>>>> > > +    <version>2.0-SNAPSHOT</version>
>>>>>> > > +  </parent>
>>>>>> > > +  <modelVersion>4.0.0</modelVersion>
>>>>>> > > +
>>>>>> > > +  <artifactId>log4j-mom</artifactId>
>>>>>> > > +  <name>Log4j 2 MOM Plugins</name>
>>>>>> > > +  <description>Message Oriented Middleware plugins for Log4j
>>>>>> > 2</description>
>>>>>> > > +
>>>>>> > > +  <dependencies>
>>>>>> > > +    <dependency>
>>>>>> > > +      <groupId>org.apache.logging.log4j</groupId>
>>>>>> > > +      <artifactId>log4j-api</artifactId>
>>>>>> > > +    </dependency>
>>>>>> > > +    <dependency>
>>>>>> > > +      <groupId>org.apache.logging.log4j</groupId>
>>>>>> > > +      <artifactId>log4j-core</artifactId>
>>>>>> > > +    </dependency>
>>>>>> > > +    <dependency>
>>>>>> > > +      <groupId>org.jboss.spec.javax.jms</groupId>
>>>>>> > > +      <artifactId>jboss-jms-api_1.1_spec</artifactId>
>>>>>> > > +    </dependency>
>>>>>> > > +    <dependency>
>>>>>> > > +      <groupId>junit</groupId>
>>>>>> > > +      <artifactId>junit</artifactId>
>>>>>> > > +      <scope>test</scope>
>>>>>> > > +    </dependency>
>>>>>> > > +    <dependency>
>>>>>> > > +      <groupId>org.mockejb</groupId>
>>>>>> > > +      <artifactId>mockejb</artifactId>
>>>>>> > > +      <scope>test</scope>
>>>>>> > > +    </dependency>
>>>>>> > > +    <dependency>
>>>>>> > > +      <groupId>org.apache.logging.log4j</groupId>
>>>>>> > > +      <artifactId>log4j-core</artifactId>
>>>>>> > > +      <type>test-jar</type>
>>>>>> > > +      <scope>test</scope>
>>>>>> > > +    </dependency>
>>>>>> > > +    <dependency>
>>>>>> > > +      <groupId>org.mockito</groupId>
>>>>>> > > +      <artifactId>mockito-all</artifactId>
>>>>>> > > +      <version>1.9.5</version>
>>>>>> > > +      <scope>test</scope>
>>>>>> > > +    </dependency>
>>>>>> > > +  </dependencies>
>>>>>> > > +
>>>>>> > > +</project>
>>>>>> > > \ No newline at end of file
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
>>>>>> > >
>>>>>> ----------------------------------------------------------------------
>>>>>> > > diff --git
>>>>>> >
>>>>>> a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
>>>>>> > > new file mode 100644
>>>>>> > > index 0000000..284e1f6
>>>>>> > > --- /dev/null
>>>>>> > > +++
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsQueueAppender.java
>>>>>> > > @@ -0,0 +1,111 @@
>>>>>> > > +/*
>>>>>> > > + * 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.mom.jms.appender;
>>>>>> > > +
>>>>>> > > +import java.io.Serializable;
>>>>>> > > +
>>>>>> > > +import org.apache.logging.log4j.core.Filter;
>>>>>> > > +import org.apache.logging.log4j.core.Layout;
>>>>>> > > +import org.apache.logging.log4j.core.LogEvent;
>>>>>> > > +import org.apache.logging.log4j.core.appender.AbstractAppender;
>>>>>> > > +import
>>>>>> org.apache.logging.log4j.core.appender.AppenderLoggingException;
>>>>>> > > +import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>>>> > > +import
>>>>>> org.apache.logging.log4j.core.config.plugins.PluginAttribute;
>>>>>> > > +import
>>>>>> org.apache.logging.log4j.core.config.plugins.PluginElement;
>>>>>> > > +import
>>>>>> org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>>>>> > > +import org.apache.logging.log4j.core.layout.SerializedLayout;
>>>>>> > > +import org.apache.logging.log4j.mom.jms.receiver.JmsQueueManager;
>>>>>> > > +import org.apache.logging.log4j.core.util.Booleans;
>>>>>> > > +
>>>>>> > > +/**
>>>>>> > > + * Appender to write to a JMS Queue.
>>>>>> > > + */
>>>>>> > > +@Plugin(name = "JMSQueue", category = "Core", elementType =
>>>>>> "appender",
>>>>>> > printObject = true)
>>>>>> > > +public final class JmsQueueAppender extends AbstractAppender {
>>>>>> > > +
>>>>>> > > +    private final JmsQueueManager manager;
>>>>>> > > +
>>>>>> > > +    private JmsQueueAppender(final String name, final Filter
>>>>>> filter,
>>>>>> > final Layout<? extends Serializable> layout,
>>>>>> > > +                             final JmsQueueManager manager, final
>>>>>> > boolean ignoreExceptions) {
>>>>>> > > +        super(name, filter, layout, ignoreExceptions);
>>>>>> > > +        this.manager = manager;
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Actual writing occurs here.
>>>>>> > > +     *
>>>>>> > > +     * @param event The LogEvent.
>>>>>> > > +     */
>>>>>> > > +    @Override
>>>>>> > > +    public void append(final LogEvent event) {
>>>>>> > > +        try {
>>>>>> > > +            manager.send(getLayout().toSerializable(event));
>>>>>> > > +        } catch (final Exception ex) {
>>>>>> > > +            throw new AppenderLoggingException(ex);
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Create a JmsQueueAppender.
>>>>>> > > +     * @param name The name of the Appender.
>>>>>> > > +     * @param factoryName The fully qualified class name of the
>>>>>> > InitialContextFactory.
>>>>>> > > +     * @param providerURL The URL of the provider to use.
>>>>>> > > +     * @param urlPkgPrefixes A colon-separated list of package
>>>>>> prefixes
>>>>>> > for the class name of the factory class that
>>>>>> > > +     * will create a URL context factory
>>>>>> > > +     * @param securityPrincipalName The name of the identity of
>>>>>> the
>>>>>> > Principal.
>>>>>> > > +     * @param securityCredentials The security credentials of the
>>>>>> > Principal.
>>>>>> > > +     * @param factoryBindingName The name to locate in the
>>>>>> Context that
>>>>>> > provides the QueueConnectionFactory.
>>>>>> > > +     * @param queueBindingName The name to use to locate the
>>>>>> Queue.
>>>>>> > > +     * @param userName The user ID to use to create the Queue
>>>>>> > Connection.
>>>>>> > > +     * @param password The password to use to create the Queue
>>>>>> > Connection.
>>>>>> > > +     * @param layout The layout to use (defaults to
>>>>>> SerializedLayout).
>>>>>> > > +     * @param filter The Filter or null.
>>>>>> > > +     * @param ignore If {@code "true"} (default) exceptions
>>>>>> encountered
>>>>>> > when appending events are logged; otherwise
>>>>>> > > +     *               they are propagated to the caller.
>>>>>> > > +     * @return The JmsQueueAppender.
>>>>>> > > +     */
>>>>>> > > +    @PluginFactory
>>>>>> > > +    public static JmsQueueAppender createAppender(
>>>>>> > > +            @PluginAttribute("name") final String name,
>>>>>> > > +            @PluginAttribute("factoryName") final String
>>>>>> factoryName,
>>>>>> > > +            @PluginAttribute("providerURL") final String
>>>>>> providerURL,
>>>>>> > > +            @PluginAttribute("urlPkgPrefixes") final String
>>>>>> > urlPkgPrefixes,
>>>>>> > > +            @PluginAttribute("securityPrincipalName") final
>>>>>> String
>>>>>> > securityPrincipalName,
>>>>>> > > +            @PluginAttribute("securityCredentials") final String
>>>>>> > securityCredentials,
>>>>>> > > +            @PluginAttribute("factoryBindingName") final String
>>>>>> > factoryBindingName,
>>>>>> > > +            @PluginAttribute("queueBindingName") final String
>>>>>> > queueBindingName,
>>>>>> > > +            @PluginAttribute("userName") final String userName,
>>>>>> > > +            @PluginAttribute("password") final String password,
>>>>>> > > +            @PluginElement("Layout") Layout<? extends
>>>>>> Serializable>
>>>>>> > layout,
>>>>>> > > +            @PluginElement("Filter") final Filter filter,
>>>>>> > > +            @PluginAttribute("ignoreExceptions") final String
>>>>>> ignore) {
>>>>>> > > +        if (name == null) {
>>>>>> > > +            LOGGER.error("No name provided for
>>>>>> JmsQueueAppender");
>>>>>> > > +            return null;
>>>>>> > > +        }
>>>>>> > > +        final boolean ignoreExceptions =
>>>>>> Booleans.parseBoolean(ignore,
>>>>>> > true);
>>>>>> > > +        final JmsQueueManager manager =
>>>>>> > JmsQueueManager.getJmsQueueManager(factoryName, providerURL,
>>>>>> urlPkgPrefixes,
>>>>>> > > +            securityPrincipalName, securityCredentials,
>>>>>> > factoryBindingName, queueBindingName, userName, password);
>>>>>> > > +        if (manager == null) {
>>>>>> > > +            return null;
>>>>>> > > +        }
>>>>>> > > +        if (layout == null) {
>>>>>> > > +            layout = SerializedLayout.createLayout();
>>>>>> > > +        }
>>>>>> > > +        return new JmsQueueAppender(name, filter, layout,
>>>>>> manager,
>>>>>> > ignoreExceptions);
>>>>>> > > +    }
>>>>>> > > +}
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
>>>>>> > >
>>>>>> ----------------------------------------------------------------------
>>>>>> > > diff --git
>>>>>> >
>>>>>> a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
>>>>>> > > new file mode 100644
>>>>>> > > index 0000000..9985746
>>>>>> > > --- /dev/null
>>>>>> > > +++
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/JmsTopicAppender.java
>>>>>> > > @@ -0,0 +1,112 @@
>>>>>> > > +/*
>>>>>> > > + * 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.mom.jms.appender;
>>>>>> > > +
>>>>>> > > +import java.io.Serializable;
>>>>>> > > +
>>>>>> > > +import org.apache.logging.log4j.core.Filter;
>>>>>> > > +import org.apache.logging.log4j.core.Layout;
>>>>>> > > +import org.apache.logging.log4j.core.LogEvent;
>>>>>> > > +import org.apache.logging.log4j.core.appender.AbstractAppender;
>>>>>> > > +import
>>>>>> org.apache.logging.log4j.core.appender.AppenderLoggingException;
>>>>>> > > +import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>>>> > > +import
>>>>>> org.apache.logging.log4j.core.config.plugins.PluginAttribute;
>>>>>> > > +import
>>>>>> org.apache.logging.log4j.core.config.plugins.PluginElement;
>>>>>> > > +import
>>>>>> org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>>>>> > > +import org.apache.logging.log4j.core.layout.SerializedLayout;
>>>>>> > > +import org.apache.logging.log4j.mom.jms.receiver.JmsTopicManager;
>>>>>> > > +import org.apache.logging.log4j.core.util.Booleans;
>>>>>> > > +
>>>>>> > > +/**
>>>>>> > > + * Appender to write to a JMS Topic.
>>>>>> > > + */
>>>>>> > > +@Plugin(name = "JMSTopic", category = "Core", elementType =
>>>>>> "appender",
>>>>>> > printObject = true)
>>>>>> > > +public final class JmsTopicAppender extends AbstractAppender {
>>>>>> > > +
>>>>>> > > +    private final JmsTopicManager manager;
>>>>>> > > +
>>>>>> > > +    private JmsTopicAppender(final String name, final Filter
>>>>>> filter,
>>>>>> > final Layout<? extends Serializable> layout,
>>>>>> > > +                             final JmsTopicManager manager, final
>>>>>> > boolean ignoreExceptions) {
>>>>>> > > +        super(name, filter, layout, ignoreExceptions);
>>>>>> > > +        this.manager = manager;
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Actual writing occurs here.
>>>>>> > > +     * <p/>
>>>>>> > > +     * @param event The LogEvent.
>>>>>> > > +     */
>>>>>> > > +    @Override
>>>>>> > > +    public void append(final LogEvent event) {
>>>>>> > > +        try {
>>>>>> > > +            manager.send(getLayout().toSerializable(event));
>>>>>> > > +        } catch (final Exception ex) {
>>>>>> > > +            throw new AppenderLoggingException(ex);
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Create a JmsTopicAppender.
>>>>>> > > +     * @param name The name of the Appender.
>>>>>> > > +     * @param factoryName The fully qualified class name of the
>>>>>> > InitialContextFactory.
>>>>>> > > +     * @param providerURL The URL of the provider to use.
>>>>>> > > +     * @param urlPkgPrefixes A colon-separated list of package
>>>>>> prefixes
>>>>>> > for the class name of the factory class that
>>>>>> > > +     * will create a URL context factory
>>>>>> > > +     * @param securityPrincipalName The name of the identity of
>>>>>> the
>>>>>> > Principal.
>>>>>> > > +     * @param securityCredentials The security credentials of the
>>>>>> > Principal.
>>>>>> > > +     * @param factoryBindingName The name to locate in the
>>>>>> Context that
>>>>>> > provides the TopicConnectionFactory.
>>>>>> > > +     * @param topicBindingName The name to use to locate the
>>>>>> Topic.
>>>>>> > > +     * @param userName The userid to use to create the Topic
>>>>>> Connection.
>>>>>> > > +     * @param password The password to use to create the Topic
>>>>>> > Connection.
>>>>>> > > +     * @param layout The layout to use (defaults to
>>>>>> SerializedLayout).
>>>>>> > > +     * @param filter The Filter or null.
>>>>>> > > +     * @param ignore If {@code "true"} (default) exceptions
>>>>>> encountered
>>>>>> > when appending events are logged; otherwise
>>>>>> > > +     *               they are propagated to the caller.
>>>>>> > > +     * @return The JmsTopicAppender.
>>>>>> > > +     */
>>>>>> > > +    @PluginFactory
>>>>>> > > +    public static JmsTopicAppender createAppender(
>>>>>> > > +            @PluginAttribute("name") final String name,
>>>>>> > > +            @PluginAttribute("factoryName") final String
>>>>>> factoryName,
>>>>>> > > +            @PluginAttribute("providerURL") final String
>>>>>> providerURL,
>>>>>> > > +            @PluginAttribute("urlPkgPrefixes") final String
>>>>>> > urlPkgPrefixes,
>>>>>> > > +            @PluginAttribute("securityPrincipalName") final
>>>>>> String
>>>>>> > securityPrincipalName,
>>>>>> > > +            @PluginAttribute("securityCredentials") final String
>>>>>> > securityCredentials,
>>>>>> > > +            @PluginAttribute("factoryBindingName") final String
>>>>>> > factoryBindingName,
>>>>>> > > +            @PluginAttribute("topicBindingName") final String
>>>>>> > topicBindingName,
>>>>>> > > +            @PluginAttribute("userName") final String userName,
>>>>>> > > +            @PluginAttribute("password") final String password,
>>>>>> > > +            @PluginElement("Layout") Layout<? extends
>>>>>> Serializable>
>>>>>> > layout,
>>>>>> > > +            @PluginElement("Filters") final Filter filter,
>>>>>> > > +            @PluginAttribute("ignoreExceptions") final String
>>>>>> ignore) {
>>>>>> > > +
>>>>>> > > +        if (name == null) {
>>>>>> > > +            LOGGER.error("No name provided for
>>>>>> JmsQueueAppender");
>>>>>> > > +            return null;
>>>>>> > > +        }
>>>>>> > > +        final boolean ignoreExceptions =
>>>>>> Booleans.parseBoolean(ignore,
>>>>>> > true);
>>>>>> > > +        final JmsTopicManager manager =
>>>>>> > JmsTopicManager.getJmsTopicManager(factoryName, providerURL,
>>>>>> urlPkgPrefixes,
>>>>>> > > +            securityPrincipalName, securityCredentials,
>>>>>> > factoryBindingName, topicBindingName, userName, password);
>>>>>> > > +        if (manager == null) {
>>>>>> > > +            return null;
>>>>>> > > +        }
>>>>>> > > +        if (layout == null) {
>>>>>> > > +            layout = SerializedLayout.createLayout();
>>>>>> > > +        }
>>>>>> > > +        return new JmsTopicAppender(name, filter, layout,
>>>>>> manager,
>>>>>> > ignoreExceptions);
>>>>>> > > +    }
>>>>>> > > +}
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
>>>>>> > >
>>>>>> ----------------------------------------------------------------------
>>>>>> > > diff --git
>>>>>> >
>>>>>> a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
>>>>>> > > new file mode 100644
>>>>>> > > index 0000000..0c7a4ff
>>>>>> > > --- /dev/null
>>>>>> > > +++
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/appender/package-info.java
>>>>>> > > @@ -0,0 +1,20 @@
>>>>>> > > +/*
>>>>>> > > + * 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.
>>>>>> > > + */
>>>>>> > > +/**
>>>>>> > > + * Appender classes for using JMS. These are directly configured
>>>>>> > through your log4j2 configuration file.
>>>>>> > > + */
>>>>>> > > +package org.apache.logging.log4j.mom.jms.appender;
>>>>>> > > \ No newline at end of file
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
>>>>>> > >
>>>>>> ----------------------------------------------------------------------
>>>>>> > > diff --git
>>>>>> >
>>>>>> a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
>>>>>> > > new file mode 100644
>>>>>> > > index 0000000..d3ae2a3
>>>>>> > > --- /dev/null
>>>>>> > > +++
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsManager.java
>>>>>> > > @@ -0,0 +1,155 @@
>>>>>> > > +/*
>>>>>> > > + * 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.mom.jms.receiver;
>>>>>> > > +
>>>>>> > > +import java.io.Serializable;
>>>>>> > > +import java.util.Properties;
>>>>>> > > +
>>>>>> > > +import javax.jms.JMSException;
>>>>>> > > +import javax.jms.Message;
>>>>>> > > +import javax.jms.MessageProducer;
>>>>>> > > +import javax.jms.ObjectMessage;
>>>>>> > > +import javax.jms.Session;
>>>>>> > > +import javax.jms.TextMessage;
>>>>>> > > +import javax.naming.Context;
>>>>>> > > +import javax.naming.InitialContext;
>>>>>> > > +import javax.naming.NameNotFoundException;
>>>>>> > > +import javax.naming.NamingException;
>>>>>> > > +
>>>>>> > > +import org.apache.logging.log4j.core.appender.AbstractManager;
>>>>>> > > +
>>>>>> > > +/**
>>>>>> > > + * Base Class for Managers of JMS connections.
>>>>>> > > + */
>>>>>> > > +public abstract class AbstractJmsManager extends AbstractManager
>>>>>> {
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * The Constructor.
>>>>>> > > +     * @param name The name of the Appender.
>>>>>> > > +     */
>>>>>> > > +    public AbstractJmsManager(final String name) {
>>>>>> > > +        super(name);
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Create the InitialContext.
>>>>>> > > +     * @param factoryName The fully qualified class name of the
>>>>>> > InitialContextFactory.
>>>>>> > > +     * @param providerURL The URL of the provider to use.
>>>>>> > > +     * @param urlPkgPrefixes A colon-separated list of package
>>>>>> prefixes
>>>>>> > for the class name of the factory class that
>>>>>> > > +     * will create a URL context factory
>>>>>> > > +     * @param securityPrincipalName The name of the identity of
>>>>>> the
>>>>>> > Principal.
>>>>>> > > +     * @param securityCredentials The security credentials of the
>>>>>> > Principal.
>>>>>> > > +     * @return the InitialContext.
>>>>>> > > +     * @throws NamingException if a naming error occurs.
>>>>>> > > +     */
>>>>>> > > +    protected static Context createContext(final String
>>>>>> factoryName,
>>>>>> > final String providerURL,
>>>>>> > > +                                           final String
>>>>>> urlPkgPrefixes,
>>>>>> > final String securityPrincipalName,
>>>>>> > > +                                           final String
>>>>>> > securityCredentials)
>>>>>> > > +        throws NamingException {
>>>>>> > > +
>>>>>> > > +        final Properties props = getEnvironment(factoryName,
>>>>>> > providerURL, urlPkgPrefixes, securityPrincipalName,
>>>>>> > > +                                          securityCredentials);
>>>>>> > > +        return new InitialContext(props);
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Looks up the name in the context.
>>>>>> > > +     * @param ctx The Context.
>>>>>> > > +     * @param name The name to locate.
>>>>>> > > +     * @return The object to be located.
>>>>>> > > +     * @throws NamingException If an error occurs locating the
>>>>>> name.
>>>>>> > > +     */
>>>>>> > > +    protected static Object lookup(final Context ctx, final
>>>>>> String
>>>>>> > name) throws NamingException {
>>>>>> > > +        try {
>>>>>> > > +            return ctx.lookup(name);
>>>>>> > > +        } catch (final NameNotFoundException e) {
>>>>>> > > +            LOGGER.warn("Could not find name [{}].", name);
>>>>>> > > +            throw e;
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Sets up the properties to pass to the InitialContext.
>>>>>> > > +     * @param factoryName The fully qualified class name of the
>>>>>> > InitialContextFactory.
>>>>>> > > +     * @param providerURL The URL of the provider to use.
>>>>>> > > +     * @param urlPkgPrefixes A colon-separated list of package
>>>>>> prefixes
>>>>>> > for the class name of the factory class that
>>>>>> > > +     * will create a URL context factory
>>>>>> > > +     * @param securityPrincipalName The name of the identity of
>>>>>> the
>>>>>> > Principal.
>>>>>> > > +     * @param securityCredentials The security credentials of the
>>>>>> > Principal.
>>>>>> > > +     * @return The Properties.
>>>>>> > > +     */
>>>>>> > > +    protected static Properties getEnvironment(final String
>>>>>> > factoryName, final String providerURL,
>>>>>> > > +                                               final String
>>>>>> > urlPkgPrefixes, final String securityPrincipalName,
>>>>>> > > +                                               final String
>>>>>> > securityCredentials) {
>>>>>> > > +        final Properties props = new Properties();
>>>>>> > > +        if (factoryName != null) {
>>>>>> > > +            props.put(Context.INITIAL_CONTEXT_FACTORY,
>>>>>> factoryName);
>>>>>> > > +            if (providerURL != null) {
>>>>>> > > +                props.put(Context.PROVIDER_URL, providerURL);
>>>>>> > > +            } else {
>>>>>> > > +                LOGGER.warn("The InitialContext factory name has
>>>>>> been
>>>>>> > provided without a ProviderURL. " +
>>>>>> > > +                    "This is likely to cause problems");
>>>>>> > > +            }
>>>>>> > > +            if (urlPkgPrefixes != null) {
>>>>>> > > +                props.put(Context.URL_PKG_PREFIXES,
>>>>>> urlPkgPrefixes);
>>>>>> > > +            }
>>>>>> > > +            if (securityPrincipalName != null) {
>>>>>> > > +                props.put(Context.SECURITY_PRINCIPAL,
>>>>>> > securityPrincipalName);
>>>>>> > > +                if (securityCredentials != null) {
>>>>>> > > +                    props.put(Context.SECURITY_CREDENTIALS,
>>>>>> > securityCredentials);
>>>>>> > > +                } else {
>>>>>> > > +                    LOGGER.warn("SecurityPrincipalName has been
>>>>>> set
>>>>>> > without SecurityCredentials. " +
>>>>>> > > +                        "This is likely to cause problems.");
>>>>>> > > +                }
>>>>>> > > +            }
>>>>>> > > +            return props;
>>>>>> > > +        }
>>>>>> > > +        return null;
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Send the message.
>>>>>> > > +     * @param object The Object to sent.
>>>>>> > > +     * @throws Exception if an error occurs.
>>>>>> > > +     */
>>>>>> > > +    public abstract void send(Serializable object) throws
>>>>>> Exception;
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Send the Object.
>>>>>> > > +     * @param object The Object to send.
>>>>>> > > +     * @param session The Session.
>>>>>> > > +     * @param producer The MessageProducer.
>>>>>> > > +     * @throws Exception if an error occurs.
>>>>>> > > +     */
>>>>>> > > +    public synchronized void send(final Serializable object,
>>>>>> final
>>>>>> > Session session, final MessageProducer producer)
>>>>>> > > +        throws Exception {
>>>>>> > > +        try {
>>>>>> > > +            Message msg;
>>>>>> > > +            if (object instanceof String) {
>>>>>> > > +                msg = session.createTextMessage();
>>>>>> > > +                ((TextMessage) msg).setText((String) object);
>>>>>> > > +            } else {
>>>>>> > > +                msg = session.createObjectMessage();
>>>>>> > > +                ((ObjectMessage) msg).setObject(object);
>>>>>> > > +            }
>>>>>> > > +            producer.send(msg);
>>>>>> > > +        } catch (final JMSException ex) {
>>>>>> > > +            LOGGER.error("Could not publish message via JMS {}",
>>>>>> > getName());
>>>>>> > > +            throw ex;
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +}
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
>>>>>> > >
>>>>>> ----------------------------------------------------------------------
>>>>>> > > diff --git
>>>>>> >
>>>>>> a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
>>>>>> > > new file mode 100644
>>>>>> > > index 0000000..bf86c65
>>>>>> > > --- /dev/null
>>>>>> > > +++
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/AbstractJmsReceiver.java
>>>>>> > > @@ -0,0 +1,83 @@
>>>>>> > > +/*
>>>>>> > > + * 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.mom.jms.receiver;
>>>>>> > > +
>>>>>> > > +import java.io.Serializable;
>>>>>> > > +
>>>>>> > > +import javax.jms.JMSException;
>>>>>> > > +import javax.jms.ObjectMessage;
>>>>>> > > +import javax.naming.Context;
>>>>>> > > +import javax.naming.NameNotFoundException;
>>>>>> > > +import javax.naming.NamingException;
>>>>>> > > +
>>>>>> > > +import org.apache.logging.log4j.LogManager;
>>>>>> > > +import org.apache.logging.log4j.Logger;
>>>>>> > > +import org.apache.logging.log4j.core.LogEvent;
>>>>>> > > +import org.apache.logging.log4j.core.LogEventListener;
>>>>>> > > +
>>>>>> > > +/**
>>>>>> > > + * Abstract base class for receiving LogEvents over JMS. This
>>>>>> class
>>>>>> > expects all messages to be serialized log events.
>>>>>> > > + */
>>>>>> > > +public abstract class AbstractJmsReceiver extends
>>>>>> LogEventListener
>>>>>> > implements javax.jms.MessageListener {
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Logger to capture diagnostics.
>>>>>> > > +     */
>>>>>> > > +    protected Logger logger =
>>>>>> > LogManager.getLogger(this.getClass().getName());
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Listener that receives the event.
>>>>>> > > +     * @param message The received message.
>>>>>> > > +     */
>>>>>> > > +    @Override
>>>>>> > > +    public void onMessage(final javax.jms.Message message) {
>>>>>> > > +        try {
>>>>>> > > +            if (message instanceof ObjectMessage) {
>>>>>> > > +                final ObjectMessage objectMessage =
>>>>>> (ObjectMessage)
>>>>>> > message;
>>>>>> > > +                final Serializable object =
>>>>>> objectMessage.getObject();
>>>>>> > > +                if (object instanceof LogEvent) {
>>>>>> > > +                    log((LogEvent) object);
>>>>>> > > +                } else {
>>>>>> > > +                    logger.warn("Received message is of type " +
>>>>>> > object.getClass().getName() + ", was expecting LogEvent.");
>>>>>> > > +                }
>>>>>> > > +            } else {
>>>>>> > > +                logger.warn("Received message is of type " +
>>>>>> > message.getJMSType()
>>>>>> > > +                    + ", was expecting ObjectMessage.");
>>>>>> > > +            }
>>>>>> > > +        } catch (final JMSException jmse) {
>>>>>> > > +            logger.error("Exception thrown while processing
>>>>>> incoming
>>>>>> > message.",
>>>>>> > > +                jmse);
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Looks up an object from the Context.
>>>>>> > > +     * @param ctx The Context.
>>>>>> > > +     * @param name The name of the object to locate.
>>>>>> > > +     * @return The object.
>>>>>> > > +     * @throws NamingException if an error occurs.
>>>>>> > > +     */
>>>>>> > > +    protected Object lookup(final Context ctx, final String name)
>>>>>> > throws NamingException {
>>>>>> > > +        try {
>>>>>> > > +            return ctx.lookup(name);
>>>>>> > > +        } catch (final NameNotFoundException e) {
>>>>>> > > +            logger.error("Could not find name [" + name + "].");
>>>>>> > > +            throw e;
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +}
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
>>>>>> > >
>>>>>> ----------------------------------------------------------------------
>>>>>> > > diff --git
>>>>>> >
>>>>>> a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
>>>>>> > > new file mode 100644
>>>>>> > > index 0000000..6825282
>>>>>> > > --- /dev/null
>>>>>> > > +++
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueManager.java
>>>>>> > > @@ -0,0 +1,237 @@
>>>>>> > > +/*
>>>>>> > > + * 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.mom.jms.receiver;
>>>>>> > > +
>>>>>> > > +import java.io.Serializable;
>>>>>> > > +
>>>>>> > > +import javax.jms.JMSException;
>>>>>> > > +import javax.jms.Queue;
>>>>>> > > +import javax.jms.QueueConnection;
>>>>>> > > +import javax.jms.QueueConnectionFactory;
>>>>>> > > +import javax.jms.QueueSender;
>>>>>> > > +import javax.jms.QueueSession;
>>>>>> > > +import javax.jms.Session;
>>>>>> > > +import javax.naming.Context;
>>>>>> > > +import javax.naming.NamingException;
>>>>>> > > +
>>>>>> > > +import org.apache.logging.log4j.core.appender.ManagerFactory;
>>>>>> > > +
>>>>>> > > +/**
>>>>>> > > + * Manager for a JMS Queue.
>>>>>> > > + */
>>>>>> > > +public class JmsQueueManager extends AbstractJmsManager {
>>>>>> > > +
>>>>>> > > +    private static final JMSQueueManagerFactory FACTORY = new
>>>>>> > JMSQueueManagerFactory();
>>>>>> > > +
>>>>>> > > +    private QueueInfo info;
>>>>>> > > +    private final String factoryBindingName;
>>>>>> > > +    private final String queueBindingName;
>>>>>> > > +    private final String userName;
>>>>>> > > +    private final String password;
>>>>>> > > +    private final Context context;
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * The Constructor.
>>>>>> > > +     * @param name The unique name of the connection.
>>>>>> > > +     * @param context The context.
>>>>>> > > +     * @param factoryBindingName The factory binding name.
>>>>>> > > +     * @param queueBindingName The queue binding name.
>>>>>> > > +     * @param userName The user name.
>>>>>> > > +     * @param password The credentials for the user.
>>>>>> > > +     * @param info The Queue connection info.
>>>>>> > > +     */
>>>>>> > > +    protected JmsQueueManager(final String name, final Context
>>>>>> context,
>>>>>> > final String factoryBindingName,
>>>>>> > > +                              final String queueBindingName,
>>>>>> final
>>>>>> > String userName, final String password,
>>>>>> > > +                              final QueueInfo info) {
>>>>>> > > +        super(name);
>>>>>> > > +        this.context = context;
>>>>>> > > +        this.factoryBindingName = factoryBindingName;
>>>>>> > > +        this.queueBindingName = queueBindingName;
>>>>>> > > +        this.userName = userName;
>>>>>> > > +        this.password = password;
>>>>>> > > +        this.info = info;
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Obtain a JmsQueueManager.
>>>>>> > > +     * @param factoryName The fully qualified class name of the
>>>>>> > InitialContextFactory.
>>>>>> > > +     * @param providerURL The URL of the provider to use.
>>>>>> > > +     * @param urlPkgPrefixes A colon-separated list of package
>>>>>> prefixes
>>>>>> > for the class name of the factory class that
>>>>>> > > +     * will create a URL context factory
>>>>>> > > +     * @param securityPrincipalName The name of the identity of
>>>>>> the
>>>>>> > Principal.
>>>>>> > > +     * @param securityCredentials The security credentials of the
>>>>>> > Principal.
>>>>>> > > +     * @param factoryBindingName The name to locate in the
>>>>>> Context that
>>>>>> > provides the QueueConnectionFactory.
>>>>>> > > +     * @param queueBindingName The name to use to locate the
>>>>>> Queue.
>>>>>> > > +     * @param userName The userid to use to create the Queue
>>>>>> Connection.
>>>>>> > > +     * @param password The password to use to create the Queue
>>>>>> > Connection.
>>>>>> > > +     * @return The JmsQueueManager.
>>>>>> > > +     */
>>>>>> > > +    public static JmsQueueManager getJmsQueueManager(final String
>>>>>> > factoryName, final String providerURL,
>>>>>> > > +                                                     final String
>>>>>> > urlPkgPrefixes, final String securityPrincipalName,
>>>>>> > > +                                                     final String
>>>>>> > securityCredentials, final String factoryBindingName,
>>>>>> > > +                                                     final String
>>>>>> > queueBindingName, final String userName,
>>>>>> > > +                                                     final String
>>>>>> > password) {
>>>>>> > > +
>>>>>> > > +        if (factoryBindingName == null) {
>>>>>> > > +            LOGGER.error("No factory name provided for
>>>>>> > JmsQueueManager");
>>>>>> > > +            return null;
>>>>>> > > +        }
>>>>>> > > +        if (queueBindingName == null) {
>>>>>> > > +            LOGGER.error("No topic name provided for
>>>>>> JmsQueueManager");
>>>>>> > > +            return null;
>>>>>> > > +        }
>>>>>> > > +
>>>>>> > > +        final String name = "JMSQueue:" + factoryBindingName +
>>>>>> '.' +
>>>>>> > queueBindingName;
>>>>>> > > +        return getManager(name, FACTORY, new
>>>>>> FactoryData(factoryName,
>>>>>> > providerURL, urlPkgPrefixes,
>>>>>> > > +            securityPrincipalName, securityCredentials,
>>>>>> > factoryBindingName, queueBindingName, userName, password));
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    @Override
>>>>>> > > +    public synchronized void send(final Serializable object)
>>>>>> throws
>>>>>> > Exception {
>>>>>> > > +        if (info == null) {
>>>>>> > > +            info = connect(context, factoryBindingName,
>>>>>> > queueBindingName, userName, password, false);
>>>>>> > > +        }
>>>>>> > > +        try {
>>>>>> > > +            super.send(object, info.session, info.sender);
>>>>>> > > +        } catch (final Exception ex) {
>>>>>> > > +            cleanup(true);
>>>>>> > > +            throw ex;
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    @Override
>>>>>> > > +    public void releaseSub() {
>>>>>> > > +        if (info != null) {
>>>>>> > > +            cleanup(false);
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    private void cleanup(final boolean quiet) {
>>>>>> > > +        try {
>>>>>> > > +            info.session.close();
>>>>>> > > +        } catch (final Exception e) {
>>>>>> > > +            if (!quiet) {
>>>>>> > > +                LOGGER.error("Error closing session for " +
>>>>>> getName(),
>>>>>> > e);
>>>>>> > > +            }
>>>>>> > > +        }
>>>>>> > > +        try {
>>>>>> > > +            info.conn.close();
>>>>>> > > +        } catch (final Exception e) {
>>>>>> > > +            if (!quiet) {
>>>>>> > > +                LOGGER.error("Error closing connection for " +
>>>>>> > getName(), e);
>>>>>> > > +            }
>>>>>> > > +        }
>>>>>> > > +        info = null;
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Data for the factory.
>>>>>> > > +     */
>>>>>> > > +    private static class FactoryData {
>>>>>> > > +        private final String factoryName;
>>>>>> > > +        private final String providerURL;
>>>>>> > > +        private final String urlPkgPrefixes;
>>>>>> > > +        private final String securityPrincipalName;
>>>>>> > > +        private final String securityCredentials;
>>>>>> > > +        private final String factoryBindingName;
>>>>>> > > +        private final String queueBindingName;
>>>>>> > > +        private final String userName;
>>>>>> > > +        private final String password;
>>>>>> > > +
>>>>>> > > +        public FactoryData(final String factoryName, final String
>>>>>> > providerURL, final String urlPkgPrefixes,
>>>>>> > > +                           final String securityPrincipalName,
>>>>>> final
>>>>>> > String securityCredentials,
>>>>>> > > +                           final String factoryBindingName, final
>>>>>> > String queueBindingName, final String userName,
>>>>>> > > +                           final String password) {
>>>>>> > > +            this.factoryName = factoryName;
>>>>>> > > +            this.providerURL = providerURL;
>>>>>> > > +            this.urlPkgPrefixes = urlPkgPrefixes;
>>>>>> > > +            this.securityPrincipalName = securityPrincipalName;
>>>>>> > > +            this.securityCredentials = securityCredentials;
>>>>>> > > +            this.factoryBindingName = factoryBindingName;
>>>>>> > > +            this.queueBindingName = queueBindingName;
>>>>>> > > +            this.userName = userName;
>>>>>> > > +            this.password = password;
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    private static QueueInfo connect(final Context context, final
>>>>>> > String factoryBindingName,
>>>>>> > > +                                     final String
>>>>>> queueBindingName,
>>>>>> > final String userName, final String password,
>>>>>> > > +                                     final boolean suppress)
>>>>>> throws
>>>>>> > Exception {
>>>>>> > > +        try {
>>>>>> > > +            final QueueConnectionFactory factory =
>>>>>> > (QueueConnectionFactory) lookup(context, factoryBindingName);
>>>>>> > > +            QueueConnection conn;
>>>>>> > > +            if (userName != null) {
>>>>>> > > +                conn = factory.createQueueConnection(userName,
>>>>>> > password);
>>>>>> > > +            } else {
>>>>>> > > +                conn = factory.createQueueConnection();
>>>>>> > > +            }
>>>>>> > > +            final QueueSession sess =
>>>>>> conn.createQueueSession(false,
>>>>>> > Session.AUTO_ACKNOWLEDGE);
>>>>>> > > +            final Queue queue = (Queue) lookup(context,
>>>>>> > queueBindingName);
>>>>>> > > +            final QueueSender sender = sess.createSender(queue);
>>>>>> > > +            conn.start();
>>>>>> > > +            return new QueueInfo(conn, sess, sender);
>>>>>> > > +        } catch (final NamingException ex) {
>>>>>> > > +            LOGGER.warn("Unable to locate connection factory " +
>>>>>> > factoryBindingName, ex);
>>>>>> > > +            if (!suppress) {
>>>>>> > > +                throw ex;
>>>>>> > > +            }
>>>>>> > > +        } catch (final JMSException ex) {
>>>>>> > > +            LOGGER.warn("Unable to create connection to queue " +
>>>>>> > queueBindingName, ex);
>>>>>> > > +            if (!suppress) {
>>>>>> > > +                throw ex;
>>>>>> > > +            }
>>>>>> > > +        }
>>>>>> > > +        return null;
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /** Queue connection information */
>>>>>> > > +    private static class QueueInfo {
>>>>>> > > +        private final QueueConnection conn;
>>>>>> > > +        private final QueueSession session;
>>>>>> > > +        private final QueueSender sender;
>>>>>> > > +
>>>>>> > > +        public QueueInfo(final QueueConnection conn, final
>>>>>> QueueSession
>>>>>> > session, final QueueSender sender) {
>>>>>> > > +            this.conn = conn;
>>>>>> > > +            this.session = session;
>>>>>> > > +            this.sender = sender;
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Factory to create the JmsQueueManager.
>>>>>> > > +     */
>>>>>> > > +    private static class JMSQueueManagerFactory implements
>>>>>> > ManagerFactory<JmsQueueManager, FactoryData> {
>>>>>> > > +
>>>>>> > > +        @Override
>>>>>> > > +        public JmsQueueManager createManager(final String name,
>>>>>> final
>>>>>> > FactoryData data) {
>>>>>> > > +            try {
>>>>>> > > +                final Context ctx =
>>>>>> createContext(data.factoryName,
>>>>>> > data.providerURL, data.urlPkgPrefixes,
>>>>>> > > +
>>>>>> data.securityPrincipalName,
>>>>>> > data.securityCredentials);
>>>>>> > > +                final QueueInfo info = connect(ctx,
>>>>>> > data.factoryBindingName, data.queueBindingName, data.userName,
>>>>>> > > +                    data.password, true);
>>>>>> > > +                return new JmsQueueManager(name, ctx,
>>>>>> > data.factoryBindingName, data.queueBindingName,
>>>>>> > > +                    data.userName, data.password, info);
>>>>>> > > +            } catch (final NamingException ex) {
>>>>>> > > +                LOGGER.error("Unable to locate resource", ex);
>>>>>> > > +            } catch (final Exception ex) {
>>>>>> > > +                LOGGER.error("Unable to connect", ex);
>>>>>> > > +            }
>>>>>> > > +
>>>>>> > > +            return null;
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +}
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
>>>>>> > >
>>>>>> ----------------------------------------------------------------------
>>>>>> > > diff --git
>>>>>> >
>>>>>> a/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
>>>>>> > > new file mode 100644
>>>>>> > > index 0000000..b231489
>>>>>> > > --- /dev/null
>>>>>> > > +++
>>>>>> >
>>>>>> b/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsQueueReceiver.java
>>>>>> > > @@ -0,0 +1,107 @@
>>>>>> > > +/*
>>>>>> > > + * 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.mom.jms.receiver;
>>>>>> > > +
>>>>>> > > +import java.io.BufferedReader;
>>>>>> > > +import java.io.InputStreamReader;
>>>>>> > > +import java.nio.charset.Charset;
>>>>>> > > +
>>>>>> > > +import javax.jms.JMSException;
>>>>>> > > +import javax.jms.Queue;
>>>>>> > > +import javax.jms.QueueConnection;
>>>>>> > > +import javax.jms.QueueConnectionFactory;
>>>>>> > > +import javax.jms.QueueReceiver;
>>>>>> > > +import javax.jms.QueueSession;
>>>>>> > > +import javax.jms.Session;
>>>>>> > > +import javax.naming.Context;
>>>>>> > > +import javax.naming.InitialContext;
>>>>>> > > +import javax.naming.NamingException;
>>>>>> > > +
>>>>>> > > +/**
>>>>>> > > + * Receives Log Events over a JMS Queue. This implementation
>>>>>> expects
>>>>>> > that all messages will
>>>>>> > > + * contain a serialized LogEvent.
>>>>>> > > + */
>>>>>> > > +public class JmsQueueReceiver extends AbstractJmsReceiver {
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Constructor.
>>>>>> > > +     * @param qcfBindingName The QueueConnectionFactory binding
>>>>>> name.
>>>>>> > > +     * @param queueBindingName The Queue binding name.
>>>>>> > > +     * @param username The userid to connect to the queue.
>>>>>> > > +     * @param password The password to connect to the queue.
>>>>>> > > +     */
>>>>>> > > +    public JmsQueueReceiver(final String qcfBindingName, final
>>>>>> String
>>>>>> > queueBindingName, final String username,
>>>>>> > > +                            final String password) {
>>>>>> > > +
>>>>>> > > +        try {
>>>>>> > > +            final Context ctx = new InitialContext();
>>>>>> > > +            QueueConnectionFactory queueConnectionFactory;
>>>>>> > > +            queueConnectionFactory = (QueueConnectionFactory)
>>>>>> > lookup(ctx, qcfBindingName);
>>>>>> > > +            final QueueConnection queueConnection =
>>>>>> > queueConnectionFactory.createQueueConnection(username, password);
>>>>>> > > +            queueConnection.start();
>>>>>> > > +            final QueueSession queueSession =
>>>>>> > queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
>>>>>> > > +            final Queue queue = (Queue)
>>>>>> ctx.lookup(queueBindingName);
>>>>>> > > +            final QueueReceiver queueReceiver =
>>>>>> > queueSession.createReceiver(queue);
>>>>>> > > +            queueReceiver.setMessageListener(this);
>>>>>> > > +        } catch (final JMSException e) {
>>>>>> > > +            logger.error("Could not read JMS message.", e);
>>>>>> > > +        } catch (final NamingException e) {
>>>>>> > > +            logger.error("Could not read JMS message.", e);
>>>>>> > > +        } catch (final RuntimeException e) {
>>>>>> > > +            logger.error("Could not read JMS message.", e);
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +    /**
>>>>>> > > +     * Main startup for the receiver.
>>>>>> > > +     * @param args The command line arguments.
>>>>>> > > +     * @throws Exception if an error occurs.
>>>>>> > > +     */
>>>>>> > > +    public static void main(final String[] args) throws
>>>>>> Exception {
>>>>>> > > +        if (args.length != 4) {
>>>>>> > > +            usage("Wrong number of arguments.");
>>>>>> > > +        }
>>>>>> > > +
>>>>>> > > +        final String qcfBindingName = args[0];
>>>>>> > > +        final String queueBindingName = args[1];
>>>>>> > > +        final String username = args[2];
>>>>>> > > +        final String password = args[3];
>>>>>> > > +
>>>>>> > > +        new JmsQueueReceiver(qcfBindingName, queueBindingName,
>>>>>> > username, password);
>>>>>> > > +
>>>>>> > > +        final Charset enc = Charset.defaultCharset();
>>>>>> > > +        final BufferedReader stdin = new BufferedReader(new
>>>>>> > InputStreamReader(System.in, enc));
>>>>>> > > +        // Loop until the word "exit" is typed
>>>>>> > > +        System.out.println("Type \"exit\" to quit
>>>>>> JmsQueueReceiver.");
>>>>>> > > +        while (true) {
>>>>>> > > +            final String line = stdin.readLine();
>>>>>> > > +            if (line == null || line.equalsIgnoreCase("exit")) {
>>>>>> > > +                System.out.println("Exiting. Kill the
>>>>>> application if it
>>>>>> > does not exit "
>>>>>> > > +                    + "due to daemon threads.");
>>>>>> > > +                return;
>>>>>> > > +            }
>>>>>> > > +        }
>>>>>> > > +    }
>>>>>> > > +
>>>>>> > > +
>>>>>> > > +    private static void usage(final String msg) {
>>>>>> > > +        System.err.println(msg);
>>>>>> > > +        System.err.println("Usage: java " +
>>>>>> > JmsQueueReceiver.class.getName()
>>>>>> > > +            + " QueueConnectionFactoryBindingName
>>>>>> QueueBindingName
>>>>>> > username password");
>>>>>> > > +        System.exit(1);
>>>>>> > > +    }
>>>>>> > > +}
>>>>>> > >
>>>>>> > >
>>>>>> >
>>>>>> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1274408e/log4j-mom/src/main/java/org/apache/logging/log4j/mom/jms/receiver/JmsTop
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Matt Sicker <boards@gmail.com>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Matt Sicker <boards@gmail.com>
>>>>
>>>
>>>
>>>
>>> --
>>> E-Mail: garydgregory@gmail.com | ggregory@apache.org
>>> Java Persistence with Hibernate, Second Edition
>>> <http://www.manning.com/bauer3/>
>>> JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
>>> Spring Batch in Action <http://www.manning.com/templier/>
>>> Blog: http://garygregory.wordpress.com
>>> Home: http://garygregory.com/
>>> Tweet! http://twitter.com/GaryGregory
>>>
>>>
>>
>>
>> --
>> Matt Sicker <boards@gmail.com>
>>
>
>
>
> --
> E-Mail: garydgregory@gmail.com | ggregory@apache.org
> Java Persistence with Hibernate, Second Edition
> <http://www.manning.com/bauer3/>
> JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
> Spring Batch in Action <http://www.manning.com/templier/>
> Blog: http://garygregory.wordpress.com
> Home: http://garygregory.com/
> Tweet! http://twitter.com/GaryGregory
>



-- 
Matt Sicker <boards@gmail.com>

Mime
View raw message