1 24 package org.riotfamily.website.css; 25 26 import java.io.File ; 27 import java.io.IOException ; 28 import java.io.StringWriter ; 29 import java.util.HashMap ; 30 import java.util.Map ; 31 import java.util.regex.Matcher ; 32 import java.util.regex.Pattern ; 33 34 import javax.servlet.ServletContext ; 35 import javax.servlet.http.HttpServletRequest ; 36 import javax.servlet.http.HttpServletResponse ; 37 38 import org.riotfamily.cachius.spring.AbstractCacheableController; 39 import org.riotfamily.common.web.filter.ResourceStamper; 40 import org.springframework.beans.factory.InitializingBean; 41 import org.springframework.core.io.Resource; 42 import org.springframework.web.context.ServletContextAware; 43 import org.springframework.web.servlet.ModelAndView; 44 import org.springframework.web.servlet.mvc.LastModified; 45 import org.springframework.web.util.UrlPathHelper; 46 47 import freemarker.template.Configuration; 48 import freemarker.template.Template; 49 import freemarker.template.TemplateException; 50 51 79 public class CssTemplateController extends AbstractCacheableController 80 implements LastModified, ServletContextAware, InitializingBean { 81 82 public static final String KEY_PROPERTY = "key"; 83 84 public static final String CONTEXT_PATH_PROPERTY = "contextPath"; 85 86 private static final String DEFAULT_INI_FILE_NAME = "css.ini"; 87 88 private static final String CSS_SUFFIX = ".css"; 89 90 private UrlPathHelper urlPathHelper = new UrlPathHelper(); 91 92 private ServletContext servletContext; 93 94 private Pattern keyPattern = Pattern.compile("(/[^/]+?)_(.*?)(\\.css)"); 95 96 private String contentType = "text/css"; 97 98 private Configuration freeMarkerConfig; 99 100 private IniFile iniFile; 101 102 private Pattern urlPattern = Pattern.compile( 103 "(url\\s*\\(\\s*[\"']?)(.*?)(['\"]?\\s*\\))"); 104 105 private ResourceStamper stamper; 106 107 private ColorTool colorTool = new ColorTool(); 108 109 private boolean addContextPathToUrls = false; 110 111 public void setServletContext(ServletContext servletContext) { 112 this.servletContext = servletContext; 113 } 114 115 public void setFreeMarkerConfig(Configuration configuration) { 116 this.freeMarkerConfig = configuration; 117 } 118 119 126 public void setStamper(ResourceStamper stamper) { 127 this.stamper = stamper; 128 } 129 130 136 public void setAddContextPathToUrls(boolean addContextPathToUrls) { 137 this.addContextPathToUrls = addContextPathToUrls; 138 } 139 140 public void setIniFileLocation(Resource resource) throws IOException { 141 iniFile = new IniFile(resource.getFile()); 142 } 143 144 public void afterPropertiesSet() throws Exception { 145 if (freeMarkerConfig == null) { 146 freeMarkerConfig = new Configuration(); 147 } 148 freeMarkerConfig.setDirectoryForTemplateLoading( 149 new File (servletContext.getRealPath("/"))); 150 } 151 152 public long getLastModified(HttpServletRequest request) { 153 DynamicStylesheet stylesheet = lookup(request); 154 return stylesheet.lastModified(); 155 } 156 157 public ModelAndView handleRequest(HttpServletRequest request, 158 HttpServletResponse response) throws Exception { 159 160 DynamicStylesheet stylesheet = lookup(request); 161 stylesheet.serve(request, response); 162 return null; 163 } 164 165 protected DynamicStylesheet lookup(HttpServletRequest request) { 166 String path = urlPathHelper.getPathWithinApplication(request); 167 String key = null; 168 File file = new File (servletContext.getRealPath(path)); 169 if (!file.exists()) { 170 Matcher matcher = keyPattern.matcher(path); 171 if (matcher.find()) { 172 key = matcher.group(2); 173 path = matcher.replaceFirst("$1$3"); 174 file = new File (servletContext.getRealPath(path)); 175 } 176 } 177 return new DynamicStylesheet(file, path, key); 178 } 179 180 protected class DynamicStylesheet { 181 182 private File file; 183 184 private String path; 185 186 private String key; 187 188 public DynamicStylesheet(File file, String path, String key) { 189 this.file = file; 190 this.path = path; 191 this.key = key; 192 } 193 194 public long lastModified() { 195 long lastModified = -1; 196 if (file != null) { 197 lastModified = file.lastModified(); 198 } 199 if (iniFile != null) { 200 lastModified = Math.max(lastModified, iniFile.lastModified()); 201 } 202 return lastModified; 203 } 204 205 public void serve(HttpServletRequest request, 206 HttpServletResponse response) 207 throws IOException , TemplateException { 208 209 if (file == null) { 210 response.sendError(HttpServletResponse.SC_NOT_FOUND); 211 return; 212 } 213 if (!file.getName().endsWith(CSS_SUFFIX)) { 214 response.sendError(HttpServletResponse.SC_FORBIDDEN); 215 } 216 if (!file.canRead()) { 217 response.sendError(HttpServletResponse.SC_NOT_FOUND, 218 "Can't read file " + file.getAbsolutePath()); 219 220 return; 221 } 222 223 if (iniFile == null) { 224 File f = new File (file.getParentFile(), DEFAULT_INI_FILE_NAME); 225 if (f.canRead()) { 226 iniFile = new IniFile(f); 227 } 228 } 229 230 response.setContentType(contentType); 231 232 Map model = buildModel(); 233 model.put(KEY_PROPERTY, key); 234 model.put(CONTEXT_PATH_PROPERTY, request.getContextPath()); 235 236 Template template = freeMarkerConfig.getTemplate(path); 237 StringWriter sw = new StringWriter (); 238 template.process(model, sw); 239 response.getWriter().print( 240 processUrls(sw.toString(), request.getContextPath())); 241 } 242 243 private Map buildModel() { 244 HashMap model = new HashMap (); 245 model.put("color", colorTool); 246 if (iniFile != null) { 247 Map sections = iniFile.getSections(); 248 model.putAll(sections); 249 model.putAll((Map ) sections.get(IniFile.GLOBAL_SECTION)); 250 if (key != null) { 251 Map current = (Map ) sections.get(key); 252 if (current != null) { 253 model.putAll(current); 254 } 255 } 256 } 257 return model; 258 } 259 260 private String processUrls(String css, String contextPath) { 261 if (stamper == null && !addContextPathToUrls) { 262 return css; 263 } 264 StringBuffer sb = new StringBuffer (); 265 Matcher matcher = urlPattern.matcher(css); 266 while (matcher.find()) { 267 String url = matcher.group(2); 268 if (stamper != null) { 269 url = stamper.stamp(url); 270 } 271 if (addContextPathToUrls && url.startsWith("/")) { 272 url = contextPath + url; 273 } 274 matcher.appendReplacement(sb, "$1" + url + "$3"); 275 } 276 matcher.appendTail(sb); 277 return sb.toString(); 278 } 279 280 } 281 } 282 | Popular Tags |