1/*
2 * Copyright (C) 2010 Google Inc.
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 * http://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
17package com.google.clearsilver.jsilver.resourceloader;
18
19import com.google.clearsilver.jsilver.exceptions.JSilverTemplateNotFoundException;
20
21import java.io.FilterReader;
22import java.io.IOException;
23import java.io.Reader;
24import java.util.ArrayList;
25import java.util.List;
26
27/**
28 * ResourceLoader composed of other ResourceLoaders. When a resource is loaded, it will search
29 * through each ResourceLoader until it finds something.
30 *
31 * @see ResourceLoader
32 */
33public class CompositeResourceLoader implements ResourceLoader {
34
35  private final List<ResourceLoader> loaders = new ArrayList<ResourceLoader>();
36
37  public CompositeResourceLoader(Iterable<ResourceLoader> loaders) {
38    for (ResourceLoader loader : loaders) {
39      add(loader);
40    }
41  }
42
43  public CompositeResourceLoader(ResourceLoader... loaders) {
44    for (ResourceLoader loader : loaders) {
45      add(loader);
46    }
47  }
48
49  public void add(ResourceLoader loader) {
50    loaders.add(loader);
51  }
52
53  public Reader open(String name) throws IOException {
54    for (ResourceLoader loader : loaders) {
55      Reader reader = loader.open(name);
56      if (reader != null) {
57        return new ReaderTracer(reader, loader);
58      }
59    }
60    return null;
61  }
62
63  @Override
64  public Reader openOrFail(String name) throws JSilverTemplateNotFoundException, IOException {
65    Reader reader = open(name);
66    if (reader == null) {
67      throw new JSilverTemplateNotFoundException(name);
68    } else {
69      return reader;
70    }
71  }
72
73  public void close(Reader reader) throws IOException {
74    if (!(reader instanceof ReaderTracer)) {
75      throw new IllegalArgumentException("I can't close a reader I didn't open.");
76    }
77    reader.close();
78  }
79
80  /**
81   * We return the filename as the key of uniqueness as we assume that if this
82   * CompositeResourceLoader is in use, then there won't be another ResourceLoader that we are
83   * competing against. If we did need to worry about it we would want to prepend the key from
84   * above.
85   */
86  @Override
87  public Object getKey(String filename) {
88    return filename;
89  }
90
91  /**
92   * Return the first non-null version identifier found among the ResourceLoaders, using the same
93   * search order as {@link #open(String)}.
94   */
95  @Override
96  public Object getResourceVersionId(String filename) {
97    for (ResourceLoader loader : loaders) {
98      Object currentKey = loader.getResourceVersionId(filename);
99      if (currentKey != null) {
100        return currentKey;
101      }
102    }
103    return null;
104  }
105
106  /**
107   * Wraps a reader, associating it with the original ResourceLoader - this is necessary so when
108   * close() is called, we delegate back to original ResourceLoader.
109   */
110  private static class ReaderTracer extends FilterReader {
111
112    private final ResourceLoader originalLoader;
113
114    public ReaderTracer(Reader in, ResourceLoader originalLoader) {
115      super(in);
116      this.originalLoader = originalLoader;
117    }
118
119    public void close() throws IOException {
120      originalLoader.close(in);
121    }
122  }
123
124}
125