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.wicket.resource.loader; 018 019import org.apache.wicket.Application; 020import org.apache.wicket.Component; 021import org.apache.wicket.settings.ResourceSettings; 022import org.apache.wicket.util.lang.Args; 023 024import java.util.ArrayList; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Locale; 028import java.util.regex.Matcher; 029import java.util.regex.Pattern; 030 031/** 032 * Creates a nested string resource loader which resolves nested keys.<br> 033 * <br> 034 * Example: 035 * 036 * <pre> 037 * <code> 038 * List<IStringResourceLoader> loaders = getResourceSettings().getStringResourceLoaders(); 039 * // Add more loaders here 040 * NestedStringResourceLoader element = new NestedStringResourceLoader(loaders,Pattern.compile("#\\(([^ ]*?)\\)")); 041 * loaders.clear(); 042 * loaders.add(element); 043 * </code> 044 * </pre> 045 * 046 * @author Sven Meier 047 * @author Tobias Soloschenko 048 * 049 */ 050public class NestedStringResourceLoader implements IStringResourceLoader 051{ 052 private final Pattern pattern; 053 054 private final List<IStringResourceLoader> loaders; 055 056 private final ResourceSettings resourceSettings; 057 058 /** 059 * Creates a nested string resource loader 060 * 061 * @param loaders 062 * the loaders to be added in a chain 063 * @param pattern 064 * the pattern for nested keys. Example for <b>#(key)</b> is the pattern: 065 * <b>Pattern.compile("#\\(([^ ]*?)\\)");</b> 066 */ 067 public NestedStringResourceLoader(List<IStringResourceLoader> loaders, Pattern pattern) 068 { 069 this.loaders = new ArrayList<>(loaders); 070 this.pattern = Args.notNull(pattern, "pattern"); 071 this.resourceSettings = Application.get().getResourceSettings(); 072 } 073 074 @Override 075 public String loadStringResource(Component component, String key, Locale locale, String style, 076 String variation) 077 { 078 return loadNestedStringResource(component, key, locale, style, variation); 079 } 080 081 @Override 082 public String loadStringResource(Class<?> clazz, String key, Locale locale, String style, 083 String variation) 084 { 085 return loadNestedStringResource(clazz, key, locale, style, variation); 086 } 087 088 /** 089 * loads nested string resources 090 * 091 * @param scope 092 * the scope to find the key 093 * @param key 094 * the actual key 095 * @param locale 096 * the locale 097 * @param style 098 * the style 099 * @param variation 100 * the variation 101 * @return the load string 102 */ 103 private String loadNestedStringResource(Object scope, String key, Locale locale, String style, 104 String variation) 105 { 106 Class<?> clazz = null; 107 Component component = null; 108 if (scope instanceof Component) 109 { 110 component = (Component)scope; 111 } 112 else 113 { 114 clazz = (Class<?>)scope; 115 } 116 117 Iterator<IStringResourceLoader> iter = loaders.iterator(); 118 String value = null; 119 while (iter.hasNext() && (value == null)) 120 { 121 IStringResourceLoader loader = iter.next(); 122 value = component != null 123 ? loader.loadStringResource(component, key, locale, style, variation) 124 : loader.loadStringResource(clazz, key, locale, style, variation); 125 } 126 127 if (value == null) 128 { 129 return null; 130 } 131 132 StringBuffer output = new StringBuffer(); 133 Matcher matcher = pattern.matcher(value); 134 // Search for other nested keys to replace 135 while (matcher.find()) 136 { 137 String nestedKey = matcher.group(1); 138 String replacedPlaceHolder = component != null 139 ? loadNestedStringResource(component, nestedKey, locale, style, variation) 140 : loadNestedStringResource(clazz, nestedKey, locale, style, variation); 141 142 if (replacedPlaceHolder == null) 143 { 144 return null; 145 } 146 matcher.appendReplacement(output, replacedPlaceHolder); 147 } 148 matcher.appendTail(output); 149 return output.toString(); 150 } 151}