001package org.javasimon.console;
002
003import java.lang.reflect.Constructor;
004import java.lang.reflect.InvocationTargetException;
005
006/**
007 * Simple action bindings which is triggered by the path and produces
008 * actions of given type
009 *
010 * @author gquintana
011 */
012@SuppressWarnings("UnusedDeclaration")
013public class SimpleActionBinding<T extends Action> implements ActionBinding<T> {
014
015        /**
016         * Path
017         */
018        private final String path;
019        /**
020         * Constructor used to instantiate actions
021         */
022        private final Class<T> actionClass;
023        /**
024         * Constructor used to instantiate actions
025         */
026        private final Constructor<T> actionConstructor;
027
028        /**
029         * Constructor.
030         *
031         * @param path Supported path.
032         * @param actionClass Create Action class
033         */
034        public SimpleActionBinding(String path, Class<T> actionClass) {
035                this.path = path;
036                this.actionClass = actionClass;
037                Constructor<T> constructor;
038                try {
039                        try {
040                                constructor = actionClass.getConstructor(ActionContext.class);
041                        } catch (NoSuchMethodException noSuchMethodException) {
042                                constructor = actionClass.getConstructor();
043                        }
044                } catch (SecurityException securityException) {
045                        throw new IllegalStateException("Can get constructor for class " + actionClass.getName(), securityException);
046                } catch (NoSuchMethodException noSuchMethodException) {
047                        throw new IllegalArgumentException("Can find constructor for class " + actionClass.getName());
048                }
049                this.actionConstructor = constructor;
050        }
051
052        /**
053         * Returns true when {@link ActionContext#getPath()} equals {@link #path}.
054         */
055        public boolean supports(ActionContext actionContext) {
056                return actionContext.getPath().equals(this.path);
057        }
058
059        /**
060         * Create a new {@link Action} using {@link #actionConstructor}.
061         */
062        public T create(ActionContext actionContext) {
063                try {
064                        T action;
065                        Class[] actionConstructorParams = actionConstructor.getParameterTypes();
066                        switch (actionConstructorParams.length) {
067                                case 0:
068                                        action = actionConstructor.newInstance();
069                                        break;
070                                case 1:
071                                        if (actionConstructorParams[0].equals(ActionContext.class)) {
072                                                action = actionConstructor.newInstance(actionContext);
073                                        } else {
074                                                throw new IllegalStateException("Unknown argument type in action constructor " + actionConstructorParams[0].getName());
075                                        }
076                                        break;
077                                default:
078                                        throw new IllegalStateException("Invalid argument number in action constructor: " + actionConstructorParams.length);
079                        }
080                        return action;
081                } catch (InstantiationException | InvocationTargetException | IllegalAccessException instantiationException) {
082                        throw new IllegalStateException("Failed to create action", instantiationException);
083                }
084        }
085
086        public Constructor<T> getActionConstructor() {
087                return actionConstructor;
088        }
089
090        public Class<T> getActionClass() {
091                return actionClass;
092        }
093
094        public String getPath() {
095                return path;
096        }
097}