package qa.qcri.aidr.collector.api; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import javax.ws.rs.QueryParam; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.log4j.Logger; import org.codehaus.jackson.map.ObjectMapper; import org.glassfish.jersey.jackson.JacksonFeature; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import qa.qcri.aidr.collector.beans.CollectionTask; import qa.qcri.aidr.collector.beans.ResponseWrapper; import qa.qcri.aidr.collector.beans.SMS; import qa.qcri.aidr.collector.collectors.JedisPublisher; import qa.qcri.aidr.collector.utils.CollectorConfigurationProperty; import qa.qcri.aidr.collector.utils.CollectorConfigurator; import qa.qcri.aidr.collector.utils.CollectorErrorLog; import qa.qcri.aidr.collector.utils.GenericCache; import qa.qcri.aidr.common.redis.LoadShedder; /** * @author Imran * Provides RESTFul APIS to start and stop SMS collections. * TODO: remove non-API methods from this class. */ @Controller @RequestMapping("/sms") public class SMSCollectionController { private static Logger logger = Logger.getLogger(SMSCollectionController.class.getName()); private static CollectorConfigurator configProperties= CollectorConfigurator.getInstance(); public static final String CHANNEL = configProperties.getProperty(CollectorConfigurationProperty.COLLECTOR_CHANNEL) + ".%s"; private static ConcurrentHashMap<String, LoadShedder> redisLoadShedder = null; @RequestMapping("/start") @ResponseBody public Response startTask(@RequestParam("collection_code") String collectionCode) { if (null == redisLoadShedder) { redisLoadShedder = new ConcurrentHashMap<String, LoadShedder>(20); } String channelName = String.format(CHANNEL, collectionCode); redisLoadShedder.put(channelName, new LoadShedder( Integer.parseInt(configProperties.getProperty(CollectorConfigurationProperty.PERSISTER_LOAD_LIMIT)), Integer.parseInt(configProperties.getProperty(CollectorConfigurationProperty.PERSISTER_LOAD_CHECK_INTERVAL_MINUTES)), true,channelName)); GenericCache.getInstance().putSMSCollection(collectionCode, configProperties.getProperty(CollectorConfigurationProperty.STATUS_CODE_COLLECTION_RUNNING)); startPersister(collectionCode); return Response.ok().build(); } @RequestMapping("/stop") @ResponseBody public Response stopTask(@RequestParam("collection_code") String collectionCode) { GenericCache cache = GenericCache.getInstance(); CollectionTask task = cache.getSMSConfig(collectionCode); cache.removeSMSCollection(collectionCode); stopPersister(collectionCode); cache.deleteCounter(collectionCode); cache.delLastDownloadedDoc(collectionCode); if (task != null) return Response.ok(task).build(); ResponseWrapper response = new ResponseWrapper(); response.setMessage("Invalid key. No running collector found for the given id."); response.setStatusCode(configProperties.getProperty(CollectorConfigurationProperty.STATUS_CODE_COLLECTION_NOTFOUND)); return Response.ok(response).build(); } @RequestMapping(value = "/endpoint/receive/{collection_code}", method={RequestMethod.POST}) @ResponseBody public Response receive(@PathVariable("collection_code") String code, SMS sms) { GenericCache cache = GenericCache.getInstance(); String smsCollections = cache.getSMSCollection(code.trim()); if (configProperties.getProperty(CollectorConfigurationProperty.STATUS_CODE_COLLECTION_RUNNING).equals(smsCollections)) { try { ObjectMapper objectMapper = new ObjectMapper(); String channelName = String.format(CHANNEL, code); if (redisLoadShedder.get(channelName).canProcess()) { JedisPublisher publisherJedis = JedisPublisher.newInstance(); SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZ yyyy"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); sms.setCreated_at(sdf.format(new Date())); publisherJedis.publish(channelName, objectMapper.writeValueAsString(sms)); cache.increaseSMSCount(code); cache.setLastDownloadedDoc(code, sms.getText()); publisherJedis.close(); } } catch (Exception e) { logger.error("Exception in receiving from SMS collection: " + code + ", data: " + sms); } } return Response.ok().build(); } @RequestMapping("/status") @ResponseBody public Response getStatus(@RequestParam("collection_code") String code) { CollectionTask config = GenericCache.getInstance().getSMSConfig(code); return Response.ok(config).build(); } @RequestMapping("/status/all") public Map getStatusAll() { return GenericCache.getInstance().getSMSCollections(); } public void startPersister(String collectionCode) { Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); try { WebTarget webResource = client.target(configProperties.getProperty(CollectorConfigurationProperty.PERSISTER_REST_URI) + "collectionPersister/start?channel_provider=" + URLEncoder.encode(configProperties.getProperty(CollectorConfigurationProperty.TAGGER_CHANNEL), "UTF-8") + "&collection_code=" + URLEncoder.encode(collectionCode, "UTF-8")); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON).get(); String jsonResponse = clientResponse.readEntity(String.class); logger.info(collectionCode + ": Collector persister response = " + jsonResponse); } catch (RuntimeException e) { logger.error(collectionCode + ": Could not start persister. Is persister running?"); CollectorErrorLog.sendErrorMail(collectionCode, "Unable to start persister."); } catch (UnsupportedEncodingException e) { logger.error(collectionCode + ": Unsupported Encoding scheme used"); } } public void stopPersister(String collectionCode) { Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); try { WebTarget webResource = client.target(configProperties.getProperty(CollectorConfigurationProperty.PERSISTER_REST_URI) + "collectionPersister/stop?collection_code=" + URLEncoder.encode(collectionCode, "UTF-8")); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON).get(); String jsonResponse = clientResponse.readEntity(String.class); logger.info(collectionCode + ": Collector persister response = " + jsonResponse); } catch (RuntimeException e) { logger.error(collectionCode + ": Could not stop persister. Is persister running?"); } catch (UnsupportedEncodingException e) { logger.error(collectionCode + ": Unsupported Encoding scheme used"); } } }