001/*
002 * Stallion Core: A Modern Web Framework
003 *
004 * Copyright (C) 2015 - 2016 Stallion Software LLC.
005 *
006 * This program is free software: you can redistribute it and/or modify it under the terms of the
007 * GNU General Public License as published by the Free Software Foundation, either version 2 of
008 * the License, or (at your option) any later version. This program is distributed in the hope that
009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
011 * License for more details. You should have received a copy of the GNU General Public License
012 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
013 *
014 *
015 *
016 */
017
018package io.stallion.asyncTasks;
019
020import io.stallion.plugins.StallionJavaPlugin;
021import io.stallion.plugins.PluginRegistry;
022import io.stallion.plugins.javascript.JsAsyncTaskHandler;
023import io.stallion.services.Log;
024import io.stallion.utils.json.JSON;
025
026import java.util.HashMap;
027import java.util.Map;
028
029import static io.stallion.utils.Literals.empty;
030
031public class AsyncTaskExecuteRunnable implements Runnable {
032
033    private Boolean triggerShutdown = false;
034    private AsyncTask task;
035    private static final Map<String, Class> classCache = new HashMap<>();
036
037    public AsyncTaskExecuteRunnable(AsyncTask task) {
038        this.task = task;
039    }
040
041    public static void registerClass(String name, Class<? extends AsyncTaskHandler> cls) {
042        classCache.put(name, cls);
043    }
044
045    @Override
046    public void run() {
047        run(false);
048    }
049
050
051
052    public void run(boolean synchronousMode) {
053        try {
054            Log.info("Executing task: {0}", task.getId());
055
056            Class cls = lookupClass(task.getHandlerName());
057            Log.info("Loaded async handler class: {0}", cls.getName());
058            AsyncTaskHandler handler = (AsyncTaskHandler)JSON.parse(task.getDataJson(), cls);
059            if (handler instanceof JsAsyncTaskHandler && !empty(task.getDataJson())) {
060                ((JsAsyncTaskHandler)handler).putAll(JSON.parseMap(task.getDataJson()));
061            }
062            handler.setTask(task);
063            handler.process();
064            AsyncCoordinator.instance().markCompleted(task);
065        } catch(Exception e) {
066            if (synchronousMode) {
067                throw new RuntimeException(e);
068            }
069            String dump = "";
070            try {
071                dump = JSON.stringify(task);
072            } catch (Exception e1) {
073            }
074            Log.exception(e, "Exception processing task id:{0} handler:{1} customKey:{2} dump:{3}",
075                    task.getId(), task.getHandlerName(), task.getCustomKey(), dump);
076            try {
077                AsyncCoordinator.instance().markFailed(task, e);
078                if (task.getTryCount() < 5) {
079                    Log.info("Adding task back into the queue {0}", task.getId());
080                    ((AsyncFileCoordinator)AsyncCoordinator.instance()).getTaskQueue().add(task);
081                }
082            } catch (Exception persistException) {
083                Log.exception(persistException, "Exception persisting task changes for id:{0}", task.getId());
084            }
085        }
086    }
087
088    private Class lookupClass(String className) throws ClassNotFoundException {
089        if (classCache.containsKey(className)) {
090            return classCache.get(className);
091        }
092        Class cls = null;
093
094        try {
095            cls = getClass().getClassLoader().loadClass(task.getHandlerName());
096        } catch (ClassNotFoundException e) {
097
098        }
099        if (cls != null) {
100            classCache.put(className, cls);
101        }
102        for (StallionJavaPlugin booter: PluginRegistry.instance().getJavaPluginByName().values()) {
103            try {
104                cls = booter.getClass().getClassLoader().loadClass(task.getHandlerName());
105                if (cls != null) {
106                    classCache.put(className, cls);
107                    return cls;
108                }
109            } catch (ClassNotFoundException e) {
110
111            }
112        }
113        for (ClassLoader loader: AsyncCoordinator.instance().getExtraClassLoaders()) {
114            try {
115                cls = loader.loadClass(task.getHandlerName());
116                if (cls != null) {
117                    classCache.put(className, cls);
118                    return cls;
119                }
120            } catch (ClassNotFoundException e) {
121
122            }
123        }
124        throw new ClassNotFoundException("Class not found: " + className);
125    }
126
127
128    public Boolean getTriggerShutdown() {
129        return triggerShutdown;
130    }
131
132    public void setTriggerShutdown(Boolean triggerShutdown) {
133        this.triggerShutdown = triggerShutdown;
134    }
135
136}