blob: bd3b04ba98e09978534f645bdb00a67c6000a1ef [file] [log] [blame]
/*******************************************************************************
* 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.jsp;
import java.io.IOException;
import java.io.InputStream;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jst.jsf.core.internal.JSFCorePlugin;
class ResourceBundleMapSource extends AbstractMap
{
private static final String PROPERTY_QUALIFIER = "org.eclipse.jst.jsf.designtime.internal.jsp";
private static final String SESSION_PROPERTY_NAME_PROJECT = "ResourceBundleMapSource";
private static final QualifiedName SESSION_PROPERTY_KEY_PROJECT
= new QualifiedName(PROPERTY_QUALIFIER, SESSION_PROPERTY_NAME_PROJECT);
private static IFile getCachedBundleFile(final IProject project, final String baseName)
{
if (project != null)
{
return (IFile) getBundleFileCache(project).get(baseName);
}
return null;
}
private static Map getBundleFileCache(IProject project)
{
synchronized(project)
{
Map bundleFileCache = null;
try
{
bundleFileCache =
(Map) project.getSessionProperty(SESSION_PROPERTY_KEY_PROJECT);
if (bundleFileCache == null)
{
bundleFileCache = new HashMap();
project.setSessionProperty(SESSION_PROPERTY_KEY_PROJECT, bundleFileCache);
}
}
catch (CoreException ce)
{
JSFCorePlugin.log("Error creating bundle file cache", ce);
}
return bundleFileCache;
}
}
private static IFile createCachedBundleFile(final IProject project,
final String resourcePathStr)
throws IOException, JavaModelException, CoreException
{
final IJavaProject javaProject = JavaCore.create(project);
final String pathStr =
resourcePathStr.
substring(0, resourcePathStr.lastIndexOf('.'));
final String bundleName =
resourcePathStr.substring(resourcePathStr.lastIndexOf('.')+1);
if (pathStr == null
|| pathStr.length() < 1
|| bundleName == null
|| bundleName.length() < 1)
{
throw new IOException("Cannot resolve bundle name to file");
}
final SearchPattern jdtSearchPattern =
SearchPattern.createPattern(pathStr,
IJavaSearchConstants.PACKAGE,
IJavaSearchConstants.DECLARATIONS,
SearchPattern.R_EQUIVALENT_MATCH);
if (jdtSearchPattern == null)
{
throw new IOException("Cannot resolve bundle name to file");
}
final IJavaSearchScope searchScope =
SearchEngine.createJavaSearchScope(new IJavaElement[]{javaProject});
final List matches = new ArrayList();
final SearchRequestor requestor = new SearchRequestor()
{
public void acceptSearchMatch(SearchMatch match)
{
if (match.isExact()
&& match.getResource() != null)
{
matches.add(match);
}
}
};
final SearchEngine searchEngine = new SearchEngine();
searchEngine.search(jdtSearchPattern, new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()}, searchScope, requestor, null);
if (matches.size() < 1)
{
throw new IOException("Cannot resolve bundle name to package");
}
final SearchMatch firstMatch = ((SearchMatch)matches.get(0));
final IResource res = firstMatch.getResource();
if (res.getType() != IResource.FOLDER)
{
throw new IOException("Cannot resolve bundle package to folder");
}
final IFolder folder = (IFolder) res;
final IResource bundleRes = folder.findMember(bundleName+".properties");
if (bundleRes == null
|| bundleRes.getType() != IResource.FILE)
{
throw new IOException("Cannot resolve bundle name to file");
}
getBundleFileCache(project).put(resourcePathStr, bundleRes);
return (IFile) bundleRes;
}
private Properties _resourceBundle; // = null; set on first access or changes
private final IFile _bundleFile; // the resource
// 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;
}
private void checkAndRefreshBundle()
{
if (_resourceBundle == null
|| _bundleFile.getModificationStamp() != _lastModificationStamp)
{
InputStream bundleStream = null;
try
{
bundleStream = _bundleFile.getContents();
_resourceBundle = new Properties();
_resourceBundle.load(bundleStream);
_lastModificationStamp = _bundleFile.getModificationStamp();
}
catch (Exception ioe)
{
JSFCorePlugin.log("Error refreshing bundle", ioe);
}
finally
{
if (bundleStream != null)
{
try
{
bundleStream.close();
}
catch (IOException ioe)
{
JSFCorePlugin.log("Error closing bundle", ioe);
}
}
}
}
}
public Set entrySet()
{
checkAndRefreshBundle();
return _resourceBundle.entrySet();
}
/**
* @see java.util.AbstractMap#get(java.lang.Object)
* @overrride to optimize for the fact that we are doing a hash get
*/
//
public Object get(Object key)
{
checkAndRefreshBundle();
return _resourceBundle.get(key);
}
}