| /******************************************************************************* |
| * Copyright (c) 2001, 2008 Oracle Corporation 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: |
| * Oracle Corporation - initial API and implementation |
| *******************************************************************************/ |
| /** |
| * |
| */ |
| package org.eclipse.jst.jsf.designtime.context; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.jst.jsf.core.internal.JSFCorePlugin; |
| import org.eclipse.jst.jsf.designtime.internal.view.DTUIViewRoot; |
| import org.eclipse.jst.jsf.designtime.internal.view.IDTViewHandler; |
| import org.eclipse.jst.jsf.designtime.internal.view.IViewRootHandle; |
| import org.eclipse.jst.jsf.designtime.internal.view.DTUIViewRoot.StalenessListener; |
| import org.eclipse.jst.jsf.designtime.internal.view.IDTViewHandler.ViewHandlerException; |
| |
| /* package */ final class ViewRootHolder implements IViewRootHandle, Cloneable |
| { |
| private final Object _recalcViewRootExclusion; |
| private final DTFacesContext _facesContext; |
| private DTUIViewRoot _viewRoot; |
| private final List<StalenessListener> _waitingToAdd; |
| private final List<StalenessListener> _waitingToRemove; |
| |
| public ViewRootHolder(final DTFacesContext facesContext, final Object recalcViewRootExclusion) |
| { |
| _facesContext = facesContext; |
| _recalcViewRootExclusion = recalcViewRootExclusion; |
| _waitingToAdd = new ArrayList<StalenessListener>(); |
| _waitingToRemove = new ArrayList<StalenessListener>(); |
| } |
| |
| private ViewRootHolder(ViewRootHolder cloneFrom) |
| { |
| _recalcViewRootExclusion = cloneFrom._recalcViewRootExclusion; |
| _facesContext = cloneFrom._facesContext; |
| _viewRoot = cloneFrom.getCachedViewRoot(); |
| |
| // create brand new copies |
| _waitingToAdd = new ArrayList<StalenessListener>(); |
| _waitingToRemove = new ArrayList<StalenessListener>(); |
| } |
| |
| public synchronized DTUIViewRoot getCachedViewRoot() |
| { |
| return _viewRoot; |
| } |
| |
| public DTUIViewRoot updateViewRoot() |
| { |
| DTUIViewRoot viewRoot = null; |
| final IResource contextResource = _facesContext.adaptContextObject(); |
| |
| // we create this additional exclusion so that we avoid a |
| // situation |
| // where two threads enter and start recalculating the same view |
| // root in parallel. Only one thread may be working on creating |
| // a new view root for a particular view at any given time. Note |
| // that due to read/write lock on the value, there is nothing |
| // to stop readers from simultaneous getting the old value until |
| // the new value is ready and has been set. |
| synchronized (_recalcViewRootExclusion) |
| { |
| viewRoot = getCachedViewRoot(); |
| |
| if (viewRoot == null || viewRoot.isStale()) |
| { |
| // if the view root hasn't been created, then do so |
| // and populate it |
| final IDTViewHandler viewHandler = _facesContext |
| .getViewHandler(contextResource); |
| |
| if (viewHandler != null) |
| { |
| final String viewId = viewHandler.getViewId( |
| _facesContext, contextResource); |
| |
| try |
| { |
| viewRoot = viewHandler.createView(_facesContext, |
| viewId); |
| if (viewRoot != null) |
| { |
| setCachedViewRoot(viewRoot); |
| } |
| |
| // do adds first, let remove trump all |
| for (final StalenessListener addListener : _waitingToAdd) |
| { |
| viewRoot.addListener(addListener); |
| } |
| |
| for (final StalenessListener removeListener : _waitingToRemove) |
| { |
| viewRoot.removeListener(removeListener); |
| } |
| } |
| catch (final ViewHandlerException e) |
| { |
| JSFCorePlugin.log(e, |
| "While creating dt viewroot for viewId: " //$NON-NLS-1$ |
| + viewId); |
| } |
| } |
| } |
| } |
| // return the copy. NEVER return _viewRoot directly since we are not |
| // synchronized here. |
| return viewRoot; |
| } |
| |
| private synchronized void setCachedViewRoot( |
| final DTUIViewRoot newViewRoot) |
| { |
| if (!Thread.holdsLock(_recalcViewRootExclusion)) |
| { |
| throw new IllegalStateException( |
| "Must hold _recalcViewRootExclusion to modify view root"); //$NON-NLS-1$ |
| } |
| _viewRoot = newViewRoot; |
| } |
| |
| @Override |
| protected synchronized IViewRootHandle clone() |
| { |
| return new ViewRootHolder(this); |
| } |
| |
| public void addListener(StalenessListener listener) |
| { |
| if (_viewRoot != null) |
| { |
| synchronized(this) |
| { |
| _viewRoot.addListener(listener); |
| } |
| } |
| else |
| { |
| // ensure that if we calculating a new view root, then there isn't |
| // an issue. |
| synchronized(_recalcViewRootExclusion) |
| { |
| synchronized(this) |
| { |
| _waitingToAdd.add(listener); |
| } |
| } |
| } |
| } |
| |
| public void removeListener(StalenessListener listener) |
| { |
| DTUIViewRoot viewRoot = null; |
| |
| synchronized(this) |
| { |
| viewRoot = _viewRoot; |
| } |
| |
| if (viewRoot != null) |
| { |
| synchronized(this) |
| { |
| viewRoot.removeListener(listener); |
| } |
| } |
| else |
| { |
| // ensure that if we calculating a new view root, then there isn't |
| // an issue. |
| // always acquire the recalcViewRootExclusion first |
| synchronized(_recalcViewRootExclusion) |
| { |
| synchronized(this) |
| { |
| _waitingToAdd.add(listener); |
| } |
| } |
| } |
| } |
| } |