Ensure single instance of a spring managed bean - java

I have created a spring aspect to handle Retry mechanism. I have also created a Retry annotation.
Following is the code for Retry annotation and an aspect which processes this annotation.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Retry {
/**
* List of exceptions for which we need to retry method invocation.
*
* #return Array of classes.
*/
Class<?>[] exceptions();
/**
* Number of retries. Default is 3.
*
* #return Number of retires.
*/
int retries() default 3;
/**
* Back of period in ms. Default is 1000 ms.
*
* #return Back off Period.
*/
int backOffPeriod() default 1000;
}
#Aspect
public class RetryInterceptor implements Ordered {
private static final RetryInterceptor instance = new RetryInterceptor();
private RetryInterceptor() {
}
private static final Log logger = LogFactory.getLog(RetryInterceptor.class);
private int order = 100;
#Around("#annotation(retry)")
public Object performOperation(ProceedingJoinPoint pjp, Retry retry) throws Throwable {
Class<?>[] exceptionClasses = retry.exceptions();
Assert.notEmpty(exceptionClasses, "Exception classes cannot be empty.");
int retries = retry.retries();
if (logger.isInfoEnabled()) {
logger.info("Attempting to call " + pjp.toShortString() + " with potential for " + getExceptionClasses(exceptionClasses)
+ " with maximum " + retries + " retries");
}
int numAttempts = 0;
do {
try {
return pjp.proceed();
} catch (Throwable ex) {
// if the exception is not what we're looking for, pass it through
boolean canThrowException = true;
for (Class<?> exceptionClass : exceptionClasses) {
if (exceptionClass.isAssignableFrom(ex.getClass())) {
canThrowException = false;
break;
}
}
// A non-configured exception was found.
if (canThrowException) {
throw ex;
}
// we caught the configured exception, retry unless we've reached the maximum
if (++numAttempts > retries) {
logger.warn("Caught " + ex.getClass().getCanonicalName() + " and exceeded maximum retries (" + retries
+ "), rethrowing.");
throw ex;
}
if (logger.isInfoEnabled()) {
logger.info("Caught " + ex.getClass().getCanonicalName() + " and will retry, attempts: " + numAttempts);
}
}
sleep(retry.backOffPeriod());
} while (numAttempts <= retries);
// this will never execute - we will have either successfully returned or re-thrown an
// exception
return null;
}
#Override
public int getOrder() {
return order;
}
private String getExceptionClasses(Class<?>[] classes) {
StringBuilder builder = new StringBuilder();
builder.append(classes[0].getCanonicalName());
for (int i = 1; i < classes.length; i++) {
builder.append(", ").append(classes[i].getCanonicalName());
}
return builder.toString();
}
public static RetryInterceptor getInstance() {
return instance;
}
// Better than Thread.sleep().
public void sleep(long backOffPeriod) throws InterruptedException {
Object mutex = new Object();
synchronized (mutex) {
mutex.wait(backOffPeriod);
}
}
}
To enable the annotation, I need to instantiate the RetryInterceptor class. I want to ensure that for a given context there is only one instance of this object. If for some reason multiple objects are created my advice is applied that many times. How can I totally ensure that there will always be 1 instance?

