AemObjectInjector.java
- /*
- * #%L
- * wcm.io
- * %%
- * Copyright (C) 2014 wcm.io
- * %%
- * 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 io.wcm.sling.models.injectors.impl;
- import java.lang.reflect.AnnotatedElement;
- import java.lang.reflect.Type;
- import java.util.Locale;
- import org.apache.commons.lang3.StringUtils;
- import org.apache.sling.api.SlingHttpServletRequest;
- import org.apache.sling.api.resource.Resource;
- import org.apache.sling.api.resource.ResourceResolver;
- import org.apache.sling.api.scripting.SlingBindings;
- import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
- import org.apache.sling.models.spi.AcceptsNullName;
- import org.apache.sling.models.spi.DisposalCallbackRegistry;
- import org.apache.sling.models.spi.Injector;
- import org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor2;
- import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor2;
- import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory;
- import org.apache.sling.xss.XSSAPI;
- import org.jetbrains.annotations.NotNull;
- import org.jetbrains.annotations.Nullable;
- import org.osgi.framework.Constants;
- import org.osgi.service.component.annotations.Component;
- import org.osgi.service.component.annotations.Reference;
- import com.adobe.cq.sightly.WCMBindings;
- import com.adobe.granite.workflow.WorkflowSession;
- import com.day.cq.i18n.I18n;
- import com.day.cq.tagging.TagManager;
- import com.day.cq.wcm.api.AuthoringUIMode;
- import com.day.cq.wcm.api.Page;
- import com.day.cq.wcm.api.PageManager;
- import com.day.cq.wcm.api.WCMMode;
- 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 io.wcm.sling.commons.request.RequestContext;
- import io.wcm.sling.models.annotations.AemObject;
- /**
- * Injects common AEM objects that can be derived from a SlingHttpServletRequest.
- * Documentation see {@link AemObject}.
- */
- @Component(service = { Injector.class, StaticInjectAnnotationProcessorFactory.class }, property = {
- /*
- * 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.
- * Additionally it should be lower than the ACS commons AemObjectInjector (4500).
- */
- Constants.SERVICE_RANKING + ":Integer=" + 4400
- })
- public final class AemObjectInjector implements Injector, StaticInjectAnnotationProcessorFactory, AcceptsNullName {
- /**
- * Injector name
- */
- public static final @NotNull String NAME = "wcm-io-aem-object";
- static final String RESOURCE_PAGE = "resourcePage";
- static final String USER_I18N = "userI18n";
- @Reference
- private RequestContext requestContext;
- @Reference
- private ModelsImplConfiguration modelsImplConfiguration;
- @Override
- public @NotNull String getName() {
- return NAME;
- }
- @Override
- @SuppressWarnings("java:S3776") // complexity
- public Object getValue(@NotNull final Object adaptable, final String name, @NotNull final Type type,
- @NotNull final AnnotatedElement element, @NotNull final DisposalCallbackRegistry callbackRegistry) {
- // only class types are supported
- if (!(type instanceof Class<?>)) {
- return null;
- }
- Class<?> requestedClass = (Class<?>)type;
- SlingHttpServletRequest request = getRequest(adaptable);
- if (request != null) {
- if (requestedClass.equals(WCMMode.class)) {
- return getWcmMode(request);
- }
- if (requestedClass.equals(AuthoringUIMode.class)) {
- return getAuthoringUiMode(request);
- }
- if (requestedClass.equals(ComponentContext.class)) {
- return getComponentContext(request);
- }
- if (requestedClass.equals(Style.class)) {
- return getStyle(request);
- }
- if (requestedClass.equals(XSSAPI.class)) {
- return getXssApi(request);
- }
- if (requestedClass.equals(I18n.class)) {
- if (StringUtils.equals(name, USER_I18N)) {
- return getUserI18n(request);
- }
- else {
- return getResourceI18n(request);
- }
- }
- }
- if (requestedClass.equals(PageManager.class)) {
- return getPageManager(adaptable);
- }
- else if (requestedClass.equals(Page.class)) {
- if (StringUtils.equals(name, RESOURCE_PAGE)) {
- return getResourcePage(adaptable);
- }
- else {
- return getCurrentPage(adaptable);
- }
- }
- else if (requestedClass.equals(Designer.class)) {
- return getDesigner(adaptable);
- }
- else if (requestedClass.equals(Design.class)) {
- return getCurrentDesign(adaptable);
- }
- else if (requestedClass.equals(TagManager.class)) {
- return getTagManager(adaptable);
- }
- else if (requestedClass.equals(WorkflowSession.class)) {
- return getWorkflowSession(adaptable);
- }
- return null;
- }
- private @Nullable SlingHttpServletRequest getRequest(@NotNull final Object adaptable) {
- if (adaptable instanceof SlingHttpServletRequest) {
- return (SlingHttpServletRequest)adaptable;
- }
- else if (modelsImplConfiguration.isRequestThreadLocal()) {
- return requestContext.getThreadRequest();
- }
- else {
- return null;
- }
- }
- private @Nullable ResourceResolver getResourceResolver(@NotNull final Object adaptable) {
- if (adaptable instanceof ResourceResolver) {
- return (ResourceResolver)adaptable;
- }
- if (adaptable instanceof Resource) {
- return ((Resource)adaptable).getResourceResolver();
- }
- if (adaptable instanceof Page) {
- Resource resource = ((Page)adaptable).adaptTo(Resource.class);
- if (resource != null) {
- return resource.getResourceResolver();
- }
- }
- SlingHttpServletRequest request = getRequest(adaptable);
- if (request != null) {
- return request.getResourceResolver();
- }
- return null;
- }
- private @Nullable Resource getResource(@NotNull final Object adaptable) {
- if (adaptable instanceof Resource) {
- return (Resource)adaptable;
- }
- if (adaptable instanceof Page) {
- return ((Page)adaptable).adaptTo(Resource.class);
- }
- SlingHttpServletRequest request = getRequest(adaptable);
- if (request != null) {
- return request.getResource();
- }
- return null;
- }
- private @Nullable PageManager getPageManager(@NotNull final Object adaptable) {
- ResourceResolver resolver = getResourceResolver(adaptable);
- if (resolver != null) {
- return resolver.adaptTo(PageManager.class);
- }
- return null;
- }
- private @Nullable Designer getDesigner(@NotNull final Object adaptable) {
- ResourceResolver resolver = getResourceResolver(adaptable);
- if (resolver != null) {
- return resolver.adaptTo(Designer.class);
- }
- return null;
- }
- private @Nullable Page getCurrentPage(@NotNull final Object adaptable) {
- SlingHttpServletRequest request = getRequest(adaptable);
- if (request != null) {
- ComponentContext context = getComponentContext(request);
- if (context != null) {
- return context.getPage();
- }
- }
- return getResourcePage(adaptable);
- }
- private @Nullable Page getResourcePage(@NotNull final Object adaptable) {
- PageManager pageManager = getPageManager(adaptable);
- Resource resource = getResource(adaptable);
- if (pageManager != null && resource != null) {
- return pageManager.getContainingPage(resource);
- }
- return null;
- }
- private @NotNull WCMMode getWcmMode(@NotNull final SlingHttpServletRequest request) {
- return WCMMode.fromRequest(request);
- }
- private @NotNull AuthoringUIMode getAuthoringUiMode(@NotNull final SlingHttpServletRequest request) {
- AuthoringUIMode mode = AuthoringUIMode.fromRequest(request);
- if (mode == null) {
- // if no mode is set (e.g. if WCMMode is disabled) default to Touch UI
- mode = AuthoringUIMode.TOUCH;
- }
- return mode;
- }
- private @Nullable ComponentContext getComponentContext(@NotNull final SlingHttpServletRequest request) {
- return WCMUtils.getComponentContext(request);
- }
- private @Nullable Design getCurrentDesign(final Object adaptable) {
- Page currentPage = getCurrentPage(adaptable);
- Designer designer = getDesigner(adaptable);
- if (currentPage != null && designer != null) {
- return designer.getDesign(currentPage);
- }
- return null;
- }
- @SuppressWarnings("deprecation")
- private @Nullable Style getStyle(@NotNull final SlingHttpServletRequest request) {
- Style style = null;
- // first try to get from sling bindings
- SlingBindings slingBindings = getSlingBindings(request);
- if (slingBindings != null) {
- style = (Style)slingBindings.get(WCMBindings.CURRENT_STYLE);
- }
- if (style == null) {
- // fallback to current design
- Design currentDesign = getCurrentDesign(request);
- ComponentContext componentContext = getComponentContext(request);
- if (currentDesign != null && componentContext != null) {
- style = currentDesign.getStyle(componentContext.getCell());
- }
- }
- return style;
- }
- private @Nullable XSSAPI getXssApi(@NotNull final SlingHttpServletRequest request) {
- return request.adaptTo(XSSAPI.class);
- }
- private @Nullable I18n getResourceI18n(@NotNull final SlingHttpServletRequest request) {
- Page currentPage = getCurrentPage(request);
- if (currentPage != null) {
- Locale currentLocale = currentPage.getLanguage(false);
- return new I18n(getI18nEnabledRequest(request).getResourceBundle(currentLocale));
- }
- return null;
- }
- private @NotNull I18n getUserI18n(@NotNull final SlingHttpServletRequest request) {
- return new I18n(getI18nEnabledRequest(request));
- }
- private @Nullable TagManager getTagManager(@NotNull final Object adaptable) {
- ResourceResolver resolver = getResourceResolver(adaptable);
- if (resolver != null) {
- return resolver.adaptTo(TagManager.class);
- }
- return null;
- }
- private @Nullable WorkflowSession getWorkflowSession(@NotNull final Object adaptable) {
- ResourceResolver resolver = getResourceResolver(adaptable);
- if (resolver != null) {
- return resolver.adaptTo(WorkflowSession.class);
- }
- return null;
- }
- /**
- * Returns a sling request that has a resource bundle set. Due to several wrappings inside Sling
- * this is not always the request that is available in the script or java code initiating the injection.
- * If a SlingBindings object is available the request from this is returned.
- * If not it is checked if the current request that was recorded in a ThreadLocal can be used.
- * As a last resort a fallback to the request that was used for the adaption is returned, but this
- * is likely to not be i18n-enabled.
- * @param request Original request
- * @return Request from sling bindings
- */
- private @NotNull SlingHttpServletRequest getI18nEnabledRequest(@NotNull SlingHttpServletRequest request) {
- SlingBindings bindings = getSlingBindings(request);
- if (bindings != null) {
- SlingHttpServletRequest bindingsRequest = bindings.getRequest();
- if (bindingsRequest != null) {
- return bindingsRequest;
- }
- }
- if (modelsImplConfiguration.isRequestThreadLocal()) {
- SlingHttpServletRequest threadLocalRequest = requestContext.getThreadRequest();
- if (threadLocalRequest != null) {
- return threadLocalRequest;
- }
- }
- return request;
- }
- private @Nullable SlingBindings getSlingBindings(@NotNull SlingHttpServletRequest request) {
- return (SlingBindings)request.getAttribute(SlingBindings.class.getName());
- }
- @SuppressWarnings({ "null", "unused" })
- @Override
- public InjectAnnotationProcessor2 createAnnotationProcessor(final AnnotatedElement element) {
- // check if the element has the expected annotation
- AemObject annotation = element.getAnnotation(AemObject.class);
- if (annotation != null) {
- return new AemObjectAnnotationProcessor(annotation);
- }
- return null;
- }
- private static class AemObjectAnnotationProcessor extends AbstractInjectAnnotationProcessor2 {
- private final AemObject annotation;
- AemObjectAnnotationProcessor(final AemObject annotation) {
- this.annotation = annotation;
- }
- @Override
- public InjectionStrategy getInjectionStrategy() {
- return annotation.injectionStrategy();
- }
- @Override
- @SuppressWarnings("deprecation")
- public Boolean isOptional() {
- return annotation.optional();
- }
- }
- }