返回列表 上一筆 下一筆

📄 資料內容

package com.taiwanlife.agw.webservice.config;

import java.util.Iterator;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;

import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.HeaderElement;
import org.apache.hc.core5.http.HeaderElements;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.message.MessageSupport;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.hc.core5.util.TimeValue;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.client.RestTemplate;

import com.taiwanlife.agw.webservice.AgwWebServiceLog;

/**
 * - Supports both HTTP and HTTPS - Uses a connection pool to re-use connections
 * and save overhead of creating connections. - Has a custom connection
 * keep-alive strategy (to apply a default keep-alive if one isn't specified) -
 * Starts an idle connection monitor to continuously clean up stale connections.
 */
@Configuration
@EnableScheduling
public class HttpClientConfig implements AgwWebServiceLog {
	// private static final Logger LOGGER =
	// LoggerFactory.getLogger(HttpClientConfig.class);
	// Determines the timeout in milliseconds until a connection is established.
	@Value("${api.connectionPool.connectTimeout}")
	private int CONNECT_TIMEOUT;
	// The timeout when requesting a connection from the connection manager.
	@Value("${api.connectionPool.requestTimeout}")
	private int REQUEST_TIMEOUT;
	// The timeout for waiting for data
	@Value("${api.connectionPool.socketTimeout}")
	private int SOCKET_TIMEOUT;
	@Value("${api.connectionPool.maxTotalConnections}")
	private int MAX_TOTAL_CONNECTIONS;
	@Value("${api.connectionPool.defaultKeepAliveTimeMillis}")
	private int DEFAULT_KEEP_ALIVE_TIME_MILLIS;
	@Value("${api.connectionPool.closeIdleConnectionWaitTimeSecs}")
	private int CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS;

	// === 共用連線池 ===
	@Bean
	public PoolingHttpClientConnectionManager poolingConnectionManager() {
		return new PoolingHttpClientConnectionManager();
	}

	@Bean
	public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
		return new ConnectionKeepAliveStrategy() {
			@Override
			public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context) {
				final Iterator<HeaderElement> it = MessageSupport.iterate(response, HeaderElements.KEEP_ALIVE);
				if (it.hasNext()) {
					final HeaderElement he = it.next();
					final String param = he.getName();
					final String value = he.getValue();
					if (value != null && param.equalsIgnoreCase("timeout")) {
						return TimeValue.ofSeconds(Long.parseLong(value));
					}
				}
				return TimeValue.ofSeconds(DEFAULT_KEEP_ALIVE_TIME_MILLIS);
			}
		};
	}

	// === 一般的 HttpClient ===
	@Bean
	public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager connectionManager) {
		RequestConfig config = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
				.setConnectionRequestTimeout(REQUEST_TIMEOUT, TimeUnit.MILLISECONDS)
				.setResponseTimeout(SOCKET_TIMEOUT, TimeUnit.MILLISECONDS).build();

		return HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(config)
				.setKeepAliveStrategy(connectionKeepAliveStrategy()).evictIdleConnections(TimeValue.ofMinutes(5))
				.build();
	}

	// === 一般的 RestTemplate ===
	@Bean(name = "secureRestTemplate")
	public RestTemplate secureRestTemplate(CloseableHttpClient httpClient) {
		return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
	}

	// === 繞過 SSL 驗證的 HttpClient ===
	@Bean(name = "insecureHttpClient")
	public CloseableHttpClient insecureHttpClient() throws Exception {
		SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build();

		SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
				NoopHostnameVerifier.INSTANCE);

		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
				.register("https", socketFactory).register("http", new PlainConnectionSocketFactory()).build();

		PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
		connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS);
		connectionManager.setDefaultMaxPerRoute(20);

		RequestConfig config = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
				.setConnectionRequestTimeout(REQUEST_TIMEOUT, TimeUnit.MILLISECONDS)
				.setResponseTimeout(SOCKET_TIMEOUT, TimeUnit.MILLISECONDS).build();

		return HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(config)
				.setKeepAliveStrategy(connectionKeepAliveStrategy()).evictIdleConnections(TimeValue.ofMinutes(5))
				.build();
	}

	// === 繞過 SSL 驗證的 RestTemplate ===
	@Bean(name = "insecureRestTemplate")
	public RestTemplate insecureRestTemplate(@Qualifier("insecureHttpClient") CloseableHttpClient httpClient) {
		return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
	}

	// === 閒置連線清理排程 ===
	@Bean
	public Runnable idleConnectionMonitor(PoolingHttpClientConnectionManager connectionManager) {
		return new Runnable() {
			@Override
			@Scheduled(fixedDelay = 10000)
			public void run() {
				try {
					LOGGER.debug("IdleConnectionMonitor - Closing expired and idle connections...");
					connectionManager.closeExpired();
					connectionManager.closeIdle(TimeValue.ofSeconds(CLOSE_IDLE_CONNECTION_WAIT_TIME_SECS));
				} catch (Exception e) {
					LOGGER.error("IdleConnectionMonitor - Exception occurred: {}", e.getMessage(), e);
				}
			}
		};
	}

}

