diff --git a/src/main/java/altk/comm/engine/Broadcast.java b/src/main/java/altk/comm/engine/Broadcast.java index 47dc97d..ee2ba90 100644 --- a/src/main/java/altk/comm/engine/Broadcast.java +++ b/src/main/java/altk/comm/engine/Broadcast.java @@ -1006,6 +1006,8 @@ public abstract class Broadcast */ protected void pause(String reason, PrintWriter out) { + if (state == BroadcastState.ACCEPTED || state.isFinal) return; + // Sets state to PAUSING, which is monitored by Broadcast.Service threads. // EVentually, when all service activity ends, the state transitions to PAUSED StateChangeResult result = setState(BroadcastState.PAUSING, reason, null); @@ -1025,6 +1027,7 @@ public abstract class Broadcast protected void resume(String reason, PrintWriter out) { + if (state == BroadcastState.ACCEPTED || state.isFinal) return; if (!withinOperatingHours()) { if (out != null) out.write("Cannot resume outside operating hours"); @@ -1450,16 +1453,37 @@ public abstract class Broadcast for (String key : new String[] {DAILY_STOP_KEY, DAILY_START_KEY}) { String value = (String)configuration.get(key); if (value != null) { - timeChanged = timeChanged || setOperatingHours(key, value); + if (setOperatingHours(key, value)) { + timeChanged = true; + } } } if (timeChanged) enforceOperationHours(); } + /** + * YML: At this time, we only enforce pause action when a broadcast is + * outside its operating hours. The current design is not satisfactory and needs + * a better solution. + * + * We are not automatically resuming a paused broadcast because the difference + * between intention of an operator-initiated pause and + * that of a clock pause needs clarification in their operation paradigm. + * Question is when or if we allow a operator-initiated pause be resumed + * when someone changes the operating hours of a broadcast in such a way + * that the broadcast is at once within its operasting hours. it may be + * be counter to the intention of the original operator. + * + * On the other hand, if that places the broadcast outside it operating hours, + * it is safer to immediately pause it. + * + * To add clarity, we may need to separate the PAUSE state into OPERATOR_PAUSE and CLOCK_PAUSE, + * and similarly PAUING state. + */ void enforceOperationHours() { if (state == BroadcastState.ABORTED) return; if (withinOperatingHours()) { - resume("clock", null); +// resume("clock", null); } else { pause("clock", null); } @@ -1476,11 +1500,11 @@ public abstract class Broadcast if (timeOfDay == null) throw new RuntimeException(String.format("Invalid value for %s: %s", timeParam, value)); switch (timeParam) { case DAILY_STOP_KEY: - if (daily_stop == timeOfDay) return false; + if (timeOfDay.equals(daily_stop)) return false; daily_stop = timeOfDay; return true; case DAILY_START_KEY: - if (daily_start == timeOfDay) return false; + if (timeOfDay.equals(daily_start)) return false; daily_start = timeOfDay; return true; default: diff --git a/src/main/java/altk/comm/engine/CommEngine.java b/src/main/java/altk/comm/engine/CommEngine.java index 292e482..af86a7e 100644 --- a/src/main/java/altk/comm/engine/CommEngine.java +++ b/src/main/java/altk/comm/engine/CommEngine.java @@ -5,6 +5,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; @@ -25,6 +27,7 @@ import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; import altk.comm.engine.Broadcast.BroadcastState; @@ -92,13 +95,25 @@ public abstract class CommEngine extends HttpServlet { while (!threadShouldStop) { + String timeOfDay = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm")); + // Check for pause for (Broadcast broadcast : broadcasts.values()) - { - broadcast.enforceOperationHours(); + {; + // Check for pause + if (broadcast.daily_stop.length() > 0) + { + if (timeOfDay.equals(broadcast.daily_stop)) broadcast.pause("clock", null); + } + + // Check for resume + if (broadcast.daily_start.length() > 0) + { + if (timeOfDay.equals(broadcast.daily_start)) broadcast.resume("clock", null); + } } long currentTime = System.currentTimeMillis(); - long sleepTime = 60000 - currentTime % 60000; + long sleepTime = 60000 + 30000 - currentTime % 60000; if (sleepTime > 0) { try @@ -508,13 +523,13 @@ public abstract class CommEngine extends HttpServlet protected static String checkTimeOfDay(String timeOfDay) { timeOfDay = timeOfDay.trim(); // pattern hh:mm - Pattern pattern = Pattern.compile("^(\\d\\d):[0-5]\\d$"); + Pattern pattern = Pattern.compile("^(\\d+):([0-5]\\d)$"); Matcher matcher = pattern.matcher(timeOfDay); if (!matcher.find()) return null; // Check hour in range - String hh = matcher.group(1); + String hh = matcher.group(1).trim(); if (Integer.parseInt(hh) > 23) return null; - return timeOfDay; + return (hh.length()==1? "0" + hh : hh) + ":" + matcher.group(2); } /** @@ -532,12 +547,15 @@ public abstract class CommEngine extends HttpServlet JSONObject configuration = (JSONObject) parser.parse(jsonString); configure(configuration); } catch (Exception e) { - myLogger.error(e); - out.write("Error - " + e.getMessage()); + String errMsg = + (e instanceof ParseException)? ("JSON error: " + e) : e.getMessage(); + myLogger.error(errMsg, e); + out.write("Error - " + errMsg); // restore current confiuration try { configure(origConfigJSON); } catch (Exception e1) { + myLogger.error("Internal error in restoring original configuration: " + e1.getMessage(), e1); out.write("\nInternal error in restoring original configuration: " + e1.getMessage()); } }