Clover icon

Magnolia Resources Module 2.4.2

  1. Project Clover database Fri Nov 6 2015 16:15:26 CET
  2. Package info.magnolia.module.resources

File ResourceLinker.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

12
39
6
1
166
88
12
0.31
6.5
6
2
3.4% of code in this file is excluded from these metrics.

Classes

Class Line # Actions
ResourceLinker 58 39 3.4% 12 0
1.0100%
 

Contributing tests

This file is covered by 17 tests. .

Source view

1    /**
2    * This file Copyright (c) 2015 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.module.resources;
35   
36    import info.magnolia.cms.core.AggregationState;
37    import info.magnolia.link.LinkUtil;
38    import info.magnolia.resourceloader.Resource;
39    import info.magnolia.resourceloader.ResourceOrigin;
40    import info.magnolia.templating.functions.TemplatingFunctions;
41   
42    import java.util.TimeZone;
43    import java.util.regex.Matcher;
44    import java.util.regex.Pattern;
45   
46    import javax.inject.Inject;
47    import javax.inject.Provider;
48    import javax.inject.Singleton;
49   
50    import org.apache.commons.lang3.StringUtils;
51    import org.apache.commons.lang3.time.FastDateFormat;
52   
53    /**
54    * A simple component that helps locating resources in {@link ResourceOrigin} and generate links to them. Specifically,
55    * it handles prefixing links with context path, site prefix if needed, and the fingerprinting.
56    */
57    @Singleton
 
58    public class ResourceLinker {
59    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ResourceLinker.class);
60   
61    // Currently lenient, allowing both ~ and .
62    private static final Pattern CACHE_PATTERN = Pattern.compile("[~.]\\d{4}(-\\d{2}){5}-\\d{3}[~.]cache");
63   
64    private static final FastDateFormat TIME_STAMP_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd-HH-mm-ss-SSS", TimeZone.getTimeZone("GMT"));
65   
66    private final ResourceOrigin origin;
67    private final Provider<ResourcesModule> configuration;
68    private final TemplatingFunctions templatingFunctions;
69    private final Provider<AggregationState> aggregationStateProvider;
70   
 
71  28 toggle @Inject
72    public ResourceLinker(ResourceOrigin origin, Provider<ResourcesModule> configuration, Provider<AggregationState> aggregationStateProvider, TemplatingFunctions templatingFunctions) {
73  28 this.origin = origin;
74  28 this.configuration = configuration;
75  28 this.aggregationStateProvider = aggregationStateProvider;
76  28 this.templatingFunctions = templatingFunctions;
77    }
78   
 
79    toggle public String getServletMapping() {
80    return cleanDownloadPath() + "/*";
81    }
82   
83    /**
84    * Returns whatever's been configured as {@link ResourcesModule#downloadPath}, with a single leading slash and no leading slash.
85    */
 
86  18 toggle protected String cleanDownloadPath() {
87  18 final String downloadPath = configuration.get().getDownloadPath();
88  18 return downloadPath.replaceFirst("^/*(.*?)/*$", "/$1");
89    }
90   
 
91  9 toggle public String linkTo(String path, boolean addFingerPrint) {
92  9 if (LinkUtil.EXTERNAL_LINK_PATTERN.matcher(path).matches()) {
93    // TODO Client code should do this check, ideally. See e.g feature/better-resdef branch of magnolia-site (ResourceDefinition)
94  1 log.debug("Ignoring request to transform a link to {}, it's already an external link.", path);
95  1 return path;
96    }
97   
98    // Link prefix will be contextPath and site-prefix if any. The servlet will be matched because matching is done against AggState.currentURI. See info.magnolia.cms.filters.Mapping.findMatcher(javax.servlet.http.HttpServletRequest)
99    // TODO this should neither be in templatingFunctions nor be so bloody complicated
100  8 final String linkPrefix = templatingFunctions.linkPrefix(aggregationStateProvider.get().getMainContentNode());
101  8 final StringBuilder sb = new StringBuilder();
102  8 sb.append(linkPrefix);
103   
104  8 final String servletMappingPrefix = cleanDownloadPath();
105   
106    // We support links configured with the (servlet mapping) prefix and without (one can configure just the path as in the resources app)
107  8 final String resourcePath;
108  8 if (path.startsWith(servletMappingPrefix)) {
109  4 resourcePath = path.substring(servletMappingPrefix.length());
110    } else {
111  4 resourcePath = path;
112    }
113   
114  8 final boolean isKnownResource = origin.hasPath(resourcePath);
115  8 if (isKnownResource) {
116  4 sb.append(servletMappingPrefix);
117  4 if (addFingerPrint) {
118  2 final Resource resource = origin.getByPath(resourcePath);
119  2 final String fingerPrint = fingerPrintFor(resource);
120  2 final String ext = StringUtils.substringAfterLast(resourcePath, ".");
121  2 final String withoutExt = StringUtils.substringBeforeLast(resourcePath, ".");
122  2 sb.append(withoutExt).append("~").append(fingerPrint).append("~cache.").append(ext);
123    } else {
124  2 sb.append(resourcePath);
125    }
126    } else {
127    // Then we use the given path regardless of prefix
128  4 sb.append(path);
129  4 if (addFingerPrint) {
130  2 log.warn("Could not generate fingerprint for unknown resource {}", path);
131    }
132    }
133   
134  8 return sb.toString();
135    }
136   
137    /**
138    * Called with a pathInfo, cleans up the given path and returns the corresponding {@link Resource}.
139    * Leniently returns null if no such resource exists.
140    *
141    * @see javax.servlet.http.HttpServletRequest#getPathInfo()
142    */
 
143  10 toggle public Resource getResource(String pathInfo) {
144  10 final String path = stripFarFutureCachingTimestamp(pathInfo);
145  10 if (!origin.hasPath(path)) {
146  2 return null;
147    }
148  8 return origin.getByPath(path);
149    }
150   
151    // We have to do this here - AggregationState has a cleaned up version, but we can't rely on this,
152    // since it's currently done in RepositoryMappingFilter, which is later than servlets in the chain.
153    // Besides, that'd prevent us from using request.pathInfo as well.
154    // TODO This should really be factored out - see info.magnolia.module.resources.Resource.getLink()
155    // and info.magnolia.cms.util.LinkUtil
 
156  10 toggle protected String stripFarFutureCachingTimestamp(String resourcePath) {
157  10 final Matcher matcher = CACHE_PATTERN.matcher(resourcePath);
158  10 return matcher.replaceFirst("");
159    }
160   
 
161  2 toggle protected String fingerPrintFor(info.magnolia.resourceloader.Resource resource) {
162  2 final long lastMod = resource.getLastModified();
163  2 return TIME_STAMP_FORMAT.format(lastMod);
164    }
165   
166    }