/*****************************************************************************
* Copyright (c) 2006-2013, Cloudsmith Inc.
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text of
* such license is available at www.eclipse.org.
*****************************************************************************/
package org.eclipse.buckminster.core.resolver;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.eclipse.buckminster.core.Messages;
import org.eclipse.buckminster.core.helpers.AbstractExtension;
import org.eclipse.buckminster.core.helpers.IllegalParameterException;
import org.eclipse.buckminster.core.prefedit.IPreferenceDescriptor;
import org.eclipse.buckminster.core.prefedit.PreferenceDescriptor;
import org.eclipse.buckminster.core.prefedit.PreferenceType;
import org.eclipse.buckminster.core.query.model.ComponentQuery;
import org.eclipse.buckminster.core.rmap.model.ResourceMap;
import org.eclipse.buckminster.runtime.Buckminster;
import org.eclipse.buckminster.runtime.BuckminsterException;
import org.eclipse.buckminster.runtime.URLUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.ecf.core.security.IConnectContext;
/**
* @author Thomas Hallgren
*/
public class ResourceMapResolverFactory extends AbstractExtension implements IResourceMapResolverFactory {
private static final IEclipsePreferences preferencesNode = InstanceScope.INSTANCE.getNode(Buckminster.PLUGIN_ID);
private static final IEclipsePreferences defaultNode = DefaultScope.INSTANCE.getNode(Buckminster.PLUGIN_ID);
public static final String RESOURCE_MAP_URL_PARAM = "resourceMapURL"; //$NON-NLS-1$
public static final String OVERRIDE_QUERY_URL_PARAM = "overrideQueryURL"; //$NON-NLS-1$
public static final boolean OVERRIDE_QUERY_URL_DEFAULT = false;
public static final String LOCAL_RESOLVE_PARAM = "localResolve"; //$NON-NLS-1$
public static final boolean LOCAL_RESOLVE_DEFAULT = true;
public static final String RESOLVER_THREADS_MAX_PARAM = "resolverThreadsMax"; //$NON-NLS-1$
public static final int RESOLVER_THREADS_MAX_DEFAULT = 4;
public static void addListener(IPreferenceChangeListener listener) {
preferencesNode.addPreferenceChangeListener(listener);
}
public static void removeListener(IPreferenceChangeListener listener) {
preferencesNode.removePreferenceChangeListener(listener);
}
private IEclipsePreferences prefsNode;
private String resourceMapURL;
private boolean overrideQueryURL = OVERRIDE_QUERY_URL_DEFAULT;
private boolean localResolve = LOCAL_RESOLVE_DEFAULT;
private int resolverThreadsMax = RESOLVER_THREADS_MAX_DEFAULT;
private static final UUID CACHE_KEY_RESOURCE_MAP = UUID.randomUUID();
public static ResourceMap getCachedResourceMap(ResolutionContext context, URL url, IConnectContext cctx) throws CoreException {
Map<String, ResourceMap> rmapCache = getResourceMapCache(context.getUserCache());
String key = url.toString().intern();
synchronized (key) {
ResourceMap rmap = rmapCache.get(key);
if (rmap == null) {
rmap = ResourceMap.fromURL(url, cctx);
rmapCache.put(key, rmap);
}
return rmap;
}
}
@SuppressWarnings("unchecked")
private static Map<String, ResourceMap> getResourceMapCache(Map<UUID, Object> ctxUserCache) {
synchronized (ctxUserCache) {
Map<String, ResourceMap> resourceMapCache = (Map<String, ResourceMap>) ctxUserCache.get(CACHE_KEY_RESOURCE_MAP);
if (resourceMapCache == null) {
resourceMapCache = Collections.synchronizedMap(new HashMap<String, ResourceMap>());
ctxUserCache.put(CACHE_KEY_RESOURCE_MAP, resourceMapCache);
}
return resourceMapCache;
}
}
@Override
public IResolver createResolver(ResolutionContext context) throws CoreException {
ComponentQuery query = context.getComponentQuery();
URL url;
if (isOverrideQueryURL())
url = getResourceMapURL();
else {
url = query.getResolvedResourceMapURL();
if (url == null)
url = getResourceMapURL();
}
return (url == null) ? new LocalResolver(context) : new ResourceMapResolver(this, context, false);
}
@Override
public IPreferenceDescriptor[] getPreferenceDescriptors() {
PreferenceDescriptor[] pds = new PreferenceDescriptor[4];
pds[0] = new PreferenceDescriptor(RESOURCE_MAP_URL_PARAM, PreferenceType.String, Messages.Resource_map_URL);
pds[1] = new PreferenceDescriptor(OVERRIDE_QUERY_URL_PARAM, PreferenceType.Boolean, Messages.Override_URL_in_Component_Query);
pds[2] = new PreferenceDescriptor(LOCAL_RESOLVE_PARAM, PreferenceType.Boolean, Messages.Perform_local_resolution);
pds[3] = new PreferenceDescriptor(RESOLVER_THREADS_MAX_PARAM, PreferenceType.Integer, Messages.Maximum_number_of_resolver_threads);
pds[3].setTextWidth(2);
pds[3].setIntegerRange(1, 12);
return pds;
}
public synchronized IEclipsePreferences getPreferences() {
if (prefsNode == null) {
prefsNode = (IEclipsePreferences) preferencesNode.node(getId());
initDefaultPreferences();
}
return prefsNode;
}
@Override
public int getResolutionPriority() {
return 0;
}
@Override
public int getResolverThreadsMax() {
return getPreferences().getInt(RESOLVER_THREADS_MAX_PARAM, resolverThreadsMax);
}
@Override
public ResourceMap getResourceMap(ResolutionContext context, URL url, IConnectContext cctx) throws CoreException {
if (url == null || isOverrideQueryURL())
url = getResourceMapURL();
return getCachedResourceMap(context, url, cctx);
}
/**
* Obtains the {@link #RESOURCE_MAP_URL_PARAM} setting for this factory from
* the preference store. If not found there, it defaults to the value set in
* the extension definition.
*
* @return The URL or <code>null</code> if it has not been set.
*/
@Override
public URL getResourceMapURL() throws CoreException {
try {
return URLUtils.normalizeToURL(getPreferences().get(RESOURCE_MAP_URL_PARAM, resourceMapURL));
} catch (MalformedURLException e) {
throw BuckminsterException.wrap(e);
}
}
@Override
public void initDefaultPreferences() {
IEclipsePreferences dfltNode = (IEclipsePreferences) defaultNode.node(getId());
if (dfltNode.getInt(RESOLVER_THREADS_MAX_PARAM, 0) == 0) {
// Defaults not initialized. Do it now
//
dfltNode.putBoolean(OVERRIDE_QUERY_URL_PARAM, OVERRIDE_QUERY_URL_DEFAULT);
dfltNode.putBoolean(LOCAL_RESOLVE_PARAM, LOCAL_RESOLVE_DEFAULT);
dfltNode.putInt(RESOLVER_THREADS_MAX_PARAM, RESOLVER_THREADS_MAX_DEFAULT);
}
}
/**
* Obtains the {@link #LOCAL_RESOLVE_PARAM} setting for this factory from
* the preference store. If not found there, it defaults to the value set in
* the extension definition.
*
* @return <code>true</code>ue if local resolutions should be performed.
*/
@Override
public boolean isLocalResolve() {
return getPreferences().getBoolean(LOCAL_RESOLVE_PARAM, localResolve);
}
/**
* Obtains the {@link #OVERRIDE_QUERY_URL_PARAM} setting for this factory
* from the preference store. If not found there, it defaults to the value
* set in the extension definition.
*
* @return the overrideQueryURL
*/
@Override
public boolean isOverrideQueryURL() {
return getPreferences().getBoolean(OVERRIDE_QUERY_URL_PARAM, overrideQueryURL);
}
@Override
public void setExtensionParameter(String key, String value) throws CoreException {
if (RESOURCE_MAP_URL_PARAM.equalsIgnoreCase(key)) {
resourceMapURL = value;
} else if (OVERRIDE_QUERY_URL_PARAM.equalsIgnoreCase(key)) {
overrideQueryURL = Boolean.parseBoolean(value);
} else if (LOCAL_RESOLVE_PARAM.equalsIgnoreCase(key)) {
localResolve = Boolean.parseBoolean(value);
} else if (RESOLVER_THREADS_MAX_PARAM.equalsIgnoreCase(key)) {
resolverThreadsMax = Integer.parseInt(value);
} else
throw new IllegalParameterException(ResolverFactoryMaintainer.QUERY_RESOLVERS_POINT, this.getId(), key);
}
public void setLocalResolve(boolean localResolve) {
getPreferences().putBoolean(LOCAL_RESOLVE_PARAM, localResolve);
}
public void setOverrideQueryURL(boolean overrideQueryURL) {
getPreferences().putBoolean(OVERRIDE_QUERY_URL_PARAM, overrideQueryURL);
}
public void setResolverThreadsMax(int resolverThreadsMax) {
getPreferences().putInt(RESOLVER_THREADS_MAX_PARAM, resolverThreadsMax);
}
public void setResourceMapURL(URL resourceMapURL) {
getPreferences().put(RESOURCE_MAP_URL_PARAM, resourceMapURL.toExternalForm());
}
}