Enterprise Integration Zone is brought to you in partnership with:

Shashank has posted 15 posts at DZone. View Full User Profile

Integrating Flex 4 and Spring 3 based JMS Applications

11.29.2010
| 16257 views |
  • submit to reddit

This article explains the essentials of leveraging the Spring BlazeDS project to integrate Spring based JMS systems with Flex powered rich internet applications (RIAs).  The fundamental concepts involved in the integration of Spring and Flex are explained and the role of the Spring BlazeDS project and its mechanics are illustrated. Instead of a detailed theoretical explanation, a simple example is included to show how such a stack can be setup and used. Advanced configuration and the use of the productivity enhancing Spring Roo toolkit are not included in this article.

 

Note: This article is an updated version of an earlier article on the same topic. The original article is available here. This updated version covers information pertinent to the following:

  • Adobe Flex Framework/SDK 4.5+
  • Adobe Flash Builder 4+
  • Adobe BlazeDS 4.0+
  • Spring Framework 3.0.5+
  • Spring BlazeDS Integration (or Spring Flex) 1.5.0.M1+

 The examples and illustrations in this article also require a few other pieces of software, namely Apache Tomcat, Apache ActiveMQ and the Eclipse IDE. The most recent stable versions of each of these pieces of software are used in this article.

 

Spring is a popular open source enterprise Java framework for building robust and scalable applications whereas Adobe Flex is an open source framework for creating rich and engaging interfaces.  Both these technologies are fairly mature and enjoy a healthy rate of adoption among developers. Adobe BlazeDS is an open source application that allows Flex applications to connect with Java server side applications via remote procedure calls and message exchanges.

Flex applications can connect with Spring server sides, using any of the following four mechanisms:

  • HTTP based requests and responses
  • Web Services
  • Remote procedure calls
  • Message Exchanges

 

The first two of the above listed four options, namely HTTP based requests and responses and web services, are agnostic to the server side technology and so the integration of Flex and Spring using these techniques involves no special considerations beyond the standard support for HTTP and the web services protocol and the availability of data through these endpoints.  Usually text based payload exchanges, especially XML, or JSON encoded data are common when HTTP services and web services are used. When using HTTP service or web service, BlazeDS or any such intermediary is not required, unless the security restrictions do not allow you to fetch data from the remote sources. Considering the relevance of BlazeDS is limited when using these two methods, I will not discuss the use of these methods any further in this article.

For remote procedure calls to server side objects and message exchanges, BlazeDS and similar intermediary products, play an important role. These types of interactions and specifically message-based exchanges are the focus of this article.

Prior to the existence of the Spring BlazeDS Integration (also known as Spring-Flex) project, an Adobe supported SpringSource project, using BlazeDS to connect with Spring based Java servers involved use of a custom factory to access the Spring Beans. This is because Spring Beans and the objects instantiated by standard BlazeDS reside in separate namespaces. Not only did one need a custom factory, one could not use Spring style configuration to wire-up the BlazeDS artifacts. One had to use the BlazeDS specific xml based configurations to set it up. With Spring BlazeDS integration much of the tedious coupling between Spring and BlazeDS has been reduced to simple uniform configuration and first class support for Spring Beans as remoting destinations. Besides, Spring messaging related goodies like the JMSTemplate and the Message Driven POJOs, Spring security and the rest of its framework components become available as server side counterparts for Flex applications.

In the next few sections, I will explain how you could use Spring BlazeDS to integrate Flex and Spring based JMS systems. As I do that I will assume that you have essential knowledge of the Spring framework, Flex framework and even BlazeDS. If these assumptions don’t hold true for you, you may benefit from getting yourself up to speed with the fundamentals of Spring, Flex and BlazeDS, before you proceed further. That way you will get the most out of this article.

A few recommended resources for quick knowledge acquisition on the basics of Spring (especially Spring MVC based web application development), Flex and BlazeDS are:

 

Downloading and Setting Up the Software Stack

To get started download, install and configure all the following required pieces of software:

 

