/*
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2013 - 2014 Adobe
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.adobe.acs.commons.models.injectors.impl;
import org.apache.sling.xss.XSSAPI;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.components.ComponentContext;
import com.day.cq.wcm.api.designer.Design;
import com.day.cq.wcm.api.designer.Designer;
import com.day.cq.wcm.api.designer.Style;
import com.day.cq.wcm.commons.WCMUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.spi.DisposalCallbackRegistry;
import org.apache.sling.models.spi.Injector;
import org.osgi.framework.Constants;
import javax.jcr.Session;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Type;
/**
* Sling Models Injector which injects the Adobe AEM objects defined in
* <a href="http://bit.ly/1gmlmfE"><cq:defineObjects/></a>.
* <p>
* the following objects can be injected:
* <ul>
* <li> resource the current resource
* <li> resourceResolver the current resource resolver
*
* <li> componentContext component context of this request
*
* <li> pageManager page manager
* <li> currentPage containing page addressed by the request
* <li> resourcePage containing page of the addressed resource
*
* <li> designer the designer
* <li> currentDesign design of the addressed resource
* <li> resourceDesign design of the addressed resource
*
* <li> currentStyle style addressed by the request
* <li> session the current session
* <li> xssApi cross site scripting provider for the current request
* </ul>
*
* Note: This Injector requires at least org.apache.sling.models.impl version 1.0.2
*
*/
@Component
@Service
/*
* SERVICE_RANKING of this service should be lower than the ranking of the OsgiServiceInjector (5000),
* otherwise the generic XSSAPI service would be injected from the OSGi Service Registry instead of the
* pre-configured from the current request.
*/
@Property(name = Constants.SERVICE_RANKING, intValue = 4500)
public final class AemObjectInjector implements Injector {
private static final String COM_DAY_CQ_WCM_TAGS_DEFINE_OBJECTS_TAG = "com.day.cq.wcm.tags.DefineObjectsTag";
@Override
public String getName() {
return "define-objects";
}
@Override
public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element,
DisposalCallbackRegistry callbackRegistry) {
// sanity check
if (!(adaptable instanceof Resource || adaptable instanceof SlingHttpServletRequest)) {
return null;
}
ObjectType nameEnum = ObjectType.fromString(name);
if (nameEnum == null) {
return null;
}
switch (nameEnum) {
case RESOURCE:
return getResource(adaptable);
case RESOURCE_RESOLVER:
return getResourceResolver(adaptable);
case COMPONENT_CONTEXT:
return getComponentContext(adaptable);
case PAGE_MANAGER:
return getPageManager(adaptable);
case CURRENT_PAGE:
return getCurrentPage(adaptable);
case RESOURCE_PAGE:
return getResourcePage(adaptable);
case DESIGNER:
return getDesigner(adaptable);
case CURRENT_DESIGN:
return getCurrentDesign(adaptable);
case RESOURCE_DESIGN:
return getResourceDesign(adaptable);
case CURRENT_STYLE:
return getCurrentStyle(adaptable);
case SESSION:
return getSession(adaptable);
case XSS_API:
return getXssApi(adaptable);
default:
return null;
}
}
// --- private stuff --
private Resource getResource(Object adaptable) {
if (adaptable instanceof SlingHttpServletRequest) {
return ((SlingHttpServletRequest) adaptable).getResource();
}
if (adaptable instanceof Resource) {
return (Resource) adaptable;
}
return null;
}
private ResourceResolver getResourceResolver(Object adaptable) {
if (adaptable instanceof SlingHttpServletRequest) {
return ((SlingHttpServletRequest) adaptable).getResourceResolver();
}
if (adaptable instanceof Resource) {
return ((Resource) adaptable).getResourceResolver();
}
return null;
}
private PageManager getPageManager(Object adaptable) {
ResourceResolver resolver = getResourceResolver(adaptable);
if (resolver != null) {
return resolver.adaptTo(PageManager.class);
}
return null;
}
private Designer getDesigner(Object adaptable) {
ResourceResolver resolver = getResourceResolver(adaptable);
if (resolver != null) {
return resolver.adaptTo(Designer.class);
}
return null;
}
/**
* Get the current component context.
*
* @param adaptable a SlingHttpServletRequest
* @return the ComponentContext if the adaptable was a SlingHttpServletRequest, or null otherwise
*/
private ComponentContext getComponentContext(Object adaptable) {
if (adaptable instanceof SlingHttpServletRequest) {
SlingHttpServletRequest request = ((SlingHttpServletRequest) adaptable);
return WCMUtils.getComponentContext(request);
}
// ComponentContext is not reachable from Resource
return null;
}
private Page getResourcePage(Object adaptable) {
PageManager pageManager = getPageManager(adaptable);
Resource resource = getResource(adaptable);
if (pageManager != null && resource != null) {
return pageManager.getContainingPage(resource);
}
return null;
}
/**
* Get the current page.
*
* @param adaptable a SlingHttpServletRequest
* @return the current Page if the adaptable was a SlingHttpServletRequest, null otherwise
*/
private Page getCurrentPage(Object adaptable) {
ComponentContext context = getComponentContext(adaptable);
return (context != null) ? context.getPage() : null;
}
/**
* Get the current design.
*
* @param adaptable a SlingHttpServletRequest
* @return the current Design if the adaptable was a SlingHttpServletRequest, the default Design otherwise
*/
private Design getCurrentDesign(Object adaptable) {
Page currentPage = getCurrentPage(adaptable);
Designer designer = getDesigner(adaptable);
if (currentPage != null && designer != null) {
return designer.getDesign(currentPage);
}
return null;
}
private Design getResourceDesign(Object adaptable) {
Page resourcePage = getResourcePage(adaptable);
Designer designer = getDesigner(adaptable);
if (adaptable instanceof SlingHttpServletRequest) {
SlingHttpServletRequest request = (SlingHttpServletRequest) adaptable;
if (resourcePage != null && designer != null) {
String resourceDesignKey = COM_DAY_CQ_WCM_TAGS_DEFINE_OBJECTS_TAG + resourcePage.getPath();
Object cachedResourceDesign = request.getAttribute(resourceDesignKey);
if (cachedResourceDesign != null) {
return (Design) cachedResourceDesign;
} else {
Design resourceDesign = designer.getDesign(resourcePage);
request.setAttribute(resourceDesignKey, resourceDesign);
return resourceDesign;
}
}
}
if (adaptable instanceof Resource) {
return designer != null ? designer.getDesign(resourcePage) : null;
}
return null;
}
/**
* Get the current style.
*
* @param adaptable a SlingHttpServletRequest
* @return the current Style if the adaptable was a SlingHttpServletRequest, null otherwise
*/
private Style getCurrentStyle(Object adaptable) {
Design currentDesign = getCurrentDesign(adaptable);
ComponentContext componentContext = getComponentContext(adaptable);
if (currentDesign != null && componentContext != null) {
return currentDesign.getStyle(componentContext.getCell());
}
return null;
}
/**
* Get the session.
*
* @param adaptable Either a SlingHttpServletRequest or a Resource
* @return the current Session
*/
private Session getSession(Object adaptable) {
ResourceResolver resolver = getResourceResolver(adaptable);
return resolver != null ? resolver.adaptTo(Session.class) : null;
}
/**
* Get the XSS API.
*
* @param adaptable a SlingHttpServletRequest
* @return a XSSAPI object configured for the current request, or null otherwise
*/
private XSSAPI getXssApi(Object adaptable) {
if (adaptable instanceof SlingHttpServletRequest) {
SlingHttpServletRequest request = (SlingHttpServletRequest) adaptable;
return request.adaptTo(XSSAPI.class);
}
// otherwise will fetch generic XSSAPI from OSGiServiceInjector
return null;
}
// --- inner classes ---
/**
* Enumeration which encapsulated the available objects.
*/
private enum ObjectType {
RESOURCE("resource"),
RESOURCE_RESOLVER("resourceResolver"),
COMPONENT_CONTEXT("componentContext"),
PAGE_MANAGER("pageManager"),
CURRENT_PAGE("currentPage"),
RESOURCE_PAGE("resourcePage"),
DESIGNER("designer"),
CURRENT_DESIGN("currentDesign"),
RESOURCE_DESIGN("resourceDesign"),
CURRENT_STYLE("currentStyle"),
SESSION("session"),
XSS_API("xssApi");
private String text;
ObjectType(String text) {
this.text = text;
}
public static ObjectType fromString(String text) {
if (text != null) {
for (ObjectType b : ObjectType.values()) {
if (text.equalsIgnoreCase(b.text)) {
return b;
}
}
}
return null;
}
}
}