1 /* 2 * Copyright 2002-2012 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.apache.velocity.spring; 18 19 import java.io.IOException; 20 import java.io.InputStreamReader; 21 import java.io.Reader; 22 import java.util.Arrays; 23 24 import org.apache.velocity.exception.ResourceNotFoundException; 25 import org.apache.velocity.runtime.resource.Resource; 26 import org.apache.velocity.runtime.resource.loader.ResourceLoader; 27 28 import org.apache.velocity.util.ExtProperties; 29 import org.slf4j.Logger; 30 import org.slf4j.LoggerFactory; 31 import org.springframework.util.StringUtils; 32 33 /** 34 * Velocity ResourceLoader adapter that loads via a Spring ResourceLoader. 35 * Used by VelocityEngineFactory for any resource loader path that cannot 36 * be resolved to a {@code java.io.File}. 37 * 38 * <p>Note that this loader does not allow for modification detection: 39 * Use Velocity's default FileResourceLoader for {@code java.io.File} 40 * resources. 41 * 42 * <p>Expects "spring.resource.loader" and "spring.resource.loader.path" 43 * application attributes in the Velocity runtime: the former of type 44 * {@code org.springframework.core.io.ResourceLoader}, the latter a String. 45 * 46 * @author Juergen Hoeller 47 * @author Claude Brisson 48 * @since 2020-05-29 49 * @see VelocityEngineFactory#setResourceLoaderPath 50 * @see org.springframework.core.io.ResourceLoader 51 * @see org.apache.velocity.runtime.resource.loader.FileResourceLoader 52 */ 53 public class SpringResourceLoader extends ResourceLoader { 54 55 public static final String NAME = "spring"; 56 57 public static final String SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; 58 59 public static final String SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; 60 61 public static final String SPRING_RESOURCE_LOADER = "spring.resource.loader"; 62 63 public static final String SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; 64 65 66 protected final Logger logger = LoggerFactory.getLogger(getClass()); 67 68 private org.springframework.core.io.ResourceLoader resourceLoader; 69 70 private String[] resourceLoaderPaths; 71 72 73 @Override init(ExtProperties configuration)74 public void init(ExtProperties configuration) { 75 this.resourceLoader = (org.springframework.core.io.ResourceLoader) 76 this.rsvc.getApplicationAttribute(SPRING_RESOURCE_LOADER); 77 String resourceLoaderPath = (String) this.rsvc.getApplicationAttribute(SPRING_RESOURCE_LOADER_PATH); 78 if (this.resourceLoader == null) { 79 throw new IllegalArgumentException( 80 "'resourceLoader' application attribute must be present for SpringResourceLoader"); 81 } 82 if (resourceLoaderPath == null) { 83 throw new IllegalArgumentException( 84 "'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); 85 } 86 this.resourceLoaderPaths = StringUtils.commaDelimitedListToStringArray(resourceLoaderPath); 87 for (int i = 0; i < this.resourceLoaderPaths.length; i++) { 88 String path = this.resourceLoaderPaths[i]; 89 if (!path.endsWith("/")) { 90 this.resourceLoaderPaths[i] = path + "/"; 91 } 92 } 93 if (logger.isInfoEnabled()) { 94 logger.info("SpringResourceLoader for Velocity: using resource loader [" + this.resourceLoader + 95 "] and resource loader paths " + Arrays.asList(this.resourceLoaderPaths)); 96 } 97 } 98 99 /** 100 * Get the Reader that the Runtime will parse 101 * to create a template. 102 * 103 * @param source resource name 104 * @param encoding resource encoding 105 * @return The reader for the requested resource. 106 * @throws ResourceNotFoundException 107 * @since 2.0 108 */ 109 @Override getResourceReader(String source, String encoding)110 public Reader getResourceReader(String source, String encoding) throws ResourceNotFoundException { 111 if (logger.isDebugEnabled()) { 112 logger.debug("Looking for Velocity resource with name [" + source + "]"); 113 } 114 for (String resourceLoaderPath : this.resourceLoaderPaths) { 115 org.springframework.core.io.Resource resource = 116 this.resourceLoader.getResource(resourceLoaderPath + source); 117 try { 118 return new InputStreamReader(resource.getInputStream(), encoding); 119 } 120 catch (IOException ex) { 121 if (logger.isDebugEnabled()) { 122 logger.debug("Could not find Velocity resource: " + resource); 123 } 124 } 125 } 126 throw new ResourceNotFoundException( 127 "Could not find resource [" + source + "] in Spring resource loader path"); 128 } 129 130 @Override isSourceModified(Resource resource)131 public boolean isSourceModified(Resource resource) { 132 return false; 133 } 134 135 @Override getLastModified(Resource resource)136 public long getLastModified(Resource resource) { 137 return 0; 138 } 139 140 } 141