/* * #%L * ACS AEM Commons Bundle * %% * Copyright (C) 2013 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.replication.dispatcher; import aQute.bnd.annotation.ProviderType; import com.day.cq.replication.Agent; import com.day.cq.replication.AgentConfig; import com.day.cq.replication.AgentFilter; import org.apache.commons.lang.StringUtils; import org.apache.sling.api.resource.ValueMap; /** * Replication Agent Filter used to identify Flush agents. */ @ProviderType public class DispatcherFlushFilter implements AgentFilter { /** * All: All Enablied Dispatcher Flush Agents. * Hierarchical: "Normal" flush invalidation that effects entire content hierarchies. * ResourceOnly: Targets agents with a CQ-Action-Scope of "Resource Only" defined. */ public static enum FlushType { All, Hierarchical, ResourceOnly } public static final DispatcherFlushFilter ALL = new DispatcherFlushFilter(FlushType.All); public static final DispatcherFlushFilter HIERARCHICAL = new DispatcherFlushFilter(FlushType.Hierarchical); public static final DispatcherFlushFilter RESOURCE_ONLY = new DispatcherFlushFilter(FlushType.ResourceOnly); private static final String SERIALIZATION_TYPE = "flush"; private static final String HTTP = "http://"; private static final String HTTPS = "https://"; private static final String CQ_ACTION_HEADER = "CQ-Action:"; private static final String CQ_SCOPE_ACTION_HEADER = "CQ-Action-Scope: ResourceOnly"; private final FlushType flushType; /** * Default constructor; Same as: new DispatcherFlushFilter(FlushType.All);. */ public DispatcherFlushFilter() { this.flushType = FlushType.All; } /** * Targets a set of Dispatcher Flush agents based on the parameter flushType. * * @param flushType The type of Flush agents this Agent should target */ public DispatcherFlushFilter(final FlushType flushType) { this.flushType = flushType; } /** * Checks if the @agent is considered an active Flush agent (Serialization Type ~> Flush and is enabled). * * @param agent the agent to test test * @return true is is considered an enabled Flush agent */ @Override public final boolean isIncluded(final Agent agent) { if (FlushType.All.equals(this.flushType)) { return this.isIncludedCommon(agent); } else if (FlushType.Hierarchical.equals(this.flushType)) { return this.isIncludedHierarchical(agent); } else if (FlushType.ResourceOnly.equals(this.flushType)) { return this.isIncludedResourceOnly(agent); } return false; } /** * Returns the Dispatcher FlushType this filter was created with. * @return this filter's dispatcher flushType */ public final FlushType getFlushType() { return this.flushType; } private boolean isIncludedCommon(final Agent agent) { return this.isFlushingAgent(agent) && this.isDispatcherTransportURI(agent) && this.isDispatcherHeaders(agent) && this.isEnabled(agent); } private boolean isIncludedHierarchical(final Agent agent) { return this.isIncludedCommon(agent) && !this.isResourceOnly(agent); } private boolean isIncludedResourceOnly(final Agent agent) { return this.isIncludedCommon(agent) && this.isResourceOnly(agent); } /** * Checks if the agent is enabled. * * @param agent Agent to check * @return true if the agent is enabled */ private boolean isEnabled(final Agent agent) { return agent.isEnabled(); } /** * Checks if the agent has a "flush" serialization type. * * @param agent Agent to check * @return true if the Agent's serialization type is "flush" */ private boolean isFlushingAgent(final Agent agent) { return StringUtils.equals(SERIALIZATION_TYPE, agent.getConfiguration().getSerializationType()); } /** * Checks if the agent has a valid transport URI set. * * @param agent Agent to check * @return true if the Agent's transport URI is in the proper form */ private boolean isDispatcherTransportURI(final Agent agent) { final String transportURI = agent.getConfiguration().getTransportURI(); return (StringUtils.startsWith(transportURI, HTTP) || StringUtils.startsWith(transportURI, HTTPS)); } /** * Checks if the agent has a valid dispatcher headers. * * @param agent Agent to check * @return true if the Agent's headers contain the proper values */ private boolean isDispatcherHeaders(final Agent agent) { final ValueMap properties = agent.getConfiguration().getProperties(); final String[] headers = properties.get(AgentConfig.PROTOCOL_HTTP_HEADERS, new String[]{}); for (final String header : headers) { if (StringUtils.startsWith(header, CQ_ACTION_HEADER)) { return true; } } return false; } /** * Checks if the agent has valid CQ-Action-Scope: ResourceOnly header. * * @param agent Agent to check * @return true if the Agent's headers contain the expected values */ private boolean isResourceOnly(final Agent agent) { final ValueMap properties = agent.getConfiguration().getProperties(); final String[] headers = properties.get(AgentConfig.PROTOCOL_HTTP_HEADERS, new String[]{}); for (final String header : headers) { if (StringUtils.equals(header, CQ_SCOPE_ACTION_HEADER)) { return true; } } return false; } }