ActiveMQ WebLogic IntegrationActiveMQ clients and brokers can be run in WebLogic Server or WebLogic Express. This is usually done for licensing reasons:
ActiveMQ Clients in WebLogicAn ActiveMQ client can be run in any recent version of WebLogic. However, the specifics depend on which revision of JMS is supported by your version of WebLogic. WebLogic Server/Express versions including JMS 1.0.xThis is known to include WebLogic 8.1 and all previous versions. Note: ActiveMQ cannot deliver messages to message-driven beans in this version of WebLogic. You will need to create JMS clients manually to send and receive JMS messages. To work with ActiveMQ from one of these releases of WebLogic, you should not include any Further, your code should use only JMS 1.0.x versions of the JMS interfaces (such as Finally, you can connect to ActiveMQ using the normal ActiveMQ JNDI settings including a connect URL. Do not attempt to use WebLogic JNDI to connect to ActiveMQ, and do not use the WebLogic host name or listen port in the ActiveMQ connect URL – even if the ActiveMQ broker is run within WebLogic it will listen on a separate network port from the one that WebLogic uses. TODO: Add sample JMS 1.0.x code WebLogic Server versions including JMS 1.1WebLogic 9.2 and above are known to support JMS 1.1. (I don't know what JMS release WebLogic 9.0-9.1 support) To work with ActiveMQ in one of these release of WebLogic Server, you can use the J2EE Connector included with ActiveMQ (known as ActiveMQ-RA). This will provide full ActiveMQ support to J2EE applications – ActiveMQ can be used to both send messages and to deliver incoming messages to message-driven beans. Your J2EE applications can map connection factory and destination references in JNDI. I don't have an example of using the J2EE Connector from a J2EE 1.4 application in WebLogic. If someone can contribute one that would be great! If you're using Spring or another non-J2EE architecture in your application, you may choose to skip the J2EE Connector and just connect directly to ActiveMQ using the technique described in the next section. WebLogic Express versions including JMS 1.1WebLogic 9.2 and above are known to support JMS 1.1. (I don't know what JMS release WebLogic 9.0-9.1 support) J2EE Connectors are not supported in WebLogic Express, so that approach is out. Instead, any components that want to connect to ActiveMQ need to manually create the connection (or use a technique like Spring message-driven POJOs to manage it). However, this should be relatively trouble-free since ActiveMQ and WebLogic support the same JMS release. TODO: Example of JMS 1.1 client and Spring Message-Driven POJO client for WebLogic ActiveMQ Brokers in WebLogicOn the surface it's not obvious why you might want to run an ActiveMQ broker within WebLogic instead of standalone, but the considerations include:
If you decide to run ActiveMQ standalone, that's fine, you can skip this section. Otherwise, read on. The specific integration techniques depend on whether you're using WebLogic Server or WebLogic Express, and whether your version supports JMS 1.0.x or JMS 1.1. WebLogic Server/Express versions including JMS 1.0.xDeploying an ActiveMQ broker in a release of WebLogic Server or WebLogic Express that supports only JMS 1.0.x has not been tested. This is known to include WebLogic 8.1 and all previous versions. It will probably have trouble due to conflicting versions of JMS used by ActiveMQ and by WebLogic. Please report your results if you try this WebLogic Server versions including JMS 1.1WebLogic 9.2 and above are known to support JMS 1.1. (I don't know what JMS release WebLogic 9.0-9.1 support) It is possible to deploy ActiveMQ in WebLogic Server in one of two ways:
The J2EE Connector approach has not be specifically tested, but should work well. It would need some additional classes to support the security and management integration as described in the next section, so those would need to be added to a JAR which is in turn added to the J2EE Connector RAR file. Please report your results if you try this WebLogic Express versions including JMS 1.1WebLogic 9.2 and above are known to support JMS 1.1. (I don't know what JMS release WebLogic 9.0-9.1 support) Since WebLogic Express does not support J2EE Connectors, it is necessary to deploy ActiveMQ wrapped in an application that is deployed to WebLogic. Note that ActiveMQ runs in the XBean container, so XBean must be pointed to an appropriate configuration file to start up and it will then configure and start all the ActiveMQ components. The first challenge is then to construct an application that locates the right config file(s) and starts the ActiveMQ broker when it is deployed. ActiveMQ as a WebLogic ApplicationThe easiest type of WebLogic application to configure with all the needed ActiveMQ libraries and configuration and not much else is a web application. The JARs go in Management OptionsActiveMQ exposes a number of management and monitoring features via JMX. There are three ways to expose these JMX objects:
Each approach has its advantages and disadvantages. A few things to note:
The sample below includes an optional configuration block that lets ActiveMQ hook into the WebLogic runtime MBeanServer. This means ActiveMQ MBeans will appear alongside WebLogic MBeans (and even JVM MBeans if they are enabled). With this approach, management clients will access ActiveMQ MBeans through the normal WebLogic listen port (e.g. 7001) rather than using a dedicated JMX port, though IIOP must be enabled for this to work. However, note that this is optional, and you can skip that configuration block and use one of the other approaches (JVM or embedded MBeanServer) to expose the ActiveMQ MBeans. Security OptionsActiveMQ has optional authentication and authorization plugins, which are based on JAAS. Fortunately, WebLogic provides a JAAS LoginModule that performs the authentication against the default WebLogic security realm, and returns the appropriate principals for authorization. Unfortunately, by default, ActiveMQ cannot authorize access to specific users within the security realm based on WebLogic principals, meaning either there's no security or a login is required but any user with a valid login has full access to ActiveMQ. However, with custom security classes like the ones shown below, ActiveMQ can use the WebLogic security realm to process a login and then you can configure the WebLogic principals (users and/or groups) that should be allowed to perform read/write/create/remove actions on a per-broker or per-destination basis. You may choose to use authentication only, in which case any user with a valid WebLogic login can access ActiveMQ, and no custom code is necessary. You may also add authorization to that using some custom code, to apply specific security constraints to specific users or destinations. For purposes of this example, we have only implemented an authorization approach that allows any member of a single specific WebLogic group to access all resources in ActiveMQ. Between the authorization plugin provided here and the default one provided with ActiveMQ, you should have the foundation to enhance this if more feature-rich authorization is required. Persistence OptionsActiveMQ uses a combination of a local journal (files on the file system) and a backing database by default. In the standard configuration, an embedded Derby database is used. This runs fine in WebLogic, but it's also possible to have ActiveMQ use a database connection pool defined in WebLogic, rather than using a separate Derby database. The configuration files shown later have commented-out sections referring to a WebLogic database connection pool – if you want to use those, you'll just need to set the correct JNDI name that was used for the database connection pool. Note that ActiveMQ will create the tables it needs the first time it connects to a database, so no particular preparation is required for the database. ActiveMQ Integration ArchitectureThe ActiveMQ-in-WebLogic combination looks like this:
To summarize this diagram:
Building the ActiveMQ to WebLogic Integration WARThis section discusses the code, libraries, and configuration files necessary to build the ActiveMQ web application that will be deployed in WebLogic Express. Starting and Stopping ActiveMQActiveMQ needs to start when the web application is deployed or started, and stop when the web application is stopped or undeployed. The easiest way to do this is to a use the commonly available Spring listeners, which start a Spring context, which can point ActiveMQ to an XBean configuration file, which starts ActiveMQ. A little roundabout, but it works well in practice with very little configuration. J2EE WEB-INF/web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" > <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app> Spring WEB-INF/applicationContext.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="brokerService" class="org.apache.activemq.xbean.BrokerFactoryBean"> <property name="config" value="classpath:activemq-config.xml"/> </bean> </beans> Again, the With this approach, the normal WebLogic deployment tools, admin console, etc. can be used to deploy, start, stop, and restart ActiveMQ (packaged into a web application WAR). Required LibrariesActiveMQ required a number of JARs which should be included in the web application This list was generated for ActiveMQ 4.0.1:
Additionally, to build the custom security plugins, the WebLogic Of these, Derby could be omitted if ActiveMQ was configured to not use a database for persistence or to use a separate database (e.g. a WebLogic database pool) for persistence. The WebLogic JAR is needed only at build time (it's provided by the server at runtime). Spring could be omitted if a different strategy was used to start and stop ActiveMQ when the web app was started or stopped (a little custom code could replace this dependency). The rest are probably unavoidable, unless ActiveMQ changes its dependencies in a future version. WebLogic Integration CodeThere are two custom classes used for this example. We'll show in a minute how to configure ActiveMQ to use these. Note that these are optional – if you don't want to leverage WebLogic's security realm, you can skip these. The first class makes ActiveMQ use the WebLogic security realm for authentication, and lets you specify a single WebLogic group to use for authorization (only members of that group can access ActiveMQ, though group members have full access to ActiveMQ). ActiveMQToWebLogicSecurity.java This class is an ActiveMQ "plugin", which installs two filters (authorization and authentication) which will be invoked on every request. This is similar to the default behavior provided by ActiveMQ's /** * An ActiveMQ security plugin that installs two security filters * (authentication and authorization) that use WebLogic security realms to * handle the login and provide user and group principals. */ public class ActiveMQToWebLogicSecurity implements BrokerPlugin { private String authorizedGroup; public Broker installPlugin(Broker broker) { // Install the first filter for authentication Broker first = new ActiveMQWebLogicAuthenticationFilter(broker); // Configure and install the second filter for authorization AuthorizationEntry entry = new AuthorizationEntry(); Set acls = new HashSet(); acls.add(new WLSGroupImpl(authorizedGroup)); entry.setAdminACLs(acls); entry.setReadACLs(acls); entry.setWriteACLs(acls); DefaultAuthorizationMap map = new DefaultAuthorizationMap(); map.setDefaultEntry(entry); //todo: if finer-grained access is required, add more entries to the authorization map Broker second = new AuthorizationBroker(first, map); return second; } public String getAuthorizedGroup() { return authorizedGroup; } /** * Called by XBean at configuration time to set the authorized group from a * property in the main ActiveMQ configuration file. */ public void setAuthorizedGroup(String authorizedGroup) { this.authorizedGroup = authorizedGroup; } } The second class is the authentication filter used by the class above to authenticate all logins against the WebLogic default security realm. ActiveMQWebLogicAuthenticationFilter.java /** * A broker filter that authenticates callers against WebLogic security. * This is similar to the ActiveMQ JaasAuthenticationBroker except for two * things: * <ul> * <li>Instead of reading a JAAS configuration file, it hardcodes the JAAS * configuration to require authentication against WebLogic</li> * * <li>The SecurityContext implementation overrides the method used to * compare actual and eligible principals in order to handle the fact * that WebLogic principals (WLSGroupImpl in particular) do not seem * to match according to equals and hashCode even if the principal class * and principal name are the same (perhaps having to do with the * signature data on the WLSAbstractPrincipal).</li> * </ul> */ public class ActiveMQWebLogicAuthenticationFilter extends BrokerFilter { private final static Configuration WEBLOGIC_JAAS_CONFIGURATION = new Configuration() { public AppConfigurationEntry[] getAppConfigurationEntry(String name) { return new AppConfigurationEntry[]{ new AppConfigurationEntry("weblogic.security.auth.login.UsernamePasswordLoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, Collections.EMPTY_MAP) }; } public void refresh() { } }; private final CopyOnWriteArrayList securityContexts = new CopyOnWriteArrayList(); public ActiveMQWebLogicAuthenticationFilter(Broker next) { super(next); } static class JaasSecurityContext extends SecurityContext { private final Subject subject; public JaasSecurityContext(String userName, Subject subject) { super(userName); this.subject = subject; } public Set getPrincipals() { return subject.getPrincipals(); } /** * This is necessary because WebLogic uses extra logic when comparing principals, * probably to check whether they are cryptographically signed (which WebLogic * supports). We skip that test because ActiveMQ does not sign the principals * it deals with. */ public boolean isInOneOf(Set eligiblePrincipals) { for (Iterator it = getPrincipals().iterator(); it.hasNext();) { Principal test = (Principal) it.next(); for (Iterator el = eligiblePrincipals.iterator(); el.hasNext();) { Principal eligible = (Principal) el.next(); if(test.getName().equals(eligible.getName()) && test.getClass().getName().equals(eligible.getClass().getName())) { return true; } } } return false; } } public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { if( context.getSecurityContext()==null ) { // Do the login. try { LoginContext lc = new LoginContext("ActiveMQ", new Subject(), new URLCallbackHandler(info.getUserName(), info.getPassword()), WEBLOGIC_JAAS_CONFIGURATION); lc.login(); Subject subject = lc.getSubject(); SecurityContext s = new JaasSecurityContext(info.getUserName(), subject); context.setSecurityContext(s); securityContexts.add(s); } catch (Exception e) { throw (SecurityException)new SecurityException("User name or password is invalid.").initCause(e); } } super.addConnection(context, info); } public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception { super.removeConnection(context, info, error); if( securityContexts.remove(context.getSecurityContext()) ) { context.setSecurityContext(null); } } /** * Previously logged in users may no longer have the same access anymore. Refresh * all the logged into users. */ public void refresh() { for (Iterator iter = securityContexts.iterator(); iter.hasNext();) { SecurityContext sc = (SecurityContext) iter.next(); sc.getAuthorizedReadDests().clear(); sc.getAuthorizedWriteDests().clear(); } } } Sample ActiveMQ Configuration FilesThis section shows three sample ActiveMQ configuration files – one for a single broker with the security and management plugins listed above, and one for a network of two brokers with the security and management plugins listed above. If you want to skip the security and management plugins, you can remove those attributes from the main It also shows a Log4J configuration file, which controls the ActiveMQ log output. Single Broker <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://activemq.org/config/1.0"> <!-- Allows us to use system properties as variables in this configuration file --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/> <broker useJmx="true" brokerName="MyBroker" useShutdownHook="false" plugins="#WebLogicSecurity"> <!-- Register all ActiveMQ MBeans with the WebLogic runtime MBeanServer --> <managementContext> <managementContext> <MBeanServer> <bean class="org.springframework.jndi.JndiObjectFactoryBean" xmlns=""> <property name="jndiName" value="java:comp/env/jmx/runtime" /> <property name="lookupOnStartup" value="true" /> <property name="expectedType" value="javax.management.MBeanServer" /> </bean> </MBeanServer> </managementContext> </managementContext> <persistenceAdapter> <!-- By default, use an embedded Derby database --> <journaledJDBC journalLogFiles="5" dataDirectory="/server/bea/weblogic920/domains/jms/activemq-data"/> <!-- Use this with the WebLogicDataSource below to use a WebLogic database connection pool instead of the embedded Derby database <journaledJDBC journalLogFiles="5" dataDirectory="/server/bea/weblogic920/domains/jms/activemq-data" dataSource="#WebLogicDataSource" /> --> </persistenceAdapter> <transportConnectors> <transportConnector name="MyBrokerTCP" uri="tcp://0.0.0.0:61616" /> </transportConnectors> </broker> <bean id="WebLogicSecurity" class="com.example.activemq.weblogic.ActiveMQToWebLogicSecurity"> <property name="authorizedGroup" value="ActiveMQUsers" /> </bean> <!-- Uncomment and configure this if you want to use a WebLogic database connection pool for persistent messages <bean id="WebLogicDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="db/pool/jndi/name"/> </bean> --> </beans> Network of Brokers (Broker 1/2) <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://activemq.org/config/1.0"> <!-- Allows us to use system properties as variables in this configuration file --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/> <broker useJmx="true" brokerName="FirstBroker" useShutdownHook="false" plugins="#WebLogicSecurity"> <!-- Register all ActiveMQ MBeans with the WebLogic runtime MBeanServer --> <managementContext> <managementContext> <MBeanServer> <bean class="org.springframework.jndi.JndiObjectFactoryBean" xmlns=""> <property name="jndiName" value="java:comp/env/jmx/runtime" /> <property name="lookupOnStartup" value="true" /> <property name="expectedType" value="javax.management.MBeanServer" /> </bean> </MBeanServer> </managementContext> </managementContext> <persistenceAdapter> <!-- By default, use an embedded Derby database --> <journaledJDBC journalLogFiles="5" dataDirectory="/server/bea/weblogic920/domains/jms/activemq-b1-data"/> <!-- Use this with the WebLogicDataSource below to use a WebLogic database connection pool instead of the embedded Derby database <journaledJDBC journalLogFiles="5" dataDirectory="/server/bea/weblogic920/domains/jms/activemq-b1-data" dataSource="#WebLogicDataSource" /> --> </persistenceAdapter> <transportConnectors> <transportConnector name="FirstBrokerTCP" uri="tcp://0.0.0.0:60010" /> </transportConnectors> <networkConnectors> <networkConnector name="Broker1ToBroker2" uri="static://(tcp://localhost:60011)" failover="true" userName="fixme" password="fixme"/> </networkConnectors> </broker> <bean id="WebLogicSecurity" class="com.example.activemq.weblogic.ActiveMQToWebLogicSecurity"> <property name="authorizedGroup" value="ActiveMQUsers" /> </bean> <!-- Uncomment and configure this if you want to use a WebLogic database connection pool for persistent messages <bean id="WebLogicDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="db/pool/jndi/name"/> </bean> --> </beans> Network of Brokers (Broker 2/2) <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://activemq.org/config/1.0"> <!-- Allows us to use system properties as variables in this configuration file --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/> <broker useJmx="true" brokerName="SecondBroker" useShutdownHook="false" plugins="#WebLogicSecurity"> <!-- Register all ActiveMQ MBeans with the WebLogic runtime MBeanServer --> <managementContext> <managementContext> <MBeanServer> <bean class="org.springframework.jndi.JndiObjectFactoryBean" xmlns=""> <property name="jndiName" value="java:comp/env/jmx/runtime" /> <property name="lookupOnStartup" value="true" /> <property name="expectedType" value="javax.management.MBeanServer" /> </bean> </MBeanServer> </managementContext> </managementContext> <persistenceAdapter> <!-- By default, use an embedded Derby database --> <journaledJDBC journalLogFiles="5" dataDirectory="/server/bea/weblogic920/domains/jms/activemq-b2-data"/> <!-- Use this with the WebLogicDataSource below to use a WebLogic database connection pool instead of the embedded Derby database <journaledJDBC journalLogFiles="5" dataDirectory="/server/bea/weblogic920/domains/jms/activemq-b2-data" dataSource="#WebLogicDataSource" /> --> </persistenceAdapter> <transportConnectors> <transportConnector name="SecondBrokerTCP" uri="tcp://0.0.0.0:60011" /> </transportConnectors> <networkConnectors> <networkConnector name="Broker2ToBroker1" uri="static://(tcp://localhost:60010)" failover="true" userName="fixme" password="fixme" /> </networkConnectors> </broker> <bean id="WebLogicSecurity" class="com.example.activemq.weblogic.ActiveMQToWebLogicSecurity"> <property name="authorizedGroup" value="activemq" /> </bean> <!-- Uncomment and configure this if you want to use a WebLogic database connection pool for persistent messages <bean id="WebLogicDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="db/pool/jndi/name"/> </bean> --> </beans> Log4J Configuration File ( # Can change this to "INFO, out" or "INFO, out, stdout" # to enable logging to the file defined down below log4j.rootLogger=INFO, stdout log4j.logger.org.apache.activemq.spring=WARN log4j.logger.org.springframework=WARN log4j.logger.org.apache.xbean.spring=WARN # Configuration to log to stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%-5p %-30.30c{1} - %m%n log4j.appender.stdout.threshold=INFO # Configuration for a log file (in addition to or instead of stdout) log4j.appender.out=org.apache.log4j.RollingFileAppender log4j.appender.out.file=/server/bea/weblogic920/domains/test/activemq.log log4j.appender.out.maxFileSize=1024KB log4j.appender.out.maxBackupIndex=5 log4j.appender.out.append=true log4j.appender.out.layout=org.apache.log4j.PatternLayout log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n Installation ProcedureThis procedure makes the following assumptions:
Prerequisites
Installation Procedure
|