001/* 002 * Copyright 2024 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.core.source; 017 018import java.util.LinkedHashMap; 019import java.util.Map; 020import java.util.Map.Entry; 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.configuration.Configurable; 026import org.apache.avalon.framework.configuration.Configuration; 027import org.apache.avalon.framework.configuration.ConfigurationException; 028import org.apache.excalibur.source.SourceUtil; 029 030import org.ametys.runtime.plugin.component.PluginAware; 031 032/** 033 * A configurable static fallback for optional sources 034 */ 035public class StaticOptionalSourceFallback implements OptionalSourceFallback, Component, Configurable, PluginAware 036{ 037 private Fallbacks _fallbacks; 038 private String _pluginName; 039 040 public void configure(Configuration configuration) throws ConfigurationException 041 { 042 _fallbacks = configureFallbacks(configuration, "plugin:" + _pluginName + "://"); 043 } 044 045 public void setPluginInfo(String pluginName, String featureName, String id) 046 { 047 _pluginName = pluginName; 048 } 049 050 /** 051 * Configure fallbacks based upon a static xml configuration 052 * @param configuration The configuration 053 * @param baseUri The uri of the configuration. For example, if the configuration is in a plugin, should be the root of the plugin 054 * @return The fallbacks configured 055 * @throws ConfigurationException If the configuration has issues 056 */ 057 public static Fallbacks configureFallbacks(Configuration configuration, String baseUri) throws ConfigurationException 058 { 059 Map<String, String> stringFallbacks = new LinkedHashMap<>(); 060 Map<Pattern, String> patternFallbacks = new LinkedHashMap<>(); 061 062 for (Configuration fallback : configuration.getChildren("fallback")) 063 { 064 String uri = fallback.getChild("uri").getValue(); 065 String value = fallback.getChild("fallback").getValue(); 066 boolean isRegexp = fallback.getChild("uri").getAttributeAsBoolean("regexp", false); 067 068 if (isRegexp) 069 { 070 patternFallbacks.put(Pattern.compile(uri), value); 071 } 072 else 073 { 074 stringFallbacks.put(uri, value); 075 } 076 } 077 078 return new Fallbacks(baseUri, stringFallbacks, patternFallbacks); 079 } 080 081 public String fallback(String uri) 082 { 083 return applyFallbacks(uri, _fallbacks); 084 } 085 086 /** 087 * Apply the given fallbacks to an uri 088 * @param uri The uri to consider 089 * @param fallbacks The fallbacks to applu 090 * @return The fallback or null if no one apply 091 */ 092 public static String applyFallbacks(String uri, Fallbacks fallbacks) 093 { 094 if (fallbacks.stringFallbacks().containsKey(uri)) 095 { 096 return fallbacks.stringFallbacks().get(uri); 097 } 098 else 099 { 100 for (Entry<Pattern, String> patternFallback : fallbacks.patternFallbacks().entrySet()) 101 { 102 Matcher matcher = patternFallback.getKey().matcher(uri); 103 if (matcher.matches()) 104 { 105 String value = patternFallback.getValue(); 106 for (int g = 1; g <= matcher.groupCount(); g++) 107 { 108 value = value.replace("$" + g, matcher.group(g)); 109 } 110 return SourceUtil.absolutize(fallbacks.baseUri(), value); 111 } 112 } 113 114 return fallbacks.patternFallbacks().entrySet().stream() 115 .filter(e -> e.getKey().matcher(uri).matches()) 116 .findFirst().map(e -> SourceUtil.absolutize(fallbacks.baseUri(), e.getValue())) 117 .orElse(null); 118 } 119 } 120 121 /** 122 * A fallback static configuration 123 * @param baseUri The base uri for values 124 * @param stringFallbacks Simple string fallbacks 125 * @param patternFallbacks Fallbacks with pattern 126 */ 127 public record Fallbacks(String baseUri, Map<String, String> stringFallbacks, Map<Pattern, String> patternFallbacks) { } 128}