Spring Aspect: surround entire method with try catch - spring

How can I create a Spring Aspect (annotation driven e.g. #ExceptionTranslation) surrounding an entire method and put this method in a try...catch method?
#ExceptionTranslation
public void method() {
// do some stuff here...
}
so logically it does:
public void method() {
try {
// do some stuff here ...
} catch( Exception ex ) {
}
}

Below you can find a sample implementation of AfterThrows advice solving your problem.
CustomException.java
package com.yourpackage;
public class CustomException extends Exception {
public CustomException(final Throwable cause) {
super(cause);
}
}
ErrorBean.java
package com.yourpackage;
public class ErrorBean {
#ExceptionTranslation
public void translatedException() throws Exception {
throw new Exception("Foo");
}
public void notTranslatedException() throws Exception {
throw new Exception("Bar");
}
}
ExceptionTranslation.java
package com.yourpackage;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface ExceptionTranslation {
}
SimpleThrowsAdvice.java
package com.yourpackage;
import org.springframework.aop.Advisor;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
public class SimpleThrowsAdvice implements ThrowsAdvice {
public static void main(String[] args) throws Exception {
ErrorBean errorBean = new ErrorBean();
AnnotationMatchingPointcut pc = AnnotationMatchingPointcut.forMethodAnnotation(ExceptionTranslation.class);
SimpleThrowsAdvice advice = new SimpleThrowsAdvice();
Advisor advisor = new DefaultPointcutAdvisor(pc, advice);
ProxyFactory pf = new ProxyFactory();
pf.setTarget(errorBean);
pf.addAdvisor(advisor);
ErrorBean proxy = (ErrorBean) pf.getProxy();
try {
proxy.translatedException();
} catch (CustomException ex) {
System.out.println("CustomException caught");
} catch (Exception ex) {
System.out.println("Exception caught");
}
try {
proxy.notTranslatedException();
} catch (CustomException ex) {
System.out.println("CustomException caught");
} catch (Exception ex) {
System.out.println("Exception caught");
}
}
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("***");
System.out.println("Generic Exception Capture");
System.out.println("Caught: " + ex.getClass().getName());
System.out.println("***\n");
throw new CustomException(ex);
}
}

Related

JMS listener processes message twice

