/*
* Copyright 2006-2010 the original author or authors.
*
* 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 org.springframework.amqp.rabbit.stocks.web;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.stocks.context.RefreshScope;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
/**
* @author Dave Syer
*
*/
@Controller
public class EnvironmentController {
private static Log logger = LogFactory.getLog(EnvironmentController.class);
private RefreshScope refreshScope;
private AmqpTemplate amqpTemplate;
private RedisOperations<String, String> redisTemplate;
private Properties environmentProperties = new Properties();
public void setAmqpTemplate(AmqpTemplate amqpTemplate) {
this.amqpTemplate = amqpTemplate;
}
public void setRefreshScope(RefreshScope refreshScope) {
this.refreshScope = refreshScope;
}
public void setRedisTemplate(RedisOperations<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* @param properties the envProperties to set
*/
public void setEnvironmentProperties(Properties properties) {
this.environmentProperties = properties;
}
/**
* Get the system properties (key value "system") and the OS environment (key value "host") if available and the
* persistent back-end (key value "env" if present).
*
* @return the system properties and OS environment
*/
@RequestMapping(value = "/env", method = RequestMethod.GET)
@ResponseBody
public Map<String, Properties> env() {
Map<String, Properties> model = new HashMap<String, Properties>();
model.put("system", getSystemProperties());
model.put("host", getHostProperties());
model.put("env", environmentProperties);
return model;
}
/**
* Use this endpoint to refresh the cron trigger that is used to send market data to the broker. It builds a refresh
* request and sends it to the broker using the AMQP template provided.
*
* @param bean a bean id
* @return a refresh request object (as information for the caller)
*
* @see #handleRefresh(RefreshRequest) a handler for the request generated here
*/
@RequestMapping(value = "/refresh/{bean}", method = RequestMethod.POST)
@ResponseBody
public RefreshRequest refresh(@PathVariable String bean, WebRequest webRequest) {
RefreshRequest request = new RefreshRequest();
Properties updates = new Properties();
Properties oldValues = new Properties();
for (Iterator<String> keys = webRequest.getParameterNames(); keys.hasNext();) {
String key = keys.next();
updates.setProperty(key, webRequest.getParameter(key));
String value = environmentProperties.getProperty(key);
if (value != null) {
oldValues.setProperty(key, value);
}
}
request.setUpdates(updates);
request.setOldValues(oldValues);
request.setBeanName(bean);
if (amqpTemplate != null) {
amqpTemplate.convertAndSend(request);
}
return request;
}
/**
* Set some system properties and refresh a bean in the application context (provided it is in refresh scope).
*
* @param request a refresh request
*/
public void handleRefresh(RefreshRequest request) {
logger.info("Handling refresh: " + request);
String name = request.getBeanName();
Properties updates = request.getUpdates();
for (String property : updates.stringPropertyNames()) {
String old = environmentProperties.getProperty(property);
String update = updates.getProperty(property);
if (update.length() > 0 && !update.equals(old)) {
environmentProperties.setProperty(property, update);
if (redisTemplate != null) {
redisTemplate.boundValueOps("env." + property).set(update);
}
}
}
if (name != null && refreshScope != null) {
refreshScope.refresh(name);
}
}
private Properties getSystemProperties() {
Properties env = new Properties();
try {
env.putAll(System.getProperties());
} catch (Exception e) {
logger.warn("Could not obtain System properties", e);
}
return env;
}
private Properties getHostProperties() {
Properties env = new Properties();
try {
Map<String, String> values = System.getenv();
for (String key : values.keySet()) {
env.setProperty(key, values.get(key));
}
} catch (Exception e) {
logger.warn("Could not obtain OS environment", e);
}
return env;
}
public static class RefreshRequest {
private String beanName;
private Properties updates = new Properties();
private Properties oldValues = new Properties();
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public Properties getUpdates() {
return updates;
}
public Properties getOldValues() {
return oldValues;
}
public void setOldValues(Properties oldValues) {
this.oldValues = oldValues;
}
public void setUpdates(Properties oldValues) {
this.updates = oldValues;
}
@Override
public String toString() {
return "RefreshRequest [beanName=" + beanName + ", updates=" + updates + ", oldValues=" + oldValues + "]";
}
}
}