1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.resourceloader.layered;
35
36 import static com.google.common.collect.Iterables.*;
37
38 import info.magnolia.resourceloader.AbstractResourceOrigin;
39 import info.magnolia.resourceloader.Resource;
40 import info.magnolia.resourceloader.ResourceOrigin;
41 import info.magnolia.resourceloader.ResourceOriginFactory;
42 import info.magnolia.resourceloader.ResourceVisitor;
43 import info.magnolia.resourceloader.util.Functions;
44
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.io.Reader;
48 import java.nio.charset.Charset;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.List;
52
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 import com.google.auto.factory.AutoFactory;
57 import com.google.common.base.Function;
58 import com.google.common.base.Optional;
59 import com.google.common.base.Predicate;
60 import com.google.common.collect.Iterables;
61 import com.google.common.collect.Lists;
62 import com.google.common.collect.Ordering;
63
64
65
66
67
68
69 @AutoFactory(implementing = ResourceOriginFactory.class)
70 public class LayeredResourceOrigin extends AbstractResourceOrigin<LayeredResource> {
71
72 private static final Logger log = LoggerFactory.getLogger(LayeredResourceOrigin.class);
73
74 private final List<ResourceOrigin> origins;
75
76
77 LayeredResourceOrigin(String name, ResourceOrigin... origins) {
78 super(name);
79 this.origins = Arrays.asList(origins);
80 }
81
82 @Override
83 public LayeredResource getRoot() {
84 final List<Resource> roots = Lists.transform(origins, Functions.getRoot());
85 return newLayeredResource(roots);
86 }
87
88 @Override
89 public void watchForChanges(ResourceVisitor visitor) {
90 for (ResourceOrigin origin : origins) {
91 origin.watchForChanges(new RelayerResourceVisitor(this, visitor));
92 }
93 }
94
95 @Override
96 public LayeredResource getByPath(String path) {
97 final Iterable<ResourceOrigin> matchingOrigins = filter(this.origins, Functions.hasPath(path));
98 final List<Resource> matchingResources = Lists.newArrayList(transform(matchingOrigins, Functions.getByPath(path)));
99 if (matchingResources.isEmpty()) {
100 throw new ResourceNotFoundException(this, path);
101 }
102 return newLayeredResource(matchingResources);
103 }
104
105 @Override
106 public boolean hasPath(String path) {
107 return any(origins, Functions.hasPath(path));
108 }
109
110 @Override
111 protected boolean isFile(LayeredResource resource) {
112 return resource.getFirst().isFile();
113 }
114
115 @Override
116 protected boolean isDirectory(LayeredResource resource) {
117 return resource.getFirst().isDirectory();
118 }
119
120 @Override
121 protected boolean isEditable(LayeredResource resource) {
122 return resource.getFirst().isEditable();
123 }
124
125 @Override
126 protected String getPath(LayeredResource resource) {
127 return resource.getFirst().getPath();
128 }
129
130 @Override
131 protected String getName(LayeredResource resource) {
132 return resource.getFirst().getName();
133 }
134
135 @Override
136 protected long getLastModified(LayeredResource resource) {
137 return resource.getFirst().getLastModified();
138 }
139
140 @Override
141 protected List<LayeredResource> listChildren(LayeredResource resource) {
142 List<LayeredResource> layeredResources = new ArrayList<>();
143
144
145 final List<Resource> layers = resource.getLayers();
146 for (Resource layer : layers) {
147 List<Resource> layerChildren = layer.listChildren();
148
149
150 if (layeredResources.isEmpty()) {
151 layeredResources.addAll(Lists.transform(layerChildren, new Function<Resource, LayeredResource>() {
152 @Override
153 public LayeredResource apply(Resource input) {
154 return new LayeredResource(LayeredResourceOrigin.this, input.getPath(), Lists.newArrayList(input));
155 }
156 }));
157 continue;
158 }
159
160 for (final Resource r : layerChildren) {
161 Optional<LayeredResource> matchingResource = Iterables.tryFind(layeredResources, new Predicate<LayeredResource>() {
162 @Override
163 public boolean apply(LayeredResource input) {
164 return r.getPath().equals(input.getPath()) && r.isFile() == input.isFile();
165 }
166 });
167 if (matchingResource.isPresent()) {
168 LayeredResource l = matchingResource.get();
169 l.getLayers().add(r);
170 } else {
171 LayeredResource l = new LayeredResource(this, r.getPath(), Lists.newArrayList(r));
172 layeredResources.add(l);
173 }
174 }
175 }
176 return Ordering.from(Functions.compareByHandle()).immutableSortedCopy(layeredResources);
177 }
178
179 @Override
180 protected LayeredResource getParent(LayeredResource resource) {
181
182
183
184
185 Resource parent = resource.getFirst().getParent();
186 return parent != null ? getByPath(parent.getPath()) : null;
187 }
188
189 @Override
190 protected InputStream doOpenStream(LayeredResource resource) throws IOException {
191 return resource.getFirst().openStream();
192 }
193
194 @Override
195 protected Reader openReader(LayeredResource resource) throws IOException {
196 return resource.getFirst().openReader();
197 }
198
199
200
201
202
203
204 @Override
205 protected Charset getCharsetFor(LayeredResource resource) {
206 throw new IllegalStateException("This method should not be called");
207 }
208
209 protected LayeredResource newLayeredResource(List<Resource> resources) {
210
211 final String path = resources.get(0).getPath();
212 final boolean isDirectory = resources.get(0).isDirectory();
213 if (!all(resources, Functions.pathEquals(path))) {
214 throw new IllegalStateException("Given resources don't match path [" + path + "]: " + resources);
215 }
216 final Predicate<Resource> dirOrFilePredicate = isDirectory ? Functions.isDirectory() : Functions.isFile();
217 if (!all(resources, dirOrFilePredicate)) {
218 log.warn("Resources at {} are not all directory/file: {}", path, resources);
219 resources = Lists.newArrayList(Iterables.filter(resources, dirOrFilePredicate));
220 }
221 return new LayeredResource(this, path, resources);
222 }
223
224 }