The list of software to install is long but I assume you will have a few of these already setup. At minimum I assume you will have the JDK installed on your machine. If not, then that’s the first piece of software you need to get.

Once Java is installed, go ahead and download Apache Tomcat, Apache ActiveMQ, Spring Framework, Eclipse, Flash Builder Eclipse Plugin, Flex SDK, BlazeDS and the Spring-flex distribution. Go to the URL listed against the name of the software, in the list above, to get to the specific website. In each of the cases you will easily be able to locate the link to download the latest release build for the particular software. All pieces of software in the list, except the Flash Builder Eclipse plug-in are open source. You can get a 60-day trial version of the Flash Builder Eclipse plug-in, if you choose to get familiar with the tool before you plan to buy it. You can build a Flex and Spring application without Flash Builder but having it enhances productivity. The preferred versions of the tools are listed against their respective names. It’s advised that you stick to those versions to avoid any additional configuration and integration complexities. Although not guaranteed, examples in this article may work with older versions of software that make up the stack.

Walking through the installation and configuration of each of these pieces of software is beyond the scope of this article but you will find ample resources online to help you out in this regard. In this article, I will point to a few important installation steps and configuration details only. You will have to piece the rest of it together, although I don’t anticipate you should have much trouble doing that.

Your first step should be to extract the Tomcat and ActiveMQ distributions you downloaded. Getting Tomcat to run is easy and requires little effort. On most platforms extracting the distribution is all you need to do to start using it.

The next step should be to setup the IDE, namely Eclipse and the Flash Builder plug-in. You may additionally need to configure the latest Flex SDK within Flash Builder. Eclipse can be installed simply by expanding the archive distribution. The Flash Builder plug-in installs with the help of a step-by-step wizard. On the Mac OSX platform you may have to choose the Eclipse Carbon build over the preferred Cocoa build to get Flash Builder plug-in to install without any trouble. In future versions of Flash Builder this may not be a problem. Also, on all platforms, stick to the 32-bit version of Eclipse as Flash Builder doesn’t support the 64-bit platform yet.

To configure the latest Flex SDK with Flash Builder, open the Flash Builder preferences in your Eclipse IDE. Browse to the section on “Installed Flex SDKs”, which will appear as depicted in Figure 1 and add the newly downloaded SDK to the list. Additionally set the latest SDK as the default SDK. I extracted the downloaded the latest Flex SDK to ~/Applications/flex_sdks/flex_sdk_4.5.0.17689. Then I added this new SDK to the list of installed SDKs. See Figure 2 and 3 to view parts of the steps I carried out to configure the SDK.

 

(Click for larger image)









 

Last of all, download the Spring framework, Spring-Flex and BlazeDS distributions and expand the downloaded file, if available in a zip or tar format, to a folder in your file system. You will need a few JAR files from these distributions to make Flex work with Spring JMS.

 

Setting up a Flex and Spring JMS Project

In this section you will learn the essentials of setting up and configuring a Flex and Spring JMS project. To keep things interesting and in context, I will use the help of a simple example application that you can build along as you read this and the following sections.

In the earlier version of this article, I created a combined Flex and WTP project. In this updated write-up I create two separate projects:

  • A dynamic web project for the web layer and
  • A Flex project that connects to the web application built using the first project.

 

In the last section, I installed Flash Builder 4 as a plug-in in an Eclipse 3.6 installation. I have Web Tools Platform (WTP) installed in this Eclipse installation as well. WTP and the Java EE plugins help create dynamic web projects with ease. For Spring development the presence of Spring Tools Suite (STS) plug-in in Eclipse is helpful, although I don’t use that plug-in in this example at all.

 

Creating a Dynamic Web Project

To get started, open Eclipse and create a new dynamic web project as shown in Figure 4.  Name it “flexspring”.  Although, I have Tomcat server runtime installed and configured with Eclipse for a dynamic web project, I use Apache Ant to build and deploy the project.

