/* * Copyright 2015 Evgeny Dolganov (evgenij.dolganov@gmail.com). * * 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. */ package och.service.props.impl; import static java.lang.System.*; import static och.util.Util.*; import java.util.Map.Entry; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import och.service.props.Props; import och.service.props.net.GetUpdateReq; import och.service.props.net.GetUpdateResp; import och.util.concurrent.AsyncListener; import och.util.concurrent.ExecutorsUtil; import och.util.model.SecureKeyHolder; import och.util.socket.json.client.JsonSocketClient; import org.apache.commons.logging.Log; public class NetPropsClient implements SecureKeyHolder { public static final String CONFIG_SLEEP_TO_INIT_RETRY = "NetPropsClient.sleepToInitRetry"; public static final String CONFIG_RETRY_COUNT = "NetPropsClient.retryCount"; private Log log = getLog(getClass()); private JsonSocketClient jsonSocketClient; private ScheduledExecutorService scheduledService; private long delta; //wait config private long sleepToInitRetry = tryParseInt(getProperty(CONFIG_SLEEP_TO_INIT_RETRY), 2000); private int initRetryCount = tryParseInt(getProperty(CONFIG_RETRY_COUNT), -1); //model private final MultiProps externalProps; private MapProps intProps; public NetPropsClient(String host, int port, String secureKey, boolean waitConnect) { this(host, port, secureKey, waitConnect, 1000*60*2, 10000); } public NetPropsClient(String host, int port, String secureKey, boolean waitConnect, long updateTimeMs) { this(host, port, secureKey, waitConnect, updateTimeMs, 10000); } public NetPropsClient(String host, int port, String secureKey, boolean waitConnect, long updateTimeMs, Integer socketSoTimeout) { jsonSocketClient = new JsonSocketClient(host, port, 1, 1, socketSoTimeout); jsonSocketClient.setSecureKey(secureKey); intProps = new MapProps(); externalProps = new MultiProps(intProps); //first load boolean loaded = updateFromNetIfNeed(); while(waitConnect && !loaded){ if(initRetryCount > -1){ if(initRetryCount == 0) throw new IllegalStateException("can't init props - no connection to server"); initRetryCount--; } log.info("wait connection to server ("+sleepToInitRetry/1000.+"s)..."); try { Thread.sleep(sleepToInitRetry); }catch(Exception e){ throw new IllegalStateException("can't sleep to wait", e); } loaded = updateFromNetIfNeed(); } //server ping updateTimeMs = updateTimeMs > 0 && updateTimeMs < 50? 50 : updateTimeMs; if(updateTimeMs > 0){ scheduledService = ExecutorsUtil.newScheduledThreadPool("NetPropsClient", 1); scheduledService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { updateFromNetIfNeed(); } }, updateTimeMs, updateTimeMs, TimeUnit.MILLISECONDS); } } public void addListener(AsyncListener l){ jsonSocketClient.addListener(l); } public Props getProps() { return externalProps; } @Override public void setSecureKey(String key){ jsonSocketClient.setSecureKey(key); } @Override public boolean isSecuredByKey(){ return jsonSocketClient.isSecuredByKey(); } public void shutdown(){ scheduledService.shutdown(); } public synchronized boolean updateFromNetIfNeed() { try { GetUpdateResp res = (GetUpdateResp)jsonSocketClient.invoke(new GetUpdateReq(delta)); if(isEmpty(res)) return true; delta = res.delta; res = res.putDeletedKeysToUpdates(); if(isEmpty(res.updated)) return true; if(res.full) { log.info("load props from "+jsonSocketClient.getRemoteAddress()+": "+res.updated.keySet()); intProps = new MapProps(res.updated); externalProps.resetSources(intProps); } else { log.info("load updates from "+jsonSocketClient.getRemoteAddress()+": "+res.updated.keySet()); for (Entry<String, String> entry : res.updated.entrySet()) { intProps.putVal(entry.getKey(), entry.getValue()); } } return true; }catch(Throwable t){ log.error("can't load props from "+jsonSocketClient.getRemoteAddress()+": "+t); return false; } } }