package org.springframework.cloud.pcf.configserver;

import org.springframework.cloud.Cloud;
import org.springframework.cloud.CloudFactory;
import org.springframework.cloud.service.ServiceInfo;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Collections;

/**
 * Connector to Config Server service
 *
 * @author Chris Schaefer
 */
@Configuration
public class ConfigServerServiceConnector implements ApplicationListener<ApplicationEvent>, Ordered {
	/**
	 * TODO:
	 * Bind ApplicationListener to ApplicationEnvironmentPreparedEvent, remove reflection
	 * and add test after repo migration in which we will have a direct dependency on boot.
	 */

	private static final String PROPERTY_SOURCE_NAME = "vcapConfigServerUri";
	private static final String EVENT_ENVIRONMENT_METHOD_NAME = "getEnvironment";
	private static final String SPRING_CLOUD_CONFIG_URI = "spring.cloud.config.uri";
	private static final String EVENT_CLASS_NAME = "org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent";

	private Cloud cloud;

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if(!supports(event.getClass().getName()) || cloud != null) {
			return;
		}

		cloud = new CloudFactory().getCloud();

		for(ServiceInfo serviceInfo : cloud.getServiceInfos()) {
			if(serviceInfo instanceof ConfigServerServiceInfo) {
				String uri = ((ConfigServerServiceInfo) serviceInfo).getUri();

				MapPropertySource mapPropertySource = new MapPropertySource(PROPERTY_SOURCE_NAME,
						Collections.<String, Object>singletonMap(SPRING_CLOUD_CONFIG_URI, uri));

				getEnvironment(event).getPropertySources().addFirst(mapPropertySource);
			}
		}
	}

	private boolean supports(String className) {
		return EVENT_CLASS_NAME.equals(className);
	}

	private ConfigurableEnvironment getEnvironment(ApplicationEvent event) {
		Method method = ReflectionUtils.findMethod(event.getClass(), EVENT_ENVIRONMENT_METHOD_NAME);

		try {
			return (ConfigurableEnvironment) method.invoke(event);
		} catch (Exception e) {
			throw new RuntimeException("Error obtaining Environment from event", e);
		}
	}

	@Override
	public int getOrder() {
		return Ordered.HIGHEST_PRECEDENCE + 4;
	}
}

@@ -46,16 +46,99 @@
 erver;%0A%0A
+import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;%0A
 import o
@@ -274,61 +274,8 @@
 fo;%0A
-import org.springframework.context.ApplicationEvent;%0A
 impo
@@ -468,170 +468,27 @@
 env.
-ConfigurableEnvironment;%0Aimport org.springframework.core.env.MapPropertySource;%0Aimport org.springframework.util.ReflectionUtils;%0A%0Aimport java.lang.reflect.Method;
+MapPropertySource;%0A
 %0Aimp
@@ -682,84 +682,8 @@
 ner%3C
-ApplicationEvent%3E, Ordered %7B%0A%09/**%0A%09 * TODO:%0A%09 * Bind ApplicationListener to 
 Appl
@@ -717,482 +717,175 @@
 vent
+%3E
 , 
-remove reflection%0A%09 * and add test after repo migration in which we will have a direct dependency on boot.%0A%09 */%0A%0A%09private static final String PROPERTY_SOURCE_NAME = %22vcapConfigServerUri%22;%0A%09private static final String EVENT_ENVIRONMENT_METHOD_NAME = %22getEnvironment%22;%0A%09private static final String SPRING_CLOUD_CONFIG_URI = %22spring.cloud.config.uri%22;%0A%09private static final String EVENT_CLASS_NAME = %22org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent
+Ordered %7B%0A%09private static final String PROPERTY_SOURCE_NAME = %22vcapConfigServerUri%22;%0A%09private static final String SPRING_CLOUD_CONFIG_URI = %22spring.cloud.config.uri
 %22;%0A%0A
@@ -954,32 +954,51 @@
 ent(ApplicationE
+nvironmentPreparedE
 vent event) %7B%0A%09%09
@@ -1004,49 +1004,8 @@
 %09if(
-!supports(event.getClass().getName()) %7C%7C 
 clou
@@ -1428,16 +1428,22 @@
 );%0A%0A%09%09%09%09
+event.
 getEnvir
@@ -1449,21 +1449,16 @@
 ronment(
-event
 ).getPro
@@ -1518,449 +1518,8 @@
 %09%7D%0A%0A
-%09private boolean supports(String className) %7B%0A%09%09return EVENT_CLASS_NAME.equals(className);%0A%09%7D%0A%0A%09private ConfigurableEnvironment getEnvironment(ApplicationEvent event) %7B%0A%09%09Method method = ReflectionUtils.findMethod(event.getClass(), EVENT_ENVIRONMENT_METHOD_NAME);%0A%0A%09%09try %7B%0A%09%09%09return (ConfigurableEnvironment) method.invoke(event);%0A%09%09%7D catch (Exception e) %7B%0A%09%09%09throw new RuntimeException(%22Error obtaining Environment from event%22, e);%0A%09%09%7D%0A%09%7D%0A%0A
 %09@Ov

Remove event reflection usage and bind to boot ApplicationEnvironmentPreparedEvent directly