diff --git a/src/main/java/com/vmware/vipclient/i18n/base/cache/MessageCacheItem.java b/src/main/java/com/vmware/vipclient/i18n/base/cache/MessageCacheItem.java index 5db259e13..123e981dd 100644 --- a/src/main/java/com/vmware/vipclient/i18n/base/cache/MessageCacheItem.java +++ b/src/main/java/com/vmware/vipclient/i18n/base/cache/MessageCacheItem.java @@ -40,10 +40,6 @@ public void addCacheData(String key, String value) { this.cachedData.put(key, value); } - public boolean isCachedDataEmpty() { - return this.cachedData.isEmpty(); - } - public synchronized void addCachedData(Map cachedData) { if (cachedData != null) this.cachedData.putAll(cachedData); diff --git a/src/main/java/com/vmware/vipclient/i18n/common/ConstantsMsg.java b/src/main/java/com/vmware/vipclient/i18n/common/ConstantsMsg.java index e73d212a5..3d8e77791 100644 --- a/src/main/java/com/vmware/vipclient/i18n/common/ConstantsMsg.java +++ b/src/main/java/com/vmware/vipclient/i18n/common/ConstantsMsg.java @@ -12,5 +12,6 @@ public class ConstantsMsg { public static final String SERVER_RETURN_ERROR = "Server returned error! Status: %d. Message: %s"; public static final String SERVER_CONTENT_ERROR = "The content from server is wrong!"; public static final String UNKNOWN_ERROR = "Unknown error."; + public static final String GET_MESSAGES_FAILED = "Failed to get messages for component {0}, locale: {1}."; } diff --git a/src/main/java/com/vmware/vipclient/i18n/messages/service/ComponentService.java b/src/main/java/com/vmware/vipclient/i18n/messages/service/ComponentService.java index d730bfe3f..7f0b9e65b 100644 --- a/src/main/java/com/vmware/vipclient/i18n/messages/service/ComponentService.java +++ b/src/main/java/com/vmware/vipclient/i18n/messages/service/ComponentService.java @@ -6,6 +6,8 @@ import java.util.ListIterator; import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.FutureTask; import org.json.simple.JSONValue; import org.json.simple.parser.ParseException; @@ -15,12 +17,13 @@ import com.vmware.vipclient.i18n.VIPCfg; import com.vmware.vipclient.i18n.base.DataSourceEnum; import com.vmware.vipclient.i18n.base.cache.MessageCacheItem; -import com.vmware.vipclient.i18n.base.cache.CacheMode; -import com.vmware.vipclient.i18n.base.cache.persist.DiskCacheLoader; -import com.vmware.vipclient.i18n.base.cache.persist.Loader; +import com.vmware.vipclient.i18n.common.ConstantsMsg; import com.vmware.vipclient.i18n.messages.api.opt.server.ComponentBasedOpt; import com.vmware.vipclient.i18n.messages.dto.MessagesDTO; +import com.vmware.vipclient.i18n.util.ConstantsKeys; +import com.vmware.vipclient.i18n.util.FormatUtils; import com.vmware.vipclient.i18n.util.JSONUtils; +import com.vmware.vipclient.i18n.util.LocaleUtility; public class ComponentService { private MessagesDTO dto = null; @@ -40,39 +43,74 @@ public ComponentService(MessagesDTO dto) { public void getMessages(final MessageCacheItem cacheItem, ListIterator msgSourceQueueIter) { if (!msgSourceQueueIter.hasNext()) return; + + long timestampOld = cacheItem.getTimestamp(); DataSourceEnum dataSource = (DataSourceEnum) msgSourceQueueIter.next(); dataSource.createMessageOpt(dto).getComponentMessages(cacheItem); + long timestampNew = cacheItem.getTimestamp(); - // If failed to get messages from the dataSource, try the next dataSource in the queue - if (cacheItem.getCachedData().isEmpty()) { - getMessages(cacheItem, msgSourceQueueIter); + // If failed to get messages from the data source + if (timestampNew == timestampOld) { + // Try the next dataSource in the queue + if (msgSourceQueueIter.hasNext()) { + getMessages(cacheItem, msgSourceQueueIter); + // If no more data source in queue, log the error. This means that neither online nor offline fetch succeeded. + } else { + logger.error(FormatUtils.format(ConstantsMsg.GET_MESSAGES_FAILED, LocaleUtility.getDefaultLocale(), + dto.getComponent(), dto.getLocale())); + } } } - + public Map getComponentTranslation() { - CacheService cs = new CacheService(dto); - - if (cs.isContainComponent()) { - return cs.getCacheOfComponent().getCachedData(); - } else { - // Messages are not cached in memory, so try to look in disk cache - if (VIPCfg.getInstance().getCacheMode() == CacheMode.DISK) { - Loader loader = VIPCfg.getInstance().getCacheManager() - .getLoaderInstance(DiskCacheLoader.class); - Map cachedMessages = loader.load(dto.getCompositStrAsCacheKey()); - if (cachedMessages != null) // Messages are in disk cache - return cachedMessages; - } - - // Prepare a new CacheItem to store cache properties - MessageCacheItem cacheItem = new MessageCacheItem(); - // Pass this cacheItem to getMessages so that it will be populated from the http request - this.getMessages(cacheItem, VIPCfg.getInstance().getMsgOriginsQueue().listIterator()); - // Store the messages and properties in cache using a single CacheItem object - cs.addCacheOfComponent(cacheItem); - return cacheItem.getCachedData(); - } + return fetchMessages().getCachedData(); + } + + public MessageCacheItem fetchMessages() { + CacheService cacheService = new CacheService(dto); + Map cacheOfComponent = null; + MessageCacheItem cacheItem = null; + if (cacheService.isContainComponent()) { // Item is in cache + cacheItem = cacheService.getCacheOfComponent(); + cacheOfComponent = cacheItem.getCachedData(); + if (cacheItem.isExpired()) { // cacheItem has expired + // Update the cache in a separate thread + populateCacheTask(cacheService, dto, cacheItem); + } + } else { // Item is not in cache + // Create a new cacheItem object to be stored in cache + cacheItem = new MessageCacheItem(); + getMessages(cacheItem, VIPCfg.getInstance().getMsgOriginsQueue().listIterator()); + cacheOfComponent = cacheItem.getCachedData(); + + if (cacheOfComponent != null && !cacheOfComponent.isEmpty()) { + cacheService.addCacheOfComponent(cacheItem); + } + } + return cacheItem; } + + private void populateCacheTask(final CacheService cacheService, MessagesDTO dto, MessageCacheItem cacheItem) { + Callable callable = () -> { + try { + + // Pass cacheItem to getMessages so that: + // 1. A previously stored etag, if any, can be used for the next HTTP request. + // 2. CacheItem properties such as etag, timestamp and maxAgeMillis can be refreshed + // with new properties from the next HTTP response. + getMessages(cacheItem, VIPCfg.getInstance().getMsgOriginsQueue().listIterator()); + + return cacheItem; + } catch (Exception e) { + // To make sure that the thread will close + // even when an exception is thrown + return null; + } + }; + FutureTask task = new FutureTask(callable); + Thread thread = new Thread(task); + thread.start(); + } public boolean isComponentAvailable() { boolean r = false; diff --git a/src/main/java/com/vmware/vipclient/i18n/messages/service/StringService.java b/src/main/java/com/vmware/vipclient/i18n/messages/service/StringService.java index 20a85ee6d..c096dba4a 100644 --- a/src/main/java/com/vmware/vipclient/i18n/messages/service/StringService.java +++ b/src/main/java/com/vmware/vipclient/i18n/messages/service/StringService.java @@ -7,8 +7,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; import org.json.simple.JSONObject; import org.json.simple.JSONValue; @@ -33,7 +31,7 @@ public class StringService { public String getString(MessagesDTO dto) { String key = dto.getKey(); - MessageCacheItem cacheItem = fetchMessages(dto); + MessageCacheItem cacheItem = new ComponentService(dto).fetchMessages(); // If failed to get MessageCacheItem of a non-default locale, // use MessageCacheItem of the default locale instead. @@ -42,11 +40,11 @@ public String getString(MessagesDTO dto) { MessagesDTO defaultLocaleDTO = new MessagesDTO(dto.getComponent(), dto.getKey(), dto.getSource(), LocaleUtility.getDefaultLocale().toLanguageTag(), null); // MessageCacheItem of the default locale - cacheItem = fetchMessages(defaultLocaleDTO); + cacheItem = new ComponentService(defaultLocaleDTO).fetchMessages(); // The MessageCacheItem for the requested locale will be a reference // to the MessageCacheItem of the default locale - if (!cacheItem.isCachedDataEmpty()) { + if (!cacheItem.getCachedData().isEmpty()) { CacheService cacheService = new CacheService(dto); cacheService.addCacheOfComponent(cacheItem); cacheOfComponent = cacheItem.getCachedData(); @@ -56,55 +54,6 @@ public String getString(MessagesDTO dto) { } - public MessageCacheItem fetchMessages(MessagesDTO dto) { - CacheService cacheService = new CacheService(dto); - Map cacheOfComponent = null; - MessageCacheItem cacheItem = null; - if (cacheService.isContainComponent()) { // Item is in cache - cacheItem = cacheService.getCacheOfComponent(); - cacheOfComponent = cacheItem.getCachedData(); - if (cacheItem.isExpired()) { // cacheItem has expired - // Update the cache in a separate thread - populateCacheTask(cacheService, dto, cacheItem); - } - } else { // Item is not in cache - // Create a new cacheItem object to be stored in cache - cacheItem = new MessageCacheItem(); - cacheOfComponent = populateCache(cacheService, dto, cacheItem).getCachedData(); - - if (cacheOfComponent != null && !cacheOfComponent.isEmpty()) { - cacheService.addCacheOfComponent(cacheItem); - } - } - return cacheItem; - } - - private void populateCacheTask(final CacheService cacheService, MessagesDTO dto, MessageCacheItem cacheItem) { - Callable callable = () -> { - try { - // Use the cacheProps that is already in the cache. - MessageCacheItem updatedCacheItem = populateCache(cacheService, dto, cacheItem); - return updatedCacheItem; - } catch (Exception e) { - // To make sure that the thread will close - // even when an exception is thrown - return null; - } - }; - FutureTask task = new FutureTask(callable); - Thread thread = new Thread(task); - thread.start(); - } - - private MessageCacheItem populateCache(CacheService cacheService, MessagesDTO dto, MessageCacheItem cacheItem) { - // Pass cacheitem to getMessages so that: - // 1. A previously stored etag, if any, can be used for the next HTTP request. - // 2. CacheItem properties such as etag, timestamp and maxAgeMillis can be refreshed - // with new properties from the next HTTP response. - new ComponentService(dto).getMessages(cacheItem, VIPCfg.getInstance().getMsgOriginsQueue().listIterator()); - - return cacheItem; - } public String postString(MessagesDTO dto) { String r = ""; diff --git a/src/main/java/com/vmware/vipclient/i18n/util/ConstantsKeys.java b/src/main/java/com/vmware/vipclient/i18n/util/ConstantsKeys.java index 1a19826d2..86bd07f63 100644 --- a/src/main/java/com/vmware/vipclient/i18n/util/ConstantsKeys.java +++ b/src/main/java/com/vmware/vipclient/i18n/util/ConstantsKeys.java @@ -67,5 +67,4 @@ public class ConstantsKeys { public static final String DISPLAY_NAME = "displayName"; public static final String JSON_KEYSET = "jsonkeyset"; public static final String TRANSLATION_STATUS = "translationStatus"; - }