Java tutorial
/* **************************************************************************** * Ldap Synchronization Connector provides tools to synchronize * electronic identities from a list of data sources including * any database with a JDBC connector, another LDAP directory, * flat files... * * ==LICENSE NOTICE== * * Copyright (c) 2008 - 2011 LSC Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the LSC Project nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ==LICENSE NOTICE== * * (c) 2008 - 2011 LSC Project * Sebastien Bahloul <seb@lsc-project.org> * Thomas Chemineau <thomas@lsc-project.org> * Jonathan Clarke <jon@lsc-project.org> * Remy-Christophe Schermesser <rcs@lsc-project.org> **************************************************************************** */ package org.lsc; import java.io.Closeable; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import org.apache.commons.lang.ArrayUtils; import org.lsc.beans.IBean; import org.lsc.configuration.LscConfiguration; import org.lsc.configuration.TaskType; import org.lsc.exception.LscConfigurationException; import org.lsc.jmx.LscServerImpl; import org.lsc.service.IAsynchronousService; import org.lsc.utils.LSCStructuralLogger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Extends AbstractSynchronize to instantiate a simple synchronization engine * This class is responsible for reading LSC properties and using specified classes * and objects to avoid implementing each every time. You may want to override * this class to implement your own way of synchronizing - but you also need * to rewrite the org.lsc.Launcher class. * * @author Sebastien Bahloul <seb@lsc-project.org> */ public class SimpleSynchronize extends AbstractSynchronize { /** the magic keyword for all synchronization. */ public static final String ALL_TASKS_KEYWORD = "all"; private static final Logger LOGGER = LoggerFactory.getLogger(SimpleSynchronize.class); public static final List<String> EMPTY_LIST = new ArrayList<String>(); Map<String, Task> cache; /** * Default constructor */ public SimpleSynchronize() { super(); setThreads(5); cache = new TreeMap<String, Task>(); } public void init() throws LscConfigurationException { Collection<TaskType> tasks = LscConfiguration.getTasks(); for (TaskType t : tasks) { cache.put(t.getName(), new Task(t)); } } private void close() { for (Task task : cache.values()) { if (task.getSourceService() instanceof Closeable) { try { ((Closeable) task.getSourceService()).close(); } catch (IOException e) { LOGGER.error("Error while closing service."); } } if (task.getDestinationService() instanceof Closeable) { try { ((Closeable) task.getDestinationService()).close(); } catch (IOException e) { LOGGER.error("Error while closing service."); } } } } /** * Main method Check properties, and for each task, launch the * synchronization and the cleaning phases. * @param asyncTasks * string list of the asynchronous synchronization tasks to launch * @param syncTasks string list of the synchronization tasks to launch * @param cleanTasks string list of the cleaning tasks to launch * * @return the launch status - true if all tasks executed successfully, * false if no tasks were executed or any failed * @throws Exception */ public final boolean launch(final List<String> asyncTasks, final List<String> syncTasks, final List<String> cleanTasks) throws Exception { Boolean foundATask = false; boolean canClose = true; boolean launchResult = true; // Get the list of defined tasks from LSC properties // Iterate on each task boolean isASyncTaskAll = asyncTasks.contains(ALL_TASKS_KEYWORD); boolean isSyncTaskAll = syncTasks.contains(ALL_TASKS_KEYWORD); boolean isCleanTaskAll = cleanTasks.contains(ALL_TASKS_KEYWORD); if (getTasksName() == null) { return false; } else if (getTasks().length == 0) { init(); } if (!asyncTasks.isEmpty()) { LscServerImpl.startJmx(this); } for (Task task : cache.values()) { // Launch the task either if explicitly specified or if "all" magic keyword used if (isSyncTaskAll || syncTasks.contains(task.getName())) { foundATask = true; if (!launchTask(task, Task.Mode.sync)) { launchResult = false; } else { if (task.getSyncHook() != null && task.getSyncHook() != "") { runPostHook(task.getName(), task.getSyncHook(), task.getTaskType()); } } } if (isCleanTaskAll || cleanTasks.contains(task.getName())) { foundATask = true; if (!launchTask(task, Task.Mode.clean)) { launchResult = false; } else { if (task.getCleanHook() != null && task.getCleanHook() != "") { runPostHook(task.getName(), task.getCleanHook(), task.getTaskType()); } } } if (isASyncTaskAll || asyncTasks.contains(task.getName())) { foundATask = true; canClose = false; if (!launchTask(task, Task.Mode.async)) { launchResult = false; } } } if (canClose) { close(); } if (!foundATask) { LOGGER.error( "No specified tasks could be launched! Check spelling and that they exist in the configuration file."); return false; } return launchResult; } /** * Launch a task. Call this for once each task type and task mode. * * @param taskName * the task name (historically the LDAP object class name, but can be any string) * @param taskMode * the task mode (clean or sync) * * @return boolean true on success, false if an error occurred * @throws Exception */ private boolean launchTask(final Task task, final Task.Mode taskMode) throws Exception { boolean status = true; addScriptingContext(task); try { LSCStructuralLogger.DESTINATION.info("Starting {} for {}", taskMode.name(), task.getName()); // Do the work! switch (taskMode) { case clean: status = clean2Ldap(task); break; case sync: status = synchronize2Ldap(task); break; case async: if (task.getSourceService() instanceof IAsynchronousService || task.getDestinationService() instanceof IAsynchronousService) { startAsynchronousSynchronize2Ldap(task); } else { LOGGER.error("Requested asynchronous source service does not implement IAsynchronousService ! (" + task.getSourceService().getClass().getName() + ")"); } break; default: //Should not happen LOGGER.error("Unknown task mode type {}", taskMode.toString()); throw new InvalidParameterException("Unknown task mode type " + taskMode.toString()); } // Manage exceptions } catch (Exception e) { Class<?>[] exceptionsCaught = { InstantiationException.class, IllegalAccessException.class, ClassNotFoundException.class, SecurityException.class, NoSuchMethodException.class, IllegalArgumentException.class, InvocationTargetException.class }; if (ArrayUtils.contains(exceptionsCaught, e.getClass())) { String errorDetail; if (e instanceof InvocationTargetException && e.getCause() != null) { errorDetail = e.getCause().toString(); } else { errorDetail = e.toString(); } LOGGER.error("Error while launching task \"{}\". Please check your configuration! ({})", task.getName(), errorDetail); LOGGER.debug(e.toString(), e); return false; } throw e; } return status; } private void addScriptingContext(Task task) { task.addScriptingVar("nocreate", nocreate); task.addScriptingVar("noupdate", noupdate); task.addScriptingVar("nodelete", nodelete); task.addScriptingVar("nomodrdn", nomodrdn); } /** * Invoke the hook method whether it's a postsync or postclean * * @param taskName the task name * @param servicePostHook the fully qualified name of the method to invoke * @param taskType the TaskType used to initialize the task */ private void runPostHook(String taskName, String servicePostHook, TaskType taskType) { if (servicePostHook != null && servicePostHook.length() > 0) { LOGGER.debug("Service Post Hook found: " + servicePostHook); String hookClass = servicePostHook.substring(0, servicePostHook.lastIndexOf('.')); String hookMethod = servicePostHook.substring(servicePostHook.lastIndexOf('.') + 1); LOGGER.debug("Hook Class: " + hookClass); LOGGER.debug("Hook Method: " + hookMethod); if (hookClass.length() > 0 && hookMethod.length() > 0) { try { Class<?> clazz = Class.forName(hookClass); try { // Try with a TaskType parameter Method hook = clazz.getMethod(hookMethod, new Class<?>[] { TaskType.class }); hook.invoke(null, taskType); } catch (NoSuchMethodException e) { // Try without parameter Method hook = clazz.getMethod(hookMethod, new Class<?>[] {}); hook.invoke(null, new Object[0]); } } catch (ClassNotFoundException e) { LOGGER.error("Invalid Hook Class specified " + hookClass + " for task " + taskName); LOGGER.debug(e.toString(), e); } catch (NoSuchMethodException e) { LOGGER.error("Invalid hook method " + hookMethod + " specified for task " + taskName); LOGGER.debug(e.toString(), e); } catch (IllegalArgumentException e) { LOGGER.error("Invalid argument exception for hook method " + hookClass + "." + hookMethod); LOGGER.debug(e.toString(), e); } catch (IllegalAccessException e) { LOGGER.error("Illegal access exception for hook method " + hookClass + "." + hookMethod); LOGGER.debug(e.toString(), e); } catch (InvocationTargetException e) { LOGGER.error("Invocation target exception for hook method " + hookClass + "." + hookMethod); LOGGER.debug(e.toString(), e); } } } } public Set<Entry<String, Task>> getTasksName() { return cache.entrySet(); } public boolean isAsynchronousTask(String taskName) { return cache.get(taskName).getSourceService() instanceof IAsynchronousService; } @Override public Task getTask(String taskName) { return cache.get(taskName); } @Override public Task[] getTasks() { return cache.values().toArray(new Task[cache.values().size()]); } /** * Launch a sequential synchronization based on identifiers got from the source * @param taskName the task name to launch * @param entries the entries to synchronize * @return false if at least one synchronization has failed, true if all of them have succeeded */ public final boolean launchById(String taskName, Map<String, LscDatasets> entries) { Task task = cache.get(taskName); InfoCounter counter = new InfoCounter(); for (Entry<String, LscDatasets> entry : entries.entrySet()) { new SynchronizeTask(task, counter, this, entry, true).run(); } return counter.getCountError() == 0; } public final boolean launch(String taskName, IBean bean) { Task task = cache.get(taskName); InfoCounter counter = new InfoCounter(); return new SynchronizeTask(task, counter, this, null, true).run(bean); } }