inti.ws.spring.resource.config.ResourceConfigProviderImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ws-spring-resource Show documentation
Show all versions of ws-spring-resource Show documentation
An utility library for spring-based web-services for compressing / optimizing JS and CSS resources.
/**
* Copyright 2012 the project-owners
*
* 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 inti.ws.spring.resource.config;
import inti.ws.spring.resource.WebResource;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.ServletContextResource;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@Component
public class ResourceConfigProviderImpl implements InitializingBean, ResourceConfigProvider {
private static final String DEFAULT_CONFIG_NAME = "_default";
private static final String CONFIG_EXTENSION = ".json";
private static final String HOSTS_DIR = "/WEB-INF/hosts/";
private static final String HOSTS_META_DIR = "META-INF/hosts/index";
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceConfigProviderImpl.class);
@Inject
protected ServletContext ctx;
@Inject
protected ConfigParserProvider configParserProvider;
protected boolean updateConfig = false;
protected Map lastModifies = new HashMap();
protected Map> hostToConfigfileMapping = new HashMap<>();
protected Map> configs = new HashMap<>();
protected ObjectMapper mapper = new ObjectMapper();
@Override
public void afterPropertiesSet() throws Exception {
updateConfig = true;
Set paths = ctx.getResourcePaths(HOSTS_DIR);
Enumeration urls = getClass().getClassLoader().getResources(HOSTS_META_DIR);
Set metaPaths = getPaths(urls);
String host;
metaPaths.addAll(paths);
LOGGER.debug("afterPropertiesSet - available paths={}", metaPaths);
for (String path : metaPaths) {
if (path.endsWith(CONFIG_EXTENSION)) {
LOGGER.debug("afterPropertiesSet - scanning config-file={}", path);
host = path.substring(path.lastIndexOf('/') + 1, path.lastIndexOf(CONFIG_EXTENSION));
List resources = hostToConfigfileMapping.get(host);
if (resources == null) {
resources = new ArrayList<>();
hostToConfigfileMapping.put(host, resources);
}
resources.add(path);
update(host);
}
}
updateConfig = !(System.getProperty("DEBUG_MODE") == null || !System.getProperty("DEBUG_MODE").equals("true"));
}
protected Set getPaths(Enumeration urls) {
URL url;
InputStream input;
List lines;
Set paths = new HashSet<>();
String tmp;
while (urls.hasMoreElements()) {
try {
url = urls.nextElement();
LOGGER.debug("getPaths - checking url: {}", url);
input = url.openStream();
try {
lines = IOUtils.readLines(input);
} finally {
try {
input.close();
} catch (IOException exception) {
LOGGER.error("error while reading hosts config", exception);
}
}
for (String line : lines) {
if (line.trim().length() > 0) {
tmp = url.toExternalForm();
paths.add(tmp.substring(0, tmp.length() - 5) + line);
}
}
LOGGER.debug("getPaths - got paths {} from url {}", paths, url);
} catch (IOException exception) {
LOGGER.error("error while reading hosts config", exception);
}
}
return paths;
}
@Override
public Map getResourceConfig(HttpServletRequest request) {
String key = getKey(request);
if (updateConfig) {
try {
update(key);
} catch (Exception exception) {
LOGGER.error("", exception);
}
}
return configs.get(key);
}
protected String getKey(HttpServletRequest request) {
String key = request.getHeader(HttpHeaders.HOST);
int index;
if (key == null) {
key = DEFAULT_CONFIG_NAME;
} else if ((index = key.indexOf(":")) != -1) {
key = key.substring(0, index);
}
if (!configs.containsKey(key)) {
key = DEFAULT_CONFIG_NAME;
}
return key;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void update(String key) throws Exception {
Resource configFile;
Map> parsers;
ConfigParser extends WebResource> parser;
JsonNode configNode;
Entry field;
Iterator> fields;
Map resources;
Map resourceConfigs;
Map> resourceStack = new HashMap<>();
ResourceConfig config;
InputStream inputStream;
LOGGER.debug("update - paths for key {}: {}", key, hostToConfigfileMapping.get(key));
for (String path : hostToConfigfileMapping.get(key)) {
if (path.startsWith("/")) {
configFile = new ServletContextResource(ctx, path);
} else {
configFile = new UrlResource(path);
}
LOGGER.debug("update - updating {} for key {}", path, key);
if (lastModifies.containsKey(path) && configFile.lastModified() <= lastModifies.get(path)) {
LOGGER.debug("update - no newer version available for {} for key {}", path, key);
continue;
} else {
lastModifies.put(path, configFile.lastModified());
}
inputStream = configFile.getInputStream();
try {
configNode = mapper.readTree(inputStream);
} finally {
inputStream.close();
}
fields = configNode.fields();
parsers = configParserProvider.getConfigParsers(getClass().getClassLoader());
LOGGER.debug("update - scanning with parsers={}", parsers);
resourceConfigs = configs.get(key);
if (resourceConfigs == null) {
resourceConfigs = new HashMap<>();
configs.put(key, resourceConfigs);
}
while (fields.hasNext()) {
field = fields.next();
parser = parsers.get(field.getKey());
LOGGER.debug("update - got parser for field={}: {}", field.getKey(), parser);
config = new ResourceConfig();
if (parser != null) {
resources = parser.instanceWebResources(mapper, field.getValue());
resourceStack.put(field.getKey(), resources);
config.setResources(resources);
config.setSettings(parser.getConfigParserSettings());
if (parser.getConfigParserSettings().getRoutes() != null) {
for (String route : parser.getConfigParserSettings().getRoutes()) {
if (resourceConfigs.containsKey(route)) {
LOGGER.info(
"update - host: '{}', route: '{}' - config in '{}' overrides previous config",
new Object[] { key, route, path });
}
resourceConfigs.put(route, config);
}
}
}
}
fields = configNode.fields();
while (fields.hasNext()) {
field = fields.next();
parser = parsers.get(field.getKey());
if (parser != null) {
parser.configureWebResources(mapper, field.getValue(), (Map) resourceStack.get(field.getKey()),
(Map) resourceStack);
}
}
LOGGER.debug("update - added config with key={}: {}", key, resourceConfigs);
}
}
}