/* * #%L * Even Distribution Service Locator Selection Strategy * %% * Copyright (C) 2011 - 2012 Talend Inc. * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package org.talend.esb.servicelocator.cxf.internal; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.namespace.QName; import org.talend.esb.servicelocator.client.SLPropertiesMatcher; import org.talend.esb.servicelocator.client.ServiceLocator; import org.talend.esb.servicelocator.client.ServiceLocatorException; public class LocatorCache { private static Map<String, List<String>> cachedAddresses = new HashMap<String, List<String>>(); private static Map<String, Integer> lastIndex = new HashMap<String, Integer>(); private static Map<String, Integer> cacheCounter = new HashMap<String, Integer>(); private ServiceLocator serviceLocator; private SLPropertiesMatcher matcher = SLPropertiesMatcher.ALL_MATCHER; private int reloadCount = 10; private Random random = new Random(); private String strategyId = ""; static final Logger LOG = Logger.getLogger(LocatorCache.class.getName()); public void setMatcher(SLPropertiesMatcher matcher) { this.matcher = matcher; } public void setServiceLocator(ServiceLocator serviceLocator) { this.serviceLocator = serviceLocator; } public void setReloadCount(int reloadCount) { this.reloadCount = reloadCount; } public void setStrategyId(String strategyId) { this.strategyId = strategyId; } synchronized String getPrimaryAddressSame(QName serviceName) { List<String> endpoints = getEndpoints(serviceName, false); if (endpoints == null || endpoints.isEmpty()) return null; String key = getPrimaryAddressKey(serviceName); if (!lastIndex.containsKey(key) || lastIndex.get(key) >= endpoints.size()) { lastIndex.put(key, random.nextInt(endpoints.size())); } String primaryAddress = endpoints.get(lastIndex.get(key)); cacheCounter.put(key, 0); // cache never expires for this strategy if (LOG.isLoggable(Level.INFO)) { LOG.log(Level.INFO, "Get same primary address for service " + serviceName + " selecting from " + endpoints + " selected = " + primaryAddress); } return primaryAddress; } synchronized String getPrimaryAddressNext(QName serviceName) { List<String> endpoints = getEndpoints(serviceName, false); if (endpoints == null || endpoints.isEmpty()) return null; String key = getPrimaryAddressKey(serviceName); if (!lastIndex.containsKey(key)) { lastIndex.put(key, random.nextInt(endpoints.size())); } else { lastIndex.put(key, (lastIndex.get(key) + 1) % endpoints.size()); } String primaryAddress = endpoints.get(lastIndex.get(key)); if (LOG.isLoggable(Level.INFO)) { LOG.log(Level.INFO, "Get next primary address for service " + serviceName + " selecting from " + endpoints + " selected = " + primaryAddress); } return primaryAddress; } synchronized String getPrimaryAddressRandom(QName serviceName) { List<String> endpoints = getEndpoints(serviceName, false); if (endpoints == null || endpoints.isEmpty()) return null; String key = getPrimaryAddressKey(serviceName); lastIndex.put(key, random.nextInt(endpoints.size())); String primaryAddress = endpoints.get(lastIndex.get(key)); if (LOG.isLoggable(Level.INFO)) { LOG.log(Level.INFO, "Get random primary address for service " + serviceName + " selecting from " + endpoints + " selected = " + primaryAddress); } return primaryAddress; } synchronized List<String> getFailoverEndpoints(QName serviceName) { List<String> endpoints = getEndpoints(serviceName, true); return new ArrayList<String>(endpoints); } private synchronized List<String> getEndpoints(QName serviceName, boolean isFailover) { List<String> endpoints = Collections.emptyList(); String key = getPrimaryAddressKey(serviceName); if (isFailover || !cacheCounter.containsKey(key) || cacheCounter.get(key) >= reloadCount) { endpoints = getLocatorEndpoints(serviceName); if (endpoints != null && !endpoints.isEmpty()) { cachedAddresses.put(key, endpoints); cacheCounter.put(key, 1); } } else { cacheCounter.put(key, cacheCounter.get(key) + 1); endpoints = cachedAddresses.get(key); } return endpoints; } private String getPrimaryAddressKey(QName serviceName) { return strategyId + "." + matcher == null ? serviceName.toString() : serviceName.toString() + "." + matcher.getAssertionsAsString(); } synchronized private List<String> getLocatorEndpoints(QName serviceName) { List<String> endpoints = Collections.emptyList(); try { endpoints = serviceLocator.lookup(serviceName, matcher); if (LOG.isLoggable(Level.INFO)) { LOG.log(Level.INFO, "serviceLocator.lookup " + " serviceName = " + serviceName + " matcher = " + matcher.getAssertionsAsString() + " endpoints " + endpoints); } } catch (ServiceLocatorException e) { if (LOG.isLoggable(Level.SEVERE)) { LOG.log(Level.SEVERE, "Can not refresh list of endpoints due to ServiceLocatorException", e); } } catch (InterruptedException e) { if (LOG.isLoggable(Level.SEVERE)) { LOG.log(Level.SEVERE, "Can not refresh list of endpoints due to InterruptedException", e); } } return endpoints; } }