I am new with AspectJ annotation for Java, and I am wondering if it is possible to put pointcut on a cross thread invocation.
Here is the code:
public class App {
public static void main( String[] args ) {
new Connector().getStart("testtest");
}
}
public class Connector {
public void getStart(String s1) {
Handler h = new Handler(s1);
h.start();
}
}
public class Handler extends Thread {
String s1;
public Handler(String s1) {
this.s1 = s1;
}
public void run() {
new Plain().getValue(s1);
}
}
public class Plain {
public void getValue(String s1) {
System.out.println("Plain getValue: " + s1);
}
}
I would like to have a pointcut that only triggers when Plain.getValue() is called by Connector.getStart().
Is it possible? Thanks.
You are making a mistake believing that Plain.getValue(..) is called by Connector.getStart(..) because in a multi-threaded environment it is not. Let me prove it with a little tweak to the getValue(..) method, printing a stack trace:
package de.scrum_master.app;
public class Plain {
public void getValue(String s1) {
System.out.println("Plain getValue: " + s1);
new Exception().printStackTrace(System.out);
}
}
By the way, I have moved all your classes to package de.scrum_master.app because using the default package is discouraged in Java and also AspectJ does not like it when trying to match pointcuts.
Console log (multi-threaded):
Plain getValue: testtest
java.lang.Exception
at de.scrum_master.app.Plain.getValue(Plain.java:4)
at de.scrum_master.app.Handler.run(Handler.java:9)
See? There is no trace of Connector.getStart(..) in the log. If we also tweak getStart(..) so as to call the thread's run() method directly (i.e. not starting a new thread but executing in the same thread) instead of start(), the situation changes:
package de.scrum_master.app;
public class Connector {
public void getStart(String s1) {
Handler h = new Handler(s1);
h.run();
}
}
Console log (single-threaded):
Plain getValue: testtest
java.lang.Exception
at de.scrum_master.app.Plain.getValue(Plain.java:4)
at de.scrum_master.app.Handler.run(Handler.java:9)
at de.scrum_master.app.Connector.getStart(Connector.java:4)
at de.scrum_master.app.App.main(App.java:3)
In this situation we could use AspectJ's dynamic cflow() (control flow) pointcut like this:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class SingleThreadAspect {
#Before("execution(* de.scrum_master.app.Plain.getValue(..)) && cflow(execution(* de.scrum_master.app.Connector.getStart(..)))")
public void interceptControlFlow(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
The advice would be triggered just as you wish. But for the reason explained at the beginning of my answer cflow() does not (and cannot) work across threads because there is no such thing as a direct control flow across threads. Each thread's control flow starts with its run() method, no earlier. That is the whole concept of multi-threading.
So if you really want to emulate something like a cross-thread control flow for whatever doubtful reason, you need to do some manual bookkeeping.
But first let us revert the tweaked h.run() back to the original h.start() so as to reinstate the multi-threading situation. Let us also remove the printStackTrace(..) line from Plain.getStart(..).
Solution:
Disclaimer: I do not like annotation-style #AspectJ syntax, so I am switching over to native syntax. It is much more expressive and we can achieve what we want more easily in terms of ITD (inter-type definition) because
in native syntax we can just declare an additional instance member variable for a given class while
in #AspectJ syntax we would have to declare the target class to implement an interface with a default implementation which in turn would carry the member variable for our manual bookkeeping.
Let us modify App so as to also start a Handler thread directly. This is our negative test case because we do not want to trigger our advice there as the thread is started outside of Plain.getValue(..):
package de.scrum_master.app;
public class App {
public static void main(String[] args) throws InterruptedException {
// The aspect should ignore this thread
new Handler("foo").start();
// Wait a little while so as not to mess up log output
Thread.sleep(250);
new Connector().getStart("testtest");
}
}
Console log without aspect:
Plain getValue: foo
Plain getValue: testtest
Aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.*;
public aspect CrossThreadAspect {
// Declare a new instance member for our bookkeeping
private boolean Handler.cflowConnectorGetStart = false;
// If handler thread is started from Connector.getStart(..), set a mark
before(Handler handler) :
call(void Handler.start()) &&
cflow(execution(* Connector.getStart(..))) &&
target(handler)
{
System.out.println(thisJoinPoint + "\n doing bookkeeping");
handler.cflowConnectorGetStart = true;
}
// If current thread is a marked Handler, log it
before() :
execution(* Plain.getValue(..)) &&
if(Thread.currentThread() instanceof Handler) &&
if(((Handler) Thread.currentThread()).cflowConnectorGetStart)
{
System.out.println(thisJoinPoint + "\n triggered from parent thread via Connector.getStart(..)");
}
}
Console log with aspect:
As you can see, the Handler thread started from App.main(..) is ignored by the aspect as expected. The Handler started from Connector.getStart(..) triggers the aspect.
Plain getValue: foo
call(void de.scrum_master.app.Handler.start())
doing bookkeeping
execution(void de.scrum_master.app.Plain.getValue(String))
triggered from parent thread via Connector.getStart(..)
Plain getValue: testtest
Related
I am looking into implementing a standard error handling on my application. I want errors that cant be dealt with(custom unchecked errors) but that also aren't catastrophic to be logged by a fault barrier without having to clutter my code with pesky try catches and logger calls.
Let me illustrate.
I have an intake that receives a json string and set it into my object model, one of the fields in said model call a timeHelper function, this function can throw an exception if the arguments are invalid(null or empty). The yield of this function is not critical to the program, in fact this program should never crash( to the best of my abilities) as it should stay up 24/7.
Model
public class MyModel{
private string myField
public void setMyField(String myfield){
this.myField = Helper.DoStuff(myField)
}
}
Intake
public class Intake{
public MyModel receiveJson(){
return JacksonMagic(arguments,MyModel.class)
}
}
Helper
Public class Helper{
public String DoStuff(String myField){
//Check that can throw exception
//regular operation with return
}
}
Now, when life is beautiful DoStuff returns a string, in fact the exception should never be thrown because it implies that the source of the json, which is external to my application, sent wrong/missing information. If it does happen I want it to be logged so I can investigate what happened. I also want to set a framework in place, probably with Spring AOP, to handle that logging. But as you can see through the example, I also want execution to continue as this is not some app breaking thing.
The execution flow I am looking for is something like
Intake > Model > Helper(THROW EXCEPTION) > Logger > Whoever Called Intake
And again, I want to do that without the try catch logger call cluter
Is this something possible with AOP?
Post answer Edit
Just want to leave some sources here.
To set up your IDE for AspectJ compilation, this article is really helpful.
https://www.baeldung.com/aspectj
This is not a good use case for exceptions.
An exception represents something that you're not able to handle, an "exceptional" occurrence that you're not able to deal with. The fact that you're saying this is a possible scenario changes this from an exception to a use-case, in which case logging a warning in your service tier is probably the best solution.
Exceptions have their place, however overusing them makes code harder to follow, since it breaks the "flow" of an application. Exceptions should not be used to control flow.
AOP, in my option, offers little when it comes to exception handling. At best it can log the exception (which can also be achieved in a much clearer way using an ExceptionHandler pattern), however it certainly can't trigger your code to continue as though it didn't happen.
If you haven't already, look into logging strategies, they can be really useful in this kind of scenario.
The bottom line is: if you want control flow to continue, don't throw an exception (checked or unchecked).
Okay, here we go with a complete MCVE, assuming you know how to use the AspectJ compiler in order to compile your project. Sorry for repeating your classes with package names, imports etc., but I like you to see all details:
First we need our helper which randomly throws unchecked exceptions so we can see the aspect in action later:
package de.scrum_master.app;
import java.util.Random;
public class Helper {
private static final Random RANDOM = new Random();
public static String doStuff(String myField) {
if (RANDOM.nextBoolean())
throw new RuntimeException("uh-oh!");
return "processed " + myField;
}
}
package de.scrum_master.app;
public class MyModel {
private String myField;
public void setMyField(String myField) {
this.myField = Helper.doStuff(myField);
}
#Override
public String toString() {
return "MyModel(myField=" + myField + ")";
}
}
package de.scrum_master.app;
public class Intake {
public MyModel receiveJson(String... arguments) {
return jacksonMagic(arguments, MyModel.class);
}
public MyModel jacksonMagic(String[] arguments, Class<?> clazz) {
MyModel myModel = new MyModel();
myModel.setMyField(arguments[0]);
return myModel;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++)
System.out.println(new Intake().receiveJson("foo"));
}
}
Now when you run the little driver application via Intake.main you will see unhandled exceptions on the console. Here is how to handle this using an aspect. I am limiting the aspect to matching all method executions with a String return type, stupidly returning a dummy value whenever an exception occurs. You just add your more sophisticated logic in there as you see fit and also adjust the aspect's pointcut to match the methods you want to handle.
package de.scrum_master.aspect;
public aspect ErrorHandler {
String around() : execution(String *(..)) {
try {
return proceed();
} catch (Exception e) {
System.out.println("Exception handled: " + e);
return "dummy";
}
}
}
I love the expressive native AspectJ syntax, but I know that some people for whatever reason feel more comfortable with annotation-based syntax. Just look at the throws declaration, the pointcuts in string constants, the explicit joinpoint declaration, the cast - yuck! Anyway, here we go:
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class ErrorHandler {
#Around("execution(String *(..))")
public String handleErrors(ProceedingJoinPoint thisJoinPoint) throws Throwable {
try {
return (String) thisJoinPoint.proceed();
} catch (Exception e) {
System.out.println("Exception handled: " + e);
return "dummy";
}
}
}
The console log looks like this with the aspect in place:
MyModel(myField=processed foo)
MyModel(myField=processed foo)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
MyModel(myField=processed foo)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
MyModel(myField=processed foo)
Exception handled: java.lang.RuntimeException: uh-oh!
MyModel(myField=dummy)
MyModel(myField=processed foo)
I'm coming to Java from C#, and I'm really just trying to figure out how to do things in Java world. I'm running Java 8 in IntelliJ IDEA. I found this explaining events in Java as basically being hand-made through manual registration and an interface method call. The code example has enough problems that I assume it was never compiled. After cleaning that up a bit I have this:
Interface MetronomeEvent:
public interface MetronomeEvent {
void Tick(Date tickDate);
}
Class EventFiringSource:
public class EventFiringSource {
// Our collection of classes that are subscribed as listeners of our
protected List<MetronomeEvent> _listeners=new ArrayList();
// Method for listener classes to register themselves
public void addMetronomeEventListener(MetronomeEvent listener)
{
_listeners.add(listener);
}
// "fires" the event
protected void fireMetronomeEvent()
{
if (_listeners != null && !_listeners.isEmpty())
{
for (MetronomeEvent e:_listeners)
{
e.Tick(new Date());
}
}
}
public void Start()
{
fireMetronomeEvent();
}
}
Main console application:
public class MainApp implements MetronomeEvent {
public static void main(String[] args) {
EventFiringSource source = new EventFiringSource();
source.addMetronomeEventListener(this); // Adds itself as a listener for the event
source.Start();
}
public void Tick(Date tickDate)
{
System.out.println(tickDate.toString());
}
}
The one remaining error is source.addMetronomeEventListener(this); where the compiler complains that it cannot reference MyApp.this from a static context. That makes sense, but I don't see any way then that I could, after implementing the MetronomeEvent interface on the main program class, actually pass it to source.addMetronomeEventListener() for registration. Is it impossible to directly register the main program class for events? Am I supposed to create and register a Listener class that implements MetronomeEvent and will act on behalf of the main application? Like this?
public class Listener implements MetronomeEvent {
public void Tick(Date tickDate){
System.out.println(tickDate.toString());
}
}
And then:
public static void main(String[] args) {
EventFiringSource source = new EventFiringSource();
Listener l=new Listener();
source.addMetronomeEventListener(l); // Adds another object to listen on behalf of main()
source.Start();
}
This is not about events, it's about main() and static methods in general.
I would suggest writing your main() as
public static void main(String[] args) {
new MainApp(args).execute();
}
This way you're immediately jumping from static function world into object-oriented world.
Based on Vince Emigh's comment/answer I was led to this Oracle doc on lamda expressions and to this one on method references. I've found 3 ways to do this so far.
1) Anonymous class:
source.addMetronomeEventListener(
new MetronomeEvent() {
#Override
public void Tick(Date tickDate) {
System.out.println("anonymous class:");
System.out.println(tickDate.toString());
}
}
); // Adds itself as a listener for the event
2) Lambda expression:
source.addMetronomeEventListener(d -> System.out.println("lambda:\n"+d.toString()));
3) Method reference, which is the closest to what I am accustomed to. A method is defined in the main class:
public static void processTick(Date tickDate){
System.out.println("method reference:");
System.out.println(tickDate.toString());
}
...and then in the body of main() it is added as an event handler like this:
source.addMetronomeEventListener(MainApp::processTick);
There's a piece of code im trying to test,
which goes something like this:
class Foo {
//do some operations
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//some piece of code
}
}
}
So how do i test the code within the run function.
I am using powermock,
The thread is started in another class so i should not invoke it there right??
im still a beginner.
The code in the Runnable's run() method will be invoked on the Event Dispatch Thread. Usually only GUI updates should be performed on this thread. Using mock objects to test the GUI is not a good idea.
Depends on what you're trying to test.
If you're testing the behavior of Foo - don't worry about the concurrency. Just make your calls to Foo and assert that the result obtained matches your expectations. Just org.junit.Assert will be enough.
If you're testing what this Runnable will actually do, you need to break dependencies first. Now your class Foo depends on some Runnable, which is instantiated and called internally. Convert it to an argument of Foo:
class Foo {
private Runnable runnable;
public Foo(Runnable rnbl) {
this.runnable = rnbl;
}
// somewhere later in the class
SwingUtilities.invokeLater(this.runnable);
}
Now you can mock this Runnable with, say, Mockito and test (in your unit test):
Runnable mock = Mockito.mock(Runnable.class);
Foo foo = new Foo(mock);
foo.doSomething();
Mockito.verify(mock).run(); // verify that it was called
This is how you turn your multi-thread application into single-thread for testing only.
As i understand the main problem is asynchrony. Test checks a result before we'll get result from invokeLater() block. So we need to wait until EDT run our code and after that check. We can do it via invokeAndWait method with empty runnable block. Example Foo class:
import javax.swing.SwingUtilities;
public class Foo {
private String myLine;
public void executeInEDT(final String line) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
myLine = line;
}
});
}
public String getLine() {
return myLine;
}
}
and test method:
#Test
public void testInvokeLater() throws InterruptedException, InvocationTargetException {
String testLine = "Test line";
Foo foo = new Foo();
foo.executeInEDT(testLine);
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
// Just for sync
}
});
assertEquals(testLine, foo.getLine());
// And more asserts
}
UPD: Found some more information in Netbeans test patterns:
As the queue of runnables is FIFO, the runnable is scheduled at the
end after all tasks posted by the application and when it is finally
executed one can be sure that all delayed tasks of the application in
the AWT event queue are over as well. See DataEditorSupportTest.java
for an example of a test that needs to wait while the application code
finishes some actions posted to the AWT event thread.
I want to use local variable annotations to do better AOP. One idea is to implement the Future<T> concept with a proxy using an annotation.
#NonBlocking ExpensiveObject exp = new ExpensiveObject();
//returns immediately, but has threaded out instantiation of the ExpensiveObject.
exp.doStuff();
//okay, now it blocks until it's finished instantiating and then executes #doStuff
Can I sick AspectJ on this somehow and get what I want done with local variable annotations? I know other threads have indicated that Java doesn't really support them but it would be magical. I really don't want to pass around a Future and break encapsulation.
You can not do this with a proxy, but real aspectj bytecode weaving will get you there if you annotate the type instead of the local variable. (I don't think local variable access is supported as a pointcut). Anyway, here's some code.
An annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Later {}
A class marked with this annotation:
package com.dummy.aspectj;
#Later
public class HeavyObject{
public HeavyObject(){
System.out.println("Boy, I am heavy");
}
}
A main class:
package com.dummy.aspectj;
public class HeavyLifter{
public static void main(final String[] args){
final HeavyObject fatman = new HeavyObject();
System.out.println("Finished with main");
}
}
and an aspect:
package com.dummy.aspectj;
public aspect LaterAspect{
pointcut laterInstantiation() :
execution(#Later *.new(..)) ;
void around() : laterInstantiation() {
new Thread(new Runnable(){
#Override
public void run(){
System.out.println("Wait... this is too heavy");
try{
Thread.sleep(2000);
} catch(final InterruptedException e){
throw new IllegalStateException(e);
}
System.out.println("OK, now I am up to the task");
proceed();
}
}).start();
}
}
Here is the output from HeavyLifter when you run it as an AspectJ/Java Application from eclipse:
Finished with main
Wait... this is too heavy
OK, now I am up to the task
Boy, I am heavy
Can anyone explain with a simple example the Command Pattern? I tried searching on the internet, but I got confused.
public interface Command {
public void execute();
}
For the most part, commands are immutable and contain instructions that encapsulate a single action that is executed on demand. You might also have a RuntimeCommand that accepts instructions upon execution, but this delves more into the Strategy or Decorator Patterns depending on the implementations.
In my own opinion, I think it's very important to heed the immutable context of a command otherwise the command becomes a suggestion. For instance:
public final class StopServerCommand implements Command {
private final Server server;
public StopServerCommand(Server server) { this.server = server; }
public void execute() {
if(server.isRunning()) server.stop();
}
}
public class Application {
//...
public void someMethod() {
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(Event e) {
stopCommand.execute();
}
});
}
}
I personally don't really like commands. In my own experience, they only work well for framework callbacks.
If it helps, think of a command in a metaphorical sense; a trained soldier is given a command by his/her commanding officer, and on demand the soldier executes this command.
You can think of Command pattern workflow as follows.
Client calls Invoker => Invoker calls ConcreteCommand => ConcreteCommand calls Receiver method, which implements abstract Command method.
UML Diagram from dofactory article:
Key features:
Command declares an interface for all commands, providing a simple execute() method which asks the Receiver of the command to carry out an operation.
The Receiver has the knowledge of what to do to carry out the request.
The Invoker holds a command and can get the Command to execute a request by calling the execute method.
The Client creates ConcreteCommands and sets a Receiver for the command.
The ConcreteCommand defines a binding between the action and the receiver.
When the Invoker calls execute the ConcreteCommand will run one or more actions on the Receiver.
Code snippet:
interface Command {
void execute();
}
interface Receiver {
public void switchOn();
}
class OnCommand implements Command{
private Receiver receiver;
public OnCommand(Receiver receiver){
this.receiver = receiver;
}
public void execute(){
receiver.switchOn();
}
}
class Invoker {
private Command command;
public Invoker(Command command){
this.command = command;
}
public void execute(){
this.command.execute();
}
}
class TV implements Receiver{
public void switchOn(){
System.out.println("Switch on from TV");
}
}
class DVDPlayer implements Receiver{
public void switchOn(){
System.out.println("Switch on from DVDPlayer");
}
}
public class CommandDemoEx{
public static void main(String args[]){
// On command for TV with same invoker
Receiver receiver = new TV();
Command onCommand = new OnCommand(receiver);
Invoker invoker = new Invoker(onCommand);
invoker.execute();
// On command for DVDPlayer with same invoker
receiver = new DVDPlayer();
onCommand = new OnCommand(receiver);
invoker = new Invoker(onCommand);
invoker.execute();
}
}
output:
Switch on from TV
Switch on from DVDPlayer
Explanation:
In this example,
Command interface defines execute() method.
OnCommand is ConcreteCommand, which implements execute() method.
Receiver is an interface and implementers have to provide implementation for the methods.
TV and DVDPlayer are two types of Receivers, which are passed to ConcreteCommand like OnCommand.
Invoker contains Command. It's the key to de-couple Sender from Receiver.
Invoker receives OnCommand -> which calls Receiver (TV) to execute this command.
By using Invoker, you can switch on TV and DVDPlayer. If you extend this program, you switch off both TV and DVDPlayer too.
You can use Command pattern to
Decouple the sender & receiver of command
Implement callback mechanism
Implement undo and redo functionality
Maintain a history of commands
Have a look at this dzone and journaldev and Wikipedia articles.
Source code as Wikipedia page is simple, cleaner and self explanatory.
You can implement Undo and Redo if you follow the steps as quoted in this article
Here is another example you can use to understand how command pattern works, using real life scenarios: You cannot travel from one place to another by airplane without using the command pattern!
If you are a frequent traveler, all you care about as a client is to travel from where you are to another . you don't care about how the pilot will fly the plane or which airline will be available .. you cant really predict that. all you want is to get the the air port and tell them to take you to your destination.
But if you do that, your command to the airport authorities will be laughed at! they need you to supply a command object, which is your ticket. as much as you don't care about which airline or which plane type, when you are ready to fly, you need to supply a ticket command object. The invoker, which is the airport officials needs to check your command (ticket) so that they can validate it, undo it if it is fake, redo it if they made a mistake (without you having to go through the booking process all over).
In short , they want to have complete control of your command (ticket) before deciding whether or not to invoke or execute your command, which lets the airline (the receiver ) execute ( put you on a plane and take you to your destination) .
Mind you, your command (your ticket) already has the information of the receiver (airline) without which the airport officials wont even start to process your ticket in the first place.
The airport authorities could even have a bunch of tickets they are working on. they may choose to delay my ticket and let someone that came after me go through (invoke another persons ticket before mine)
Here is the code :
[TestClass]
public class Client
{
[TestMethod]
public void MyFlight_UsingCommandPattern()
{
var canadianAirline = new Airline();
AirlineTicket_Command myTicket = new MyAirLineTicket(canadianAirline);
var airportOfficials = new AirportOfficials_Invoker(myTicket);
airportOfficials.ProcessPasengerTicket_And_AllowPassengerToFly_Execute();
//assert not implemented
}
}
public class AirportOfficials_Invoker
{
private AirlineTicket_Command PassengerTicket { set; get; }
public AirportOfficials_Invoker(AirlineTicket_Command passengerTicket)
{
throw new NotImplementedException();
}
public void ProcessPasengerTicket_And_AllowPassengerToFly_Execute()
{
PassengerTicket.Execute();
}
}
public abstract class AirlineTicket_Command
{
protected Airline Airline { set; get; }
protected AirlineTicket_Command(Airline airline)
{
Airline = airline;
}
public abstract void Execute();
}
public class MyAirLineTicket : AirlineTicket_Command
{
public MyAirLineTicket(Airline airline)
: base(airline)
{
}
public override void Execute()
{
Airline.FlyPassenger_Action();
}
}
public class Airline
{
public void FlyPassenger_Action()
{
//this will contain all those stuffs of getting on the plane and flying you to your destination
}
}
My requirement is to perform a sequence of tasks (which can be re-used in several Usecases) each with its own exception flow. Found Command pattern's implementation logical here.
I am trying to make it like each action executed by the command (whether normal/alternate flow) can be an exception handler too. However, If the command is registered with another handler then this should be used. Any suggestions for improvement/correction are welcome.
public interface Command {
Result run() throws Exception;
Command onException(ExceptionHandler handler);
}
public class Result {
}
public interface ExceptionHandler {
void handleException(Exception e);
}
public interface Action {
Result execute() throws Exception;
}
public class BasicCommand implements Command {
private Action action;
private ExceptionHandler handler;
public BasicCommand(Action action) {
if (action == null) {
throw new IllegalArgumentException("Action must not be null.");
}
this.action = action;
this.handler = (ExceptionHandler) this.action;
}
#Override
public Command onException(ExceptionHandler handler) {
if (handler != null) {
this.handler = handler;
}
return this;
}
public Result run() throws Exception {
Result result = null;
try {
result = action.execute();
} catch (Exception e) {
handler.handleException(e);
}
return result;
}
}
public class BasicAction implements Action, ExceptionHandler {
private Object[] params;
public BasicAction(Object... params) {
this.params = params;
}
#Override
public Result execute() throws Exception {
// TODO Auto-generated method stub
return null;
}
#Override
public void handleException(Exception e) {
// TODO exception translation: prepare unchecked application. exception and throw..
}
}
public class Main {
public static void main(String[] args) throws Exception {
int param1 = 10;
String param2 = "hello";
// command will use the action itself as an exception handler
Result result = new BasicCommand(new BasicAction(param1, param2)).run();
ExceptionHandler myHandler = new ExceptionHandler(){
#Override
public void handleException(Exception e) {
System.out.println("handled by external handler");
}
};
// command with an exception handler passed from outside.
Result result2 = new BasicCommand(new BasicAction(param1, param2)).onException(myHandler).run();
}
}
Command Design Patterns decouples invoker of service and provider of service. In general scenario, say for eg., If Object A wants service of Object B, it'll directly invoke B.requiredService(). Thus, A is aware about B. In Command pattern, this coupling is removed. Here, there's an intermediate object known as Command, which comes into picture. Thus, A deals with Command object and command object deals with actual object B. This approach has several applications such as designing applications, which are :-
Accepts commands as requests.
Undoing requests.
Requests requests.
Creating macros.
Creating Task Executors and Task Managers.
For more information regarding, Command Design Pattern, I'll recommend https://en.wikipedia.org/wiki/Command_pattern.
For all other design patterns, refer to https://www.u-cursos.cl/usuario/.../mi_blog/r/head_first_design_patterns.pdf
I would try to give you another rough analogy here.
Suppose that one day God calls on you and tells you that the world's in danger and He needs your help to save it. Further helping you , He tells you that He has sent some superheroes on earth.
Since He doesn't know oops and hence He doesn't call them superheroes (doesn't provide you any interface or abstract class over them) but just tell you their names for ex - batman, superman, iron man and the powers they have.
He also says that in future He might send more such guys in future.
Now He assigns you special responsibility -> control them and for that provides you with seven hands. He doesn't fixes the task of each hand Himself but leaves it on you.
You want flexibility in assigning any hand control of any superhero's power and don't want to repeatedly change things through multiple conditions.
You are in a fix. What do you do now?
Enter Command Pattern.
Create an interface Command and has only one method execute() in it. Encapsulate every power of each superhero and make that implement Command for ex - IronManCreatesSuitCommand
Now you can assign any hand to any command at any time giving you lot more flexibility because now none of your hands cares about the specific task it has to do. You just assign it any command to it. It calls execute on it and the command takes care of everything else.
Now even when God sends any other superhero with different powers, you know what to do.