View Javadoc
1   /**
2    * This file Copyright (c) 2015-2016 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.resourceloader.classpath;
35  
36  import static info.magnolia.resourceloader.ResourceOriginChange.resourceChange;
37  import static info.magnolia.resourceloader.classpath.service.ClasspathService.ClasspathEntryNotFoundException;
38  
39  import info.magnolia.resourceloader.AbstractResourceOrigin;
40  import info.magnolia.resourceloader.ResourceOriginChange;
41  import info.magnolia.resourceloader.ResourceOriginFactory;
42  import info.magnolia.resourceloader.classpath.hierarchy.ClasspathDirectory;
43  import info.magnolia.resourceloader.classpath.hierarchy.ClasspathEntry;
44  import info.magnolia.resourceloader.classpath.hierarchy.ClasspathFile;
45  import info.magnolia.resourceloader.classpath.service.ClasspathService;
46  import info.magnolia.resourceloader.classpath.service.MonitoredClasspathService;
47  import info.magnolia.resourceloader.classpath.service.impl.devmode.DevelopmentModeClasspathService;
48  import info.magnolia.resourceloader.classpath.service.impl.devmode.DevelopmentModeClasspathService.ClasspathResourceCallback;
49  
50  import java.io.IOException;
51  import java.io.InputStream;
52  import java.nio.charset.Charset;
53  import java.util.List;
54  
55  import com.google.auto.factory.AutoFactory;
56  import com.google.auto.factory.Provided;
57  import com.google.common.base.Function;
58  import com.google.common.collect.Lists;
59  
60  /**
61   * A {@link info.magnolia.resourceloader.ResourceOrigin} which serves resources collected from the web application classpath.
62   * Classpath file/folder hierarchy is provided by the {@link ClasspathService classpath service} which also acts as a delegate
63   * for most of this origin's calls.
64   *
65   * @see ClasspathService
66   * @see ClasspathResource
67   */
68  @AutoFactory(implementing = ResourceOriginFactory.class)
69  public class ClasspathResourceOrigin extends AbstractResourceOrigin<ClasspathResource> {
70  
71      private final Function<ClasspathEntry, ClasspathResource> getResourceInstance = new Function<ClasspathEntry, ClasspathResource>() {
72          @Override
73          @SuppressWarnings("unchecked")
74          public ClasspathResource<ClasspathEntry> apply(ClasspathEntry input) {
75              return new ClasspathResource(ClasspathResourceOrigin.this, input);
76          }
77      };
78  
79      private final ClasspathService classpathService;
80  
81      public ClasspathResourceOrigin(String name, @Provided ClasspathService classpathService) {
82          super(name);
83          this.classpathService = classpathService;
84      }
85  
86      @Override
87      protected void initializeResourceChangeMonitoring() {
88          if (classpathService instanceof MonitoredClasspathService) {
89              ((MonitoredClasspathService) classpathService).registerResourceChangeCallback(new ClasspathResourceCallback() {
90                  @Override
91                  public void onClasspathResourceChanged(DevelopmentModeClasspathService.ClasspathResourceChange change) {
92                      final ResourceOriginChange resourceOriginChange =
93                              resourceChange().
94                                      ofType(change.getType()).
95                                      inOrigin(ClasspathResourceOrigin.this).
96                                      at(change.getChangedResourcePath()).build();
97  
98                      dispatchResourceChange(resourceOriginChange);
99                  }
100             });
101         }
102     }
103 
104     @Override
105     protected boolean isFile(ClasspathResource resource) {
106         return resource.getClasspathEntry() instanceof ClasspathFile;
107     }
108 
109     @Override
110     protected boolean isDirectory(ClasspathResource resource) {
111         return resource.getClasspathEntry() instanceof ClasspathDirectory;
112     }
113 
114     @Override
115     protected String getPath(ClasspathResource resource) {
116         return resource.getClasspathEntry().getAbsolutePath();
117     }
118 
119     @Override
120     protected String getName(ClasspathResource resource) {
121         return resource.getClasspathEntry().getName();
122     }
123 
124     @Override
125     protected long getLastModified(ClasspathResource resource) {
126         return resource.getClasspathEntry().getLastModified();
127     }
128 
129     @Override
130     protected List<ClasspathResource> listChildren(ClasspathResource resource) {
131         final ClasspathEntry classpathEntry = resource.getClasspathEntry();
132         if (resource.isDirectory()) {
133             final ClasspathDirectory folder = (ClasspathDirectory) classpathEntry;
134             return Lists.transform(folder.getEntries(), getResourceInstance);
135         } else {
136             throw new IllegalArgumentException(String.format("%s is not a directory.", resource.getPath()));
137         }
138     }
139 
140     @Override
141     protected ClasspathResource getParent(ClasspathResource resource) {
142         if (getRoot().equals(resource)) {
143             return null;
144         }
145 
146         try {
147             return getResourceInstance.apply(classpathService.getParent(resource.getClasspathEntry()));
148         } catch (ClasspathEntryNotFoundException e) {
149             throw new ResourceNotFoundException(this, String.format("Failed to resolve a parent of a resource at [%s]", resource.getPath()));
150         }
151     }
152 
153     @Override
154     protected InputStream doOpenStream(ClasspathResource resource) throws IOException {
155         final ClasspathEntry classpathEntry = resource.getClasspathEntry();
156         if (!resource.isFile()) {
157             throw new IllegalArgumentException(String.format("It is not allowed to attempt to obtain an input stream for folder classpath entries (%s)", resource.getPath()));
158         }
159         return ((ClasspathFile) classpathEntry).openStream();
160     }
161 
162     @Override
163     protected Charset getCharsetFor(ClasspathResource resource) {
164         return classpathService.getConfiguration().getCharset();
165     }
166 
167     @Override
168     public ClasspathResource getRoot() {
169         return getResourceInstance.apply(classpathService.getRoot());
170     }
171 
172     @Override
173     public ClasspathResource getByPath(String path) {
174         try {
175             return getResourceInstance.apply(classpathService.getEntryAt(path));
176         } catch (ClasspathEntryNotFoundException e) {
177             throw new ResourceNotFoundException(this, String.format("Failed to resolve a classpath resource at [%s]", path));
178         }
179     }
180 
181     @Override
182     public boolean hasPath(String path) {
183         return classpathService.hasEntry(path);
184     }
185 }