| /******************************************************************************* |
| * 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.io.InputStream; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.IWorkspaceRunnable; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| 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.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.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.AbstractDTViewHandler; |
| 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 |
| { |
| private static final String SETTINGS_DIR_NAME = ".settings"; |
| private static final String ORG_ECLIPSE_JST_JSF_DESIGNTIME_APPMGR_PREFS = "org.eclipse.jst.jsf.designtime.appmgr.prefs"; |
| |
| 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 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$ |
| |
| private static final Object GET_INSTANCE_LOCK = new Object(); |
| |
| /** |
| * @param project |
| * @return the app manager associated with project |
| */ |
| public static DesignTimeApplicationManager getInstance( |
| final IProject project) |
| { |
| if (!hasJSFDesignTime(project)) |
| { |
| return null; |
| } |
| |
| try |
| { |
| synchronized (GET_INSTANCE_LOCK) |
| { |
| DesignTimeApplicationManager manager = (DesignTimeApplicationManager) project |
| .getSessionProperty(SESSION_PROPERTY_KEY_PROJECT); |
| |
| if (manager != null && !project.equals(manager._project)) |
| { |
| if (!manager._isDisposed.get()) |
| { |
| manager.dispose(); |
| } |
| // bug 147729: pretend we starting with a new project (we kind of are) |
| manager = null; |
| } |
| |
| if (manager == null) |
| { |
| manager = new DesignTimeApplicationManager(project); |
| project.setSessionProperty(SESSION_PROPERTY_KEY_PROJECT, |
| manager); |
| } |
| |
| return manager; |
| } |
| } |
| catch (final CoreException ce) |
| { |
| Platform |
| .getLog(JSFCorePlugin.getDefault().getBundle()) |
| .log( |
| new Status( |
| IStatus.ERROR, |
| JSFCorePlugin.getDefault().getBundle() |
| .getSymbolicName(), |
| 0, |
| "Problem loading design time appmanager", new Exception(ce))); //$NON-NLS-1$ |
| } |
| |
| return null; |
| } |
| |
| // private void checkAndMaybeUpdateProject(final IProject project) |
| // { |
| // boolean needsPropertyStore = false; |
| // |
| // synchronized(this) |
| // { |
| // if (!project.equals(_project)) |
| // { |
| // _lifecycleListener.removeResource(_project); |
| // _project = project; |
| // _lifecycleListener.addResource(_project); |
| // _properties.setProject(project); |
| // needsPropertyStore = true; |
| // } |
| // } |
| // |
| // if (needsPropertyStore) |
| // { |
| // _properties.store(); |
| // } |
| // } |
| |
| private synchronized void dispose() |
| { |
| if (_isDisposed.compareAndSet(false, true)) |
| { |
| // dispose viewhandler |
| removeViewHandler(); |
| _lifecycleListener.dispose(); |
| _facesContexts.clear(); |
| } |
| } |
| |
| /** |
| * <p> |
| * The criteria for a project having a JSF design time are: |
| * </p> |
| * |
| * <ul> |
| * <li>project is non-null.</li> |
| * <li>project is accessible (project.isAccessible() == true)</li> |
| * <li>project has a JSF facet (this implies that it's dependent facets are |
| * also present).</li> |
| * </ul> |
| * |
| * @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 final IProject _project; |
| private final IExternalContextFactoryLocator _locator; |
| private final LifecycleListener _lifecycleListener; |
| private final AtomicBoolean _isDisposed; |
| private final ViewHandlerManager _viewHandlerManager; |
| private final Map<IFile, DTFacesContext> _facesContexts; |
| |
| private DesignTimeApplicationManager(final IProject project) |
| { |
| _project = project; |
| _locator = new MyExternalContextFactoryLocator(); |
| _isDisposed = new AtomicBoolean(); |
| _lifecycleListener = new LifecycleListener(_project); |
| _lifecycleListener.addListener(new IResourceLifecycleListener() |
| { |
| public EventResult acceptEvent(final ResourceLifecycleEvent event) |
| { |
| if (event.getAffectedResource() == _project) |
| { |
| if (event.getEventType() == ResourceLifecycleEvent.EventType.RESOURCE_INACCESSIBLE |
| && event.getReasonType() == ResourceLifecycleEvent.ReasonType.RESOURCE_PROJECT_CLOSED) |
| { |
| dispose(); |
| } |
| } |
| return EventResult.getDefaultEventResult(); |
| } |
| }); |
| |
| final PropertyFileManager properties = new PropertyFileManager(_project); |
| |
| _viewHandlerManager = new ViewHandlerManager(properties); |
| _facesContexts = new HashMap<IFile, DTFacesContext>(); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @param file |
| * must not be null |
| * @return the faces context for the file or null if not found |
| */ |
| public DTFacesContext getFacesContext(final IFile file) |
| { |
| checkIsDisposed(); |
| if (!hasDTFacesContext(file)) |
| { |
| return null; |
| } |
| |
| synchronized (_facesContexts) |
| { |
| DTFacesContext context = _facesContexts.get(file); |
| if (context == null) |
| { |
| context = new DTFacesContext(file, _locator); |
| context.initialize(_lifecycleListener); |
| _facesContexts.put(file, context); |
| } |
| return context; |
| } |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * 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) |
| { |
| checkIsDisposed(); |
| final IDTViewHandler viewHandler = getViewHandler(); |
| |
| if (file != null && file.isAccessible() && viewHandler != null |
| && viewHandler.supportsViewDefinition(file)) |
| { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @return the design time view handler for this webapp (project). |
| */ |
| public IDTViewHandler getViewHandler() |
| { |
| checkIsDisposed(); |
| /* NOTE: it is critical that view handler calls _NEVER_ take the |
| DesignTimeApplicationManager lock. let ViewHandlerManager manage it |
| instead.*/ |
| return _viewHandlerManager.getViewHandler(_project, _lifecycleListener); |
| } |
| |
| /** |
| * Remove and dispose of any currently registered view handler |
| */ |
| private void removeViewHandler() |
| { |
| /* NOTE: it is critical that view handler calls _NEVER_ take the |
| DesignTimeApplicationManager lock. let ViewHandlerManager manage it |
| instead.*/ |
| _viewHandlerManager.removeViewHandler(_project); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * Sets the persistent id on this project that will be used to load the view |
| * handler. |
| * |
| * @param viewHandlerId |
| */ |
| public void setViewHandlerId(final String viewHandlerId) |
| { |
| checkIsDisposed(); |
| /* NOTE: it is critical that view handler calls _NEVER_ take the |
| DesignTimeApplicationManager lock. let ViewHandlerManager manage it |
| instead.*/ |
| _viewHandlerManager.setViewHandlerId(_project, viewHandlerId); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @param resolverPluginId |
| * @throws CoreException |
| */ |
| public synchronized void setExternalContextProvider( |
| final String resolverPluginId) throws CoreException |
| { |
| checkIsDisposed(); |
| _project.setPersistentProperty( |
| PERSIST_PROPERTY_KEY_EXTERNAL_CONTEXT_PROVIDER, |
| resolverPluginId); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @return the id of the active design time external context provider |
| */ |
| public synchronized String getExternalContextProvider() |
| { |
| checkIsDisposed(); |
| return getResolverId(PERSIST_PROPERTY_KEY_EXTERNAL_CONTEXT_PROVIDER, |
| DEFAULT_EXTERNAL_CONTEXT_ID); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @return the designtime variable resolver for this application |
| */ |
| public synchronized AbstractDTVariableResolver getVariableResolver() |
| { |
| checkIsDisposed(); |
| ExtensionData<AbstractDTVariableResolver> extData = null; |
| |
| final 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); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * 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 |
| { |
| checkIsDisposed(); |
| _project.setPersistentProperty( |
| PERSIST_PROPERTY_KEY_VARIABLE_RESOLVER_PROVIDER, |
| resolverPluginId); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @return the id of the active design time variable resolver |
| */ |
| public synchronized String getVariableResolverProvider() |
| { |
| checkIsDisposed(); |
| return getResolverId(PERSIST_PROPERTY_KEY_VARIABLE_RESOLVER_PROVIDER, |
| DEFAULT_VARIABLE_RESOLVER_ID); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @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() |
| { |
| checkIsDisposed(); |
| return JSFCorePlugin.getPropertyResolver(DEFAULT_PROPERTY_RESOLVER_ID) |
| .getInstance(_project); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @return the designtime property resolver for this application |
| */ |
| public synchronized AbstractDTPropertyResolver getPropertyResolver() |
| { |
| checkIsDisposed(); |
| |
| ExtensionData<AbstractDTPropertyResolver> extData = null; |
| |
| final 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); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @param resolverPluginId |
| * @throws CoreException -- |
| * if setting the provider fails |
| */ |
| public synchronized void setPropertyResolverProvider( |
| final String resolverPluginId) throws CoreException |
| { |
| checkIsDisposed(); |
| _project.setPersistentProperty( |
| PERSIST_PROPERTY_KEY_PROPERTY_RESOLVER_PROVIDER, |
| resolverPluginId); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @return the id of the active design time variable resolver |
| */ |
| public synchronized String getPropertyResolverProvider() |
| { |
| checkIsDisposed(); |
| return getResolverId(PERSIST_PROPERTY_KEY_PROPERTY_RESOLVER_PROVIDER, |
| DEFAULT_PROPERTY_RESOLVER_ID); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @return the designtime method resolver for this application |
| */ |
| public synchronized AbstractDTMethodResolver getMethodResolver() |
| { |
| checkIsDisposed(); |
| ExtensionData<AbstractDTMethodResolver> extData = null; |
| |
| final 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); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @param resolverPluginId |
| * @throws CoreException -- |
| * if setting the plugin fails |
| */ |
| public synchronized void setMethodResolverProvider( |
| final String resolverPluginId) throws CoreException |
| { |
| checkIsDisposed(); |
| _project |
| .setPersistentProperty( |
| PERSIST_PROPERTY_KEY_METHOD_RESOLVER_PROVIDER, |
| resolverPluginId); |
| } |
| |
| /** |
| * Method is thread-safe and may block the caller. |
| * |
| * @return the id of the active design time variable resolver |
| */ |
| public synchronized String getMethodResolverProvider() |
| { |
| checkIsDisposed(); |
| 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 (final 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 (final CoreException ce) |
| { |
| // do nothing; fall through and return default |
| } |
| |
| return id; |
| } |
| |
| private class MyExternalContextFactoryLocator implements |
| IExternalContextFactoryLocator |
| { |
| public AbstractDTExternalContextFactory getFactory() |
| { |
| ExtensionData<AbstractDTExternalContextFactory> extData = null; |
| |
| final 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 void checkIsDisposed() |
| { |
| // TODO: need to add isDisposed to this and throw an exception |
| // for now, we just log what's happening to aid debugging |
| if (_isDisposed.get()) |
| { |
| JSFCorePlugin |
| .log( |
| "A call to a disposed DesignTimeApplicationManager was attempted", |
| new Throwable( |
| "This exception is only to record a stack trace")); |
| } |
| } |
| |
| private static class ViewHandlerManager |
| { |
| private final PropertyFileManager _propertyFileManager; |
| |
| ViewHandlerManager(final PropertyFileManager properties) |
| { |
| _propertyFileManager = properties; |
| } |
| |
| public synchronized void removeViewHandler(final IProject project) |
| { |
| final String viewHandlerId = _propertyFileManager |
| .getProperty(PERSIST_PROPERTY_NAME_VIEW_HANDLER, |
| DEFAULT_VIEW_HANDLER_ID); |
| |
| if (viewHandlerId != null) |
| { |
| final ExtensionData<AbstractDTViewHandler> extData = |
| JSFCorePlugin.getViewHandlers(viewHandlerId); |
| |
| if (extData != null) |
| { |
| final AbstractDTViewHandler handler = extData.removeInstance(project); |
| if (handler != null) |
| { |
| handler.dispose(); |
| } |
| } |
| } |
| } |
| |
| public synchronized IDTViewHandler getViewHandler( |
| final IProject project, final LifecycleListener listener) |
| { |
| final String viewHandlerId = _propertyFileManager |
| .getProperty(PERSIST_PROPERTY_NAME_VIEW_HANDLER, |
| DEFAULT_VIEW_HANDLER_ID); |
| |
| if (viewHandlerId != null) |
| { |
| ExtensionData<AbstractDTViewHandler> viewHandlers = JSFCorePlugin |
| .getViewHandlers(viewHandlerId); |
| if (viewHandlers == null) |
| { |
| viewHandlers = JSFCorePlugin |
| .getViewHandlers(DEFAULT_VIEW_HANDLER_ID); |
| } |
| |
| final AbstractDTViewHandler viewHandler = viewHandlers |
| .getInstance(project); |
| viewHandler.setLifecycleListener(listener); |
| return viewHandler; |
| } |
| return null; |
| } |
| |
| public void setViewHandlerId(final IProject project, |
| final String viewHandlerId) |
| { |
| // remove any previous handler before the id is lost |
| removeViewHandler(project); |
| _propertyFileManager.setProperty( |
| PERSIST_PROPERTY_NAME_VIEW_HANDLER, viewHandlerId); |
| } |
| } |
| |
| private static class PropertyFileManager |
| { |
| private final Properties _properties; |
| private IProject _project; |
| |
| PropertyFileManager(final IProject project) |
| { |
| _project = project; |
| _properties = new Properties(); |
| load(_project, _properties); |
| } |
| |
| private synchronized IProject getProject() |
| { |
| return _project; |
| } |
| |
| public void setProperty(final String key, final String value) { |
| _properties.setProperty(key, value); |
| store(); |
| } |
| |
| public String getProperty(final String key, final String defaultValue) { |
| return _properties.getProperty(key, defaultValue); |
| } |
| |
| public void store() |
| { |
| final IWorkspaceRunnable storeJob = new IWorkspaceRunnable() |
| { |
| public void run(IProgressMonitor monitor) throws CoreException { |
| IFile propFile; |
| |
| try { |
| propFile = getPropsFile(getProject()); |
| if (propFile != null) { |
| final ByteArrayOutputStream outstream = new ByteArrayOutputStream(); |
| // properties will thread-safe save to the array |
| // stream |
| // no further locking is needed since we have |
| // already have a lock |
| // on the workspace sub-tree for the settings file |
| // if this job |
| // is running. |
| _properties.store(outstream, null); |
| propFile.setContents(new ByteArrayInputStream( |
| outstream.toByteArray()), true, true, null); |
| } |
| } catch (final CoreException e) { |
| JSFCorePlugin.log(e, "Problem storing properties"); |
| } catch (final IOException e) { |
| JSFCorePlugin.log(e, "Problem storing properties"); |
| } |
| } |
| }; |
| |
| final IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
| |
| try |
| { |
| // need to lock the project tree, since may need to create |
| // .settings directory |
| workspace.run(storeJob, getProject(), IWorkspace.AVOID_UPDATE, |
| null); |
| } catch (CoreException ce) |
| { |
| JSFCorePlugin.log(ce, "Problem storing properties"); |
| } |
| } |
| |
| private static void load(final IProject project, |
| final Properties properties) |
| { |
| try |
| { |
| final IFile propFile = getPropsFileHandle(project); |
| |
| if (propFile != null && propFile.isAccessible()) |
| { |
| InputStream inStream = null; |
| |
| try |
| { |
| inStream = propFile.getContents(); |
| properties.load(inStream); |
| } |
| finally |
| { |
| if (inStream != null) |
| { |
| inStream.close(); |
| } |
| } |
| } |
| } |
| catch (final CoreException ce) |
| { |
| JSFCorePlugin.log(ce, "Problem loading properties"); |
| } |
| catch (final IOException ce) |
| { |
| JSFCorePlugin.log(ce, "Problem loading properties"); |
| } |
| } |
| |
| private static IFile getPropsFile(final IProject project) throws CoreException |
| { |
| final IFolder folder = project.getFolder(new Path(SETTINGS_DIR_NAME)); |
| 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; |
| } |
| |
| /** |
| * @param project |
| * @return the file handle for the properties file. Doesn't create the |
| * resource if it doesn't exist |
| */ |
| private static IFile getPropsFileHandle(final IProject project) |
| { |
| return project.getFile(new Path(SETTINGS_DIR_NAME).append(ORG_ECLIPSE_JST_JSF_DESIGNTIME_APPMGR_PREFS)); |
| } |
| } |
| } |