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.web.skin; 017 018import java.io.InputStream; 019 020import org.apache.avalon.framework.activity.Initializable; 021import org.apache.avalon.framework.component.Component; 022import org.apache.avalon.framework.configuration.Configuration; 023import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 024import org.apache.avalon.framework.context.Context; 025import org.apache.avalon.framework.context.ContextException; 026import org.apache.avalon.framework.context.Contextualizable; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.cocoon.components.ContextHelper; 031import org.apache.commons.lang3.StringUtils; 032import org.apache.excalibur.source.Source; 033 034import org.ametys.core.cache.AbstractCacheManager; 035import org.ametys.core.cache.Cache; 036import org.ametys.core.source.OptionalSourceFallback; 037import org.ametys.core.source.StaticOptionalSourceFallback; 038import org.ametys.core.source.StaticOptionalSourceFallback.Fallbacks; 039import org.ametys.core.util.filereloader.FileReloader; 040import org.ametys.core.util.filereloader.FileReloaderUtils; 041import org.ametys.runtime.i18n.I18nizableText; 042import org.ametys.web.WebHelper; 043import org.ametys.web.repository.site.Site; 044import org.ametys.web.repository.site.SiteManager; 045 046/** 047 * This implementation will read its configuration from the current skin in conf/optional-source-fallbacks.xml 048 */ 049public class SkinOptionalSourceFallback implements OptionalSourceFallback, Component, Serviceable, Initializable, Contextualizable, FileReloader 050{ 051 private static final String _CACHE_ID = SkinOptionalSourceFallback.class.getName(); 052 053 private FileReloaderUtils _fileReloaderUtils; 054 private AbstractCacheManager _cacheManager; 055 private Context _context; 056 private SiteManager _siteManager; 057 058 public void service(ServiceManager manager) throws ServiceException 059 { 060 _cacheManager = (AbstractCacheManager) manager.lookup(AbstractCacheManager.ROLE); 061 _fileReloaderUtils = (FileReloaderUtils) manager.lookup(FileReloaderUtils.ROLE); 062 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 063 } 064 065 public void contextualize(Context context) throws ContextException 066 { 067 _context = context; 068 } 069 070 public void initialize() throws Exception 071 { 072 _cacheManager.createMemoryCache(_CACHE_ID, 073 new I18nizableText("plugin.web", "PLUGINS_WEB_SKIN_OPTIONAL_SOURCE_FALLBACKS_CACHE_LABEL"), 074 new I18nizableText("plugin.web", "PLUGINS_WEB_SKIN_OPTIONAL_SOURCE_FALLBACKS_CACHE_DESCRIPTION"), 075 true, 076 null); 077 } 078 079 public String fallback(String uri) 080 { 081 String currentSiteName = WebHelper.getSiteName(ContextHelper.getRequest(_context)); 082 Site currentSite = _siteManager.getSite(currentSiteName); 083 if (currentSite != null) 084 { 085 String sourceUri = "skin:" + currentSite.getSkinId() + "://conf/optional-source-fallbacks.xml"; 086 087 boolean forceReload = !_getCache().hasKey(sourceUri); 088 try 089 { 090 _fileReloaderUtils.updateFile(sourceUri, forceReload, this); 091 } 092 catch (Exception e) 093 { 094 throw new RuntimeException("Cannot load file '" + sourceUri + "'", e); 095 } 096 097 StaticOptionalSourceFallback.Fallbacks fallbacks = _getCache().get(sourceUri); 098 if (fallbacks != null) 099 { 100 return StaticOptionalSourceFallback.applyFallbacks(uri, fallbacks); 101 } 102 } 103 104 return null; 105 } 106 107 public void updateFile(String sourceUrl, Source source, InputStream is) throws Exception 108 { 109 Fallbacks fallbacks = null; 110 111 if (is != null) 112 { 113 Configuration configuration = new DefaultConfigurationBuilder().build(source.getInputStream()); 114 fallbacks = StaticOptionalSourceFallback.configureFallbacks(configuration, StringUtils.substringBefore(sourceUrl, "conf")); 115 } 116 117 _getCache().put(sourceUrl, fallbacks); 118 } 119 120 public String getId(String sourceUrl) 121 { 122 return sourceUrl; 123 } 124 125 private Cache<String, StaticOptionalSourceFallback.Fallbacks> _getCache() 126 { 127 return _cacheManager.get(_CACHE_ID); 128 } 129}