/** * Copyright (c) 2009 TIBCO Software Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Adrian Price */ package org.eclipse.emf.ecore.util; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; /** * Composes multiple switches in order to handle instances of classes defined in multiple packages. * @since 2.7 */ public class ComposedSwitch<T> extends Switch<T> { private final Map<EPackage, Switch<T>> registry = new HashMap<EPackage, Switch<T>>(); private final List<Switch<T>> switches = new ArrayList<Switch<T>>(); /** * Creates a new ComposedSwitch. */ public ComposedSwitch() { super(); } /** * Creates a new ComposedSwitch. * @param switches The switches to which the composed switch will delegate. The list should generally include switches for all the * packages the composed switch will be expected to handle. */ public ComposedSwitch(Collection<? extends Switch<T>> switches) { for (Switch<T> sw : switches) { addSwitch(sw); } } public void addSwitch(Switch<T> sw) { synchronized (switches) { if (!switches.contains(sw)) { switches.add(sw); } } } public void removeSwitch(Switch<T> sw) { synchronized (switches) { if (switches.contains(sw)) { switches.remove(sw); Iterator<Switch<T>> it = registry.values().iterator(); while (it.hasNext()) { if (it.next() == sw) { it.remove(); } } } } } @Override protected T doSwitch(EClass theEClass, EObject theEObject) { Switch<T> delegate = findDelegate(theEClass.getEPackage()); if (delegate == null) { List<EClass> eSuperTypes = theEClass.getESuperTypes(); return eSuperTypes.isEmpty() ? defaultCase(theEObject) : doSwitch(eSuperTypes.get(0), theEObject); } else { T result = delegatedDoSwitch(delegate, theEClass, theEObject); return result == null ? defaultCase(theEObject) : result; } } /** * Call delegate.{@link Switch#doSwitch(EClass, EObject) doSwitch}(theEClass, theEObject). * @since 2.8 */ protected T delegatedDoSwitch(Switch<T> delegate, EClass theEClass, EObject theEObject) { return delegate.doSwitch(theEClass, theEObject); } /** * Finds a suitable delegate for the given package. * @since 2.8 */ protected Switch<T> findDelegate(EPackage ePackage) { synchronized (switches) { Switch<T> delegate = registry.get(ePackage); if (delegate == null && !registry.containsKey(ePackage)) { for (Switch<T> sw : switches) { if (sw.isSwitchFor(ePackage)) { delegate = sw; break; } } registry.put(ePackage, delegate); } return delegate; } } @Override public boolean isSwitchFor(EPackage ePackage) { return findDelegate(ePackage) != null; } }