001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2024, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014 015package ch.qos.logback.core.model.util; 016 017import ch.qos.logback.core.joran.action.ActionUtil; 018import ch.qos.logback.core.model.ModelConstants; 019import ch.qos.logback.core.model.PropertyModel; 020import ch.qos.logback.core.spi.ContextAware; 021import ch.qos.logback.core.spi.ContextAwareBase; 022import ch.qos.logback.core.spi.ContextAwarePropertyContainer; 023import ch.qos.logback.core.spi.PropertyContainer; 024import ch.qos.logback.core.util.ContextUtil; 025import ch.qos.logback.core.util.Loader; 026import ch.qos.logback.core.util.OptionHelper; 027 028import java.io.FileInputStream; 029import java.io.FileNotFoundException; 030import java.io.IOException; 031import java.io.InputStream; 032import java.net.URL; 033import java.util.Properties; 034 035/** 036 * Given a {@link PropertyModel} offers methods to inject properties into a {@link PropertyContainer}. 037 * 038 * @since 1.5.1 039 */ 040public class PropertyModelHandlerHelper extends ContextAwareBase { 041 042 public static final String HANDLE_PROPERTY_MODEL_METHOD_NAME = "handlePropertyModel"; 043 044 public PropertyModelHandlerHelper(ContextAware declaredOrigin) { 045 super(declaredOrigin); 046 } 047 048 /** 049 * Given a {@link PropertyModel} inject relevant properties into the given {@link ContextAwarePropertyContainer} 050 * parameter. 051 * 052 * @param capcm 053 * @param nameStr 054 * @param valueStr 055 * @param fileStr 056 * @param resourceStr 057 * @param scopeStr 058 * 059 */ 060 public void handlePropertyModel(ContextAwarePropertyContainer capcm, String nameStr, String valueStr, 061 String fileStr, String resourceStr, String scopeStr) { 062 PropertyModel propertyModel = new PropertyModel(); 063 propertyModel.setName(nameStr); 064 propertyModel.setValue(valueStr); 065 propertyModel.setFile(fileStr); 066 propertyModel.setResource(resourceStr); 067 068 propertyModel.setScopeStr(scopeStr); 069 070 handlePropertyModel(capcm, propertyModel); 071 } 072 073 /** 074 * Given a {@link PropertyModel} inject relevant properties into the given {@link ContextAwarePropertyContainer} 075 * parameter. 076 * 077 * @param capc 078 * @param propertyModel 079 */ 080 public void handlePropertyModel(ContextAwarePropertyContainer capc, PropertyModel propertyModel) { 081 ActionUtil.Scope scope = ActionUtil.stringToScope(propertyModel.getScopeStr()); 082 083 if (checkFileAttributeSanity(propertyModel)) { 084 String file = propertyModel.getFile(); 085 file = capc.subst(file); 086 try (FileInputStream istream = new FileInputStream(file)) { 087 PropertyModelHandlerHelper.loadAndSetProperties(capc, istream, scope); 088 } catch (FileNotFoundException e) { 089 addError("Could not find properties file [" + file + "]."); 090 } catch (IOException | IllegalArgumentException e1) { // IllegalArgumentException is thrown in case the file 091 // is badly malformed, i.e a binary. 092 addError("Could not read properties file [" + file + "].", e1); 093 } 094 } else if (checkResourceAttributeSanity(propertyModel)) { 095 String resource = propertyModel.getResource(); 096 resource = capc.subst(resource); 097 URL resourceURL = Loader.getResourceBySelfClassLoader(resource); 098 if (resourceURL == null) { 099 addError("Could not find resource [" + resource + "]."); 100 } else { 101 try (InputStream istream = resourceURL.openStream();) { 102 PropertyModelHandlerHelper.loadAndSetProperties(capc, istream, scope); 103 } catch (IOException e) { 104 addError("Could not read resource file [" + resource + "].", e); 105 } 106 } 107 } else if (checkValueNameAttributesSanity(propertyModel)) { 108 // earlier versions performed Java '\' escapes for '\\' '\t' etc. Howevver, there is no 109 // need to do this. See RegularEscapeUtil.__UNUSED__basicEscape 110 String value = propertyModel.getValue(); 111 112 // now remove both leading and trailing spaces 113 value = value.trim(); 114 value = capc.subst(value); 115 ActionUtil.setProperty(capc, propertyModel.getName(), value, scope); 116 117 } else { 118 addError(ModelConstants.INVALID_ATTRIBUTES); 119 } 120 } 121 122 public static boolean checkFileAttributeSanity(PropertyModel propertyModel) { 123 String file = propertyModel.getFile(); 124 String name = propertyModel.getName(); 125 String value = propertyModel.getValue(); 126 String resource = propertyModel.getResource(); 127 128 return !(OptionHelper.isNullOrEmptyOrAllSpaces(file)) && (OptionHelper.isNullOrEmptyOrAllSpaces(name) 129 && OptionHelper.isNullOrEmptyOrAllSpaces(value) && OptionHelper.isNullOrEmptyOrAllSpaces(resource)); 130 } 131 132 public static boolean checkResourceAttributeSanity(PropertyModel propertyModel) { 133 String file = propertyModel.getFile(); 134 String name = propertyModel.getName(); 135 String value = propertyModel.getValue(); 136 String resource = propertyModel.getResource(); 137 138 return !(OptionHelper.isNullOrEmptyOrAllSpaces(resource)) && (OptionHelper.isNullOrEmptyOrAllSpaces(name) 139 && OptionHelper.isNullOrEmptyOrAllSpaces(value) && OptionHelper.isNullOrEmptyOrAllSpaces(file)); 140 } 141 142 public static boolean checkValueNameAttributesSanity(PropertyModel propertyModel) { 143 String file = propertyModel.getFile(); 144 String name = propertyModel.getName(); 145 String value = propertyModel.getValue(); 146 String resource = propertyModel.getResource(); 147 return (!(OptionHelper.isNullOrEmptyOrAllSpaces(name) || OptionHelper.isNullOrEmptyOrAllSpaces(value)) && ( 148 OptionHelper.isNullOrEmptyOrAllSpaces(file) && OptionHelper.isNullOrEmptyOrAllSpaces(resource))); 149 } 150 151 /** 152 * Add all the properties found in the argument named 'props' to an InterpretationContext. 153 */ 154 static public void setProperty(ContextAwarePropertyContainer capc, String key, String value, 155 ActionUtil.Scope scope) { 156 switch (scope) { 157 case LOCAL: 158 capc.addSubstitutionProperty(key, value); 159 break; 160 case CONTEXT: 161 capc.getContext().putProperty(key, value); 162 break; 163 case SYSTEM: 164 OptionHelper.setSystemProperty(capc, key, value); 165 } 166 } 167 168 /** 169 * Add all the properties found in the argument named 'props' to an InterpretationContext. 170 */ 171 static public void setProperties(ContextAwarePropertyContainer capc, Properties props, ActionUtil.Scope scope) { 172 switch (scope) { 173 case LOCAL: 174 capc.addSubstitutionProperties(props); 175 break; 176 case CONTEXT: 177 ContextUtil cu = new ContextUtil(capc.getContext()); 178 cu.addProperties(props); 179 break; 180 case SYSTEM: 181 OptionHelper.setSystemProperties(capc, props); 182 } 183 } 184 185 static public void loadAndSetProperties(ContextAwarePropertyContainer capc, InputStream istream, 186 ActionUtil.Scope scope) throws IOException { 187 Properties props = new Properties(); 188 props.load(istream); 189 PropertyModelHandlerHelper.setProperties(capc, props, scope); 190 } 191}