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