001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.plugin; 018 019import org.apache.activemq.broker.BrokerContext; 020import org.apache.activemq.spring.Utils; 021import org.slf4j.Logger; 022import org.slf4j.LoggerFactory; 023import org.springframework.beans.factory.FactoryBean; 024import org.springframework.core.io.Resource; 025import org.w3c.dom.Document; 026import org.w3c.dom.Element; 027import org.w3c.dom.Node; 028import org.w3c.dom.NodeList; 029 030import java.io.IOException; 031import java.net.MalformedURLException; 032import java.util.LinkedList; 033import java.util.List; 034import java.util.Map; 035import java.util.Properties; 036import java.util.regex.Matcher; 037import java.util.regex.Pattern; 038 039public class PropertiesPlaceHolderUtil { 040 041 public static final Logger LOG = LoggerFactory.getLogger(PropertiesPlaceHolderUtil.class); 042 043 static final Pattern pattern = Pattern.compile("\\$\\{([^\\}]+)\\}"); 044 final Properties properties; 045 046 public PropertiesPlaceHolderUtil(Properties properties) { 047 this.properties = properties; 048 } 049 050 public void filter(Properties toFilter) { 051 for (Map.Entry<Object, Object> entry : toFilter.entrySet()) { 052 String val = (String) entry.getValue(); 053 String newVal = filter(val); 054 if (!val.equals(newVal)) { 055 toFilter.put(entry.getKey(), newVal); 056 } 057 } 058 } 059 060 public String filter(String str) { 061 int start = 0; 062 while (true) { 063 Matcher matcher = pattern.matcher(str); 064 if (!matcher.find(start)) { 065 break; 066 } 067 String group = matcher.group(1); 068 String property = properties.getProperty(group); 069 if (property != null) { 070 str = matcher.replaceFirst(Matcher.quoteReplacement(property)); 071 } else { 072 start = matcher.end(); 073 } 074 } 075 return replaceBytePostfix(str); 076 } 077 078 static Pattern[] byteMatchers = new Pattern[] { 079 Pattern.compile("^\\s*(\\d+)\\s*(b)?\\s*$", Pattern.CASE_INSENSITIVE), 080 Pattern.compile("^\\s*(\\d+)\\s*k(b)?\\s*$", Pattern.CASE_INSENSITIVE), 081 Pattern.compile("^\\s*(\\d+)\\s*m(b)?\\s*$", Pattern.CASE_INSENSITIVE), 082 Pattern.compile("^\\s*(\\d+)\\s*g(b)?\\s*$", Pattern.CASE_INSENSITIVE)}; 083 084 // xbean can Xb, Xkb, Xmb, Xg etc 085 private String replaceBytePostfix(String str) { 086 try { 087 for (int i=0; i< byteMatchers.length; i++) { 088 Matcher matcher = byteMatchers[i].matcher(str); 089 if (matcher.matches()) { 090 long value = Long.parseLong(matcher.group(1)); 091 for (int j=1; j<=i; j++) { 092 value *= 1024; 093 } 094 return String.valueOf(value); 095 } 096 } 097 } catch (NumberFormatException ignored) { 098 LOG.debug("nfe on: " + str, ignored); 099 } 100 return str; 101 } 102 103 public void mergeProperties(Document doc, Properties initialProperties, BrokerContext brokerContext) { 104 // find resources 105 // <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 106 // <property name="locations" || name="properties"> 107 // ... 108 // </property> 109 // </bean> 110 LinkedList<String> resources = new LinkedList<String>(); 111 LinkedList<String> propertiesClazzes = new LinkedList<String>(); 112 NodeList beans = doc.getElementsByTagNameNS("*", "bean"); 113 for (int i = 0; i < beans.getLength(); i++) { 114 Node bean = beans.item(0); 115 if (bean.hasAttributes() && bean.getAttributes().getNamedItem("class").getTextContent().contains("PropertyPlaceholderConfigurer")) { 116 if (bean.hasChildNodes()) { 117 NodeList beanProps = bean.getChildNodes(); 118 for (int j = 0; j < beanProps.getLength(); j++) { 119 Node beanProp = beanProps.item(j); 120 if (Node.ELEMENT_NODE == beanProp.getNodeType() && beanProp.hasAttributes() && beanProp.getAttributes().getNamedItem("name") != null) { 121 String propertyName = beanProp.getAttributes().getNamedItem("name").getTextContent(); 122 if ("locations".equals(propertyName)) { 123 124 // interested in value or list/value of locations property 125 Element beanPropElement = (Element) beanProp; 126 NodeList values = beanPropElement.getElementsByTagNameNS("*", "value"); 127 for (int k = 0; k < values.getLength(); k++) { 128 Node value = values.item(k); 129 resources.add(value.getFirstChild().getTextContent()); 130 } 131 } else if ("properties".equals(propertyName)) { 132 133 // bean or beanFactory 134 Element beanPropElement = (Element) beanProp; 135 NodeList values = beanPropElement.getElementsByTagNameNS("*", "bean"); 136 for (int k = 0; k < values.getLength(); k++) { 137 Node value = values.item(k); 138 if (value.hasAttributes()) { 139 Node beanClassTypeNode = value.getAttributes().getNamedItem("class"); 140 if (beanClassTypeNode != null) { 141 propertiesClazzes.add(beanClassTypeNode.getFirstChild().getTextContent()); 142 } 143 } 144 } 145 } 146 } 147 } 148 } 149 } 150 } 151 for (String value : propertiesClazzes) { 152 try { 153 Object springBean = getClass().getClassLoader().loadClass(value).newInstance(); 154 if (springBean instanceof FactoryBean) { 155 // can't access the factory or created properties from spring context so we got to recreate 156 initialProperties.putAll((Properties) FactoryBean.class.getMethod("getObject", (Class<?>[]) null).invoke(springBean)); 157 } 158 } catch (Throwable e) { 159 LOG.debug("unexpected exception processing properties bean class: " + propertiesClazzes, e); 160 } 161 } 162 List<Resource> propResources = new LinkedList<Resource>(); 163 for (String value : resources) { 164 try { 165 if (!value.isEmpty()) { 166 propResources.add(Utils.resourceFromString(filter(value))); 167 } 168 } catch (MalformedURLException e) { 169 LOG.info("failed to resolve resource: " + value, e); 170 } 171 } 172 for (Resource resource : propResources) { 173 Properties properties = new Properties(); 174 try { 175 properties.load(resource.getInputStream()); 176 } catch (IOException e) { 177 LOG.info("failed to load properties resource: " + resource, e); 178 } 179 initialProperties.putAll(properties); 180 } 181 } 182 183}