| /******************************************************************************* |
| * Copyright (c) 2008 Oracle Corporation. |
| * 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: |
| * Cameron Bateman - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.jsf.facelet.core.internal.registry.taglib; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.StringTokenizer; |
| import java.util.concurrent.CopyOnWriteArrayList; |
| |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IWorkspaceRunnable; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.jst.j2ee.model.IModelProvider; |
| import org.eclipse.jst.javaee.web.IWebCommon; |
| import org.eclipse.jst.jsf.common.internal.componentcore.AbstractVirtualComponentQuery; |
| import org.eclipse.jst.jsf.common.internal.resource.EventResult; |
| import org.eclipse.jst.jsf.common.internal.resource.IResourceLifecycleListener; |
| import org.eclipse.jst.jsf.common.internal.resource.LifecycleListener; |
| import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent; |
| import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.EventType; |
| import org.eclipse.jst.jsf.common.internal.resource.WorkspaceMediator; |
| import org.eclipse.jst.jsf.facelet.core.internal.registry.taglib.WebappConfiguration.WebappListener.WebappChangeEvent; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualFile; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualFolder; |
| |
| /** |
| * Manages the web.xml elements of interest to Facelet tag libraries |
| * |
| * @author cbateman |
| * |
| */ |
| public class WebappConfiguration |
| { |
| /** |
| * The param key for Facelet 1.x libraries declared in web.xml |
| */ |
| public static final String FACELET_10_LIBRARIES_CONTEXT_PARAM_NAME = "facelets.LIBRARIES"; //$NON-NLS-1$ |
| /** |
| * The param key for Facelet 2.0 libraries declared in web.xml |
| */ |
| public static final String JSF20_FACELET_LIBRARIES_CONTEXT_PARAM_NAME = "javax.faces.FACELETS_LIBRARIES"; //$NON-NLS-1$ |
| private final IProject _project; |
| /** |
| * Cached instance of ContextParamAdapter. |
| */ |
| private final ContextParamAdapter _contextParamAdapter; |
| private List<IFile> _cachedFiles; |
| private final IModelProvider _modelProvider; |
| private final AbstractVirtualComponentQuery _vcQuery; |
| private final LifecycleListener _lifecycleListener; |
| private final WorkspaceMediator _wsMediator; |
| |
| /** |
| * @param project |
| * @param modelProvider |
| * @param vcQuery |
| * @param wsMediator |
| */ |
| public WebappConfiguration(final IProject project, |
| final IModelProvider modelProvider, |
| final AbstractVirtualComponentQuery vcQuery, |
| final WorkspaceMediator wsMediator) |
| { |
| _project = project; |
| _vcQuery = vcQuery; |
| _lifecycleListener = new LifecycleListener(getWebXmlFile(project), |
| project.getWorkspace()); |
| _contextParamAdapter = new ContextParamAdapter(); |
| _modelProvider = modelProvider; |
| _wsMediator = wsMediator; |
| } |
| |
| /** |
| * @param listener |
| */ |
| public void addListener(final WebappListener listener) |
| { |
| _contextParamAdapter.addListener(listener); |
| } |
| |
| /** |
| * @param listener |
| */ |
| public void removeListener(final WebappListener listener) |
| { |
| _contextParamAdapter.removeListener(listener); |
| } |
| |
| /** |
| * @return the list of IFile's |
| */ |
| public List<IFile> getFiles() |
| { |
| final IVirtualFolder folder = _vcQuery.getWebContentFolder(_project); |
| |
| if (folder == null) |
| { |
| return Collections.emptyList(); |
| } |
| |
| final List<String> filenames = getConfigFilesFromContextParam(_project, |
| _modelProvider); |
| final List<IFile> files = new ArrayList<IFile>(); |
| |
| for (final String filename : filenames) |
| { |
| final IVirtualFile vfile = folder.getFile(new Path(filename)); |
| if (vfile != null) |
| { |
| files.add(vfile.getUnderlyingFile()); |
| } |
| } |
| _cachedFiles = files; |
| return Collections.unmodifiableList(_cachedFiles); |
| } |
| |
| private IFile getWebXmlFile(final IProject project) |
| { |
| final IVirtualFolder webContentFolder = _vcQuery |
| .getWebContentFolder(project); |
| final IContainer folder = webContentFolder.getUnderlyingFolder(); |
| return folder.getFile(new Path("WEB-INF/web.xml")); //$NON-NLS-1$ |
| } |
| |
| /** |
| * |
| */ |
| public void start() |
| { |
| _lifecycleListener.addListener(_contextParamAdapter); |
| } |
| |
| /** |
| * |
| */ |
| public void stop() |
| { |
| _lifecycleListener.removeListener(_contextParamAdapter); |
| } |
| |
| /** |
| * |
| */ |
| public void dispose() |
| { |
| _lifecycleListener.dispose(); |
| } |
| |
| /** |
| * Gets list of application configuration file names as listed in the JSF |
| * CONFIG_FILES context parameter ("javax.faces.CONFIG_FILES"). Will return |
| * an empty list if WebArtifactEdit is null, if WebApp is null, if context |
| * parameter does not exist, or if trimmed context parameter's value is an |
| * empty String. |
| * |
| * @param project |
| * IProject instance for which to get the context parameter's |
| * value. |
| * @param provider |
| * @return List of application configuration file names as listed in the JSF |
| * CONFIG_FILES context parameter ("javax.faces.CONFIG_FILES"); list |
| * may be empty. |
| */ |
| public static List<String> getConfigFilesFromContextParam( |
| final IProject project, final IModelProvider provider) |
| { |
| List<String> filesList = Collections.EMPTY_LIST; |
| // if (JSFAppConfigUtils.isValidJSFProject(project)) |
| { |
| final Object webAppObj = provider.getModelObject(); |
| if (webAppObj != null) |
| { |
| if (webAppObj instanceof org.eclipse.jst.javaee.web.WebApp) |
| { |
| filesList = getConfigFilesForJEEApp((org.eclipse.jst.javaee.web.WebApp) webAppObj); |
| } |
| } |
| |
| } |
| return filesList; |
| } |
| |
| private static List<String> getConfigFilesForJEEApp( |
| final org.eclipse.jst.javaee.web.WebApp webApp) |
| { |
| String filesString = null; |
| final List contextParams = webApp.getContextParams(); |
| final Iterator itContextParams = contextParams.iterator(); |
| final List<String> fileStrings = new ArrayList<String>(); |
| while (itContextParams.hasNext()) |
| { |
| final org.eclipse.jst.javaee.core.ParamValue paramValue = (org.eclipse.jst.javaee.core.ParamValue) itContextParams |
| .next(); |
| if (paramValue.getParamName().equals( |
| FACELET_10_LIBRARIES_CONTEXT_PARAM_NAME) |
| || paramValue.getParamName().equals( |
| JSF20_FACELET_LIBRARIES_CONTEXT_PARAM_NAME)) |
| { |
| filesString = paramValue.getParamValue(); |
| fileStrings.addAll(parseFilesString(filesString)); |
| } |
| } |
| return fileStrings; |
| } |
| |
| private static List<String> parseFilesString(final String filesString) |
| { |
| final List<String> filesList = new ArrayList<String>(); |
| if (filesString != null && filesString.trim().length() > 0) |
| { |
| final StringTokenizer stFilesString = new StringTokenizer( |
| filesString, ";"); //$NON-NLS-1$ |
| while (stFilesString.hasMoreTokens()) |
| { |
| final String configFile = stFilesString.nextToken().trim(); |
| filesList.add(configFile); |
| } |
| } |
| return filesList; |
| } |
| |
| /** |
| * Adapter implementation used to monitor addition/removal of context-param |
| * nodes and change in name of existing nodes in order to respond to changes |
| * to the JSF CONFIG_FILES context-param. |
| * |
| * @author Ian Trimble - Oracle |
| */ |
| private class ContextParamAdapter implements IResourceLifecycleListener |
| { |
| private final CopyOnWriteArrayList<WebappListener> _listeners = new CopyOnWriteArrayList<WebappListener>(); |
| |
| public void addListener(final WebappListener listener) |
| { |
| _listeners.addIfAbsent(listener); |
| } |
| |
| public void removeListener(final WebappListener listener) |
| { |
| _listeners.remove(listener); |
| } |
| |
| private void fireEvent(final WebappChangeEvent event) |
| { |
| for (final WebappListener listener : _listeners) |
| { |
| listener.webappChanged(event); |
| } |
| } |
| |
| private void checkAndFireFileChanges() |
| { |
| final List<IFile> oldFiles = _cachedFiles == null ? Collections.EMPTY_LIST |
| : _cachedFiles; |
| final List<IFile> newFiles = getFiles(); |
| |
| final List<IFile> filesAdded = new ArrayList<IFile>(); |
| final List<IFile> filesRemoved = new ArrayList<IFile>(); |
| |
| for (final IFile oldFile : oldFiles) |
| { |
| if (!newFiles.contains(oldFile)) |
| { |
| filesRemoved.add(oldFile); |
| } |
| } |
| |
| for (final IFile newFile : newFiles) |
| { |
| if (!oldFiles.contains(newFile)) |
| { |
| filesAdded.add(newFile); |
| } |
| } |
| |
| if (filesAdded.size() > 0 || filesRemoved.size() > 0) |
| { |
| fireEvent(new WebappChangeEvent(filesRemoved, filesAdded)); |
| } |
| } |
| |
| /** |
| * Called when a ContextParam instance is removed. |
| * |
| * @param contextParam |
| * ContextParam instance. |
| */ |
| protected void processParamValue( |
| final org.eclipse.jst.javaee.core.ParamValue contextParam) |
| { |
| checkAndFireFileChanges(); |
| } |
| |
| // /** |
| // * Tests if the passed ContextParam instance is the JSF CONFIG_FILES |
| // * context parameter. |
| // * |
| // * @param contextParam |
| // * ContextParam instance. |
| // * @return true if the passed ContextParam instance is the JSF |
| // * CONFIG_FILES context parameter, else false |
| // */ |
| // protected boolean isConfigFilesContextParam( |
| // final org.eclipse.jst.javaee.core.ParamValue contextParam) |
| // { |
| // boolean isConfigFiles = false; |
| // if (contextParam != null) |
| // { |
| // final String name = contextParam.getParamName(); |
| // if (FACELET_10_LIBRARIES_CONTEXT_PARAM_NAME.equals(name) |
| // || JSF20_FACELET_LIBRARIES_CONTEXT_PARAM_NAME |
| // .equals(name)) |
| // { |
| // isConfigFiles = true; |
| // } |
| // } |
| // return isConfigFiles; |
| // } |
| |
| public EventResult acceptEvent(final ResourceLifecycleEvent event) |
| { |
| // the event is only interesting if it is the web.xml |
| if (event.getAffectedResource() instanceof IFile |
| && "web.xml".equals(event.getAffectedResource().getProjectRelativePath().lastSegment())) //$NON-NLS-1$ |
| { |
| if (event.getEventType() == EventType.RESOURCE_CHANGED) |
| { |
| handleChange(); |
| } |
| } |
| return EventResult.getDefaultEventResult(); |
| } |
| |
| private void handleChange() |
| { |
| final IWorkspaceRunnable runnable = new IWorkspaceRunnable() |
| { |
| public void run(final IProgressMonitor monitor) throws CoreException |
| { |
| final Object modelObject = _modelProvider.getModelObject(); |
| if (modelObject instanceof org.eclipse.jst.javaee.web.WebApp) |
| { |
| for (final org.eclipse.jst.javaee.core.ParamValue paramValue : ((IWebCommon) modelObject) |
| .getContextParams()) |
| { |
| processParamValue(paramValue); |
| } |
| } |
| // TODO: possibly handle facelets 1.0 in pre-2.5 webapps in |
| // the |
| // future |
| // if it's worth the complexity. |
| // SEE previous revs in CVS. |
| } |
| }; |
| _wsMediator.runInWorkspaceJob(runnable, "Update web xml"); //$NON-NLS-1$ |
| } |
| } |
| |
| abstract static class WebappListener |
| { |
| public static class WebappChangeEvent |
| { |
| private final List<IFile> _removed; |
| private final List<IFile> _added; |
| |
| WebappChangeEvent(final List<IFile> removed, final List<IFile> added) |
| { |
| _removed = Collections.unmodifiableList(removed); |
| _added = Collections.unmodifiableList(added); |
| } |
| |
| public final List<IFile> getRemoved() |
| { |
| return _removed; |
| } |
| |
| public final List<IFile> getAdded() |
| { |
| return _added; |
| } |
| } |
| |
| public abstract void webappChanged(final WebappChangeEvent event); |
| } |
| } |