001/* 002 * Copyright 2010 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.source; 017 018import java.io.IOException; 019import java.net.MalformedURLException; 020import java.util.Map; 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023 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.logger.LogEnabled; 028import org.apache.avalon.framework.logger.Logger; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.cocoon.Constants; 033import org.apache.cocoon.components.ContextHelper; 034import org.apache.cocoon.environment.Request; 035import org.apache.commons.lang.StringUtils; 036import org.apache.excalibur.source.Source; 037import org.apache.excalibur.source.SourceNotFoundException; 038import org.apache.excalibur.source.impl.FileSource; 039import org.apache.excalibur.source.impl.FileSourceFactory; 040 041import org.ametys.web.repository.site.SiteManager; 042import org.ametys.web.skin.Skin; 043import org.ametys.web.skin.SkinsManager; 044 045/** 046 * Resolve the protocol skin:// seekingg file in skins/{siteConfiguration:skin}/ 047 */ 048public class SkinSourceFactory extends FileSourceFactory implements Contextualizable, LogEnabled, Serviceable 049{ 050 /** The regexp for a protocol */ 051 protected static final Pattern __SOURCE_PATTERN = Pattern.compile("^[\\w]+(:([^:#]+)?(#([^:]+))?)?://(.*)$"); 052 /** The skins manager */ 053 protected SkinsManager _skinsManager; 054 /** The site manager */ 055 protected SiteManager _siteManager; 056 /** Logger */ 057 protected Logger _logger; 058 /** Avalon context */ 059 protected Context _context; 060 /** Cocoon context */ 061 protected org.apache.cocoon.environment.Context _cocoonContext; 062 063 private ServiceManager _manager; 064 065 @Override 066 public void enableLogging(Logger logger) 067 { 068 _logger = logger; 069 } 070 071 @Override 072 public void service(ServiceManager manager) throws ServiceException 073 { 074 _manager = manager; 075 } 076 077 /** 078 * Lookup {@link SiteManager} and {@link SkinsManager} for lazy initialization. 079 */ 080 protected void initializeComponents() 081 { 082 try 083 { 084 if (_siteManager == null) 085 { 086 _siteManager = (SiteManager) _manager.lookup(SiteManager.ROLE); 087 } 088 089 if (_skinsManager == null) 090 { 091 _skinsManager = (SkinsManager) _manager.lookup(SkinsManager.ROLE); 092 } 093 } 094 catch (ServiceException e) 095 { 096 throw new IllegalStateException("Exception while getting components", e); 097 } 098 } 099 100 /** 101 * Return the current skin 102 * @param name the skin name. Can be null or empty 103 * @param defaultValue switch to this value if skin cannot be determined, or if the determined skin does not exist. Can be null 104 * @return the skin. Cannot be null. 105 * @throws SourceNotFoundException If the skin do not exist 106 */ 107 protected Skin getSkin(String name, String defaultValue) throws SourceNotFoundException 108 { 109 String skinName = name; 110 Request request = ContextHelper.getRequest(_context); 111 112 if (StringUtils.isEmpty(skinName)) 113 { 114 skinName = _skinsManager.getSkinNameFromRequest(request); 115 } 116 117 // Then, try the default value. 118 if (StringUtils.isEmpty(skinName)) 119 { 120 skinName = defaultValue; 121 } 122 123 if (StringUtils.isEmpty(skinName)) 124 { 125 String message = "The current skin name has to be set in current request to use this protocol."; 126 _logger.info(message); 127 throw new SourceNotFoundException(message); 128 } 129 130 Skin skin = _skinsManager.getSkin(skinName); 131 if (skin == null) 132 { 133 skin = _skinsManager.getSkin(defaultValue); 134 } 135 136 if (skin == null) 137 { 138 String message = "The skin '" + skinName + "' currently setup for this site does not exist."; 139 _logger.info(message); 140 throw new SourceNotFoundException(message); 141 } 142 143 return skin; 144 } 145 146 @Override 147 public Source getSource(String location, Map parameters) throws IOException 148 { 149 // lazy initialization to prevent chicken/egg scenario on startup 150 initializeComponents(); 151 152 Matcher m = __SOURCE_PATTERN.matcher(location); 153 if (!m.matches()) 154 { 155 throw new MalformedURLException("URI must be like protocol:<name>://path/to/resource. Location was '" + location + "'"); 156 } 157 158 Skin skin = getSkin(m.group(2), m.group(4)); 159 160 String fileLocation = m.group(5); 161 162 return new FileSource("file://" + skin.getLocation() + "/" + fileLocation); 163 } 164 165 @Override 166 public String absolutize(String baseURI, String location) 167 { 168 return location; 169 } 170 171 @Override 172 public void contextualize(Context context) throws ContextException 173 { 174 _context = context; 175 _cocoonContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT); 176 } 177}