I found a way to do this :) Ref: Going Beyond DI
I registered a BeanDefinitionRegistryPostProcessor in my root context, this will ensure that there is only one BeanDefinition of my desired class.
package test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import com.xx.xx.xx.xx.xx.RetryInterceptor;
public class TestBeanFacotryPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
String[] definitionNames = registry.getBeanDefinitionNames();
for (int i = 0, j = 0; i < definitionNames.length; i++) {
Class<?> clazz;
try {
clazz = Class.forName(registry.getBeanDefinition(definitionNames[i]).getBeanClassName());
if (RetryInterceptor.class == clazz && j++ > 0) {
registry.removeBeanDefinition(definitionNames[i]);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}

There will ever only be one instance as its a spring managed bean with the default scope of singleton. You have some singleton type stuff at the top of your class (like where you create your new instance statically etc)... this is not needed. An aspect is just a bean like any other so code it asuch. If you want to be sure, put in a PostContruct method with some logging like 'Initiating aspect' or something and you will see it only prints to your logs once.

if someone can create second bean of your type, why you are don't want to check someone creates another aspect with same logic? I think your approach is erroneous by design.
you can implement ApplicationContextAware interface and check there, that only one bean of your class present in context and throw exception if it's not true, but I'm not sure that this will work if you have context hierarchy.

Related

Share limited amount of resources between different threads

I write selenium tests and make it parallel via testng.
There are some tests which should use resource, and that resource cant be used in tests, while it using in another test.
So to make it clear let me describe in other words, I have 10 resources, and when some test start working with one of them, only 9 another resources should be available in another tests. If all 10 resources are busy, and another test attempts to get it, it should wait until one of test will finish execution and free it's resource.
Im trying to create provider which will control desired behaviour but it looks like I get deadlocks, because it hangs out some times at synchronized method call.
My plan is provider have 2 methods get() and remove()
get() called in test method to get resource
remove() called in method annotated with #AfterMethod annotation and this method is default method of specific interface which should be implemented in class, containing resource usage
Here is provider class:
public class ResourceProvider {
private static final Logger logger = LogManager.getLogger();
private static List<Resource> freeResources;
private static Map<String, List<Resource>> resourcesInUse;
static {
freeResources = new ArrayList<>();
//here is resource initialization to fill freeResources list
resourcesInUse = new HashMap<>();
}
public static synchronized Resource get() {
String testName = Thread.currentThread().getStackTrace()[2].getClassName()
+ "." + Thread.currentThread().getStackTrace()[2].getMethodName();
Resource resource = null;
logger.info(String.format("Attempt to get resource for %s test", testName));
for (int i = 0; i < 240; i++) {
if (freeResources.isEmpty()) {
try {
Thread.sleep(5_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
resource = freeResources.get(0);
if (resourcesInUse.containsKey(testName)) {
resourcesInUse.get(testName).add(resource);
} else {
List<Resource> resources = new ArrayList<>();
resources.add(resource);
resourcesInUse.put(testName, resources);
}
freeResources.remove(resource);
break;
}
}
if (resource == null) {
throw new RuntimeException(String.format("There is no free resource for '%s' in 20 minutes", testName));
}
logger.info(String.format("Resource %s used in %s", resource, testName));
return resource;
}
public static synchronized boolean remove(ITestResult result) {
String testName = result.getMethod().getTestClass().getName() + "." + result.getMethod().getMethodName();
return remove(testName);
}
public static synchronized boolean remove(String testName) {
boolean isTestUseResource = resourcesInUse.containsKey(testName);
if (isTestUseResource) {
logger.info(String.format("Removing %s resources, used in %s", resourcesInUse.get(testName), testName));
freeResources.addAll(resourcesInUse.get(testName));
resourcesInUse.remove(testName);
}
return isTestUseResource;
}
Interface:
public interface RemoveResource {
#AfterMethod
default void removeResource(ITestResult result) {
ResourceProvider.remove(result);
}
But this code doesnt work good, it hangs out at remove() call sometimes.
May you help me to understand why I get hangs out and how to resolve it?

Java: Easy way of passing a method as a parameter [duplicate]

I need to find the caller of a method. Is it possible using stacktrace or reflection?
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()
According to the Javadocs:
The last element of the array represents the bottom of the stack, which is the least recent method invocation in the sequence.
A StackTraceElement has getClassName(), getFileName(), getLineNumber() and getMethodName().
You will have to experiment to determine which index you want
(probably stackTraceElements[1] or [2]).
Note: if you are using Java 9 or later you should use StackWalker.getCallerClass() as described in Ali Dehghani's answer.
The comparison of different methods below is mostly interesting for historical reason.
An alternative solution can be found in a comment to this request for enhancement.
It uses the getClassContext() method of a custom SecurityManager and seems to be faster than the stack trace method.
The following program tests the speed of the different suggested methods (the most interesting bit is in the inner class SecurityManagerMethod):
/**
* Test the speed of various methods for getting the caller class name
*/
public class TestGetCallerClassName {
/**
* Abstract class for testing different methods of getting the caller class name
*/
private static abstract class GetCallerClassNameMethod {
public abstract String getCallerClassName(int callStackDepth);
public abstract String getMethodName();
}
/**
* Uses the internal Reflection class
*/
private static class ReflectionMethod extends GetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) {
return sun.reflect.Reflection.getCallerClass(callStackDepth).getName();
}
public String getMethodName() {
return "Reflection";
}
}
/**
* Get a stack trace from the current thread
*/
private static class ThreadStackTraceMethod extends GetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) {
return Thread.currentThread().getStackTrace()[callStackDepth].getClassName();
}
public String getMethodName() {
return "Current Thread StackTrace";
}
}
/**
* Get a stack trace from a new Throwable
*/
private static class ThrowableStackTraceMethod extends GetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) {
return new Throwable().getStackTrace()[callStackDepth].getClassName();
}
public String getMethodName() {
return "Throwable StackTrace";
}
}
/**
* Use the SecurityManager.getClassContext()
*/
private static class SecurityManagerMethod extends GetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) {
return mySecurityManager.getCallerClassName(callStackDepth);
}
public String getMethodName() {
return "SecurityManager";
}
/**
* A custom security manager that exposes the getClassContext() information
*/
static class MySecurityManager extends SecurityManager {
public String getCallerClassName(int callStackDepth) {
return getClassContext()[callStackDepth].getName();
}
}
private final static MySecurityManager mySecurityManager =
new MySecurityManager();
}
/**
* Test all four methods
*/
public static void main(String[] args) {
testMethod(new ReflectionMethod());
testMethod(new ThreadStackTraceMethod());
testMethod(new ThrowableStackTraceMethod());
testMethod(new SecurityManagerMethod());
}
private static void testMethod(GetCallerClassNameMethod method) {
long startTime = System.nanoTime();
String className = null;
for (int i = 0; i < 1000000; i++) {
className = method.getCallerClassName(2);
}
printElapsedTime(method.getMethodName(), startTime);
}
private static void printElapsedTime(String title, long startTime) {
System.out.println(title + ": " + ((double)(System.nanoTime() - startTime))/1000000 + " ms.");
}
}
An example of the output from my 2.4 GHz Intel Core 2 Duo MacBook running Java 1.6.0_17:
Reflection: 10.195 ms.
Current Thread StackTrace: 5886.964 ms.
Throwable StackTrace: 4700.073 ms.
SecurityManager: 1046.804 ms.
The internal Reflection method is much faster than the others. Getting a stack trace from a newly created Throwable is faster than getting it from the current Thread. And among the non-internal ways of finding the caller class the custom SecurityManager seems to be the fastest.
Update
As lyomi points out in this comment the sun.reflect.Reflection.getCallerClass() method has been disabled by default in Java 7 update 40 and removed completely in Java 8. Read more about this in this issue in the Java bug database.
Update 2
As zammbi has found, Oracle was forced to back out of the change that removed the sun.reflect.Reflection.getCallerClass(). It is still available in Java 8 (but it is deprecated).
Update 3
3 years after: Update on timing with current JVM.
> java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
> java TestGetCallerClassName
Reflection: 0.194s.
Current Thread StackTrace: 3.887s.
Throwable StackTrace: 3.173s.
SecurityManager: 0.565s.
Java 9 - JEP 259: Stack-Walking API
JEP 259 provides an efficient standard API for stack walking that allows easy filtering of, and lazy access to, the information in stack traces. Before Stack-Walking API, common ways of accessing stack frames were:
Throwable::getStackTrace and Thread::getStackTrace return an array of
StackTraceElement objects, which contain the class name and method
name of each stack-trace element.
SecurityManager::getClassContext is a protected method, which allows a
SecurityManager subclass to access the class context.
JDK-internal sun.reflect.Reflection::getCallerClass method which you shouldn't use anyway
Using these APIs are usually inefficient:
These APIs require the VM to eagerly capture a snapshot of the entire
stack, and they return information representing the entire stack.
There is no way to avoid the cost of examining all the frames if the
caller is only interested in the top few frames on the stack.
In order to find the immediate caller's class, first obtain a StackWalker:
StackWalker walker = StackWalker
.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
Then either call the getCallerClass():
Class<?> callerClass = walker.getCallerClass();
or walk the StackFrames and get the first preceding StackFrame:
walker.walk(frames -> frames
.map(StackWalker.StackFrame::getDeclaringClass)
.skip(1)
.findFirst());
Sounds like you're trying to avoid passing a reference to this into the method. Passing this is way better than finding the caller through the current stack trace. Refactoring to a more OO design is even better. You shouldn't need to know the caller. Pass a callback object if necessary.
Oneliner:
Thread.currentThread().getStackTrace()[2].getMethodName()
Note that you might need to replace the 2 with 1.
This method does the same thing but a little more simply and possibly a little more performant and in the event you are using reflection, it skips those frames automatically. The only issue is it may not be present in non-Sun JVMs, although it is included in the runtime classes of JRockit 1.4-->1.6. (Point is, it is not a public class).
sun.reflect.Reflection
/** Returns the class of the method <code>realFramesToSkip</code>
frames up the stack (zero-based), ignoring frames associated
with java.lang.reflect.Method.invoke() and its implementation.
The first frame is that associated with this method, so
<code>getCallerClass(0)</code> returns the Class object for
sun.reflect.Reflection. Frames associated with
java.lang.reflect.Method.invoke() and its implementation are
completely ignored and do not count toward the number of "real"
frames skipped. */
public static native Class getCallerClass(int realFramesToSkip);
As far as what the realFramesToSkip value should be, the Sun 1.5 and 1.6 VM versions of java.lang.System, there is a package protected method called getCallerClass() which calls sun.reflect.Reflection.getCallerClass(3), but in my helper utility class I used 4 since there is the added frame of the helper class invocation.
/**
* Get the method name for a depth in call stack. <br />
* Utility function
* #param depth depth in the call stack (0 means current method, 1 means call method, ...)
* #return method name
*/
public static String getMethodName(final int depth)
{
final StackTraceElement[] ste = new Throwable().getStackTrace();
//System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
return ste[ste.length - depth].getMethodName();
}
For example, if you try to get the calling method line for debug purpose, you need to get past the Utility class in which you code those static methods:
(old java1.4 code, just to illustrate a potential StackTraceElement usage)
/**
* Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils". <br />
* From the Stack Trace.
* #return "[class#method(line)]: " (never empty, first class past StackTraceUtils)
*/
public static String getClassMethodLine()
{
return getClassMethodLine(null);
}
/**
* Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
* Allows to get past a certain class.
* #param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils.
* #return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
*/
public static String getClassMethodLine(final Class aclass)
{
final StackTraceElement st = getCallingStackTraceElement(aclass);
final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
+")] <" + Thread.currentThread().getName() + ">: ";
return amsg;
}
/**
* Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
* Stored in array of the callstack. <br />
* Allows to get past a certain class.
* #param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils.
* #return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
* #throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
*/
public static StackTraceElement getCallingStackTraceElement(final Class aclass)
{
final Throwable t = new Throwable();
final StackTraceElement[] ste = t.getStackTrace();
int index = 1;
final int limit = ste.length;
StackTraceElement st = ste[index];
String className = st.getClassName();
boolean aclassfound = false;
if(aclass == null)
{
aclassfound = true;
}
StackTraceElement resst = null;
while(index < limit)
{
if(shouldExamine(className, aclass) == true)
{
if(resst == null)
{
resst = st;
}
if(aclassfound == true)
{
final StackTraceElement ast = onClassfound(aclass, className, st);
if(ast != null)
{
resst = ast;
break;
}
}
else
{
if(aclass != null && aclass.getName().equals(className) == true)
{
aclassfound = true;
}
}
}
index = index + 1;
st = ste[index];
className = st.getClassName();
}
if(resst == null)
{
//Assert.isNotNull(resst, "stack trace should null"); //NO OTHERWISE circular dependencies
throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
}
return resst;
}
static private boolean shouldExamine(String className, Class aclass)
{
final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith("LogUtils"
) == false || (aclass !=null && aclass.getName().endsWith("LogUtils")));
return res;
}
static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st)
{
StackTraceElement resst = null;
if(aclass != null && aclass.getName().equals(className) == false)
{
resst = st;
}
if(aclass == null)
{
resst = st;
}
return resst;
}
I've done this before. You can just create a new exception and grab the stack trace on it without throwing it, then examine the stack trace. As the other answer says though, it's extremely costly--don't do it in a tight loop.
I've done it before for a logging utility on an app where performance didn't matter much (Performance rarely matters much at all, actually--as long as you display the result to an action such as a button click quickly).
It was before you could get the stack trace, exceptions just had .printStackTrace() so I had to redirect System.out to a stream of my own creation, then (new Exception()).printStackTrace(); Redirect System.out back and parse the stream. Fun stuff.
private void parseExceptionContents(
final Exception exception,
final OutputStream out)
{
final StackTraceElement[] stackTrace = exception.getStackTrace();
int index = 0;
for (StackTraceElement element : stackTrace)
{
final String exceptionMsg =
"Exception thrown from " + element.getMethodName()
+ " in class " + element.getClassName() + " [on line number "
+ element.getLineNumber() + " of file " + element.getFileName() + "]";
try
{
out.write((headerLine + newLine).getBytes());
out.write((headerTitlePortion + index++ + newLine).getBytes() );
out.write((headerLine + newLine).getBytes());
out.write((exceptionMsg + newLine + newLine).getBytes());
out.write(
("Exception.toString: " + element.toString() + newLine).getBytes());
}
catch (IOException ioEx)
{
System.err.println(
"IOException encountered while trying to write "
+ "StackTraceElement data to provided OutputStream.\n"
+ ioEx.getMessage() );
}
}
}
Here is a part of the code that I made based in the hints showed in this topic.
Hope it helps.
(Feel free to make any suggestions to improve this code, please tell me)
The counter:
public class InstanceCount{
private static Map<Integer, CounterInstanceLog> instanceMap = new HashMap<Integer, CounterInstanceLog>();
private CounterInstanceLog counterInstanceLog;
public void count() {
counterInstanceLog= new counterInstanceLog();
if(counterInstanceLog.getIdHashCode() != 0){
try {
if (instanceMap .containsKey(counterInstanceLog.getIdHashCode())) {
counterInstanceLog= instanceMap .get(counterInstanceLog.getIdHashCode());
}
counterInstanceLog.incrementCounter();
instanceMap .put(counterInstanceLog.getIdHashCode(), counterInstanceLog);
}
(...)
}
And the object:
public class CounterInstanceLog{
private int idHashCode;
private StackTraceElement[] arrayStackTraceElements;
private int instanceCount;
private String callerClassName;
private StackTraceElement getProjectClasses(int depth) {
if(depth< 10){
getCallerClassName(sun.reflect.Reflection.getCallerClass(depth).getName());
if(getCallerClassName().startsWith("com.yourproject.model")){
setStackTraceElements(Thread.currentThread().getStackTrace());
setIdHashCode();
return arrayStackTraceElements[depth];
}
//+2 because one new item are added to the stackflow
return getProjectClasses(profundidade+2);
}else{
return null;
}
}
private void setIdHashCode() {
if(getNomeClasse() != null){
this.idHashCode = (getCallerClassName()).hashCode();
}
}
public void incrementaContador() {
this.instanceCount++;
}
//getters and setters
(...)
}
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
class DBConnection {
String createdBy = null;
DBConnection(Throwable whoCreatedMe) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(os);
whoCreatedMe.printStackTrace(pw);
try {
createdBy = os.toString();
pw.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ThrowableTest {
public static void main(String[] args) {
Throwable createdBy = new Throwable(
"Connection created from DBConnectionManager");
DBConnection conn = new DBConnection(createdBy);
System.out.println(conn.createdBy);
}
}
OR
public static interface ICallback<T> { T doOperation(); }
public class TestCallerOfMethod {
public static <T> T callTwo(final ICallback<T> c){
// Pass the object created at callee to the caller
// From the passed object we can get; what is the callee name like below.
System.out.println(c.getClass().getEnclosingMethod().getName());
return c.doOperation();
}
public static boolean callOne(){
ICallback callBackInstance = new ICallback(Boolean){
#Override
public Boolean doOperation()
{
return true;
}
};
return callTwo(callBackInstance);
}
public static void main(String[] args) {
callOne();
}
}
use this method:-
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
stackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
System.out.println(e.getMethodName());
Caller of method example Code is here:-
public class TestString {
public static void main(String[] args) {
TestString testString = new TestString();
testString.doit1();
testString.doit2();
testString.doit3();
testString.doit4();
}
public void doit() {
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
System.out.println(e.getMethodName());
}
public void doit1() {
doit();
}
public void doit2() {
doit();
}
public void doit3() {
doit();
}
public void doit4() {
doit();
}
}
Short answer ReflectionUtils.getCallingClass(0)
Long answer (code, Groovy)
package my
import org.codehaus.groovy.reflection.ReflectionUtils
import java.lang.reflect.Field
import java.lang.reflect.Method
trait Reflector {
static String[] fieldNames() {
List<String> names = []
Arrays.asList(naturalFields()).forEach { Field fl -> names.add(fl.name) }
return names.toArray() as String[]
}
static Field[] naturalFields() {
return finalClass().getDeclaredFields().findAll { Field fl -> !fl.synthetic }.collect()
}
static Method[] naturalMethods() {
return finalClass().getDeclaredMethods().findAll { Method md -> !md.synthetic }.collect()
}
static Class finalClass() {
return ReflectionUtils.getCallingClass(0)
}
}
class Demo implements Reflector {
int archived = 0
int demo = 100
static void playToo() {
println finalClass()
}
}
println Demo.finalClass() // class my.Demo
println Demo.naturalFields() // [private int my.Demo.archived, private int my.Demo.demo]
println Demo.fieldNames() // [archived, demo]

Need design suggestions for nested conditions

I need to write the logic with many conditions(up to 30 conditions) in one set of rule with many if else conditions and it could end in between or after all the conditions.
Here is the sample code I have tried with some possible scenario. This gives me result but doesn't look good and any minor miss in one condition would take forever to track.
What I have tried so far is, Take out common conditions and refactored to some methods. Tried creating interface with conditions and various set would implement it.
If you have any suggestion to design this, would help me. Not looking for detailed solution but even a hint would be great.
private Boolean RunCondition(Input input) {
Boolean ret=false;
//First if
if(input.a.equals("v1")){
//Somelogic1();
//Second if
if(input.b.equals("v2"))
//Third if
if(input.c >1)
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(input.d.equals("Z1"))
System.out.println("Passed 1");
// Fourth Else
else{
System.out.println("Failed at fourth");
}
//Third Else
else{
if(input.aa.equals("v2"))
System.out.println("Failed at third");
}
//Second Else
else{
if(input.bb.equals("v2"))
System.out.println("Failed at second");
}
}
//First Else
else{
if(input.cc.equals("v2"))
System.out.println("Failed aat first");
}
return ret;
}
public class Input {
String a;
String b;
int c;
String d;
String e;
String aa;
String bb;
String cc;
String dd;
String ee;
}
The flow is complicated because you have a normal flow, plus many possible exception flows when some of the values are exceptional (e.g. invalid).
This is a perfect candidate to be handled using a try/catch/finally block.
Your program can be rewritten into following:
private Boolean RunCondition(Input input) {
Boolean ret=false;
try {
//First if
if(!input.a.equals("v1")) {
throw new ValidationException("Failed aat first");
}
//Somelogic1();
//Second if
if(!input.b.equals("v2")) {
throw new ValidationException("Failed at second");
}
//Somelogic2()
//Third if
if(input.c<=1) {
throw new ValidationException("Failed at third");
}
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(!input.d.equals("Z1")) {
throw new ValidationException("Failed at fourth");
}
System.out.println("Passed 1");
} catch (ValidationException e) {
System.out.println(e.getMessage());
}
return ret;
}
Where you can define your own ValidationException (like below), or you can reuse some of the existing standard exception such as RuntimeException
class ValidationException extends RuntimeException {
public ValidationException(String arg0) {
super(arg0);
// TODO Auto-generated constructor stub
}
/**
*
*/
private static final long serialVersionUID = 1L;
}
You can read more about this in
https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html
Make a separate class for the condition:
package com.foo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App
{
static class Condition<T> {
final int idx;
final T compareValue;
public Condition(final int idx, final T compareValue) {
this.idx = idx;
this.compareValue = compareValue;
}
boolean satisfies(final T other) {
return other.equals(compareValue);
}
int getIdx() {
return idx;
}
}
public static void main( String[] args )
{
final List<Condition<String>> conditions = new ArrayList<Condition<String>>();
conditions.add(new Condition<String>(1, "v1"));
conditions.add(new Condition<String>(2, "v2"));
final List<String> inputs = new ArrayList<String>(Arrays.asList("v1", "xyz"));
boolean ret = true;
for (int i = 0; i < inputs.size(); i++) {
if (!conditions.get(i).satisfies(inputs.get(i)))
{
System.out.println("failed at " + conditions.get(i).getIdx());
ret = false;
break;
}
}
System.out.println("ret=" + ret);
}
}
#leeyuiwah's answer has a clear structure of the conditional logic, but exceptions aren't the right tool for the job here.
You shouldn't use exceptions to cope with non-exceptional conditions. For one thing, exceptions are really expensive to construct, because you have to walk all the way up the call stack to construct the stack trace; but you don't need the stack trace at all.
Check out Effective Java 2nd Ed Item 57: "Use exceptions only for exceptional conditions" for a detailed discussion of why you shouldn't use exceptions like this.
A simpler option is to define a little helper method:
private static boolean printAndReturnFalse(String message) {
System.out.println(message);
return false;
}
Then:
if(!input.a.equals("v1")) {
return printAndReturnFalse("Failed aat first");
}
// etc.
which I think is a simpler; and it'll be a lot faster.
Think of each rule check as an object, or as a Strategy that returns whether or not the rule passes. Each check should implement the same IRuleCheck interface and return a RuleCheckResult, which indicates if the check passed or the reason for failure.
public interface IRuleCheck
{
public RuleCheckResult Check(Input input);
public String Name();
}
public class RuleCheckResult
{
private String _errorMessage;
public RuleCheckResult(){}//All Good
public RuleCheckResult(String errorMessage)
{
_errorMessage = errorMessage;
}
public string ErrorMessage()
{
return _errorMessage;
}
public Boolean Passed()
{
return _errorMessage == null || _errorMessage.isEmpty();
}
}
public class CheckOne implements IRuleCheck
{
public RuleCheckResult Check(Input input)
{
if (input.d.equals("Z1"))
{
return new RuleCheckResult();//passed
}
return new RuleCheckResult("d did not equal z1");
}
public String Name();
}
Then you can simply build a list of rules and loop through them,
and either jump out when one fails, or compile a list of failures.
for (IRuleCheck check : checkList)
{
System.out.println("checking: " + check.Name());
RuleCheckResult result = check.Check(input);
if(!result.Passed())
{
System.out.println("FAILED: " + check.Name()+ " - " + result.ErrorMessage());
//either jump out and return result or add it to failure list to return later.
}
}
And the advantage of using the interface is that the checks can be as complicated or simple as necessary, and you can create arbitrary lists for checking any combination of rules in any order.

Junit4 run a test class a fixed number of times and display results (eclipse)

I want to be able to run a Test class a specified number of times. The class looks like :
#RunWith(Parameterized.class)
public class TestSmithWaterman {
private static String[] args;
private static SmithWaterman sw;
private Double[][] h;
private String seq1aligned;
#Parameters
public static Collection<Object[]> configs() {
// h and seq1aligned values
}
public TestSmithWaterman(Double[][] h, String seq1aligned) {
this.h = h;
this.seq1aligned = seq1aligned;
}
#BeforeClass
public static void init() {
// run smith waterman once and for all
}
#Test
#Repeat(value = 20) // does nothing
// see http://codehowtos.blogspot.gr/2011/04/run-junit-test-repeatedly.html
public void testCalculateMatrices() {
assertEquals(h, sw.getH());
}
#Test
public void testAlignSeq1() {
assertEquals(seq1aligned, sw.getSeq1Aligned());
}
// etc
}
Any of the tests above may fail (concurrency bugs - EDIT : the failures provide useful debug info) so I want to be able to run the class multiple times and preferably have the results grouped somehow. Tried the Repeat annotation - but this is test specific (and did not really make it work - see above) and struggled with the RepeatedTest.class, which cannot seem to transfer to Junit 4 - the closest I found on SO is this - but apparently it is Junit3. In Junit4 my suite looks like :
#RunWith(Suite.class)
#SuiteClasses({ TestSmithWaterman.class })
public class AllTests {}
and I see no way to run this multiple times.
Parametrized with empty options is not an option really - as I need my params anyway
So I am stuck hitting Control + F11 in eclipse again and again
Help
EDIT (2017.01.25): someone went ahead and flagged this as duplicate of the question whose accepted answer I explicitly say does not apply here
As suggested by #MatthewFarwell in the comments I implemented a test rule as per his answer
public static class Retry implements TestRule {
private final int retryCount;
public Retry(int retryCount) {
this.retryCount = retryCount;
}
#Override
public Statement apply(final Statement base,
final Description description) {
return new Statement() {
#Override
#SuppressWarnings("synthetic-access")
public void evaluate() throws Throwable {
Throwable caughtThrowable = null;
int failuresCount = 0;
for (int i = 0; i < retryCount; i++) {
try {
base.evaluate();
} catch (Throwable t) {
caughtThrowable = t;
System.err.println(description.getDisplayName()
+ ": run " + (i + 1) + " failed:");
t.printStackTrace();
++failuresCount;
}
}
if (caughtThrowable == null) return;
throw new AssertionError(description.getDisplayName()
+ ": failures " + failuresCount + " out of "
+ retryCount + " tries. See last throwable as the cause.", caughtThrowable);
}
};
}
}
as a nested class in my test class - and added
#Rule
public Retry retry = new Retry(69);
before my test methods in the same class.
This indeed does the trick - it does repeat the test 69 times - in the case of some exception a new AssertionError, with an individual message containing some statistics plus the original Throwable as a cause, gets thrown. So the statistics will be also visible in the jUnit view of Eclipse.

Transaction for POJOs

I'm implementing a method that does something like:
...
try {
myPojo.setProperty("foo");
myService.execute(myPojo);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
...
If some exception is thrown by my service from this try block on pojo property will have the new value. Is there some way to start a kind of transaction for pojo changes and roll it back if something goes wrong?
Something like:
PojoTransaction pt = startPojoTransaction();
transactionedPojo = pt.handleByTransaction(myPojo);
try {
transactionedPojo.setProperty("foo");
myService.execute(transactionedPojo);
pt.commit;
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
Or something similar...
Take a look at the Memento Pattern, it includes a Java example.
http://en.wikipedia.org/wiki/Memento_pattern
I toyed around with the idea, this is far from perfect, just a simple proof of concept. There are pitfalls in this implementation:
It only tries to call a parameterless constructor of the given source
object to create the target-copy, would need some logic to select a correct constructor (or only support Cloneables?)
Only copies fields declared in the class, not from superclasses (this problem can be solved walking through the inheritance tree and copying any superclass fields)
If the fields are complex types, only the references are copied to target-object, so any changes to them will not be transactional, as both the source and target share the same instance (solvable by recursively creating copies of nested objects and copying their values, requires walking through the entire object-graph, starting from source, and then doing it vice-versa on commit-time)
But, improving from here, I believe it could become very usable. Here's the POC:
import java.lang.reflect.Field;
import org.junit.Assert;
import org.junit.Test;
public class PojoTransactionTest
{
public static class PojoTransaction<T>
{
/**
* This is the original (unmodified) object
*/
private T source;
/**
* This is the object modified by within the transaction
*/
private T target;
/**
* Creates a new transaction for the given source object
* #param source Source object to modify transactionally
*/
public PojoTransaction(T source)
{
try
{
this.source = source;
this.target = (T)source.getClass().newInstance(); //Note: this only supports parameterless constructors
copyState(source, target);
}
catch(Exception e)
{
throw new RuntimeException("Failed to create PojoTransaction", e);
}
}
/**
* Copies state (member fields) from object to another
* #param from Object to copy from
* #param to Object to copy to
* #throws IllegalAccessException
*/
private void copyState(T from, T to) throws IllegalAccessException
{
//Copy internal state to target, note that this will NOT copy fields from superclasses
for(Field f : from.getClass().getDeclaredFields())
{
f.setAccessible(true);
f.set(to, f.get(from));
}
}
/**
* Returns the transaction target object, this is the one you should modify during transaction
* #return Target object
*/
public T getTransactionTarget()
{
return target;
}
/**
* Copies the changes from target object back to original object
*/
public void commit()
{
try
{
copyState(target, source);
}
catch(Exception e)
{
throw new RuntimeException("Failed to change state of original object", e);
}
}
}
public static class TestData
{
private String strValue = "TEST";
private int intValue = 1;
private float floatValue = 3.1415f;
public String getStrValue()
{
return strValue;
}
public void setStrValue(String strValue)
{
this.strValue = strValue;
}
public int getIntValue()
{
return intValue;
}
public void setIntValue(int intValue)
{
this.intValue = intValue;
}
public float getFloatValue()
{
return floatValue;
}
public void setFloatValue(float floatValue)
{
this.floatValue = floatValue;
}
}
#Test
public void testTransaction()
{
//Create some test data
TestData orig = new TestData();
//Create transaction for the test data, get the "transaction target"-object from transaction
PojoTransaction<TestData> tx = new PojoTransaction<TestData>(orig);
TestData target = tx.getTransactionTarget();
target.setFloatValue(1.0f);
target.setIntValue(5);
target.setStrValue("Another string");
//Original object is still at the original values
Assert.assertEquals(1, orig.getIntValue());
Assert.assertEquals(3.1415f, orig.getFloatValue(), 0.001f);
Assert.assertEquals("TEST", orig.getStrValue());
//Commit transaction
tx.commit();
//The "orig"-object should now have the changes made to "transaction target"-object
Assert.assertEquals(5, orig.getIntValue());
Assert.assertEquals(1.0f, orig.getFloatValue(), 0.001f);
Assert.assertEquals("Another string", orig.getStrValue());
}
}
The question is a bit vague, but it sounds like you are wrestling with the basic design pattern for transaction management. You would benefit greatly from the experience that has gone into the production of the pattern used here:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
Perhaps Spring Transaction management would suit you well for your project anyway.

Categories