/* * Copyright (C) 2004-2015 L2J Server * * This file is part of L2J Server. * * L2J Server is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * L2J Server is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.l2jserver.gameserver.taskmanager; import static com.l2jserver.gameserver.taskmanager.TaskTypes.TYPE_NONE; import static com.l2jserver.gameserver.taskmanager.TaskTypes.TYPE_SHEDULED; import static com.l2jserver.gameserver.taskmanager.TaskTypes.TYPE_TIME; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ScheduledFuture; import java.util.logging.Level; import java.util.logging.Logger; import com.l2jserver.commons.database.pool.impl.ConnectionFactory; import com.l2jserver.gameserver.ThreadPoolManager; import com.l2jserver.gameserver.taskmanager.tasks.TaskBirthday; import com.l2jserver.gameserver.taskmanager.tasks.TaskClanLeaderApply; import com.l2jserver.gameserver.taskmanager.tasks.TaskCleanUp; import com.l2jserver.gameserver.taskmanager.tasks.TaskDailySkillReuseClean; import com.l2jserver.gameserver.taskmanager.tasks.TaskGlobalVariablesSave; import com.l2jserver.gameserver.taskmanager.tasks.TaskJython; import com.l2jserver.gameserver.taskmanager.tasks.TaskOlympiadSave; import com.l2jserver.gameserver.taskmanager.tasks.TaskRaidPointsReset; import com.l2jserver.gameserver.taskmanager.tasks.TaskRecom; import com.l2jserver.gameserver.taskmanager.tasks.TaskRestart; import com.l2jserver.gameserver.taskmanager.tasks.TaskScript; import com.l2jserver.gameserver.taskmanager.tasks.TaskSevenSignsUpdate; import com.l2jserver.gameserver.taskmanager.tasks.TaskShutdown; /** * @author Layane */ public final class TaskManager { protected static final Logger _log = Logger.getLogger(TaskManager.class.getName()); private final Map _tasks = new ConcurrentHashMap<>(); protected final List _currentTasks = new CopyOnWriteArrayList<>(); protected static final String[] SQL_STATEMENTS = { "SELECT id,task,type,last_activation,param1,param2,param3 FROM global_tasks", "UPDATE global_tasks SET last_activation=? WHERE id=?", "SELECT id FROM global_tasks WHERE task=?", "INSERT INTO global_tasks (task,type,last_activation,param1,param2,param3) VALUES(?,?,?,?,?,?)" }; protected TaskManager() { initializate(); startAllTasks(); _log.log(Level.INFO, getClass().getSimpleName() + ": Loaded: " + _tasks.size() + " Tasks"); } public class ExecutedTask implements Runnable { int id; long lastActivation; Task task; TaskTypes type; String[] params; ScheduledFuture scheduled; public ExecutedTask(Task ptask, TaskTypes ptype, ResultSet rset) throws SQLException { task = ptask; type = ptype; id = rset.getInt("id"); lastActivation = rset.getLong("last_activation"); params = new String[] { rset.getString("param1"), rset.getString("param2"), rset.getString("param3") }; } @Override public void run() { task.onTimeElapsed(this); lastActivation = System.currentTimeMillis(); try (Connection con = ConnectionFactory.getInstance().getConnection(); PreparedStatement statement = con.prepareStatement(SQL_STATEMENTS[1])) { statement.setLong(1, lastActivation); statement.setInt(2, id); statement.executeUpdate(); } catch (SQLException e) { _log.log(Level.WARNING, getClass().getSimpleName() + ": Cannot updated the Global Task " + id + ": " + e.getMessage(), e); } if ((type == TYPE_SHEDULED) || (type == TYPE_TIME)) { stopTask(); } } @Override public boolean equals(Object object) { if (this == object) { return true; } if (!(object instanceof ExecutedTask)) { return false; } return id == ((ExecutedTask) object).id; } @Override public int hashCode() { return id; } public Task getTask() { return task; } public TaskTypes getType() { return type; } public int getId() { return id; } public String[] getParams() { return params; } public long getLastActivation() { return lastActivation; } public void stopTask() { task.onDestroy(); if (scheduled != null) { scheduled.cancel(true); } _currentTasks.remove(this); } } private void initializate() { registerTask(new TaskBirthday()); registerTask(new TaskClanLeaderApply()); registerTask(new TaskCleanUp()); registerTask(new TaskDailySkillReuseClean()); registerTask(new TaskGlobalVariablesSave()); registerTask(new TaskJython()); registerTask(new TaskOlympiadSave()); registerTask(new TaskRaidPointsReset()); registerTask(new TaskRecom()); registerTask(new TaskRestart()); registerTask(new TaskScript()); registerTask(new TaskSevenSignsUpdate()); registerTask(new TaskShutdown()); } public void registerTask(Task task) { int key = task.getName().hashCode(); _tasks.computeIfAbsent(key, k -> { task.initializate(); return task; }); } private void startAllTasks() { try (Connection con = ConnectionFactory.getInstance().getConnection(); PreparedStatement statement = con.prepareStatement(SQL_STATEMENTS[0]); ResultSet rset = statement.executeQuery()) { while (rset.next()) { Task task = _tasks.get(rset.getString("task").trim().toLowerCase().hashCode()); if (task == null) { continue; } final TaskTypes type = TaskTypes.valueOf(rset.getString("type")); if (type != TYPE_NONE) { ExecutedTask current = new ExecutedTask(task, type, rset); if (launchTask(current)) { _currentTasks.add(current); } } } } catch (Exception e) { _log.log(Level.SEVERE, getClass().getSimpleName() + ": Error while loading Global Task table: " + e.getMessage(), e); } } private boolean launchTask(ExecutedTask task) { final ThreadPoolManager scheduler = ThreadPoolManager.getInstance(); final TaskTypes type = task.getType(); long delay, interval; switch (type) { case TYPE_STARTUP: task.run(); return false; case TYPE_SHEDULED: delay = Long.valueOf(task.getParams()[0]); task.scheduled = scheduler.scheduleGeneral(task, delay); return true; case TYPE_FIXED_SHEDULED: delay = Long.valueOf(task.getParams()[0]); interval = Long.valueOf(task.getParams()[1]); task.scheduled = scheduler.scheduleGeneralAtFixedRate(task, delay, interval); return true; case TYPE_TIME: try { Date desired = DateFormat.getInstance().parse(task.getParams()[0]); long diff = desired.getTime() - System.currentTimeMillis(); if (diff >= 0) { task.scheduled = scheduler.scheduleGeneral(task, diff); return true; } _log.info(getClass().getSimpleName() + ": Task " + task.getId() + " is obsoleted."); } catch (Exception e) { } break; case TYPE_SPECIAL: ScheduledFuture result = task.getTask().launchSpecial(task); if (result != null) { task.scheduled = result; return true; } break; case TYPE_GLOBAL_TASK: interval = Long.valueOf(task.getParams()[0]) * 86400000L; String[] hour = task.getParams()[1].split(":"); if (hour.length != 3) { _log.warning(getClass().getSimpleName() + ": Task " + task.getId() + " has incorrect parameters"); return false; } Calendar check = Calendar.getInstance(); check.setTimeInMillis(task.getLastActivation() + interval); Calendar min = Calendar.getInstance(); try { min.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hour[0])); min.set(Calendar.MINUTE, Integer.parseInt(hour[1])); min.set(Calendar.SECOND, Integer.parseInt(hour[2])); } catch (Exception e) { _log.log(Level.WARNING, getClass().getSimpleName() + ": Bad parameter on task " + task.getId() + ": " + e.getMessage(), e); return false; } delay = min.getTimeInMillis() - System.currentTimeMillis(); if (check.after(min) || (delay < 0)) { delay += interval; } task.scheduled = scheduler.scheduleGeneralAtFixedRate(task, delay, interval); return true; default: return false; } return false; } public static boolean addUniqueTask(String task, TaskTypes type, String param1, String param2, String param3) { return addUniqueTask(task, type, param1, param2, param3, 0); } public static boolean addUniqueTask(String task, TaskTypes type, String param1, String param2, String param3, long lastActivation) { try (Connection con = ConnectionFactory.getInstance().getConnection(); PreparedStatement ps1 = con.prepareStatement(SQL_STATEMENTS[2])) { ps1.setString(1, task); try (ResultSet rs = ps1.executeQuery()) { if (!rs.next()) { try (PreparedStatement ps2 = con.prepareStatement(SQL_STATEMENTS[3])) { ps2.setString(1, task); ps2.setString(2, type.toString()); ps2.setLong(3, lastActivation); ps2.setString(4, param1); ps2.setString(5, param2); ps2.setString(6, param3); ps2.execute(); } } } return true; } catch (SQLException e) { _log.log(Level.WARNING, TaskManager.class.getSimpleName() + ": Cannot add the unique task: " + e.getMessage(), e); } return false; } public static boolean addTask(String task, TaskTypes type, String param1, String param2, String param3) { return addTask(task, type, param1, param2, param3, 0); } public static boolean addTask(String task, TaskTypes type, String param1, String param2, String param3, long lastActivation) { try (Connection con = ConnectionFactory.getInstance().getConnection(); PreparedStatement statement = con.prepareStatement(SQL_STATEMENTS[3])) { statement.setString(1, task); statement.setString(2, type.toString()); statement.setLong(3, lastActivation); statement.setString(4, param1); statement.setString(5, param2); statement.setString(6, param3); statement.execute(); return true; } catch (SQLException e) { _log.log(Level.WARNING, TaskManager.class.getSimpleName() + ": Cannot add the task: " + e.getMessage(), e); } return false; } public static TaskManager getInstance() { return SingletonHolder._instance; } private static class SingletonHolder { protected static final TaskManager _instance = new TaskManager(); } }