/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.clearsilver.jsilver.adaptor; import com.google.clearsilver.jsilver.exceptions.JSilverTemplateNotFoundException; import com.google.clearsilver.jsilver.resourceloader.ResourceLoader; import org.clearsilver.CSFileLoader; import org.clearsilver.CSUtil; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.util.List; /** * Wrap a CSFileLoader with a ResourceLoader */ public class ResourceLoaderAdaptor implements ResourceLoader { private final JHdf hdf; private final LoadPathToFileCache loadPathCache; private final CSFileLoader csFileLoader; private List loadPaths; ResourceLoaderAdaptor(JHdf hdf, LoadPathToFileCache loadPathCache, CSFileLoader csFileLoader) { this.hdf = hdf; this.loadPathCache = loadPathCache; this.csFileLoader = csFileLoader; } @Override public Reader open(String name) throws IOException { if (csFileLoader != null) { if (hdf.getData() == null) { throw new IllegalStateException("HDF is already closed"); } return new StringReader(csFileLoader.load(hdf, name)); } else { File file = locateFile(name); if (file == null) { throw new FileNotFoundException("Could not locate file " + name); } return new InputStreamReader(new FileInputStream(file), "UTF-8"); } } @Override public Reader openOrFail(String name) throws JSilverTemplateNotFoundException, IOException { Reader reader = open(name); if (reader == null) { final StringBuffer text = new StringBuffer(); text.append("No file '"); text.append(name); text.append("' "); if (loadPaths == null || loadPaths.isEmpty()) { text.append("with no load paths"); } else if (loadPaths.size() == 1) { text.append("inside directory '"); text.append(loadPaths.get(0)); text.append("'"); } else { text.append("inside directories ( "); for (String path : getLoadPaths()) { text.append("'"); text.append(path); text.append("' "); } text.append(")"); } throw new JSilverTemplateNotFoundException(text.toString()); } else { return reader; } } /** * * @param name name of the file to locate. * @return a File object corresponding to the existing file or {@code null} if it does not exist. */ File locateFile(String name) { if (name.startsWith(File.separator)) { // Full path to file was given. File file = newFile(name); return file.exists() ? file : null; } File file = null; // loadPathCache is null when load path caching is disabled at the // JSilverFactory level. This is implied by setting cache size // to 0 using JSilverOptions.setLoadPathCacheSize(0). if (loadPathCache != null) { String filePath = loadPathCache.lookup(getLoadPaths(), name); if (filePath != null) { file = newFile(filePath); return file.exists() ? file : null; } } file = locateFile(getLoadPaths(), name); if (file != null && loadPathCache != null) { loadPathCache.add(getLoadPaths(), name, file.getAbsolutePath()); } return file; } /** * Given an ordered list of directories to look in, locate the specified file. Returns * null if file not found. *

* This is copied from {@link org.clearsilver.CSUtil#locateFile(java.util.List, String)} but has * one important difference. It calls our subclassable newFile method. * * @param loadPaths the ordered list of paths to search. * @param filename the name of the file. * @return a File object corresponding to the file. null if file not found. */ File locateFile(List loadPaths, String filename) { if (filename == null) { throw new NullPointerException("No filename provided"); } if (loadPaths == null) { throw new NullPointerException("No loadpaths provided."); } for (String path : loadPaths) { File file = newFile(path, filename); if (file.exists()) { return file; } } return null; } /** * Separate methods to allow tests to subclass and override File creation and return mocks or * fakes. */ File newFile(String filename) { return new File(filename); } File newFile(String path, String filename) { return new File(path, filename); } @Override public void close(Reader reader) throws IOException { reader.close(); } @Override public Object getKey(String filename) { if (filename.startsWith(File.separator)) { return filename; } else { File file = locateFile(filename); if (file == null) { // The file does not exist, use the full loadpath and file name as the // key. return LoadPathToFileCache.makeCacheKey(getLoadPaths(), filename); } else { return file.getAbsolutePath(); } } } /** * Some applications, e.g. online help, need to know when a file has changed due to a symlink * modification hence the use of {@link File#getCanonicalFile()}, if possible. */ @Override public Object getResourceVersionId(String filename) { File file = locateFile(filename); if (file == null) { return null; } String fullPath; try { fullPath = file.getCanonicalPath(); } catch (IOException e) { fullPath = file.getAbsolutePath(); } return String.format("%s@%s", fullPath, file.lastModified()); } final CSFileLoader getCSFileLoader() { return csFileLoader; } private synchronized List getLoadPaths() { if (loadPaths == null) { if (hdf.getData() == null) { throw new IllegalStateException("HDF is already closed"); } loadPaths = CSUtil.getLoadPaths(hdf, true); } return loadPaths; } }