Note: If you choose to use an application server other than Tomcat then remember to configure ActiveMQ or an alternate JMS provider with your application server as you did with Tomcat. Also, modify the build.xml and the build.properties files to work with your application server.

(Click for larger image)

 

Next move to the second screen of the project creation wizard, where you can specify the folder where your complied Java classes would be stored. I set that as “WebContent/WEB-INF/classes”. See Figure 5.

(Click for larger image)

 

Then move to the last screen of the wizard, where you have a chance to modify the “Context root” and the “Context directory”. The pre-filled default values are good enough for this project. The “Context root” is the root of your web application. In this screen you also have the option to create a web.xml deployment description. I recommend you select that option to generate the deployment descriptor and later modify it as required. See Figure 6 for the last wizard screen.

(Click for larger image)

 

Now click the finish button and the project shell is ready. Figure 7 shows what the project structure is like when you first create it.

 

With the initial project shell in place we are ready to move forward with creating a Spring based JMS enabled application. This application will be hooked up with a Flex front end later in this article.

First create the build file to leverage Apache Ant for the compile and deploy tasks. I customized a build file on the basis of the sample build file available with the Spring MVC tutorial example app. The contents of the build file are as follows:

<?xml version="1.0"?>

<project name="flexspring" basedir="." default="usage">
<property file="build.properties"/>

<property name="src.dir" value="src"/>
<property name="web.dir" value="WebContent"/>
<property name="build.dir" value="${web.dir}/WEB-INF/classes"/>
<property name="name" value="flexspring"/>

<path id="master-classpath">
<fileset dir="${web.dir}/WEB-INF/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${appserver.lib}">
<include name="servlet*.jar"/>
</fileset>
<pathelement path="${build.dir}"/>
</path>

<target name="usage">
<echo message=""/>
<echo message="${name} build file"/>
<echo message="-----------------------------------"/>
<echo message=""/>
<echo message="Available targets are:"/>
<echo message=""/>
<echo message="build --> Build the application"/>
<echo message="deploy --> Deploy application as directory"/>
<echo message="deploywar --> Deploy application as a WAR file"/>
<echo message="reload --> Reload application in Tomcat"/>
<echo message="start --> Start Tomcat application"/>
<echo message="stop --> Stop Tomcat application"/>
<echo message="list --> List Tomcat applications"/>
<echo message=""/>
</target>

<target name="build" description="Compile main source tree java files">
<mkdir dir="${build.dir}"/>
<javac destdir="${build.dir}" source="1.6" target="1.6" debug="true"
deprecation="false" optimize="false" failonerror="true">
<src path="${src.dir}"/>
<classpath refid="master-classpath"/>
</javac>
</target>

<target name="deploy" depends="build" description="Deploy application">
<copy todir="${deploy.path}/${name}" preservelastmodified="true">
<fileset dir="${web.dir}">
<include name="**/*.*"/>
</fileset>
</copy>
</target>

<target name="deploywar" depends="build" description="Deploy application as a WAR file">
<war destfile="${name}.war"
webxml="${web.dir}/WEB-INF/web.xml">
<fileset dir="${web.dir}">
<include name="**/*.*"/>
</fileset>
</war>
<copy todir="${deploy.path}" preservelastmodified="true">
<fileset dir=".">
<include name="*.war"/>
</fileset>
</copy>
</target>

<!-- ============================================================== -->
<!-- Tomcat tasks - remove these if you don't have Tomcat installed -->
<!-- ============================================================== -->

<path id="catalina-ant-classpath">
<!-- We need the Catalina jars for Tomcat -->
<!-- * for other app servers - check the docs -->
<fileset dir="${appserver.lib}">
<include name="catalina-ant.jar"/>
</fileset>
</path>

<taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask">
<classpath refid="catalina-ant-classpath"/>
</taskdef>
<taskdef name="list" classname="org.apache.catalina.ant.ListTask">
<classpath refid="catalina-ant-classpath"/>
</taskdef>
<taskdef name="start" classname="org.apache.catalina.ant.StartTask">
<classpath refid="catalina-ant-classpath"/>
</taskdef>
<taskdef name="stop" classname="org.apache.catalina.ant.StopTask">
<classpath refid="catalina-ant-classpath"/>
</taskdef>