we migrated a websphere j2ee app to spring boot. Everything looked great but now we found out that the message listeners are sometimes processing some messages twice.
It looks like to me it happens when one message is been processed and not yet commited, an other concurrent consumer can get the same message and also process it.
Looks like the message broker doesn't hold it back, doesn't reserves it for consumer 1.
import bitronix.tm.resource.jms.PoolingConnectionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.transaction.PlatformTransactionManager;
import javax.jms.ConnectionFactory;
import javax.jms.Session;
import java.util.Properties;
#Configuration
#EnableJms
#EnableCaching(proxyTargetClass = true)
public class JmsConfig {
#Bean
ConnectionFactory jmsXAConnectionFactory() {
PoolingConnectionFactory connectionFactory = new PoolingConnectionFactory();
connectionFactory.setClassName("com.ibm.mq.jms.MQXAQueueConnectionFactory");
connectionFactory.setUniqueName("mq-xa-" + appName);
connectionFactory.setAllowLocalTransactions(true);
connectionFactory.setTestConnections(false);
connectionFactory.setUser(user);
connectionFactory.setPassword(password);
connectionFactory.setMaxIdleTime(1800);
connectionFactory.setMinPoolSize(1);
connectionFactory.setMaxPoolSize(25);
connectionFactory.setAcquisitionTimeout(60);
connectionFactory.setAutomaticEnlistingEnabled(true);
connectionFactory.setDeferConnectionRelease(true);
connectionFactory.setShareTransactionConnections(false);
Properties driverProperties = connectionFactory.getDriverProperties();
driverProperties.setProperty("queueManager", queueManager);
driverProperties.setProperty("hostName", connName);
driverProperties.setProperty("port", "1414");
driverProperties.setProperty("channel", channel);
driverProperties.setProperty("transportType", "1");
driverProperties.setProperty("messageRetention", "1");
return connectionFactory;
}
#Primary
#Bean
public BitronixTransactionManager btronixTransactionManager() throws SystemException {
TransactionManagerServices.getConfiguration().setServerId("bitronix-tm-" + appName);
TransactionManagerServices.getConfiguration().setLogPart1Filename(jtaLogDir + "/btm1.tlog");
TransactionManagerServices.getConfiguration().setLogPart2Filename(jtaLogDir + "/btm2.tlog");
TransactionManagerServices.getTransactionManager().setTransactionTimeout(180);
return TransactionManagerServices.getTransactionManager();
}
#Bean
public PlatformTransactionManager platformTransactionManager(
BitronixTransactionManager transactionManager, UserTransaction userTransaction) {
return new JtaTransactionManager(userTransaction, transactionManager);
}
#Bean("wgstatusML")
public DefaultMessageListenerContainer wagenstatusMessageListenerContainer(
ConnectionFactory jmsXAConnectionFactory,
PlatformTransactionManager jtaTransactionManager,
#Qualifier("wagenstatusBean") WagenstatusBean wagenstatusBean) {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(jmsXAConnectionFactory);
container.setTransactionManager(jtaTransactionManager);
container.setDestinationName(WAGENSTATUS_QUEUE);
container.setMessageListener(wagenstatusBean);
container.setAutoStartup(false);
container.setConcurrentConsumers(2);
container.setClientId("wgstatListener");
container.setSessionTransacted(false);
container.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
return container;
}
}
#Service("wagenstatusBean")
#Scope(SCOPE_PROTOTYPE)
public class WagenstatusBean extends AbstractMDB {
#Transactional(propagation = REQUIRED)
public void onMessage(javax.jms.Message msg) {
String localMessageText = null;
try {
try {
localMessageText = ((TextMessage) msg).getText();
} catch (JMSException e) {
}
// here goes the actual call to the impl
String errmsg = null;
readableMessageID = null;
try {
verarbeiteMeldung(msg);
} catch (InvalidMessageException ime) {
errmsg = ime.getMessage();
}
if (sendMessageToErrorQueue) {
// generate business logging entry
try {
logBusinessData(localMessageText, BusinessLogger.STATUS_ERROR);
} catch (Exception e) {
LOGGER.error("", e);
}
if (localMessageText != null) {
localMessageText = this.addErrorMessageToXML(localMessageText, errmsg);
}
DispatcherServiceLocator.getDispatcherBean().sendToDestination(
QueueNames.WAGENSTATUS_ERROR_QUEUE, localMessageText);
}
} catch (ConsistencyException ex) {
// ConsistencyException used internally in the EJBEnv
// framework/template needs to be catched and translated into an EJBException
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();;
// generate business logging entry
try {
// UE03772, RfC 169: BUSINESS LOGGING POINT
logBusinessData(localMessageText, BusinessLogger.STATUS_ERROR);
} catch (Exception e) {
LOGGER.error("", e);
}
LOGGER.error("Caught a ConsistencyException in WagenStatus-onMessage", ex);
} catch (RuntimeException ex) {
// this catching is done for logging purpouse only.
LOGGER.error("Caught a RuntimeException in WagenStatus-onMessage", ex);
// generate business logging entry
try {
logBusinessData(localMessageText, BusinessLogger.STATUS_ERROR);
} catch (Exception e) {
LOGGER.error("", e);
}
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();;
}
}

Spring AOP Not working properly

I'm trying to handle exceptions with AOP approach in my Spring/Swing Application and I couldn't make it work.
Main Class:
public class MainFrame extends JFrame {
private JPanel mainPanel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainFrame frame = new MainFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MainFrame() {
initializeMainPanel();
}
private void initializeMainPanel() {
exitLabel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
throw new Exception("test");
}
});
}
}
Aspect Class:
#Aspect
public class AspectTest{
#AfterThrowing(pointcut = "execution(* com.test.MainFrame.*(..))", throwing = "ex")
public void logError(Exception ex) throws Throwable {
// ex.printStackTrace();
}
}
So, I throw an exception within my Mouse Listener and expect to catch it in my AspectTest class' AfterThrowing method but it does not work.
Can someone please help me to understand what I'm missing here?
#AfterThrowing cannot catch exceptions, only notice them and log them or do something similar. If you want to handle exceptions in an aspect you need to use an #Around advice.

