Package org.eclipse.jst.jsf.designtime.internal.symbols

Source Code of org.eclipse.jst.jsf.designtime.internal.symbols.ResourceBundleMapSource

/*******************************************************************************
* 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.internal.symbols;

import java.io.IOException;
import java.io.InputStream;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.JavaModelException;
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.context.symbol.internal.impl.IMapSourceInfo;
import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
import org.eclipse.jst.jsf.core.internal.tld.LoadBundleUtil;

class ResourceBundleMapSource extends AbstractMap implements IMapSourceInfo
{
    private static final String   PROPERTY_QUALIFIER =
      "org.eclipse.jst.jsf.designtime.internal.jsp"; //$NON-NLS-1$
    private static final String   SESSION_PROPERTY_NAME_PROJECT =
      "ResourceBundleMapSource"; //$NON-NLS-1$
    private static final QualifiedName  SESSION_PROPERTY_KEY_PROJECT =
        new QualifiedName(PROPERTY_QUALIFIER, SESSION_PROPERTY_NAME_PROJECT);
    private static final Object  STATIC_LOCK = new Object();

    private static IFile    getCachedBundleFile(final IProject project, final String baseName)
    {
        if (project != null)
        {
            final Map<String, BundleFileCacheInfo> bundleFileCache = getBundleFileCache(project);

            if (bundleFileCache != null)
            {
                final BundleFileCacheInfo info = bundleFileCache.get(baseName);
                if (info != null)
                {
                    return info.getFile();
                }
            }
        }

        return null;
    }

    private static class BundleFileCacheInfo
    {
        private final IFile                 _file;
        private final Map<Object,CachedDataItem>    _cachedData;
        public BundleFileCacheInfo(final IFile file)
        {
            super();
            _file = file;
            _cachedData =
                Collections.synchronizedMap(new HashMap<Object, CachedDataItem>());
        }
        public IFile getFile()
        {
            return _file;
        }
        public Object getCachedData(final Object key)
        {
            CachedDataItem item = _cachedData.get(key);
           
            if (item != null)
            {
                return item.getData();
            }
            return null;
        }

        public Object putCachedData(final Object key, final Object value, final long timestamp)
        {
            CachedDataItem item = new CachedDataItem(value, timestamp);
            CachedDataItem oldItem = _cachedData.put(key, item);
            if (oldItem != null)
            {
                return oldItem.getData();
            }
            return null;
        }

        public boolean hasChanged(final Object key, final long timestamp)
        {
            CachedDataItem item = _cachedData.get(key);
            if (item != null)
            {
                return item.getTimestamp() != timestamp;
            }
            return false;
        }

        private static class CachedDataItem
        {
            private final Object        _data;
            private final long          _timestamp;
            public CachedDataItem(Object data, long timestamp)
            {
                super();
                _data = data;
                _timestamp = timestamp;
            }
            public final Object getData()
            {
                return _data;
            }
            public final long getTimestamp()
            {
                return _timestamp;
            }
        }
    }

    private static Map<String, BundleFileCacheInfo> getBundleFileCache(final IProject project)
    {
        synchronized(STATIC_LOCK)
        {
            Map<String, BundleFileCacheInfo> bundleFileCache = null;

            try
            {
                bundleFileCache =
                    (Map<String, BundleFileCacheInfo>) project.getSessionProperty(SESSION_PROPERTY_KEY_PROJECT);

                if (bundleFileCache == null)
                {
                    bundleFileCache = new HashMap<String, BundleFileCacheInfo>();
                    final LifecycleListener listener = new LifecycleListener(project, ResourcesPlugin.getWorkspace());
                    listener.addListener(new IResourceLifecycleListener()
                    {
                        public EventResult acceptEvent(final ResourceLifecycleEvent event)
                        {
                            EventResult result = EventResult.getDefaultEventResult();

                            if (event.getEventType() == EventType.RESOURCE_INACCESSIBLE)
                            {
                                try
                                {
                                  //Bug 283764: this listener may be called more than once - check project not already inaccessible
                                  if (project.isAccessible())
                                  {
                                      final Map<String, BundleFileCacheInfo> bundleCache =
                                          (Map<String, BundleFileCacheInfo>) project.getSessionProperty(SESSION_PROPERTY_KEY_PROJECT);
                                      //This listener may be called more than once - check session property not already nulled
                                      if (bundleCache != null)
                                      {
                                        bundleCache.clear();
                                          project.setSessionProperty(SESSION_PROPERTY_KEY_PROJECT, null);
                                      }
                                  }
                                }
                                catch (final CoreException ce)
                                {
                                    JSFCorePlugin.log("Error clearing bundle file cache", ce); //$NON-NLS-1$
                                }
                                result = EventResult.getDisposeAfterEventResult();
                            }

                            return result;
                        }
                    }
                    );

                    project.setSessionProperty(SESSION_PROPERTY_KEY_PROJECT, bundleFileCache);
                }
            }
            catch (final CoreException ce)
            {
                JSFCorePlugin.log("Error creating bundle file cache", ce); //$NON-NLS-1$
            }

            return bundleFileCache;
        }
    }

    private static IFile createCachedBundleFile(final IProject project,
                                                   final String  resourcePathStr)
                      throws IOException, CoreException
    {
        final IStorage storage =
            LoadBundleUtil.getLoadBundleResource(project, resourcePathStr);

        IFile bundleRes = null;

        if (storage != null
                && storage.getAdapter(IFile.class) != null)
        {
            bundleRes = (IFile) storage.getAdapter(IFile.class);
            // if file is removed, clear the bundle from the store.
            final LifecycleListener listener = new LifecycleListener(bundleRes, ResourcesPlugin.getWorkspace());
            listener.addListener(new IResourceLifecycleListener()
            {
                public EventResult acceptEvent(final ResourceLifecycleEvent event)
                {
                    EventResult result = EventResult.getDefaultEventResult();

                    if (event.getEventType() == EventType.RESOURCE_INACCESSIBLE)
                    {
                        Map<String, BundleFileCacheInfo> bundleFileCache = getBundleFileCache(project);
                        bundleFileCache.remove(resourcePathStr);
                        result = EventResult.getDisposeAfterEventResult();
                    }
                    return result;
                }
            }
            );

            getBundleFileCache(project).put(resourcePathStr, new BundleFileCacheInfo(bundleRes));
            return bundleRes;
        }

        throw new IOException("Bundle "+resourcePathStr+" not found in classpath for project: "+project.getName()); //$NON-NLS-1$ //$NON-NLS-2$
    }

    private Properties                  _resourceBundle; // = null; set on first access or changes
    private final IFile                 _bundleFile;   // the resource
    private final String                _resourcePathStr; // the key used in the file cache
    // as returned by IResource.getModificationStamp()
    // the last time _resourceBundle was loaded
    private long                        _lastModificationStamp;

    ResourceBundleMapSource(final IProject context,
                            final String  resourcePathStr)
                                throws IOException, JavaModelException, CoreException
    {
        IFile cachedBundleFile = getCachedBundleFile(context, resourcePathStr);

        if (cachedBundleFile == null)
        {
            cachedBundleFile = createCachedBundleFile(context, resourcePathStr);
        }

        _bundleFile = cachedBundleFile;
        _resourcePathStr = resourcePathStr;
    }

    private void checkAndRefreshBundle()
    {
        if (_bundleFile.isAccessible())
        {
            if (_resourceBundle == null  // doesn't exist yet
                    // exists but ws is out of sync
                    || !_bundleFile.isSynchronized(IResource.DEPTH_ZERO)
                    // exists but user has changed in workspace
                    || _bundleFile.getModificationStamp()
                            != _lastModificationStamp)
            {
                InputStream  bundleStream = null;
                try
                {
                    // force refresh if out of sync
                    bundleStream = _bundleFile.getContents(true);
                    _resourceBundle = new Properties();
                    _resourceBundle.load(bundleStream);
                    _lastModificationStamp = _bundleFile.getModificationStamp();
                }
                catch (final CoreException ce)
                {
                    JSFCorePlugin.log("Error refreshing bundle", ce); //$NON-NLS-1$
                }
                catch (final IOException ioe)
                {
                    JSFCorePlugin.log("Error refreshing bundle", ioe); //$NON-NLS-1$
                }
                finally
                {
                    if (bundleStream != null)
                    {
                        try
                        {
                            bundleStream.close();
                        }
                        catch (final IOException ioe)
                        {
                            JSFCorePlugin.log("Error closing bundle", ioe); //$NON-NLS-1$
                        }
                    }
                }
            }
        }
        else
        {
            // bundle no longer exists so remove it
            final Map<String, BundleFileCacheInfo> bundleFileCache = getBundleFileCache(_bundleFile.getProject());

            if (bundleFileCache != null &&
                    bundleFileCache.containsKey(_resourcePathStr))
            {
                bundleFileCache.remove(_resourcePathStr);
            }
            // in either case, clear the bundle entry
            if (_resourceBundle != null)
            {
                _resourceBundle.clear();
                _resourceBundle = null;
            }
        }
    }

    @Override
    public Set entrySet()
    {
        checkAndRefreshBundle();

        if (_resourceBundle == null)
        {
          return Collections.EMPTY_SET;
        }
        return _resourceBundle.entrySet();
    }

    /**
     * @param key
     * @return the value
     * @see java.util.AbstractMap#get(java.lang.Object)
     * @overrride to optimize for the fact that we are doing a hash get
     */
    //
    @Override
    public Object get(final Object key)
    {
        checkAndRefreshBundle();

        if (_resourceBundle == null)
        {
          return null;
        }
        return _resourceBundle.get(key);
    }

    public final boolean hasChanged(final Object key)
    {
        final BundleFileCacheInfo cache = getBundleFileCache(
                _bundleFile.getProject()).get(_resourcePathStr);
        if (cache != null)
        {
            return cache.hasChanged(key, _bundleFile.getModificationStamp());
        }
        // return true since if there is nothing cached, the caller will want
        // to react.
        return true;
    }

    public Object getCachedValue(final Object key)
    {
        final BundleFileCacheInfo cache = getBundleFileCache(
                _bundleFile.getProject()).get(_resourcePathStr);
        if (cache != null)
        {
            return cache.getCachedData(key);
        }
        return null;
    }

    public void putCachedValue(final Object key, final Object value)
    {
        final BundleFileCacheInfo cache = getBundleFileCache(
                _bundleFile.getProject()).get(_resourcePathStr);
        if (cache != null)
        {
            cache.putCachedData(key, value, _lastModificationStamp);
        }
    }
}
TOP

Related Classes of org.eclipse.jst.jsf.designtime.internal.symbols.ResourceBundleMapSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.