package com.ctrip.hermes.core.meta.remote;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.fluent.Request;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.annotation.Named;

import com.alibaba.fastjson.JSON;
import com.ctrip.hermes.core.config.CoreConfig;
import com.ctrip.hermes.core.env.ClientEnvironment;
import com.ctrip.hermes.core.meta.internal.MetaLoader;
import com.ctrip.hermes.core.utils.StringUtils;
import com.ctrip.hermes.meta.entity.Meta;

@Named(type = MetaLoader.class, value = RemoteMetaLoader.ID)
public class RemoteMetaLoader implements MetaLoader {

	private static final Logger log = LoggerFactory.getLogger(RemoteMetaLoader.class);

	public static final String ID = "remote-meta-loader";

	@Inject
	private ClientEnvironment m_clientEnvironment;

	@Inject
	private MetaServerLocator m_metaServerLocator;

	@Inject
	private CoreConfig m_config;

	private AtomicReference<Meta> m_metaCache = new AtomicReference<Meta>(null);

	@Override
	public Meta load() {
		List<String> metaServerList = m_metaServerLocator.getMetaServerList();
		if (metaServerList == null || metaServerList.isEmpty()) {
			throw new RuntimeException("No meta server found.");
		}

		List<String> ipPorts = new ArrayList<String>(metaServerList);

		Collections.shuffle(ipPorts);

		Meta fetchedMeta = null;
		for (String ipPort : ipPorts) {
			if (log.isDebugEnabled()) {
				log.debug("Loading meta from server: {}", ipPort);
			}

			String url = null;
			try {
				String uri = m_clientEnvironment.getGlobalConfig().getProperty("meta.fetch.remote.uri");
				if (StringUtils.isBlank(uri)) {
					if (log.isDebugEnabled()) {
						log.debug("Can not find meta fetch uri, use \"/meta\" as default.");
					}
					uri = "/meta";
				}

				url = String.format("http://%s%s", ipPort, uri);
				if (m_metaCache.get() != null) {
					url += "?version=" + m_metaCache.get().getVersion();
				}

				HttpResponse response = Request.Get(url)//
				      .connectTimeout(m_config.getMetaServerConnectTimeout())//
				      .socketTimeout(m_config.getMetaServerReadTimeout())//
				      .execute()//
				      .returnResponse();

				int statusCode = response.getStatusLine().getStatusCode();

				if (statusCode == HttpStatus.SC_OK) {
					String responseContent = EntityUtils.toString(response.getEntity());
					try {
						fetchedMeta = JSON.parseObject(responseContent, Meta.class);
						m_metaCache.set(fetchedMeta);
						return m_metaCache.get();
					} catch (Exception e) {
						log.warn("Parse meta failed, from URL %s, Reason %s", url, e.getMessage());
						log.warn("Got meta: " + responseContent);
					}
				} else if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
					return m_metaCache.get();
				}
			} catch (Exception e) {
				log.warn("Load meta failed, from URL %s, will retry other meta servers, Reason %s", url, e.getMessage());
				// ignore
			}
		}
		throw new RuntimeException(String.format("Failed to load remote meta from %s", ipPorts));
	}

}

@@ -2813,18 +2813,18 @@
 rom URL 
-%25s
+%7B%7D
 , Reason
@@ -2816,34 +2816,34 @@
  URL %7B%7D, Reason 
-%25s
+%7B%7D
 %22, url, e.getMes
@@ -3070,18 +3070,18 @@
 rom URL 
-%25s
+%7B%7D
 , will r
@@ -3112,18 +3112,18 @@
  Reason 
-%25s
+%7B%7D
 %22, url, 

fix remote meta loader log bug