Saturday, February 22, 2014

Controlling ApacheMQ through JMX

See http://activemq.apache.org/jmx.html; first option described ("The ActiveMQ broker should appear in the list of local connections, if you are running JConsole on the same host as ActiveMQ.") didnt't work for me (ActiveMQ was started as a service, maybe this was  the cause...)

So:

  • go into bin/win64 and edit wrapper.conf; uncomment the following lines:
    • wrapper.java.additional.16=-Dcom.sun.management.jmxremote.port=1616
    • wrapper.java.additional.17=-Dcom.sun.management.jmxremote.authenticate=false
    • wrapper.java.additional.18=-Dcom.sun.management.jmxremote.ssl=false
  • be aware that you need to change the default format so that 16,17 and 18 replace the original .n format (be aware that the sequence might be different depending on other changes you made to the conf file)
  • restart ActiveMQ
  • go to your JDK\bin directory and start jconsole.exe
  • provide the following URL for Remote Process:
    • service:jmx:rmi:///jndi/rmi://localhost:1616/jmxrmi
  • press Connect (do not fill in any data for user/password)
  • press Insecure on the pop-up
  • etc...
If secure connection is required (I suppose by changing the wrapper options accordingly) provide the user name/passord for the relevant role as configured in conf\jmx.access and conf\jmx.password


Debugging ApacheMQ/Camel


  • Change activemq.bat by removing comment for the following line:
    • SET ACTIVEMQ_DEBUG_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
  • start ActiveMQ through command line
  • create a Maven project with NetBeans
  • add the required dependencies to project according to the modules you want to debug (the sample is for ActiveMQ 5.9 and cxf, scripting/Groovy and stream):

    <dependencies>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-cxf</artifactId>
            <version>2.12.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-script</artifactId>
            <version>2.12.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-stream</artifactId>
            <version>2.12.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>2.7.8</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty.aggregate</groupId>
            <artifactId>jetty-all-server</artifactId>
            <version>8.1.14.v20131031</version>
        </dependency>            
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-websocket</artifactId>
            <version>8.1.14.v20131031</version>
        </dependency>
  • build the project so the dependencies are downloaded to local maven  repository
  • in NetBeans go to Dependencies and select Download Sources
  • in NetBeans go to Debug menu and choose Attach Debugger
  • chgange the port to 5005 (or whatever was specified in ACTIVEMQ_DEBUG_OPTS)
  • look for the desired package/class in Dependencies, open the class, place a breakpoint, etc

log4j.properties

Things to remember :-):

  • The  log4j.properties  is searched in the class path.
  • The rootLogger properties are inherited by all loggers in terms of appenders (if for instance it has a console appender all other defined loggers will have also this appender even if not specifically configured)
In order to configure your specific logger(s):
  • add the desired appender(s) (like below):
    • log4j.appender.myLog=org.apache.log4j.FileAppender
    • log4j.appender.myLog.File=logs/myLog.txt
    • log4j.appender.myLog.layout=org.apache.log4j.PatternLayout
    • log4j.appender.myLog.layout.conversionPattern=%-5p %d [%t] %c: %m%n
  • add the logger by specifying logging level and appender(s):
    • log4j.logger.myLog=DEBUG, myLog

The actual place where the logs will be generated depend on the implicit/explicit setting for the working directory of your application;  to have a more specific control over this behaviour you can use environment variables expansion like:

  • log4j.appender.file.File=${mule.home}/logs/mule-logging-example.log

Running ApacheMQ as a Windows service

After downloading/extracting ActiveMQ:

  • open a command window as administrator
  • place the right activemq.xml in conf directory (along with any other related config files like the one describing Camel context)
  • navigate to bin\win64 (do not try the win32 version, the service satrup will fail on x64 Windows)
  • edit wrapper.config by changing the working directory to:
    • wrapper.working.dir=%ACTIVEMQ_BASE%
  • (if not, the working directory will be win64)
  • run InstallService.bat
  • manually start the service (named ApacheMQ)

Run Mule ESB as a service on Windows

After downloading/extracting standalone version:

  • open a command line window (cmd.exe) as administrator
  • navigate to Mule bin directory
  • run mule install
  • check in Services that a service with Mule name exists; start the service
  • place any Mule packages (zip archive) in apps directory and wait for the deployment to occur (a subdirectory with exploded package content is created and a text file <package name>-anchor.txt is present)
  • you can control the service by running mule [start|stop|restart]
When running Mule as a service by default current path is set to the root directory of the expanded standalone package (on the same level with bin, apps, logs, etc) so if we have defined in log4j.properties
log4j.appender.MyLog.File=logs/MyLog.txt
teh MyLog.txt file will be created in logs subdirectory of the installation along with Mule standard log files (mule.log, etc)

Just supposing/not tried with Mule:  you can change the working path by adding an entry to conf/wrapper.conf, something like:
  • wrapper.working.dir="%MULE_HOME%/workingDir"

