/* * Copyright 2013-2015 ForgeRock, AS. * * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions copyright [year] [name of copyright owner]". */ package org.forgerock.openidm.provisioner.openicf.syncfailure; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferencePolicy; import org.apache.felix.scr.annotations.Service; import org.forgerock.openidm.router.IDMConnectionFactory; import org.forgerock.json.JsonValue; import org.forgerock.script.ScriptRegistry; /** * A factory service to create the SyncFailureHandler strategy from config. * */ @Component(name = SyncFailureHandlerFactoryImpl.PID, policy = ConfigurationPolicy.IGNORE, metatype = true, description = "OpenIDM Sync Failure Handler Factory Service", immediate = true ) @Service() public class SyncFailureHandlerFactoryImpl implements SyncFailureHandlerFactory { public static final String PID = "org.forgerock.openidm.openicf.syncfailure"; /* config tokens */ protected static final String CONFIG_MAX_RETRIES = "maxRetries"; protected static final String CONFING_POST_RETRY = "postRetryAction"; protected static final String CONFIG_DEAD_LETTER = "dead-letter-queue"; protected static final String CONFIG_LOGGED_IGNORE = "logged-ignore"; protected static final String CONFIG_SCRIPT = "script"; /** Script Registry service. */ @Reference(policy = ReferencePolicy.DYNAMIC) protected ScriptRegistry scriptRegistry; private void bindScriptRegistry(final ScriptRegistry service) { scriptRegistry = service; } private void unbindScriptRegistry(final ScriptRegistry service) { scriptRegistry = null; } /** The Connection Factory */ @Reference(policy = ReferencePolicy.STATIC) protected IDMConnectionFactory connectionFactory; /** * Create a <em>SyncFailureHandler</em> from the config. The config should optionally * describe * <ul> * <li>number of retries</li> * <li>what to do upon retry exhaustion: * <ul> * <li>whether to save the failed sync item to a dead-letter queue</li> * <li>whether to log and ignore the failure</li> * <li>whether to call an external, user-supplied script</li> * </ul> * </ul> * * @param config the config for the SyncFailureHandler * @return the SyncFailureHandler */ public SyncFailureHandler create(JsonValue config) throws Exception { if (null == config || config.isNull()) { return InfiniteRetrySyncFailureHandler.INSTANCE; } JsonValue maxRetries = config.get(CONFIG_MAX_RETRIES); JsonValue postRetry = config.get(CONFING_POST_RETRY); if (maxRetries.isNull() || maxRetries.asInteger() < 0) { return InfiniteRetrySyncFailureHandler.INSTANCE; } else if (maxRetries.asInteger() == 0) { return getPostRetryHandler(postRetry); } else { return new SimpleRetrySyncFailureHandler(maxRetries.asInteger(), getPostRetryHandler(postRetry)); } } /** * Create the SycFailureHandler to execute when the retries are exhausted (or if no retries are configured). * The config passed here is the value side of * {code} * "postRetryAction" : <value> * {code} * It may be either a String which indicates which handler to use, or a Map which indicates a handler * with more complex configuration. * * @param config the config that further specifies the sync failure handler * @return the SyncFailureHandler */ private SyncFailureHandler getPostRetryHandler(JsonValue config) throws Exception { if (config.isString()) { if (CONFIG_DEAD_LETTER.equals(config.asString())) { return new DeadLetterQueueHandler(connectionFactory); } else if (CONFIG_LOGGED_IGNORE.equals(config.asString())) { return new LoggedIgnoreHandler(); } } else if (config.isMap()) { if (config.get(CONFIG_SCRIPT).isMap()) { return new ScriptedSyncFailureHandler( scriptRegistry, config.get(CONFIG_SCRIPT), // pass internal handlers so a script can call them if desired new LoggedIgnoreHandler(), new DeadLetterQueueHandler(connectionFactory)); } } return NullSyncFailureHandler.INSTANCE; } }