View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2014 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.wcm.ui.granite.util;
21  
22  import javax.servlet.http.HttpServletRequest;
23  
24  import org.apache.commons.lang3.StringUtils;
25  import org.apache.commons.lang3.Strings;
26  import org.apache.sling.api.SlingHttpServletRequest;
27  import org.apache.sling.api.resource.Resource;
28  import org.apache.sling.api.resource.ResourceResolver;
29  import org.apache.sling.api.resource.ResourceUtil;
30  import org.jetbrains.annotations.NotNull;
31  import org.jetbrains.annotations.Nullable;
32  import org.osgi.annotation.versioning.ProviderType;
33  
34  import com.adobe.granite.ui.components.Value;
35  import com.day.cq.wcm.api.Page;
36  import com.day.cq.wcm.api.PageManager;
37  
38  /**
39   * Helper methods for GraniteUI components.
40   *
41   * <p>
42   * It uses some heuristics to get the current content path in context of a GraniteUI component:
43   * </p>
44   * <ol>
45   * <li>Inside create page wizard, try to get content path from referrer header</li>
46   * <li>Try to get content path from request suffix</li>
47   * <li>Try to get content path from "item" request parameter (inside multifield component)</li>
48   * </ol>
49   */
50  @ProviderType
51  public final class GraniteUi {
52  
53    static final String CREATEPAGEWITZARD_PROPERTIES_URI = "/mnt/overlay/wcm/core/content/sites/createpagewizard/properties.html";
54    static final String CREATEPAGEWITZARD_URI = "/mnt/overlay/wcm/core/content/sites/createpagewizard.html";
55    static final String HEADER_REFERER = "Referer";
56  
57    private GraniteUi() {
58      // static methods only
59    }
60  
61    /**
62     * Current content resource
63     * @param request Request
64     * @return Current content resource or null
65     */
66    public static @Nullable Resource getContentResource(@NotNull HttpServletRequest request) {
67      String contentPath = getContentPath(request);
68      if (contentPath != null) {
69        SlingHttpServletRequest slingRequest = (SlingHttpServletRequest)request;
70        return slingRequest.getResourceResolver().getResource(contentPath);
71      }
72      return null;
73    }
74  
75    /**
76     * Get current content resource
77     * If it does not exist, go up the content path and return the first resource that exists.
78     * @param request Request
79     * @return Current content resource or the first existing parent/ancestor.
80     */
81    public static @Nullable Resource getContentResourceOrParent(@NotNull HttpServletRequest request) {
82      String contentPath = getContentPath(request);
83      return getContentResourceOrParentFromPath((SlingHttpServletRequest)request, contentPath);
84    }
85  
86    /**
87     * Current content page. If the current resource does not exist the content page
88     * of the next-existing parent resource is returned.
89     * @param request Request
90     * @return Current content page or null
91     */
92    public static @Nullable Page getContentPage(@NotNull HttpServletRequest request) {
93      SlingHttpServletRequest slingRequest = (SlingHttpServletRequest)request;
94      Resource contentResource = getContentResourceOrParent(request);
95      if (contentResource != null) {
96        PageManager pageManager = slingRequest.getResourceResolver().adaptTo(PageManager.class);
97        if (pageManager != null) {
98          return pageManager.getContainingPage(contentResource);
99        }
100     }
101     return null;
102   }
103 
104   /**
105    * From the list of resource types get the first one that exists.
106    * @param resourceResolver Resource resolver
107    * @param resourceTypes ResourceTypes
108    * @return Existing resource type
109    */
110   public static @Nullable String getExistingResourceType(@NotNull ResourceResolver resourceResolver, @NotNull String @NotNull... resourceTypes) {
111     for (String path : resourceTypes) {
112       if (resourceResolver.getResource(path) != null) {
113         return path;
114       }
115     }
116     return null;
117   }
118 
119   /**
120    * Current content path
121    * @param request Request
122    * @return Current content path or null
123    */
124   @SuppressWarnings("deprecation")
125   private static @Nullable String getContentPath(@NotNull HttpServletRequest request) {
126 
127     String contentPath = (String)request.getAttribute(Value.CONTENTPATH_ATTRIBUTE);
128 
129     // if we are currently in create page wizard try to extract content path from referer,
130     // as it is not available via other ways
131     if (!isValidContentPath(contentPath) && StringUtils.contains(request.getRequestURI(), CREATEPAGEWITZARD_PROPERTIES_URI)) {
132       String referer = request.getHeader(HEADER_REFERER);
133       if (referer != null && StringUtils.contains(referer, CREATEPAGEWITZARD_URI)) {
134         contentPath = StringUtils.substringAfter(referer, CREATEPAGEWITZARD_URI);
135       }
136     }
137 
138     if (!isValidContentPath(contentPath)) {
139       // fallback to suffix if CONTENTPATH_ATTRIBUTE is not set
140       // (e.g. in inside a /libs/granite/ui/components/foundation/form/multifield component)
141       contentPath = ((SlingHttpServletRequest)request).getRequestPathInfo().getSuffix();
142     }
143 
144     if (!isValidContentPath(contentPath)) {
145       // fallback to suffix item parameter in query string
146       // (e.g. in inside a /libs/granite/ui/components/foundation/form/multifield component)
147       contentPath = request.getParameter("item");
148     }
149 
150     if (!isValidContentPath(contentPath)) {
151       contentPath = null;
152     }
153 
154     return contentPath;
155   }
156 
157   private static boolean isValidContentPath(@Nullable String path) {
158     if (path == null) {
159       return false;
160     }
161     return Strings.CS.startsWith(path, "/");
162   }
163 
164   private static Resource getContentResourceOrParentFromPath(SlingHttpServletRequest slingRequest, String contentPath) {
165     if (StringUtils.isNotEmpty(contentPath)) {
166       Resource contentResource = slingRequest.getResourceResolver().getResource(contentPath);
167       if (contentResource != null) {
168         return contentResource;
169       }
170       else {
171         return getContentResourceOrParentFromPath(slingRequest, ResourceUtil.getParent(contentPath));
172       }
173     }
174     return null;
175   }
176 
177 }