Be aware: if at start-up there are some unrecoverable errors Mule will try to undeploy the application by also deleting the exploded directory; since the original zip package was already deleted this means that your application will never be launched. To be more explicit:
  • we have a Mule application that uses as inbound endpoint an ActiveMQ JMS queue that is configured (by default) without the reconnect-forever option and with for the connector it references
  • First time when we configure Mule as a service the ActiveMQ broker is up so the application is deployed fine and works as expected
  •  For some maintenance activities we restart the server. Suppose that the Mule service comes up before ActiveMQ; the application start-up will fail and application will be deleted. The failure is due to the fact that Mule tries to activate the connector even before the flow that references it it is started.

Thursday, January 30, 2014

Camel cxfendpoint to ActiveMQ queue


  • cxfendpoint expects an outgoing message to be present in order to be sent back; if an out endpoint posting the message to an ActiveMQ  broker is used this will not happen and a timeout error will occur
  • By default output of cxfendpoint message  payload  is of java.io.InputStream. An outgoing ActiveMQ endpoint will just ignore the payload and will save just the headers.
Below is the solution to above mentioned problems 9this must be included in the master ActiveMQ configuration file):
<?xml version="1.0" encoding="UTF-8"?>
<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cxf="http://camel.apache.org/schema/cxf"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">


      <bean id="jmsConnectionFactory" 
         class="org.apache.activemq.ActiveMQConnectionFactory">
         <property name="brokerURL" value="vm://amq-broker?create=false" />
      </bean>
       
      <bean id="pooledConnectionFactory" 
         class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
         <property name="maxConnections" value="8" />
         <property name="connectionFactory" ref="jmsConnectionFactory" />
      </bean>
       
      <bean id="jmsConfig" 
         class="org.apache.camel.component.jms.JmsConfiguration">
         <property name="connectionFactory" ref="pooledConnectionFactory"/>
         <property name="concurrentConsumers" value="10"/>
      </bean>
       
      <bean id="activemq" 
          class="org.apache.activemq.camel.component.ActiveMQComponent">
          <property name="configuration" ref="jmsConfig"/>
       
          <!-- if we are using transacted then enable CACHE_CONSUMER (if not using XA) to run faster
               see more details at: http://camel.apache.org/jms 
          <property name="transacted" value="true"/>
          <property name="cacheLevelName" value="CACHE_CONSUMER" />
         -->
      </bean>      

    <!-- camelContext is the Camel runtime, where we can host Camel routes -->    
    <cxf:cxfEndpoint id="server"
                     address="http://localhost:8085/OTRS/service"
                     endpointName="s:BasicHttpBinding_ChangeStateOperations"
                     serviceName="s:ChangeStateService"
                     wsdlURL="examples\conf\wsdl\server.wsdl"
                     xmlns:s="http://tempuri.org/"/>
    
    
    
    <camelContext xmlns="http://camel.apache.org/schema/spring">
         <route>
            <from uri="cxf:bean:server?dataFormat=MESSAGE"/>
                <transform>
                  <simple>${bodyAs(String)}</simple>
                </transform>
                <wireTap uri="activemq:topic:otrs.statusChanged"/>
                <wireTap uri="stream:out"/>
                <transform>
                    <simple>
                        <![CDATA[
    <?xml version="1.0" encoding="utf-8"?>
    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
      <s:Body>
        <TestWm1Response xmlns="http://tempuri.org/" />
      </s:Body>
    </s:Envelope>
                        ]]>
                    </simple>
                </transform>
            <!--to uri="cxf:bean:ocalculator?dataFormat=MESSAGE"/-->
        </route>
    </camelContext>
</beans>

Camel cxfenpoint in ActiveMQ 5.9.0

Using cxfendpoints in ActiveMQ requires deplyment of dependent jars in lib\Camel subdirectory. By default just core, jms and spring (2.12.1 version) are deployed.
In order to obtain required jars:

  • create a Maven pom.xml file with the following content:

<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>


    <groupId>org.apache.camel</groupId>

    <version>2.12.1</version>


    <artifactId>camel-example-console</artifactId>
    <packaging>jar</packaging>
    <name>Camel cxf</name>
    <description>camel-cxf dependencies</description>

    <dependencies>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-cxf</artifactId>
            <version>2.12.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-stream</artifactId>
            <version>2.12.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>2.7.8</version>
        </dependency>
        
        <dependency>
          <groupId>org.eclipse.jetty.aggregate</groupId>
          <artifactId>jetty-all-server</artifactId>
          <version>8.1.14.v20131031</version>
        </dependency>            
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-websocket</artifactId>
          <version>8.1.14.v20131031</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Allows the example to be run via 'mvn compile exec:java' -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <configuration>
                    <mainClass>org.apache.camel.example.console.CamelConsoleMain</mainClass>
                    <includePluginDependencies>true</includePluginDependencies>
                </configuration>
            </plugin>
        </plugins>

    </build>

</project>
  • run the following command: mvn dependency:copy-dependencies
  • find in target\dependencies all required dependencies
Remark: because camel-cxf 2.12.1 depends on cxf-rt-transports-http-jetty 2.7.8 some newer versions of jetty jars will be aslo downloaded which will interfere with ActiveMQ already deployed jars (jetty-all-server and jetty-websocket, version 7.6.9.v20130131, lib\web ) so also jetty-all-server and jetty-websocket dependencies are downloaded. If this is not done web console will not work.

Put all jars in lib\camel.