156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/*
256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc.
356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License");
556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License.
656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at
756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0
956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software
1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS,
1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and
1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License.
1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.adaptor;
1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverTemplateNotFoundException;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport org.clearsilver.CSFileLoader;
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport org.clearsilver.CSUtil;
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.File;
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.FileInputStream;
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.FileNotFoundException;
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException;
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.InputStreamReader;
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.Reader;
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.StringReader;
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.List;
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Wrap a CSFileLoader with a ResourceLoader
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class ResourceLoaderAdaptor implements ResourceLoader {
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final JHdf hdf;
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final LoadPathToFileCache loadPathCache;
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final CSFileLoader csFileLoader;
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private List<String> loadPaths;
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  ResourceLoaderAdaptor(JHdf hdf, LoadPathToFileCache loadPathCache, CSFileLoader csFileLoader) {
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.hdf = hdf;
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.loadPathCache = loadPathCache;
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.csFileLoader = csFileLoader;
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Reader open(String name) throws IOException {
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (csFileLoader != null) {
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (hdf.getData() == null) {
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        throw new IllegalStateException("HDF is already closed");
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return new StringReader(csFileLoader.load(hdf, name));
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      File file = locateFile(name);
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (file == null) {
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        throw new FileNotFoundException("Could not locate file " + name);
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return new InputStreamReader(new FileInputStream(file), "UTF-8");
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Reader openOrFail(String name) throws JSilverTemplateNotFoundException, IOException {
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Reader reader = open(name);
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (reader == null) {
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      final StringBuffer text = new StringBuffer();
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      text.append("No file '");
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      text.append(name);
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      text.append("' ");
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (loadPaths == null || loadPaths.isEmpty()) {
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        text.append("with no load paths");
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } else if (loadPaths.size() == 1) {
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        text.append("inside directory '");
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        text.append(loadPaths.get(0));
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        text.append("'");
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } else {
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        text.append("inside directories ( ");
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        for (String path : getLoadPaths()) {
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          text.append("'");
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          text.append(path);
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          text.append("' ");
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        }
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        text.append(")");
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new JSilverTemplateNotFoundException(text.toString());
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return reader;
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param name name of the file to locate.
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @return a File object corresponding to the existing file or {@code null} if it does not exist.
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  File locateFile(String name) {
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (name.startsWith(File.separator)) {
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Full path to file was given.
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      File file = newFile(name);
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return file.exists() ? file : null;
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    File file = null;
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // loadPathCache is null when load path caching is disabled at the
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // JSilverFactory level. This is implied by setting cache size
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // to 0 using JSilverOptions.setLoadPathCacheSize(0).
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (loadPathCache != null) {
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String filePath = loadPathCache.lookup(getLoadPaths(), name);
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (filePath != null) {
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        file = newFile(filePath);
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        return file.exists() ? file : null;
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    file = locateFile(getLoadPaths(), name);
11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (file != null && loadPathCache != null) {
12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      loadPathCache.add(getLoadPaths(), name, file.getAbsolutePath());
12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return file;
12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Given an ordered list of directories to look in, locate the specified file. Returns
12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * <code>null</code> if file not found.
12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * <p>
12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * This is copied from {@link org.clearsilver.CSUtil#locateFile(java.util.List, String)} but has
13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * one important difference. It calls our subclassable newFile method.
13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param loadPaths the ordered list of paths to search.
13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param filename the name of the file.
13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @return a File object corresponding to the file. <code>null</code> if file not found.
13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  File locateFile(List<String> loadPaths, String filename) {
13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (filename == null) {
13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new NullPointerException("No filename provided");
13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (loadPaths == null) {
14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new NullPointerException("No loadpaths provided.");
14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (String path : loadPaths) {
14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      File file = newFile(path, filename);
14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (file.exists()) {
14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        return file;
14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return null;
15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Separate methods to allow tests to subclass and override File creation and return mocks or
15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * fakes.
15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  File newFile(String filename) {
15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return new File(filename);
15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  File newFile(String path, String filename) {
16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return new File(path, filename);
16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void close(Reader reader) throws IOException {
16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    reader.close();
16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Object getKey(String filename) {
17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (filename.startsWith(File.separator)) {
17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return filename;
17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      File file = locateFile(filename);
17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (file == null) {
17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        // The file does not exist, use the full loadpath and file name as the
17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        // key.
17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        return LoadPathToFileCache.makeCacheKey(getLoadPaths(), filename);
17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } else {
18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        return file.getAbsolutePath();
18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Some applications, e.g. online help, need to know when a file has changed due to a symlink
18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * modification hence the use of {@link File#getCanonicalFile()}, if possible.
18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Object getResourceVersionId(String filename) {
19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    File file = locateFile(filename);
19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (file == null) {
19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return null;
19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String fullPath;
19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    try {
19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      fullPath = file.getCanonicalPath();
19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } catch (IOException e) {
20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      fullPath = file.getAbsolutePath();
20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return String.format("%s@%s", fullPath, file.lastModified());
20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  final CSFileLoader getCSFileLoader() {
20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return csFileLoader;
20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private synchronized List<String> getLoadPaths() {
21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (loadPaths == null) {
21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (hdf.getData() == null) {
21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        throw new IllegalStateException("HDF is already closed");
21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      loadPaths = CSUtil.getLoadPaths(hdf, true);
21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return loadPaths;
21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
219