package com.universalbits.conorganizer.badger.control; import com.universalbits.conorganizer.badger.model.BadgeInfo; import com.universalbits.conorganizer.common.APIClient; import com.universalbits.conorganizer.common.Settings; import org.json.JSONException; import org.json.JSONObject; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import java.util.logging.Logger; public class ServerBadgeLoader implements Runnable { private static final Logger LOGGER = Logger.getLogger(ServerBadgeLoader.class.getName()); private static final int ERROR_DELAY = 2000; private static final String PRINT_STATUS = "___PRINT_STATUS"; private final APIClient client = new APIClient(Settings.getInstance()); private final BadgeQueue queue; private final TokenRequiredListener tokenRequiredListener; private boolean stopped = false; private final ServerBadgeNotifier serverBadgeNotifier = new ServerBadgeNotifier(); public ServerBadgeLoader(BadgeQueue queue, TokenRequiredListener listener) { this.queue = queue; this.tokenRequiredListener = listener; new Thread(serverBadgeNotifier).start(); } public APIClient getAPIClient() { return client; } public void stop() { stopped = true; } @Override public void run() { final Map<String, String> getBadgeParams = new HashMap<>(); String jsonStr = ""; BadgeInfo badgeInfo; long lastPrintTime = 0; while (!stopped) { boolean success = false; try { if (lastPrintTime == 0) { final Map<String, String> params = new HashMap<>(); params.put("name", client.getClientName()); params.put("type", "printer"); params.put("product", "BadgePrinter"); params.put("vendor", "Universal Bits"); params.put("version", "1.1"); final URL registerUrl = client.getRequestUrl("register", params); APIClient.getUrlAsString(registerUrl); } if (client.hasToken()) { final URL getUrl = client.getRequestUrl("get_badge_to_print", getBadgeParams); LOGGER.info(getUrl.toString()); jsonStr = APIClient.getUrlAsString(getUrl); LOGGER.fine("received jsonStr: " + jsonStr); if (jsonStr != null && jsonStr.length() > 0) { final JSONObject jsonBadge = new JSONObject(jsonStr); if (jsonBadge.has(BadgeInfo.ID_BADGE)) { LOGGER.fine(jsonBadge.toString(4)); badgeInfo = new BadgeInfo(jsonBadge); badgeInfo.setContext(serverBadgeNotifier); queue.queueBadge(badgeInfo); } } lastPrintTime = System.currentTimeMillis(); success = true; } else { String token = tokenRequiredListener.getToken(); if (token != null && !token.isEmpty()) { client.setToken(token); success = true; } } } catch (JSONException je) { LOGGER.log(Level.SEVERE, "Error parsing JSON " + jsonStr); } catch (UnknownHostException uhe) { LOGGER.log(Level.SEVERE, "Unknown Host Exception: " + uhe.getMessage()); } catch (SocketException se) { LOGGER.log(Level.SEVERE, "SocketException: " + se.getMessage()); } catch (SocketTimeoutException ste) { LOGGER.log(Level.SEVERE, "SocketTimeoutException: " + ste.getMessage()); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error fetching badge", e); } finally { if (!success) { try { LOGGER.log(Level.SEVERE, "Pausing for " + ERROR_DELAY + "ms to due to exception"); Thread.sleep(ERROR_DELAY); } catch (InterruptedException ie) { LOGGER.info("sleep interrupted"); } } } } } private class ServerBadgeNotifier implements Runnable, BadgeStatusListener { private final BlockingQueue<BadgeInfo> queue = new LinkedBlockingQueue<>(); private final Map<String, String> markBadgePrintedParams = new HashMap<>(); @Override public void run() { while (!stopped) { try { final BadgeInfo badgeInfo = queue.take(); final String badgeId = badgeInfo.get(BadgeInfo.ID_BADGE); final String status = badgeInfo.get(PRINT_STATUS); final String type = badgeInfo.get(BadgeInfo.TYPE); boolean markedComplete = false; while (!markedComplete) { try { LOGGER.info("Marking badge " + badgeId + " as printed. Status=" + status); markBadgePrintedParams.put("id_badge", badgeId); markBadgePrintedParams.put("status", status); final URL finishUrl = client.getRequestUrl("mark_badge_printed", markBadgePrintedParams); String finishStr = APIClient.getUrlAsString(finishUrl); LOGGER.info("Received from finishUrl: " + finishStr); markedComplete = true; } catch (UnknownHostException uhe) { LOGGER.log(Level.SEVERE, "Unknown Host Exception: " + uhe.getMessage()); } catch (SocketException se) { LOGGER.log(Level.SEVERE, "SocketException: " + se.getMessage()); } catch (SocketTimeoutException ste) { LOGGER.log(Level.SEVERE, "SocketTimeoutException: " + ste.getMessage()); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error marking badge " + badgeId + " as complete. type=" + type, e); } finally { if (!markedComplete) { try { LOGGER.log(Level.SEVERE, "Pausing for " + ERROR_DELAY + "ms to due to exception"); Thread.sleep(ERROR_DELAY); } catch (InterruptedException ie) { LOGGER.info("sleep interrupted"); } } } } } catch (InterruptedException e) { LOGGER.log(Level.INFO, "take interrupted", e); } } } @Override public void notifyBadgeStatus(BadgeInfo badgeInfo, String status) { badgeInfo.put(PRINT_STATUS, status); queue.add(badgeInfo); } } public static interface TokenRequiredListener { String getToken(); } }