Workshop 5
Workshop 5
Programmatic management is more flexible during development time but less flexible
during application life. declarative management is less flexible during development time
but more flexible during application life
1. Create a Java Project Named DeclarativeTran and include following jar files in
Java Build Path.
2. Open PhpMyAdmin and create following two tables inside your database.
create table cust_info(id int not null auto_increment, name varchar(20),
address varchar(20), primary key (id))
create table cust_bal(id int not null, bal int, foreign key(id) references
cust_info(id))
3. Create a package named ch5.declare.demo and add following Java files inside it.
4. Create a POJO class named CustBal which contains all fields from cust_info and
cust_bal table. This class is mainly used when retrieving records.
package ch5.declare.demo;
package ch5.declare.demo;
import java.util.List;
import javax.sql.DataSource;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@Override
public void create(String name, String address, int bal) {
try
{
jdbcTemplate.update("insert into cust_info(name,address)
values(?,?)",name,address);
int id=jdbcTemplate.queryForObject("select max(id) from
cust_info", Integer.class);
jdbcTemplate.update("insert into cust_bal(id,bal)
values(?,?)",id,bal);
System.out.println("Record Created for \n"+
"id="+id+",Name="+name+",Address="+address+",Balance="+bal);
throw new RuntimeException("Error Simulation");
}
catch(Exception e)
{
System.out.println("Error While Creating Record.."+e);
throw e;
}
@Override
public List<CustBal> retAllCust() {
// TODO Auto-generated method stub
List<CustBal> list=jdbcTemplate.query("select * from
cust_info,cust_bal where cust_info.id=cust_bal.id", new
CustBalanceMapper());
return list;
}
package ch5.declare.demo;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
@Override
public CustBal mapRow(ResultSet rs, int rowNum) throws
SQLException {
// TODO Auto-generated method stub
CustBal cinfo=new CustBal();
cinfo.setId(rs.getInt("id"));
cinfo.setName(rs.getString("name"));
cinfo.setAddress(rs.getString("address"));
cinfo.setBal(rs.getInt("bal"));
return cinfo;
}
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="opmcm6718"/>
</bean>
<aop:config>
<aop:pointcut id="createOperation" expression="execution(*
ch5.declare.demo.CustDAOImpl.create(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
</aop:config>
</beans>
<aop:config>
<aop:pointcut id="createOperation" expression="execution(*
ch5.declare.demo.CustDAOImpl.create(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
</aop:config>
Hence, transactionmaner automatically comes in action if create methods throws
Exception [ in our case RuntimeException]
9. Create a file named TestApp.java and include following codes inside it:
package ch5.declare.demo;
import java.util.List;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
In this approach we will not define Transaction Manager in an XML file through AOP
rather we will define hard code Transaction Manager in CustDaoImpl class i.e. We will
initiate the transaction by writing code and in case of any error after the transaction is
started, then rollback code also we specify programmatically inside catch block.
1. Create a package named ch5.prog.demo inside src folder of above Project that
you had created for declarative transaction management.
2. We are going to use the same project and same database tables and hence not
necessary to import separate jar files and re-create the tables.
3. Inside ch5.demo.prog package create following Java classes and files.
4. Create a POJO class named CustBal which contains all fields from cust_info and
cust_bal table. This class is mainly used when retrieving records.
package ch5.prog.demo;
public class CustBal {
int id;
String name;
String address;
int bal;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getBal() {
return bal;
}
public void setBal(int bal) {
this.bal = bal;
}
}
import java.util.List;
import javax.sql.DataSource;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import
org.springframework.transaction.support.DefaultTransactionDefinition;
@Override
public void setDataSource(DataSource datasource) {
// TODO Auto-generated method stub
this.dataSource=datasource;
this.jdbcTemplate=new JdbcTemplate(datasource);
}
@Override
public void create(String name, String address, int bal) {
TransactionDefinition def = new
DefaultTransactionDefinition();
TransactionStatus status =
transactionManager.getTransaction(def);
try
{
jdbcTemplate.update("insert into
cust_info(name,address) values(?,?)",name,address);
int id=jdbcTemplate.queryForObject("select max(id) from
cust_info", Integer.class);
jdbcTemplate.update("insert into cust_bal(id,bal)
values(?,?)",id,bal);
//throw new RuntimeException("Error Simulation");
transactionManager.commit(status);
System.out.println("Record Created for \n"+
"id="+id+",Name="+name+",Address="+address+",Balance="+bal);
//throw new RuntimeException("Error Simulation");
}
catch(Exception e)
{
System.out.println("Error While Creating Record.."+e);
transactionManager.rollback(status);
throw e;
}
@Override
public List<CustBal> retAllCust() {
// TODO Auto-generated method stub
List<CustBal> list=jdbcTemplate.query("select * from
cust_info,cust_bal where cust_info.id=cust_bal.id", new
CustBalanceMapper());
return list;
}
}
Note that here we have to specify transaction start, commit and rollback code
manually.
package ch5.prog.demo;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
@Override
public CustBal mapRow(ResultSet rs, int rowNum) throws
SQLException {
// TODO Auto-generated method stub
CustBal cinfo=new CustBal();
cinfo.setId(rs.getInt("id"));
cinfo.setName(rs.getString("name"));
cinfo.setAddress(rs.getString("address"));
cinfo.setBal(rs.getInt("bal"));
return cinfo;
}
}
8. Create an XML file named beans.xml
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="opmcm6718"/>
</bean>
<!-- Initialization for TransactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionMana
ger">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
9. Create a file named TestApp.java and include following codes inside it:
package ch5.prog.demo;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestApp {
Reference:
1. http://www.tutorialspoint.com/spring/declarative_management.htm
2. http://www.tutorialspoint.com/spring/programmatic_management.htm
<tx:annotation-driven transaction-manager="transactionManager"/>
Reference:
1. http://stackoverflow.com/questions/10740021/transactionalpropagation-
propagation-required
2. https://mybolder.com/2015/12/07/spring-transactional-propagation-and-isolation/
3. http://www.skill-guru.com/blog/2010/12/19/transactionalreadonlytrue-in-spring/
In the Java programming language, an MBean (managed bean) is a Java object that
represents a manageable resource, such as an application, a service, a component, or
a device.
Reference
1.
http://www.brainoverload.nl/java/73/mbeans-using-spring-and-annotations
http://www.javalobby.org/java/forums/t49130.html
http://vijaykiran.com/2005/10/jmx-helloworld/
MBean
Let us develop a sample application in which we expose Mbean and access it from
jconsole.
Steps:
-Djava.rmi.server.hostname=localhost -Dcom.sun.management.jmxremote -
Dcom.sun.management.jmxremote.authenticate=false -
Dcom.sun.management.jmxremote.ssl=false -
Dcom.sun.management.jmxremote.port=10001
Follow the following steps to expose Java Bean as an MBean with spring.
3. Create an interface named DemoMBean and put following codes inside it.
package ch5.mbean.withspring;
public interface DemoMBean {
4. Create a class named Demo and put following codes inside it.
package ch5.mbean.withspring;
@Override
public void sayHello() {
System.out.println("Hello World !");
5. Create an XML file named beans.xml and put following codes inside it.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
</beans>
6. Create a class named TestApp and put following codes inside it.
package ch5.mbean.withspring;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
try{Thread.sleep(100000);}catch(Exception e)
{e.printStackTrace();}
System.out.println("Completed !");
7. Run TestApp
8. Start jconsole and select and establish connectivity with
ch5.mbean.withspring.TestApp and Click on "Insecure Connection" button.
9. Click on Mbeans tab and expand bean tree and click on "sayHello" button as
shown below. sayHello method of DemoMBean will be executed.
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import
org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
@Component
@ManagedResource(objectName="modelMBean:type=demo",
description="Calculator performing basic arithmetic on integers")
public class Demo {
@ManagedOperation(description="Multiplication operation")
public int multiply() {
return operand1 * operand2;
}
@ManagedOperation(description="Division operation")
@ManagedOperationParameters({
@ManagedOperationParameter(name="operand1",
description="Dividend"),
@ManagedOperationParameter(name="operand2",
description="Divisor")
})
public int divide(int operand1, int operand2) {
if(operand2 == 0) {
throw new IllegalArgumentException("Can not divide by zero");
}
return operand1 / operand2;
}
@ManagedAttribute
public int getOperand1() {
return operand1;
}
@ManagedAttribute
public void setOperand1(int operand1) {
this.operand1 = operand1;
}
@ManagedAttribute
public int getOperand2() {
return operand2;
}
@ManagedAttribute
public void setOperand2(int operand2) {
this.operand2 = operand2;
}
@ManagedOperation(description="sayHello method")
public void sayHello() {
System.out.println("Hello World !");
}
3. Create a java file named TestApp and put following source code inside it.
package ch5.mbean.annotation;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
try{Thread.sleep(100000);}catch(Exception e)
{e.printStackTrace();}
System.out.println("Completed !");
4. Create an XML file named beans.xml and put following source code inside it.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<context:component-scan base-package="ch5.mbean.annotation"/>
<context:mbean-export/>
</beans>
Note: in above source code, the various annotations have following meanings:
Reference:
1. https://blog.synyx.de/2012/05/how-to-monitor-and-manage-your-java-application-
with-jmx/
2. http://actimem.com/java/jmx-spring/
Spring IoC Container supports the beans that are going to be exposed as MBeans to publish JMX
Notification. These bean class must implement the NotificationPublisherAware interface so that
they can publish notifications. In the following example, we have a bean class called
JmxTestBean which is exposed as MBean and implements NotificationPublisheraware interface.
Hence, this class is capable of sending notification, whenever add( ) method is called. Whenever
you open jconsole and click on Notification node in the tree you have to click subscribe button.
Now, whenever the add( ) method is called by clicking the button, you can see corresponding
notification being appeared in Notification node of the tree.
Let us develop a sample program that sends JMX notification whenever add( ) method is called.
1. Create a package named ch5.notification.demo and create following files inside it.
2. Create a file named JmxTestBean.java inside ch5.notification.demo package and put
following source code inside it.
package ch5.notification.demo;
import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.jmx.export.notification.NotificationPublisher;
import javax.management.Notification;
3. Create XML file named beans.xml and put following codes inside it.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
}
5. Run TestApp.java
6. Go to command prompt and type jconsole and establish connectivity with TestApp-
>Click Insecure Connection Button-> Click on MBeans Tab-> Click on Notifications
Node-> Click on Subscribe button
Once notification occurs, it can be received by a class. Let us create a class named
ConsoleLoggingNotificaionListener inside ch5.notification.demo package and put following
codes inside it. In order for this class to receive notification published above, you have to include
this notification listener in beans.xml file as shown below:
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=MyMBeanName" value-ref="myMBean"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="bean:name=MyMBeanName">
<bean class="ch5.notification.demo.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
<property name="server" ref="mbeanServer"/>
</bean>
import javax.management.AttributeChangeNotification;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
public class ConsoleLoggingNotificationListener
System.out.println(notification);
System.out.println(handback);
return
AttributeChangeNotification.class.isAssignableFrom(notification.getClass());
}
Reference:
1. http://vard-lokkur.blogspot.com/2010/11/jmx-notification-publishing.html
2. http://docs.spring.io/spring/docs/2.5.x/reference/jmx.html#jmx-notifications-
publishing
3. http://marxsoftware.blogspot.com/2008/02/publishing-jmx-notifications-with.html
In order to expose MBean on remote machine such that it can be accessed by client
using RMI protocol, you have to add following additional codes in your beans.xml file
inside ch5.mbean.withspring package.
<bean
class="org.springframework.jmx.support.ConnectorServerFactoryBean"
depends-on="rmiRegistry">
<property name="objectName" value="connector:name=rmi" />
<property name="serviceUrl"
value="service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector" />
</bean>
<bean id="rmiRegistry"
class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="10099" />
</bean>
The complete source code of beans.xml file should look like following:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<bean id="rmiRegistry"
class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="10099" />
</bean>
value="service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector" />
</bean>
</beans>
Once, Mbean is exposed for remote access, now, the MBean named "MyBeanName"
can be accessed remotely using the following URLs:
service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector
Server Side:
1. Open Command prompt and type rmiregistry 10099 [ rmiregistry will be started]
2. Run TesApp.java
Client Side:
3. Open Command Promt and type jconsole and type following URL on remote
process text box as shown below:
4. Now, click on Connect->Insecure Connection-> You will be able to monitor
MBean named "MyBean" as shown below:
Monitoring Remote Services using Custom Application
In client side,
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
try
{
String host="localhost";
String port="10099";
JMXServiceURL target = new
JMXServiceURL("service:jmx:rmi:///jndi/rmi://"+host+":"+port+"/myconnector");
JMXConnector connector = JMXConnectorFactory.connect(target);
MBeanServerConnection remote = connector.getMBeanServerConnection();
ObjectName bean = new ObjectName("bean:name=MyMBeanName");
MBeanInfo info = remote.getMBeanInfo(bean);
MBeanAttributeInfo[] attributes = info.getAttributes();
String description= info.getDescription();
System.out.println("Description="+description);
MBeanOperationInfo ops[]= info.getOperations();
System.out.println("Operation Name="+operation.getName());
}
System.out.println("Completed");
connector.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Note: Above code is able to monitor various aspects of MBean named MyBean
[ Attributes, Operations, Notifications etc] that is exposed in Server Side over RMI.
Reference:
1. https://docs.oracle.com/javase/tutorial/jmx/remote/custom.html