001/* 002 * Copyright 2002-2018 the original author or authors. 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 * https://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 */ 016 017package org.springframework.scripting.support; 018 019import java.io.IOException; 020import java.io.Reader; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024 025import org.springframework.core.io.Resource; 026import org.springframework.core.io.support.EncodedResource; 027import org.springframework.lang.Nullable; 028import org.springframework.scripting.ScriptSource; 029import org.springframework.util.Assert; 030import org.springframework.util.FileCopyUtils; 031import org.springframework.util.StringUtils; 032 033/** 034 * {@link org.springframework.scripting.ScriptSource} implementation 035 * based on Spring's {@link org.springframework.core.io.Resource} 036 * abstraction. Loads the script text from the underlying Resource's 037 * {@link org.springframework.core.io.Resource#getFile() File} or 038 * {@link org.springframework.core.io.Resource#getInputStream() InputStream}, 039 * and tracks the last-modified timestamp of the file (if possible). 040 * 041 * @author Rob Harrop 042 * @author Juergen Hoeller 043 * @since 2.0 044 * @see org.springframework.core.io.Resource#getInputStream() 045 * @see org.springframework.core.io.Resource#getFile() 046 * @see org.springframework.core.io.ResourceLoader 047 */ 048public class ResourceScriptSource implements ScriptSource { 049 050 /** Logger available to subclasses. */ 051 protected final Log logger = LogFactory.getLog(getClass()); 052 053 private EncodedResource resource; 054 055 private long lastModified = -1; 056 057 private final Object lastModifiedMonitor = new Object(); 058 059 060 /** 061 * Create a new ResourceScriptSource for the given resource. 062 * @param resource the EncodedResource to load the script from 063 */ 064 public ResourceScriptSource(EncodedResource resource) { 065 Assert.notNull(resource, "Resource must not be null"); 066 this.resource = resource; 067 } 068 069 /** 070 * Create a new ResourceScriptSource for the given resource. 071 * @param resource the Resource to load the script from (using UTF-8 encoding) 072 */ 073 public ResourceScriptSource(Resource resource) { 074 Assert.notNull(resource, "Resource must not be null"); 075 this.resource = new EncodedResource(resource, "UTF-8"); 076 } 077 078 079 /** 080 * Return the {@link org.springframework.core.io.Resource} to load the 081 * script from. 082 */ 083 public final Resource getResource() { 084 return this.resource.getResource(); 085 } 086 087 /** 088 * Set the encoding used for reading the script resource. 089 * <p>The default value for regular Resources is "UTF-8". 090 * A {@code null} value implies the platform default. 091 */ 092 public void setEncoding(@Nullable String encoding) { 093 this.resource = new EncodedResource(this.resource.getResource(), encoding); 094 } 095 096 097 @Override 098 public String getScriptAsString() throws IOException { 099 synchronized (this.lastModifiedMonitor) { 100 this.lastModified = retrieveLastModifiedTime(); 101 } 102 Reader reader = this.resource.getReader(); 103 return FileCopyUtils.copyToString(reader); 104 } 105 106 @Override 107 public boolean isModified() { 108 synchronized (this.lastModifiedMonitor) { 109 return (this.lastModified < 0 || retrieveLastModifiedTime() > this.lastModified); 110 } 111 } 112 113 /** 114 * Retrieve the current last-modified timestamp of the underlying resource. 115 * @return the current timestamp, or 0 if not determinable 116 */ 117 protected long retrieveLastModifiedTime() { 118 try { 119 return getResource().lastModified(); 120 } 121 catch (IOException ex) { 122 if (logger.isDebugEnabled()) { 123 logger.debug(getResource() + " could not be resolved in the file system - " + 124 "current timestamp not available for script modification check", ex); 125 } 126 return 0; 127 } 128 } 129 130 @Override 131 @Nullable 132 public String suggestedClassName() { 133 String filename = getResource().getFilename(); 134 return (filename != null ? StringUtils.stripFilenameExtension(filename) : null); 135 } 136 137 @Override 138 public String toString() { 139 return this.resource.toString(); 140 } 141 142}