| /******************************************************************************* |
| * Copyright (c) 2006 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/Oracle - initial API and implementation |
| * |
| ********************************************************************************/ |
| |
| package org.eclipse.jst.jsf.designtime; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.util.Properties; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.QualifiedName; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jst.jsf.core.internal.JSFCorePlugin; |
| import org.eclipse.jst.jsf.core.jsfappconfig.JSFAppConfigUtils; |
| import org.eclipse.jst.jsf.designtime.context.AbstractDTExternalContextFactory; |
| import org.eclipse.jst.jsf.designtime.context.DTFacesContext; |
| import org.eclipse.jst.jsf.designtime.context.IExternalContextFactoryLocator; |
| import org.eclipse.jst.jsf.designtime.el.AbstractDTMethodResolver; |
| import org.eclipse.jst.jsf.designtime.el.AbstractDTPropertyResolver; |
| import org.eclipse.jst.jsf.designtime.el.AbstractDTVariableResolver; |
| import org.eclipse.jst.jsf.designtime.internal.BasicExtensionFactory.ExtensionData; |
| import org.eclipse.jst.jsf.designtime.internal.view.IDTViewHandler; |
| |
| |
| /** |
| * Per-web-application manager that manages design time information for a corresponding |
| * project. |
| * |
| * TODO: migrate to managed singleton |
| * @author cbateman |
| * |
| */ |
| public final class DesignTimeApplicationManager |
| { |
| // TODO: load from property file? |
| private static final String PROPERTY_QUALIFIER = "org.eclipse.jst.jsf.designtime.internal"; //$NON-NLS-1$ |
| private static final String SESSION_PROPERTY_NAME_PROJECT = "DesignTimeApplicationManager"; //$NON-NLS-1$ |
| private static final QualifiedName SESSION_PROPERTY_KEY_PROJECT |
| = new QualifiedName(PROPERTY_QUALIFIER, SESSION_PROPERTY_NAME_PROJECT); |
| |
| private static final String SESSION_PROPERTY_NAME_FACES_CONTEXT = "DTFacesContext"; //$NON-NLS-1$ |
| private static final QualifiedName SESSION_PROPERTY_KEY_FACES_CONTEXT |
| = new QualifiedName(PROPERTY_QUALIFIER, SESSION_PROPERTY_NAME_FACES_CONTEXT); |
| |
| private static final String PERSIST_PROPERTY_NAME_EXTERNAL_CONTEXT_PROVIDER = |
| "ExternalContextProvider"; //$NON-NLS-1$ |
| private static final QualifiedName PERSIST_PROPERTY_KEY_EXTERNAL_CONTEXT_PROVIDER = |
| new QualifiedName(PROPERTY_QUALIFIER, PERSIST_PROPERTY_NAME_EXTERNAL_CONTEXT_PROVIDER); |
| |
| private static final String PERSIST_PROPERTY_NAME_VARIABLE_RESOLVER_PROVIDER = |
| "VariableResolverProvider"; //$NON-NLS-1$ |
| private static final QualifiedName PERSIST_PROPERTY_KEY_VARIABLE_RESOLVER_PROVIDER |
| = new QualifiedName(PROPERTY_QUALIFIER, PERSIST_PROPERTY_NAME_VARIABLE_RESOLVER_PROVIDER); |
| |
| private static final String PERSIST_PROPERTY_NAME_PROPERTY_RESOLVER_PROVIDER = |
| "PropertyResolverProvider"; //$NON-NLS-1$ |
| private static final QualifiedName PERSIST_PROPERTY_KEY_PROPERTY_RESOLVER_PROVIDER = |
| new QualifiedName(PROPERTY_QUALIFIER, PERSIST_PROPERTY_NAME_PROPERTY_RESOLVER_PROVIDER); |
| |
| private static final String PERSIST_PROPERTY_NAME_METHOD_RESOLVER_PROVIDER = |
| "MethodResolverProvider"; //$NON-NLS-1$ |
| private static final QualifiedName PERSIST_PROPERTY_KEY_METHOD_RESOLVER_PROVIDER = |
| new QualifiedName(PROPERTY_QUALIFIER, PERSIST_PROPERTY_NAME_METHOD_RESOLVER_PROVIDER); |
| |
| private static final String PERSIST_PROPERTY_NAME_VIEW_HANDLER = |
| "ViewHandler"; //$NON-NLS-1$ |
| |
| private static final String DEFAULT_EXTERNAL_CONTEXT_ID = |
| "org.eclipse.jst.jsf.core.externalcontext.default"; //$NON-NLS-1$ |
| |
| private static final String DEFAULT_VARIABLE_RESOLVER_ID = |
| "org.eclipse.jst.jsf.core.variableresolver.default.decorative"; //$NON-NLS-1$ |
| |
| private static final String DEFAULT_PROPERTY_RESOLVER_ID = |
| "org.eclipse.jst.jsf.core.propertyresolver.default.decorative"; //$NON-NLS-1$ |
| |
| private static final String DEFAULT_METHOD_RESOLVER_ID = |
| "org.eclipse.jst.jsf.core.methodresolver.default"; //$NON-NLS-1$ |
| |
| private static final String DEFAULT_VIEW_HANDLER_ID = |
| "org.eclipse.jst.jsf.designtime.view.jspviewhandler"; //$NON-NLS-1$ |
| |
| /** |
| * @param project |
| * @return the app manager associated with project |
| */ |
| public final static DesignTimeApplicationManager getInstance(IProject project) |
| { |
| if (!hasJSFDesignTime(project)) |
| { |
| return null; |
| } |
| |
| try |
| { |
| synchronized(project) |
| { |
| DesignTimeApplicationManager manager = |
| (DesignTimeApplicationManager) project.getSessionProperty(SESSION_PROPERTY_KEY_PROJECT); |
| |
| |
| if (manager == null) |
| { |
| manager = new DesignTimeApplicationManager(project); |
| project.setSessionProperty(SESSION_PROPERTY_KEY_PROJECT, manager); |
| } |
| // bug 147729: if project was renamed, the project param will be |
| // valid, but it will not be in sync with the one for _project |
| // unfortunately, since we are using session propertie |
| else |
| { |
| synchronized(manager) |
| { |
| if (!project.equals(manager._project)) |
| { |
| manager._project = project; |
| } |
| } |
| } |
| |
| return manager; |
| } |
| } |
| catch (CoreException ce) |
| { |
| Platform.getLog(JSFCorePlugin.getDefault().getBundle()).log(new Status(IStatus.ERROR, JSFCorePlugin.getDefault().getBundle().getSymbolicName(), 0, "Problem loading design time appmanager", new Throwable(ce))); //$NON-NLS-1$ |
| } |
| |
| return null; |
| } |
| |
| /** |
| * The criteria for a project having a JSF design time are: |
| * |
| * - project is non-null. |
| * - project is accessible (project.isAccessible() == true) |
| * - project has a JSF facet (this implies that it's dependent facets are also present). |
| * |
| * @param project |
| * @return true if project can have a JSF DesignTimeApplicationManager |
| * associated with it. getInstance(project) uses this determine if should |
| * construct an instance for a project. |
| */ |
| public static boolean hasJSFDesignTime(final IProject project) |
| { |
| return project != null && project.isAccessible() && |
| JSFAppConfigUtils.isValidJSFProject(project); |
| } |
| |
| // instance definition |
| // _project must be writable in case the manager needs to be retargetted |
| // after a rename/move etc. |
| private IProject _project; |
| private final IExternalContextFactoryLocator _locator; |
| //private IDTViewHandler _viewHandler; |
| private Properties _properties; |
| |
| private DesignTimeApplicationManager(IProject project) |
| { |
| _project = project; |
| _locator = new MyExternalContextFactoryLocator(); |
| _properties = loadProperties(_project); |
| } |
| |
| /** |
| * @param file must not be null |
| * @return the faces context for the file or null if not found |
| */ |
| public DTFacesContext getFacesContext(IFile file) |
| { |
| if (!hasDTFacesContext(file)) |
| { |
| return null; |
| } |
| |
| try |
| { |
| synchronized(file) |
| { |
| Object context = file.getSessionProperty(SESSION_PROPERTY_KEY_FACES_CONTEXT); |
| |
| if (context == null) |
| { |
| context = new DTFacesContext(file, _locator); |
| file.setSessionProperty(SESSION_PROPERTY_KEY_PROJECT, context); |
| } |
| |
| return (DTFacesContext) context; |
| } |
| } |
| catch (CoreException ce) |
| { |
| Platform.getLog(JSFCorePlugin.getDefault().getBundle()) |
| .log(new Status(IStatus.ERROR, |
| JSFCorePlugin.getDefault().getBundle().getSymbolicName(), |
| 0, "Problem loading design time facescontext", //$NON-NLS-1$ |
| new Throwable(ce))); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Only files for which a runtime request context will be generated |
| * have a corresponding design time context. This is generally confined |
| * to view definition files such as JSP's. |
| * |
| * General criteria for a file to have a design time faces context are: |
| * |
| * - the file is non-null and isAccessible() |
| * - the file has designtime view handler (getViewHandler(file) != null) |
| * and it supports the content type of file. |
| * |
| * getFacesContext uses this to decide whether to generate a context |
| * for an IFile. |
| * |
| * @param file |
| * @return true if file has a design time faces context |
| */ |
| public boolean hasDTFacesContext(final IFile file) |
| { |
| IDTViewHandler viewHandler = getViewHandler(); |
| |
| if (file != null && file.isAccessible()&& |
| viewHandler != null && viewHandler.supportsViewDefinition(file)) |
| { |
| return true; |
| } |
| return false; |
| } |
| /** |
| * @return the design time view handler for this webap (project). |
| */ |
| public synchronized IDTViewHandler getViewHandler() |
| { |
| final String viewHandlerId = |
| getFromProjectSettings(PERSIST_PROPERTY_NAME_VIEW_HANDLER |
| , DEFAULT_VIEW_HANDLER_ID); |
| |
| if (viewHandlerId != null) |
| { |
| return JSFCorePlugin.getViewHandlers(viewHandlerId).getInstance(_project); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Sets the persistent id on this project that will be used to load the |
| * view handler. |
| * |
| * @param viewHandlerId |
| */ |
| public synchronized void setViewHandlerId(final String viewHandlerId) |
| { |
| setProjectSetting(PERSIST_PROPERTY_NAME_VIEW_HANDLER, viewHandlerId); |
| } |
| |
| /** |
| * @param resolverPluginId |
| * @throws CoreException |
| */ |
| public synchronized void setExternalContextProvider(final String resolverPluginId) |
| throws CoreException |
| { |
| _project.setPersistentProperty |
| (PERSIST_PROPERTY_KEY_EXTERNAL_CONTEXT_PROVIDER, resolverPluginId); |
| } |
| |
| /** |
| * @return the id of the active design time external context provider |
| */ |
| public synchronized String getExternalContextProvider() |
| { |
| return getResolverId(PERSIST_PROPERTY_KEY_EXTERNAL_CONTEXT_PROVIDER, |
| DEFAULT_EXTERNAL_CONTEXT_ID); |
| } |
| |
| /** |
| * @return the designtime variable resolver for this application |
| */ |
| public synchronized AbstractDTVariableResolver getVariableResolver() |
| { |
| ExtensionData<AbstractDTVariableResolver> extData = null; |
| |
| String id = getResolverId_OLD(PERSIST_PROPERTY_KEY_VARIABLE_RESOLVER_PROVIDER); |
| if (id != null) |
| { |
| extData = JSFCorePlugin.getVariableResolvers(id); |
| } |
| |
| if (extData == null) |
| { |
| extData = JSFCorePlugin.getVariableResolvers(DEFAULT_VARIABLE_RESOLVER_ID); |
| } |
| |
| return extData.getInstance(_project); |
| } |
| |
| /** |
| * Sets the plugin used to determine the designtime variable resolver. To |
| * reset to the default, pass null. |
| * |
| * @param resolverPluginId |
| * @throws CoreException -- if the setting the new value fails |
| */ |
| public synchronized void setVariableResolverProvider(final String resolverPluginId) |
| throws CoreException |
| { |
| _project.setPersistentProperty |
| (PERSIST_PROPERTY_KEY_VARIABLE_RESOLVER_PROVIDER, resolverPluginId); |
| } |
| |
| /** |
| * @return the id of the active design time variable resolver |
| */ |
| public synchronized String getVariableResolverProvider() |
| { |
| return getResolverId(PERSIST_PROPERTY_KEY_VARIABLE_RESOLVER_PROVIDER, |
| DEFAULT_VARIABLE_RESOLVER_ID); |
| } |
| |
| /** |
| * @return the default property resolver that will be used if no other |
| * is provided. The default property resolver is intended to match the |
| * similar resolver used by the runtime. |
| */ |
| public synchronized AbstractDTPropertyResolver getDefaultPropertyResolver() |
| { |
| return JSFCorePlugin.getPropertyResolver(DEFAULT_PROPERTY_RESOLVER_ID).getInstance(_project); |
| } |
| |
| /** |
| * @return the designtime property resolver for this application |
| */ |
| public synchronized AbstractDTPropertyResolver getPropertyResolver() |
| { |
| ExtensionData<AbstractDTPropertyResolver> extData = null; |
| |
| String id = getResolverId_OLD(PERSIST_PROPERTY_KEY_PROPERTY_RESOLVER_PROVIDER); |
| if (id != null) |
| { |
| extData = JSFCorePlugin.getPropertyResolver(id); |
| } |
| |
| if (extData == null) |
| { |
| extData = JSFCorePlugin.getPropertyResolver(DEFAULT_PROPERTY_RESOLVER_ID); |
| } |
| |
| return extData.getInstance(_project); |
| } |
| |
| /** |
| * @param resolverPluginId |
| * @throws CoreException -- if setting the provider fails |
| */ |
| public synchronized void setPropertyResolverProvider(final String resolverPluginId) |
| throws CoreException |
| { |
| _project.setPersistentProperty |
| (PERSIST_PROPERTY_KEY_PROPERTY_RESOLVER_PROVIDER, resolverPluginId); |
| } |
| |
| /** |
| * @return the id of the active design time variable resolver |
| */ |
| public synchronized String getPropertyResolverProvider() |
| { |
| return getResolverId(PERSIST_PROPERTY_KEY_PROPERTY_RESOLVER_PROVIDER, |
| DEFAULT_PROPERTY_RESOLVER_ID); |
| } |
| |
| /** |
| * @return the designtime method resolver for this application |
| */ |
| public synchronized AbstractDTMethodResolver getMethodResolver() |
| { |
| ExtensionData<AbstractDTMethodResolver> extData = null; |
| |
| String id = getResolverId_OLD(PERSIST_PROPERTY_KEY_METHOD_RESOLVER_PROVIDER); |
| if (id != null) |
| { |
| extData = JSFCorePlugin.getMethodResolvers(id); |
| } |
| |
| if (extData == null) |
| { |
| extData = JSFCorePlugin.getMethodResolvers(DEFAULT_METHOD_RESOLVER_ID); |
| } |
| |
| return extData.getInstance(_project); |
| } |
| |
| /** |
| * @param resolverPluginId |
| * @throws CoreException -- if setting the plugin fails |
| */ |
| public synchronized void setMethodResolverProvider(final String resolverPluginId) |
| throws CoreException |
| { |
| _project.setPersistentProperty |
| (PERSIST_PROPERTY_KEY_METHOD_RESOLVER_PROVIDER, resolverPluginId); |
| |
| } |
| |
| /** |
| * @return the id of the active design time variable resolver |
| */ |
| public synchronized String getMethodResolverProvider() |
| { |
| return getResolverId(PERSIST_PROPERTY_KEY_METHOD_RESOLVER_PROVIDER, |
| DEFAULT_METHOD_RESOLVER_ID); |
| } |
| |
| private String getResolverId_OLD(final QualifiedName pluginKey) |
| { |
| String pluginId = null; |
| |
| try |
| { |
| pluginId = |
| _project.getPersistentProperty(pluginKey); |
| } |
| catch (CoreException ce) |
| { |
| JSFCorePlugin.getDefault().getLog().log( |
| new Status(IStatus.ERROR, JSFCorePlugin.PLUGIN_ID, |
| 0, "Error getting plugin property", //$NON-NLS-1$ |
| ce)); |
| pluginId = null; |
| // fall-through and use the default |
| } |
| |
| return pluginId; |
| } |
| |
| private String getResolverId(final QualifiedName key, final String defaultValue) |
| { |
| String id = defaultValue; |
| |
| try |
| { |
| final String userId = |
| _project.getPersistentProperty(key); |
| |
| if (userId != null) |
| { |
| id = userId; |
| } |
| } |
| catch (CoreException ce) |
| { |
| // do nothing; fall through and return default |
| } |
| |
| return id; |
| } |
| |
| private class MyExternalContextFactoryLocator implements IExternalContextFactoryLocator |
| { |
| public AbstractDTExternalContextFactory getFactory() |
| { |
| ExtensionData<AbstractDTExternalContextFactory> extData = null; |
| |
| String id = getResolverId_OLD(PERSIST_PROPERTY_KEY_EXTERNAL_CONTEXT_PROVIDER); |
| if (id != null) |
| { |
| extData = JSFCorePlugin.getExternalContextProviders(id); |
| } |
| |
| if (extData == null) |
| { |
| extData = JSFCorePlugin.getExternalContextProviders(DEFAULT_EXTERNAL_CONTEXT_ID); |
| } |
| |
| return extData.getInstance(_project); |
| } |
| } |
| |
| private String getFromProjectSettings(final String key, final String defaultValue) |
| { |
| return _properties.getProperty(key, defaultValue); |
| } |
| |
| private void setProjectSetting(final String key, final String value) |
| { |
| _properties.setProperty(key, value); |
| storeProperties(_properties); |
| } |
| |
| private void storeProperties(final Properties properties) |
| { |
| IFile propFile; |
| try |
| { |
| propFile = getPropsFile(_project); |
| if (propFile != null) |
| { |
| final ByteArrayOutputStream outstream = |
| new ByteArrayOutputStream(); |
| properties.store(outstream, null); |
| propFile.setContents(new ByteArrayInputStream(outstream.toByteArray()) |
| , true, true, null); |
| } |
| } |
| catch (CoreException e) |
| { |
| JSFCorePlugin.log(e, "Problem storing properties"); |
| } |
| catch (IOException e) |
| { |
| JSFCorePlugin.log(e, "Problem storing properties"); |
| } |
| } |
| |
| private Properties loadProperties(final IProject project) |
| { |
| Properties props = new Properties(); |
| try |
| { |
| final IFile propFile = getPropsFile(project); |
| |
| if (propFile != null) |
| { |
| props.load(propFile.getContents()); |
| } |
| } |
| catch (CoreException ce) |
| { |
| JSFCorePlugin.log(ce, "Problem loading properties"); |
| } |
| catch (IOException ce) |
| { |
| JSFCorePlugin.log(ce, "Problem loading properties"); |
| } |
| |
| return props; |
| } |
| |
| private IFile getPropsFile(final IProject project) throws CoreException |
| { |
| IFolder folder = project.getFolder(new Path(".settings")); |
| if (!folder.exists()) |
| { |
| folder.create(false, true, null); |
| } |
| |
| final IFile file = folder.getFile( |
| new Path("org.eclipse.jst.jsf.designtime.appmgr.prefs")); |
| |
| if (!file.exists()) |
| { |
| file.create(new ByteArrayInputStream(new byte[0]), false, null); |
| } |
| |
| return file; |
| } |
| } |