<target name="reload" description="Reload application in Tomcat">
<reload url="${tomcat.manager.url}"
username="${tomcat.manager.username}"
password="${tomcat.manager.password}"
path="/${name}"/>
</target>

<target name="start" description="Start Tomcat application">
<start url="${tomcat.manager.url}"
username="${tomcat.manager.username}"
password="${tomcat.manager.password}"
path="/${name}"/>
</target>

<target name="stop" description="Stop Tomcat application">
<stop url="${tomcat.manager.url}"
username="${tomcat.manager.username}"
password="${tomcat.manager.password}"
path="/${name}"/>
</target>

<target name="list" description="List Tomcat applications">
<list url="${tomcat.manager.url}"
username="${tomcat.manager.username}"
password="${tomcat.manager.password}"/>
</target>

<!-- End Tomcat tasks -->

</project>

 

Next, I start creating a Spring BlazeDS based JMS application. In order to do that, I start out by copying over the entire set of jar files from the spring-framework and the spring-flex distribution (dist) folders. Some of the jar files may not be used but it is easier and quicker to just copy them all. Making all jars available also allows you to use the entire spring framework and spring flex feature set.

The Spring JMS application is being built out to connect via a Flex front-end. The Flex front-end will connect to the Spring JMS application using Spring BlazeDS based flex integration. Therefore download and extract the BlazeDS war file and include the BlazeDS jar files in the project. To get hold of all the jar files, un-package the contents of blazeds.war by using jar xvf on the file. Then copy over all the files in the un-packaged blazeds.war lib folder to the flexspring project’s WebContent/WEB-INF/lib directory.

In addition to the already copied jar files also copy over the following jar files to WebContent/WEB-INF/lib:


 The final list of jars in WebContent/WEB-INF/lib of the flexspring project should be as follows:

activemq-all-5.4.1.jar
aopalliance.jar
asm-all-3.3.jar
cfgatewayadapter.jar
cglib-2.2.jar
commons-codec-1.3.jar
commons-httpclient-3.0.1.jar
commons-logging.jar
flex-messaging-common.jar
flex-messaging-core.jar
flex-messaging-opt.jar
flex-messaging-proxy.jar
flex-messaging-remoting.jar
flex-rds-server.jar
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.aspects-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.context.support-3.0.5.RELEASE.jar
org.springframework.core-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.flex.roo.addon-1.0.0.M1.jar
org.springframework.flex.roo.annotations-1.0.0.M1.jar
org.springframework.instrument-3.0.5.RELEASE.jar
org.springframework.instrument.tomcat-3.0.5.RELEASE.jar
org.springframework.jdbc-3.0.5.RELEASE.jar
org.springframework.jms-3.0.5.RELEASE.jar
org.springframework.orm-3.0.5.RELEASE.jar
org.springframework.oxm-3.0.5.RELEASE.jar
org.springframework.spring-library-3.0.5.RELEASE.libd
org.springframework.test-3.0.5.RELEASE.jar
org.springframework.transaction-3.0.5.RELEASE.jar
org.springframework.web-3.0.5.RELEASE.jar
org.springframework.web.portlet-3.0.5.RELEASE.jar
org.springframework.web.servlet-3.0.5.RELEASE.jar
org.springframework.web.struts-3.0.5.RELEASE.jar
spring-flex-core-1.5.0.M1.jar
xalan.jar
xbean-spring-3.7.jar

 

