All Downloads are FREE. Search and download functionalities are using the official Maven repository.

inti.ws.spring.resource.config.ResourceConfigProviderImpl Maven / Gradle / Ivy

Go to download

An utility library for spring-based web-services for compressing / optimizing JS and CSS resources.

There is a newer version: 1.6
Show newest version
/**
 * 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 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);

		}

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy