package org.eclipse.jst.jsf.common.internal.locator; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.jst.jsf.common.internal.locator.ILocatorChangeListener.LocatorChangeEvent; /** * The abstract base class of all ILocator implementations. * * @author cbateman * * @param <LOCATORTYPE> * @param <CONTEXTTYPE> * @param <IDTYPE> */ public abstract class AbstractLocator<LOCATORTYPE, CONTEXTTYPE, IDTYPE> implements ILocator<LOCATORTYPE, CONTEXTTYPE, IDTYPE> { /** * The default value used for "no result". */ protected static final Object DEFAULT_NO_RESULT_VALUE = null; private final CopyOnWriteArrayList<ILocatorChangeListener> _listeners; private final LOCATORTYPE _noResultValue; private final IDTYPE _id; private final String _displayName; private boolean _isStarted; private Exception _startTrace; /** * Available for sub-classes that want to use reasonable defaults and only provide * mandatory data. * * No result value is null. * A new instance of CopyOnWriteArrayList is used and held private. * * @param id * @param displayName * */ public AbstractLocator(final IDTYPE id, final String displayName) { this(id, displayName, null, new CopyOnWriteArrayList<ILocatorChangeListener>()); } /** * Available for sub-classes to manually inject dependencies. * * @param id * @param displayName * @param noResultValue * @param mutableListenerList */ protected AbstractLocator( final IDTYPE id, final String displayName, final LOCATORTYPE noResultValue, final CopyOnWriteArrayList<ILocatorChangeListener> mutableListenerList) { _id = id; _displayName = displayName; _listeners = mutableListenerList; _noResultValue = noResultValue; } public final LOCATORTYPE perform(final CONTEXTTYPE context) throws Exception { return locate(context); } public LOCATORTYPE getNoResult() { return _noResultValue; } public IDTYPE getId() { return _id; } public String getDisplayName() { return _displayName; } public LOCATORTYPE locate(final CONTEXTTYPE context) { if (isStarted()) { return doLocate(context); } throw new IllegalStateException("Locator not started"); //$NON-NLS-1$ } /** * @param context * @return the located type. */ protected abstract LOCATORTYPE doLocate(CONTEXTTYPE context); public void start(final CONTEXTTYPE initialContext) { if (isStarted()) { throw new IllegalStateException("Locator was already started", _startTrace); //$NON-NLS-1$ } // set the started flag setStarted(true); _startTrace = new Exception("Locator was started on this trace"); //$NON-NLS-1$ } public void stop() { // set the started flag // clear all listeners _listeners.clear(); setStarted(false); _startTrace = null; } /** * @param listener */ public void addListener(final ILocatorChangeListener listener) { _listeners.addIfAbsent(listener); } /** * @param listener */ public void removeListener(final ILocatorChangeListener listener) { _listeners.remove(listener); } /** * @param event */ protected void fireChangeEvent(final LocatorChangeEvent event) { for (final ILocatorChangeListener listener : _listeners) { listener.changed(event); } } public final boolean isStarted() { return _isStarted; } public boolean canStart() { if (isStarted()) { return false; } return true; } /** * @param newValue */ protected final void setStarted(final boolean newValue) { _isStarted = newValue; } }