Now that all the jars are copied and hence dependencies resolved lets go ahead with some configuration. You need 4 different types of configuration files for the project. These reside within WebContent/WEB-INF and are as follows:

  • web.xml – the Java EE and servlet container standard deployment descriptor
  • flex-servlet.xml – the configuration file for the servlet that intercepts all calls to the BlazeDS message broker. By convention spring looks for a configuration file named <servlet_name>-servlet.xml for configuring a servlet named <servlet_name>. I have called my BlazeDS broker interceptor “flex”.
  • Spring specific configuration files in a sub-directory named “spring”. This path is specified in web.xml and could adhere to any other naming pattern as required. These files bootstrap and setup the spring beans.
  • BlazeDS default configurations in the flex/services-config.xml file. I leverage Spring for much of the BlazeDS destinations configuration so services-config.xml only holds some base configuration for channels and logging.

 

The contents of web.xml within <web-app> and </web-app> are as follows:

<display-name>flexspring</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/*-config.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>flex</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>flex</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

 

The first configuration element specifies the location of the context configuration files. Recall, spring configuration files are all in the “spring” folder and match the naming convention as specified. The essential configuration in the spring configuration files is like so:

<!—enables component scanning. The spring JMS classes are in the package com.treasuryofideas.flexspring -- >
<context:component-scan base-package="com.treasuryofideas.flexspring" />

<!-- Embedded ActiveMQ Broker -->
<amq:broker id="broker" useJmx="false" persistent="false">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:0" />
</amq:transportConnectors>
</amq:broker>


<!-- JMS ConnectionFactory to use, configuring the embedded broker using XML -->
<amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />

 

ActiveMQ is capable of creating destinations as required so one does not need to create the topics and queues upfront but if you were to do that, this the place for it.

Getting back to the web.xml configuration, the DispatcherServlet is configured under the name “flex” which is mapped to intercept all calls made to the url pattern: /messagebroker/*. The flex client connects to BlazeDS channels and interacts with remote destinations using URLs that match this pattern.

The servlet itself takes additional configuration, which is specified in flex-servlet.xml. The important contents of flex-servlet.xml is like so:

<flex:message-broker>
<flex:message-service
default-channels="my-streaming-amf,my-longpolling-amf,my-polling-amf" />
</flex:message-broker>

<!-- Messaging destinations -->
<flex:message-destination id="simple-feed" />

<!-- MessageTemplate makes it easy to publish messages -->
<bean id="defaultMessageTemplate" class="org.springframework.flex.messaging.MessageTemplate" />

<!-- Pojo used to start and stop the data feed that pushes data in the 'simple-feed' destination -->
<bean id="simpleFeedStarter" class="com.treasuryofideas.flexspring.SimpleFeed">
<constructor-arg ref="defaultMessageTemplate" />
<flex:remoting-destination />
</bean>

 

All of this sets up the BlazeDS remoting and messaging destinations leveraging the http://www.springframework.org/schema/flex namespace that defines the spring-flex xsd. In cases without spring-flex you configure these destinations in the flex/services-config.xml. Read more about the spring-flex configuration elements here and about flex services-config options here.

The services-config itself as mentioned earlier is a minimalist collection of configuration elements. It defines the base channel and logging definitions. The channel definitions and other details can be downloaded from the project source, available here.

 

The Sample Application: simple feed and the client

I have illustrated many steps in building the spring-flex server but haven’t alluded to the sample application features yet. That’s what is contained in this section. The heart of the spring-flex sample application is a simple feed that generates a random number and sends that out via a JMS template. The spring flex test drive has a similar example. I also have a random word generator example included with the code download.

The flex client is a simple client that starts and stops the simple feed, has the ability to subscribe to the feed and display the random number. Lets start out by creating the client app.

 

Creating the simple flex client

First open Flash Builder and create a flex project by following along the wizard as depicted in Figures 8, 9, 10 and 11.

(Click for larger image)












Once the project is created, add the following code to mainapp.mxml to create the simple flex application:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.messaging.messages.IMessage;

private function messageHandler(message:IMessage):void
{
pushedValue.text = ""+ message.body;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<mx:ChannelSet id="cs">
<mx:StreamingAMFChannel url="http://localhost:8080/flexspring/messagebroker/streamingamf"/>
<mx:AMFChannel url="http://localhost:8080/flexspring/messagebroker/amflongpolling"/>
<mx:AMFChannel url="http://localhost:8080/flexspring/messagebroker/amfpolling"/>
<mx:AMFChannel url="http://localhost:8080/flexspring/messagebroker/amf"/>
</mx:ChannelSet>

<mx:RemoteObject id="simpleFeedStarter" destination="simpleFeedStarter" channelSet="{cs}"/>

<mx:Consumer id="consumer" destination="simple-feed" channelSet="{cs}"
message="messageHandler(event.message)"/>

</fx:Declarations>
<s:layout>
<s:VerticalLayout paddingTop="20" paddingLeft="20" gap="20"/>
</s:layout>

<s:Label text="Simple Feed" fontSize="18" fontWeight="bold"/>

<s:HGroup verticalAlign="middle">
<s:Label text="Simple Feed" width="120"/>
<s:Button label="Start" click="simpleFeedStarter.start()"/>
<s:Button label="Stop" click="simpleFeedStarter.stop()"/>
</s:HGroup>

<s:TextInput id="pushedValue" width="250" verticalCenter="0" horizontalCenter="0"/>

<s:Button label="Subscribe" click="consumer.subscribe()" enabled="{!consumer.subscribed}" verticalCenter="30" horizontalCenter="-50"/>
<s:Button label="Unsubscribe" click="consumer.unsubscribe()" enabled="{consumer.subscribed}" verticalCenter="30" horizontalCenter="50"/>

</s:Application>

 

That’s it, the application is ready to be tested. Run the ant build script to deploy the flexspring web application to tomcat. Ant deploy does the trick. Then start Tomcat and finally connect to the flexspring server by running the flex client. The sample application when running looks as shown in Figure 12.

 



Summary

Spring-flex lets you leverage the power of spring with flex applications and makes it easy to configure BlazeDS destinations using the spring style configuration. It makes spring and flex application development easy for a spring developer. The sample application in this article only sctarches the surface but hopefully covers a good bit of the setup and configuration details that you need to get familiar with. Little time is spent on the application code itself but feel free to download both the server and client source code here. Last but not the least don’t hesitate to ask me a question about the article or the subject at large on twitter @tshanky or by sending me an email at tshanky at gmail dot com. You can read more about me on my website at www.shanky.org and on my Amazon author page.

AttachmentSize
Flex4andSpring3Jms_Figure1.png121.01 KB
Flex4andSpring3Jms_Figure2.png28.29 KB
Flex4andSpring3Jms_Figure3.png42.74 KB
Flex4andSpring3Jms_Figure4.png97.18 KB
Flex4andSpring3Jms_Figure5.png46.65 KB
Flex4andSpring3Jms_Figure6.png46.88 KB
Flex4andSpring3Jms_Figure7.png20.88 KB
Flex4andSpring3Jms_Figure8.png65.6 KB
Flex4andSpring3Jms_Figure9.png97.86 KB
Flex4andSpring3Jms_Figure10.png41.21 KB
Flex4andSpring3Jms_Figure11.png98.1 KB
Flex4andSpring3Jms_Figure12.png17.59 KB
Published at DZone with permission of its author, Shashank Tiwari.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

darryl west replied on Wed, 2010/12/01 - 12:14am

I've been using Flex and Grails for about three years now and have never felt the need to use Blaze or LiveCycle.  The last thing I want to do is be dependent on Adobe for the transport layer

Flex 4 is a solid platform, especially with the new spark architecture, and it does a fine job at animation (thanks mostly to Chet Haase) and runs seamlessly on most desktop browsers, but what happens when my project needs to move to the ipad?  If I commit to blaze, then I not only have to re-engineer the UI, but the entire backend needs to be replaced, or at least the transport layer.

So why not just use JSON or XML?  I know that the blaze docs say that it's faster to use binary transfers, but if small packet size is the objective, then the standard gzip utilities work much better that the blaze serializers--and, they are platform independent. 

my 2 cents...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.