What is the impact of using #non thread-safe class?

I have written the following code, as I was trying to understand the situation where I would use ThreadLocals:-
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDF {
private DateFormat df = new SimpleDateFormat("MM/dd/yy");
public String formatCurrentDate() {
System.out.println(">>>>>>>"+Thread.currentThread().getName());
Date d = new Date();
return df.format(d);
}
public String formatFirstOfJanyary1970() {
System.out.println(">>>>>>>" + Thread.currentThread().getName());
Date d = new Date(0);
return df.format(d);
}
public static void main(String[] args) {
TestDF df = new TestDF();
Thread t1 = new Thread(new WorkerThread(df));
Thread t2 = new Thread(new WorkerThread1(df));
t1.start();
t2.start();
}
public static class WorkerThread implements Runnable {
TestDF df;
public WorkerThread(TestDF df) {
this.df = df;
}
#Override
public void run() {
Thread.currentThread().setName("Worker-Thread 1");
System.out.println("Inside Thread1*");
System.out.println("Thread 1 "+df.formatCurrentDate());
System.out.println("Inside Thread1**");
try {
Thread.sleep(5000l);
System.out.println("Inside Thread1***");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static class WorkerThread1 implements Runnable {
TestDF df;
public WorkerThread1(TestDF df) {
this.df = df;
}
#Override
public void run() {
Thread.currentThread().setName("Worker-Thread 2");
System.out.println("Inside Thread2*");
System.out.println("Thread 2 "+df.formatFirstOfJanyary1970());
System.out.println("Inside Thread2**");
try {
Thread.sleep(5000l);
System.out.println("Inside Thread2***");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
The out which I am receiving is as follows:-
Inside Thread1*
Inside Thread2*
>>>>>>>Worker-Thread 2
>>>>>>>Worker-Thread 1
Thread 1 06/09/15 <--
Thread 2 06/09/15 <--
Inside Thread1**
Inside Thread2**
Inside Thread1***
Inside Thread2***
I am aware that SimpleDateFormat is not thread-safe; but still couldn't make out how is happening.

how can i use spring framework with lucene

all.
i am a newbie of lucene, and i'm using spring-mvc (3.2.5.RELEASE) and lucene(4.6.0).
both are newest version currently.
how can i use NEAR REAL TIME search?
i write this code to get instance of IndexWriter (sington)
package com.github.yingzhuo.mycar.search;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.wltea.analyzer.lucene.IKAnalyzer;
public class IndexWriterFactoryBean implements FactoryBean<IndexWriter>, InitializingBean, DisposableBean {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexWriterFactoryBean.class);
private Analyzer analyzer = new IKAnalyzer(false);
private Resource indexDirectory = null;
private IndexWriter indexWriter = null;
private Directory directory = null;
public IndexWriterFactoryBean() {
if (indexDirectory != null) {
try {
if (! indexDirectory.getFile().exists()) {
FileUtils.forceMkdir(indexDirectory.getFile());
}
} catch (IOException e) {
LOGGER.warn(e.getMessage(), e);
}
}
}
#Override
public IndexWriter getObject() throws Exception {
return indexWriter;
}
#Override
public Class<?> getObjectType() {
return IndexWriter.class;
}
#Override
public boolean isSingleton() {
return true;
}
#Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(analyzer, "property 'analyzer' must be set.");
Assert.notNull(indexDirectory, "property 'indexDirectory' must be set.");
directory = FSDirectory.open(indexDirectory.getFile());
indexWriter = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_46, analyzer));
}
#Override
public void destroy() throws Exception {
IOUtils.closeQuietly(indexWriter);
IOUtils.closeQuietly(directory);
IOUtils.closeQuietly(analyzer);
}
// getter & setter
// ------------------------------------------------------------------------------------------
public void setAnalyzer(Analyzer analyzer) {
this.analyzer = analyzer;
}
public void setIndexDirectory(Resource indexDirectory) {
this.indexDirectory = indexDirectory;
}
}
and this utility to get DirectoryReader by static method.
import java.io.IOException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import com.github.yingzhuo.mycar.config.SpringUtils;
public final class DirectoryReaderHolder {
private static DirectoryReader HOLDER = null;
public synchronized static DirectoryReader get() {
if (HOLDER == null) {
try {
HOLDER = DirectoryReader.open(SpringUtils.getBean(IndexWriter.class), true);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
return HOLDER;
}
public static synchronized void set(DirectoryReader directoryReader) {
if (directoryReader == null) {
throw new NullPointerException();
} else {
HOLDER = directoryReader;
}
}
}
and this bean to inject into my spring-mvc controller. In 'create' method, i am trying to get a new reader before i create a IndexSearcher, but HOW SHOULD I HANDLE THE OLD READER ?
can i close it directly? if other threads are still using the old reader, very bad thing will happen ?
package com.github.yingzhuo.mycar.search;
import java.io.IOException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.search.IndexSearcher;
public class IndexSearcherManager {
public IndexSearcher create() {
try {
DirectoryReader oldReader = DirectoryReaderHolder.get();
DirectoryReader newReader = DirectoryReader.openIfChanged(oldReader);
if (newReader != null) {
oldReader.close(); // AM I RIGHT ???
oldReader = newReader;
}
return new IndexSearcher(oldReader);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
Any suggestions? thank you.

Problem investigating JmDNS3.4.1 jar

I'm newbie here. I'm dealing with my first program using osgi bundles and JmDNS. After adding JmDNS 3.4.1 jar to my project, I'm testing the following basic code:
My Activator:
package test.discoverservice;
import java.io.IOException;
import test.DiscoverServices;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceTypeListener;
import org.equinoxosgi.jmdns.dev.discoverservice.DiscoverServices.SampleListener;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class JmdnsActivator implements BundleActivator {
public void start(BundleContext context) throws Exception {
System.out.println("Launching");
try {
System.out.println("step 1");
final JmDNS jmdns = JmDNS.create();
System.out.println("step 2");
jmdns.addServiceListener("_http._tcp.local.", new SampleListener());
// jmdns.close();
// System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop(BundleContext context) throws Exception {
System.out.println("Terminating");
}
}
and here is the bundle:
package test.discoverservice;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceListener;
public class DiscoverServices {
static class SampleListener implements ServiceListener {
#Override
public void serviceAdded(ServiceEvent event) {
System.out.println("Service added : " + event.getName() + "." + event.getType());
}
#Override
public void serviceRemoved(ServiceEvent event) {
System.out.println("Service removed : " + event.getName() + "." + event.getType());
}
#Override
public void serviceResolved(ServiceEvent event) {
System.out.println("Service resolved: " + event.getInfo());
}
}
}
when I run the code, I get :
osgi> Launching
step 1
and then it stops, so I guess there is a probelm with the creation of the JmDNS instance..
Any idea please?
Note that if I don't use a bundle with an activator (simple program with main) everything works properly
import java.io.IOException;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceTypeListener;
public class DiscoverServiceTypes {
static class SampleListener implements ServiceTypeListener {
#Override
public void serviceTypeAdded(ServiceEvent event) {
System.out.println("Service type added: " + event.getType());
}
public void subTypeForServiceTypeAdded(ServiceEvent event) {
System.out.println("SubType for service type added: " + event.getType());
}
}
public static void main(String[] args) {
try {
JmDNS jmdns = JmDNS.create();
System.out.println("JmDNS created !!");
jmdns.addServiceTypeListener(new SampleListener());
// jmdns.close();
// System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
}
}
PS: I'm running it on Windows
You have to add the imported library in the classpath of the MANIFEST.MF file of the OSGI Framework if not already done.
Bundle-ClassPath: org.json.jar,
lib/jmdns-3.4.1.jar, ...
If you got the lirary from sourceforge check if the jar file is correct and no class is present twice in the jar. (If so, just use the .jar from Maven)

Resources