🔐 Base64 編碼內容

cGFja2FnZSBjb20udGFpd2FubGlmZS5hZ3cud2Vic2VydmljZS5jb25maWc7CgppbXBvcnQgamF2YS51dGlsLkl0ZXJhdG9yOwppbXBvcnQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGltZVVuaXQ7CgppbXBvcnQgamF2YXgubmV0LnNzbC5TU0xDb250ZXh0OwoKaW1wb3J0IG9yZy5hcGFjaGUuaGMuY2xpZW50NS5odHRwLkNvbm5lY3Rpb25LZWVwQWxpdmVTdHJhdGVneTsKaW1wb3J0IG9yZy5hcGFjaGUuaGMuY2xpZW50NS5odHRwLmNvbmZpZy5SZXF1ZXN0Q29uZmlnOwppbXBvcnQgb3JnLmFwYWNoZS5oYy5jbGllbnQ1Lmh0dHAuaW1wbC5jbGFzc2ljLkNsb3NlYWJsZUh0dHBDbGllbnQ7CmltcG9ydCBvcmcuYXBhY2hlLmhjLmNsaWVudDUuaHR0cC5pbXBsLmNsYXNzaWMuSHR0cENsaWVudHM7CmltcG9ydCBvcmcuYXBhY2hlLmhjLmNsaWVudDUuaHR0cC5pbXBsLmlvLlBvb2xpbmdIdHRwQ2xpZW50Q29ubmVjdGlvbk1hbmFnZXI7CmltcG9ydCBvcmcuYXBhY2hlLmhjLmNsaWVudDUuaHR0cC5zb2NrZXQuQ29ubmVjdGlvblNvY2tldEZhY3Rvcnk7CmltcG9ydCBvcmcuYXBhY2hlLmhjLmNsaWVudDUuaHR0cC5zb2NrZXQuUGxhaW5Db25uZWN0aW9uU29ja2V0RmFjdG9yeTsKaW1wb3J0IG9yZy5hcGFjaGUuaGMuY2xpZW50NS5odHRwLnNzbC5Ob29wSG9zdG5hbWVWZXJpZmllcjsKaW1wb3J0IG9yZy5hcGFjaGUuaGMuY2xpZW50NS5odHRwLnNzbC5TU0xDb25uZWN0aW9uU29ja2V0RmFjdG9yeTsKaW1wb3J0IG9yZy5hcGFjaGUuaGMuY29yZTUuaHR0cC5IZWFkZXJFbGVtZW50OwppbXBvcnQgb3JnLmFwYWNoZS5oYy5jb3JlNS5odHRwLkhlYWRlckVsZW1lbnRzOwppbXBvcnQgb3JnLmFwYWNoZS5oYy5jb3JlNS5odHRwLkh0dHBSZXNwb25zZTsKaW1wb3J0IG9yZy5hcGFjaGUuaGMuY29yZTUuaHR0cC5jb25maWcuUmVnaXN0cnk7CmltcG9ydCBvcmcuYXBhY2hlLmhjLmNvcmU1Lmh0dHAuY29uZmlnLlJlZ2lzdHJ5QnVpbGRlcjsKaW1wb3J0IG9yZy5hcGFjaGUuaGMuY29yZTUuaHR0cC5tZXNzYWdlLk1lc3NhZ2VTdXBwb3J0OwppbXBvcnQgb3JnLmFwYWNoZS5oYy5jb3JlNS5odHRwLnByb3RvY29sLkh0dHBDb250ZXh0OwppbXBvcnQgb3JnLmFwYWNoZS5oYy5jb3JlNS5zc2wuU1NMQ29udGV4dEJ1aWxkZXI7CmltcG9ydCBvcmcuYXBhY2hlLmhjLmNvcmU1LnV0aWwuVGltZVZhbHVlOwppbXBvcnQgb3JnLnNwcmluZ2ZyYW1ld29yay5iZWFucy5mYWN0b3J5LmFubm90YXRpb24uUXVhbGlmaWVyOwppbXBvcnQgb3JnLnNwcmluZ2ZyYW1ld29yay5iZWFucy5mYWN0b3J5LmFubm90YXRpb24uVmFsdWU7CmltcG9ydCBvcmcuc3ByaW5nZnJhbWV3b3JrLmNvbnRleHQuYW5ub3RhdGlvbi5CZWFuOwppbXBvcnQgb3JnLnNwcmluZ2ZyYW1ld29yay5jb250ZXh0LmFubm90YXRpb24uQ29uZmlndXJhdGlvbjsKaW1wb3J0IG9yZy5zcHJpbmdmcmFtZXdvcmsuaHR0cC5jbGllbnQuSHR0cENvbXBvbmVudHNDbGllbnRIdHRwUmVxdWVzdEZhY3Rvcnk7CmltcG9ydCBvcmcuc3ByaW5nZnJhbWV3b3JrLnNjaGVkdWxpbmcuYW5ub3RhdGlvbi5FbmFibGVTY2hlZHVsaW5nOwppbXBvcnQgb3JnLnNwcmluZ2ZyYW1ld29yay5zY2hlZHVsaW5nLmFubm90YXRpb24uU2NoZWR1bGVkOwppbXBvcnQgb3JnLnNwcmluZ2ZyYW1ld29yay53ZWIuY2xpZW50LlJlc3RUZW1wbGF0ZTsKCmltcG9ydCBjb20udGFpd2FubGlmZS5hZ3cud2Vic2VydmljZS5BZ3dXZWJTZXJ2aWNlTG9nOwoKLyoqCiAqIC0gU3VwcG9ydHMgYm90aCBIVFRQIGFuZCBIVFRQUyAtIFVzZXMgYSBjb25uZWN0aW9uIHBvb2wgdG8gcmUtdXNlIGNvbm5lY3Rpb25zCiAqIGFuZCBzYXZlIG92ZXJoZWFkIG9mIGNyZWF0aW5nIGNvbm5lY3Rpb25zLiAtIEhhcyBhIGN1c3RvbSBjb25uZWN0aW9uCiAqIGtlZXAtYWxpdmUgc3RyYXRlZ3kgKHRvIGFwcGx5IGEgZGVmYXVsdCBrZWVwLWFsaXZlIGlmIG9uZSBpc24ndCBzcGVjaWZpZWQpIC0KICogU3RhcnRzIGFuIGlkbGUgY29ubmVjdGlvbiBtb25pdG9yIHRvIGNvbnRpbnVvdXNseSBjbGVhbiB1cCBzdGFsZSBjb25uZWN0aW9ucy4KICovCkBDb25maWd1cmF0aW9uCkBFbmFibGVTY2hlZHVsaW5nCnB1YmxpYyBjbGFzcyBIdHRwQ2xpZW50Q29uZmlnIGltcGxlbWVudHMgQWd3V2ViU2VydmljZUxvZyB7CgkvLyBwcml2YXRlIHN0YXRpYyBmaW5hbCBMb2dnZXIgTE9HR0VSID0KCS8vIExvZ2dlckZhY3RvcnkuZ2V0TG9nZ2VyKEh0dHBDbGllbnRDb25maWcuY2xhc3MpOwoJLy8gRGV0ZXJtaW5lcyB0aGUgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgdW50aWwgYSBjb25uZWN0aW9uIGlzIGVzdGFibGlzaGVkLgoJQFZhbHVlKCIke2FwaS5jb25uZWN0aW9uUG9vbC5jb25uZWN0VGltZW91dH0iKQoJcHJpdmF0ZSBpbnQgQ09OTkVDVF9USU1FT1VUOwoJLy8gVGhlIHRpbWVvdXQgd2hlbiByZXF1ZXN0aW5nIGEgY29ubmVjdGlvbiBmcm9tIHRoZSBjb25uZWN0aW9uIG1hbmFnZXIuCglAVmFsdWUoIiR7YXBpLmNvbm5lY3Rpb25Qb29sLnJlcXVlc3RUaW1lb3V0fSIpCglwcml2YXRlIGludCBSRVFVRVNUX1RJTUVPVVQ7CgkvLyBUaGUgdGltZW91dCBmb3Igd2FpdGluZyBmb3IgZGF0YQoJQFZhbHVlKCIke2FwaS5jb25uZWN0aW9uUG9vbC5zb2NrZXRUaW1lb3V0fSIpCglwcml2YXRlIGludCBTT0NLRVRfVElNRU9VVDsKCUBWYWx1ZSgiJHthcGkuY29ubmVjdGlvblBvb2wubWF4VG90YWxDb25uZWN0aW9uc30iKQoJcHJpdmF0ZSBpbnQgTUFYX1RPVEFMX0NPTk5FQ1RJT05TOwoJQFZhbHVlKCIke2FwaS5jb25uZWN0aW9uUG9vbC5kZWZhdWx0S2VlcEFsaXZlVGltZU1pbGxpc30iKQoJcHJpdmF0ZSBpbnQgREVGQVVMVF9LRUVQX0FMSVZFX1RJTUVfTUlMTElTOwoJQFZhbHVlKCIke2FwaS5jb25uZWN0aW9uUG9vbC5jbG9zZUlkbGVDb25uZWN0aW9uV2FpdFRpbWVTZWNzfSIpCglwcml2YXRlIGludCBDTE9TRV9JRExFX0NPTk5FQ1RJT05fV0FJVF9USU1FX1NFQ1M7CgoJLy8gPT09IOWFseeUqOmAo+e3muaxoCA9PT0KCUBCZWFuCglwdWJsaWMgUG9vbGluZ0h0dHBDbGllbnRDb25uZWN0aW9uTWFuYWdlciBwb29saW5nQ29ubmVjdGlvbk1hbmFnZXIoKSB7CgkJcmV0dXJuIG5ldyBQb29saW5nSHR0cENsaWVudENvbm5lY3Rpb25NYW5hZ2VyKCk7Cgl9CgoJQEJlYW4KCXB1YmxpYyBDb25uZWN0aW9uS2VlcEFsaXZlU3RyYXRlZ3kgY29ubmVjdGlvbktlZXBBbGl2ZVN0cmF0ZWd5KCkgewoJCXJldHVybiBuZXcgQ29ubmVjdGlvbktlZXBBbGl2ZVN0cmF0ZWd5KCkgewoJCQlAT3ZlcnJpZGUKCQkJcHVibGljIFRpbWVWYWx1ZSBnZXRLZWVwQWxpdmVEdXJhdGlvbihIdHRwUmVzcG9uc2UgcmVzcG9uc2UsIEh0dHBDb250ZXh0IGNvbnRleHQpIHsKCQkJCWZpbmFsIEl0ZXJhdG9yPEhlYWRlckVsZW1lbnQ+IGl0ID0gTWVzc2FnZVN1cHBvcnQuaXRlcmF0ZShyZXNwb25zZSwgSGVhZGVyRWxlbWVudHMuS0VFUF9BTElWRSk7CgkJCQlpZiAoaXQuaGFzTmV4dCgpKSB7CgkJCQkJZmluYWwgSGVhZGVyRWxlbWVudCBoZSA9IGl0Lm5leHQoKTsKCQkJCQlmaW5hbCBTdHJpbmcgcGFyYW0gPSBoZS5nZXROYW1lKCk7CgkJCQkJZmluYWwgU3RyaW5nIHZhbHVlID0gaGUuZ2V0VmFsdWUoKTsKCQkJCQlpZiAodmFsdWUgIT0gbnVsbCAmJiBwYXJhbS5lcXVhbHNJZ25vcmVDYXNlKCJ0aW1lb3V0IikpIHsKCQkJCQkJcmV0dXJuIFRpbWVWYWx1ZS5vZlNlY29uZHMoTG9uZy5wYXJzZUxvbmcodmFsdWUpKTsKCQkJCQl9CgkJCQl9CgkJCQlyZXR1cm4gVGltZVZhbHVlLm9mU2Vjb25kcyhERUZBVUxUX0tFRVBfQUxJVkVfVElNRV9NSUxMSVMpOwoJCQl9CgkJfTsKCX0KCgkvLyA9PT0g5LiA6Iis55qEIEh0dHBDbGllbnQgPT09CglAQmVhbgoJcHVibGljIENsb3NlYWJsZUh0dHBDbGllbnQgaHR0cENsaWVudChQb29saW5nSHR0cENsaWVudENvbm5lY3Rpb25NYW5hZ2VyIGNvbm5lY3Rpb25NYW5hZ2VyKSB7CgkJUmVxdWVzdENvbmZpZyBjb25maWcgPSBSZXF1ZXN0Q29uZmlnLmN1c3RvbSgpLnNldENvbm5lY3RUaW1lb3V0KENPTk5FQ1RfVElNRU9VVCwgVGltZVVuaXQuTUlMTElTRUNPTkRTKQoJCQkJLnNldENvbm5lY3Rpb25SZXF1ZXN0VGltZW91dChSRVFVRVNUX1RJTUVPVVQsIFRpbWVVbml0Lk1JTExJU0VDT05EUykKCQkJCS5zZXRSZXNwb25zZVRpbWVvdXQoU09DS0VUX1RJTUVPVVQsIFRpbWVVbml0Lk1JTExJU0VDT05EUykuYnVpbGQoKTsKCgkJcmV0dXJuIEh0dHBDbGllbnRzLmN1c3RvbSgpLnNldENvbm5lY3Rpb25NYW5hZ2VyKGNvbm5lY3Rpb25NYW5hZ2VyKS5zZXREZWZhdWx0UmVxdWVzdENvbmZpZyhjb25maWcpCgkJCQkuc2V0S2VlcEFsaXZlU3RyYXRlZ3koY29ubmVjdGlvbktlZXBBbGl2ZVN0cmF0ZWd5KCkpLmV2aWN0SWRsZUNvbm5lY3Rpb25zKFRpbWVWYWx1ZS5vZk1pbnV0ZXMoNSkpCgkJCQkuYnVpbGQoKTsKCX0KCgkvLyA9PT0g5LiA6Iis55qEIFJlc3RUZW1wbGF0ZSA9PT0KCUBCZWFuKG5hbWUgPSAic2VjdXJlUmVzdFRlbXBsYXRlIikKCXB1YmxpYyBSZXN0VGVtcGxhdGUgc2VjdXJlUmVzdFRlbXBsYXRlKENsb3NlYWJsZUh0dHBDbGllbnQgaHR0cENsaWVudCkgewoJCXJldHVybiBuZXcgUmVzdFRlbXBsYXRlKG5ldyBIdHRwQ29tcG9uZW50c0NsaWVudEh0dHBSZXF1ZXN0RmFjdG9yeShodHRwQ2xpZW50KSk7Cgl9CgoJLy8gPT09IOe5numBjiBTU0wg6amX6K2J55qEIEh0dHBDbGllbnQgPT09CglAQmVhbihuYW1lID0gImluc2VjdXJlSHR0cENsaWVudCIpCglwdWJsaWMgQ2xvc2VhYmxlSHR0cENsaWVudCBpbnNlY3VyZUh0dHBDbGllbnQoKSB0aHJvd3MgRXhjZXB0aW9uIHsKCQlTU0xDb250ZXh0IHNzbENvbnRleHQgPSBTU0xDb250ZXh0QnVpbGRlci5jcmVhdGUoKS5sb2FkVHJ1c3RNYXRlcmlhbCgoY2hhaW4sIGF1dGhUeXBlKSAtPiB0cnVlKS5idWlsZCgpOwoKCQlTU0xDb25uZWN0aW9uU29ja2V0RmFjdG9yeSBzb2NrZXRGYWN0b3J5ID0gbmV3IFNTTENvbm5lY3Rpb25Tb2NrZXRGYWN0b3J5KHNzbENvbnRleHQsCgkJCQlOb29wSG9zdG5hbWVWZXJpZmllci5JTlNUQU5DRSk7CgoJCVJlZ2lzdHJ5PENvbm5lY3Rpb25Tb2NrZXRGYWN0b3J5PiByZWdpc3RyeSA9IFJlZ2lzdHJ5QnVpbGRlci48Q29ubmVjdGlvblNvY2tldEZhY3Rvcnk+Y3JlYXRlKCkKCQkJCS5yZWdpc3RlcigiaHR0cHMiLCBzb2NrZXRGYWN0b3J5KS5yZWdpc3RlcigiaHR0cCIsIG5ldyBQbGFpbkNvbm5lY3Rpb25Tb2NrZXRGYWN0b3J5KCkpLmJ1aWxkKCk7CgoJCVBvb2xpbmdIdHRwQ2xpZW50Q29ubmVjdGlvbk1hbmFnZXIgY29ubmVjdGlvbk1hbmFnZXIgPSBuZXcgUG9vbGluZ0h0dHBDbGllbnRDb25uZWN0aW9uTWFuYWdlcihyZWdpc3RyeSk7CgkJY29ubmVjdGlvbk1hbmFnZXIuc2V0TWF4VG90YWwoTUFYX1RPVEFMX0NPTk5FQ1RJT05TKTsKCQljb25uZWN0aW9uTWFuYWdlci5zZXREZWZhdWx0TWF4UGVyUm91dGUoMjApOwoKCQlSZXF1ZXN0Q29uZmlnIGNvbmZpZyA9IFJlcXVlc3RDb25maWcuY3VzdG9tKCkuc2V0Q29ubmVjdFRpbWVvdXQoQ09OTkVDVF9USU1FT1VULCBUaW1lVW5pdC5NSUxMSVNFQ09ORFMpCgkJCQkuc2V0Q29ubmVjdGlvblJlcXVlc3RUaW1lb3V0KFJFUVVFU1RfVElNRU9VVCwgVGltZVVuaXQuTUlMTElTRUNPTkRTKQoJCQkJLnNldFJlc3BvbnNlVGltZW91dChTT0NLRVRfVElNRU9VVCwgVGltZVVuaXQuTUlMTElTRUNPTkRTKS5idWlsZCgpOwoKCQlyZXR1cm4gSHR0cENsaWVudHMuY3VzdG9tKCkuc2V0Q29ubmVjdGlvbk1hbmFnZXIoY29ubmVjdGlvbk1hbmFnZXIpLnNldERlZmF1bHRSZXF1ZXN0Q29uZmlnKGNvbmZpZykKCQkJCS5zZXRLZWVwQWxpdmVTdHJhdGVneShjb25uZWN0aW9uS2VlcEFsaXZlU3RyYXRlZ3koKSkuZXZpY3RJZGxlQ29ubmVjdGlvbnMoVGltZVZhbHVlLm9mTWludXRlcyg1KSkKCQkJCS5idWlsZCgpOwoJfQoKCS8vID09PSDnuZ7pgY4gU1NMIOmpl+itieeahCBSZXN0VGVtcGxhdGUgPT09CglAQmVhbihuYW1lID0gImluc2VjdXJlUmVzdFRlbXBsYXRlIikKCXB1YmxpYyBSZXN0VGVtcGxhdGUgaW5zZWN1cmVSZXN0VGVtcGxhdGUoQFF1YWxpZmllcigiaW5zZWN1cmVIdHRwQ2xpZW50IikgQ2xvc2VhYmxlSHR0cENsaWVudCBodHRwQ2xpZW50KSB7CgkJcmV0dXJuIG5ldyBSZXN0VGVtcGxhdGUobmV3IEh0dHBDb21wb25lbnRzQ2xpZW50SHR0cFJlcXVlc3RGYWN0b3J5KGh0dHBDbGllbnQpKTsKCX0KCgkvLyA9PT0g6ZaS572u6YCj57ea5riF55CG5o6S56iLID09PQoJQEJlYW4KCXB1YmxpYyBSdW5uYWJsZSBpZGxlQ29ubmVjdGlvbk1vbml0b3IoUG9vbGluZ0h0dHBDbGllbnRDb25uZWN0aW9uTWFuYWdlciBjb25uZWN0aW9uTWFuYWdlcikgewoJCXJldHVybiBuZXcgUnVubmFibGUoKSB7CgkJCUBPdmVycmlkZQoJCQlAU2NoZWR1bGVkKGZpeGVkRGVsYXkgPSAxMDAwMCkKCQkJcHVibGljIHZvaWQgcnVuKCkgewoJCQkJdHJ5IHsKCQkJCQlMT0dHRVIuZGVidWcoIklkbGVDb25uZWN0aW9uTW9uaXRvciAtIENsb3NpbmcgZXhwaXJlZCBhbmQgaWRsZSBjb25uZWN0aW9ucy4uLiIpOwoJCQkJCWNvbm5lY3Rpb25NYW5hZ2VyLmNsb3NlRXhwaXJlZCgpOwoJCQkJCWNvbm5lY3Rpb25NYW5hZ2VyLmNsb3NlSWRsZShUaW1lVmFsdWUub2ZTZWNvbmRzKENMT1NFX0lETEVfQ09OTkVDVElPTl9XQUlUX1RJTUVfU0VDUykpOwoJCQkJfSBjYXRjaCAoRXhjZXB0aW9uIGUpIHsKCQkJCQlMT0dHRVIuZXJyb3IoIklkbGVDb25uZWN0aW9uTW9uaXRvciAtIEV4Y2VwdGlvbiBvY2N1cnJlZDoge30iLCBlLmdldE1lc3NhZ2UoKSwgZSk7CgkJCQl9CgkJCX0KCQl9OwoJfQoKfQo=
返回列表 上一筆 下一筆