/
LocalConfigConnector.java
199 lines (158 loc) · 6.91 KB
/
LocalConfigConnector.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package org.springframework.cloud.localconfig;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.springframework.cloud.AbstractCloudConnector;
import org.springframework.cloud.FallbackServiceInfoCreator;
import org.springframework.cloud.app.ApplicationInstanceInfo;
import org.springframework.cloud.app.BasicApplicationInstanceInfo;
import org.springframework.cloud.service.BaseServiceInfo;
import org.springframework.cloud.service.FallbackBaseServiceInfoCreator;
import org.springframework.cloud.service.UriBasedServiceData;
import org.springframework.cloud.util.EnvironmentAccessor;
/**
*
* @author Christopher Smith
*
*/
public class LocalConfigConnector extends AbstractCloudConnector<UriBasedServiceData> {
private static final Logger logger = Logger.getLogger(LocalConfigConnector.class.getName());
/*--------------- String constants for property keys ---------------*/
public static final String PROPERTY_PREFIX = "spring.cloud.";
public static final Pattern SERVICE_PROPERTY_PATTERN = Pattern.compile("\\A" + Pattern.quote(PROPERTY_PREFIX) + "(.+)" + "\\Z");
public static final String APP_ID_PROPERTY = PROPERTY_PREFIX + "appId";
public static final String PROPERTIES_FILE_PROPERTY = PROPERTY_PREFIX + "propertiesFile";
/**
* These properties configure the connector itself and aren't service definitions.
*/
public static final List<String> META_PROPERTIES = Collections.unmodifiableList(
Arrays.asList(new String[] { APP_ID_PROPERTY, PROPERTIES_FILE_PROPERTY }));
/*--------------- inject system property access for testing ---------------*/
private EnvironmentAccessor env = new EnvironmentAccessor();
void setEnvironmentAccessor(EnvironmentAccessor env) {
this.env = env;
}
/*--------------- API implementation ---------------*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public LocalConfigConnector() {
super((Class) LocalConfigServiceInfoCreator.class);
}
/*--------------- properties read out of the file at spring.cloud.propertiesFile ---------------*/
private Properties fileProperties = null;
/**
* Returns {@code true} if a property named {@code spring.cloud.appId} is present in any of the property sources.
* On the first call, attempts to load properties from a file specified in {@code spring.cloud.propertiesFile}.
*/
@Override
public boolean isInMatchingCloud() {
if (fileProperties == null)
readFileProperties();
String appId = findProperty(APP_ID_PROPERTY);
if (appId == null)
logger.info("the property " + APP_ID_PROPERTY + " was not found in the system properties or configuration file");
return appId != null;
}
@Override
public ApplicationInstanceInfo getApplicationInstanceInfo() {
return new BasicApplicationInstanceInfo(UUID.randomUUID().toString(), findProperty(APP_ID_PROPERTY),
Collections.<String, Object> emptyMap());
}
@Override
protected List<UriBasedServiceData> getServicesData() {
if (fileProperties == null)
throw new IllegalStateException("isInMatchingCloud() must be called first to initialize connector");
LinkedHashMap<String, Properties> propertySources = new LinkedHashMap<String, Properties>();
propertySources.put("properties from file", fileProperties);
try {
propertySources.put("system properties", env.getSystemProperties());
} catch (SecurityException e) {
logger.log(Level.WARNING,
"couldn't read system properties; no service definitions from system properties will be applied", e);
}
return LocalConfigUtil.readServicesData(propertySources);
}
@Override
protected FallbackServiceInfoCreator<BaseServiceInfo, UriBasedServiceData> getFallbackServiceInfoCreator() {
return new FallbackBaseServiceInfoCreator();
}
/*--------------- methods for manipulating properties and sources ---------------*/
/**
* Checks for the presence of a supplied or system property named {@code spring.cloud.propertiesFile}. If the property
* is present, load its contents into {@link #fileProperties}. If there's a problem, log but continue.
*/
private void readFileProperties() {
fileProperties = new Properties();
logger.fine("looking for a properties file");
// will search system properties and the classpath
File propertiesFile = new PropertiesFileResolver(env).findCloudPropertiesFile();
if (propertiesFile == null) {
logger.info("not loading service definitions from a properties file");
return;
}
if (!fileExists(propertiesFile)) {
logger.info("properties file " + propertiesFile + " does not exist; probably running in a real cloud");
return;
}
logger.info("loading service definitions from properties file " + propertiesFile);
try {
InputStream fis = openFile(propertiesFile);
fileProperties.load(fis);
fis.close();
} catch (IOException e) {
logger.log(Level.SEVERE, "exception while loading properties from file " + propertiesFile, e);
return;
}
logger.info("properties loaded successfully");
}
/**
* Broken out into a separate method for mocking the filesystem.
*
* @param file
* the file to check
* @return whether the file exists
*/
boolean fileExists(File file) {
return file.exists();
}
/**
* Broken out into a separate method for mocking the filesystem.
*
* @param file
* the file to open
* @return a {@code FileInputStream} to the file
* @throws IOException
* if opening the file throws
*/
InputStream openFile(File file) throws IOException {
return new FileInputStream(file);
}
/**
* Look for a specific property in the config file or the system properties.
*
* @param key
* the property to look for
* @return the preferred value for the key, or {@code null} if the key is not found
*/
private String findProperty(String key) {
String value = fileProperties.getProperty(key);
try {
value = env.getSystemProperty(key, value);
} catch (SecurityException e) {
logSystemReadException(key, e);
}
return value;
}
private static void logSystemReadException(String key, SecurityException e) {
logger.log(Level.WARNING, "couldn't read system property " + key, e);
}
}