package edu.vandy.model.services; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import edu.vandy.common.ExecutorServiceTimeoutCache; import edu.vandy.common.GenericSingleton; import edu.vandy.common.LifecycleLoggingService; import edu.vandy.model.aidl.AcronymDataJsonParser; import edu.vandy.model.aidl.AcronymExpansion; import android.util.Log; /** * This super class factors out fields and methods shared by both * AcronymServiceSync and AcronymServiceAsync service implementations. */ public class AcronymServiceBase extends LifecycleLoggingService { /** * URL to the Acronym Service web service. */ private String sAcronym_Service_URL = "http://www.nactem.ac.uk/software/acromine/dictionary.py?sf="; /** * Default timeout is 10 seconds, after which the Cache data * expires. In a production app this value should be much higher * (e.g., 10 minutes) - we keep it small here to help with * testing. */ private int DEFAULT_CACHE_TIMEOUT = 10; /** * Define a class that will cache the AcronymData since it doesn't * change rapidly. This class is passed to the * GenericSingleton.instance() method to retrieve the one and only * instance of the AcronymCache. */ public static class AcronymCache extends ExecutorServiceTimeoutCache<String, List<AcronymExpansion>> {} /** * Hook method called when the Service is created. */ @Override public void onCreate() { super.onCreate(); // Increment the reference count for the AcronymCache // singleton, which is shared by both Services. GenericSingleton.instance(AcronymCache.class).incrementRefCount(); } /** * Hook method called when the last client unbinds from the * Service. */ @Override public void onDestroy() { super.onDestroy(); // Decrement the reference count for the AcronymCache // singleton, which shuts it down when the count drops to 0. // When this happens, the GenericSingleton needs to remove the // AcronymCache.class entry in its map. if (GenericSingleton.instance(AcronymCache.class).decrementRefCount() == 0) GenericSingleton.remove(AcronymCache.class); } /** * Conditionally queries the Acronym Service web service to obtain * a List of AcronymData corresponding to the @a acronym if it's * been more than 10 seconds since the last query to the Acronym * Service. Otherwise, simply return the cached results. */ protected List<AcronymExpansion> getAcronymExpansions(String acronym) { Log.d(TAG, "Looking up results in the cache for " + acronym); // Try to get the results from the AcronymCache. List<AcronymExpansion> results = GenericSingleton.instance(AcronymCache.class).get(acronym); if (results != null) { Log.d(TAG, "Getting results from the cache for " + acronym); // Return the results from the cache. return results; } else { Log.d(TAG, "Getting results from the Acronym Service for " + acronym); // The results weren't already in the cache or were // "stale", so obtain them from the Acronym Service. results = getResultsFromAcronymService(acronym); if (results != null) // Store the results into the cache for up to // DEFAULT_CACHE_TIMEOUT seconds based on the location // and return the results. GenericSingleton.instance(AcronymCache.class).put (acronym, results, DEFAULT_CACHE_TIMEOUT); return results; } } /** * Actually query the Acronym Service web service to get the * current AcronymData. */ private List<AcronymExpansion> getResultsFromAcronymService(String acronym) { // Create a List that will return the List of AcronymExpansion objects obtained // from the Acronym Service web service. List<AcronymExpansion> returnList = new ArrayList<>(); try { // Create a URL that points to desired location the // Acronym Service. final URL url = new URL(sAcronym_Service_URL + URLEncoder.encode(acronym, "UTF-8")); // Opens a connection to the Acronym Service. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // Sends the GET request and returns a stream containing // the Json results. try (InputStream in = new BufferedInputStream(urlConnection.getInputStream())) { // Create the parser. final AcronymDataJsonParser parser = new AcronymDataJsonParser(); // Parse the Json results and create AcronymData // objects. returnList = parser.parseJsonStream(in); } finally { urlConnection.disconnect(); } } catch (IOException e) { e.printStackTrace(); return null; } // See if we parsed any valid data. if (returnList != null && returnList.size() > 0) { // Return the List of AcronymData. return returnList; } else return null; } }