/*******************************************************************************
* Copyright (c) 2007, 2011 Intel Corporation and others.
* 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:
* Intel Corporation - Initial API and implementation
* IBM Corporation
*******************************************************************************/
package org.eclipse.cdt.build.internal.core.scannerconfig2;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.cdt.build.core.scannerconfig.CfgInfoContext;
import org.eclipse.cdt.build.core.scannerconfig.ICfgScannerConfigBuilderInfo2Set;
import org.eclipse.cdt.build.internal.core.scannerconfig.CfgScannerConfigUtil;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.make.core.MakeCorePlugin;
import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2;
import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2Set;
import org.eclipse.cdt.make.core.scannerconfig.InfoContext;
import org.eclipse.cdt.make.internal.core.scannerconfig2.ScannerConfigProfileManager;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IFileInfo;
import org.eclipse.cdt.managedbuilder.core.IFolderInfo;
import org.eclipse.cdt.managedbuilder.core.IInputType;
import org.eclipse.cdt.managedbuilder.core.IResourceInfo;
import org.eclipse.cdt.managedbuilder.core.ITool;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
import org.eclipse.cdt.managedbuilder.internal.core.Configuration;
import org.eclipse.cdt.managedbuilder.internal.dataprovider.BuildConfigurationData;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.QualifiedName;
public class CfgScannerConfigInfoFactory2 {
private static final QualifiedName CONTAINER_INFO_PROPERTY = new QualifiedName(ManagedBuilderCorePlugin.getUniqueIdentifier(), "ScannerConfigBuilderInfo2Container"); //$NON-NLS-1$
private static class ContainerInfo{
int fCode;
IScannerConfigBuilderInfo2Set fContainer;
ContainerInfo(ICProjectDescription des, IScannerConfigBuilderInfo2Set container){
this.fCode = des.hashCode();
this.fContainer = container;
}
public boolean matches(ICProjectDescription des){
return des.hashCode() == fCode;
}
}
private static class CfgInfo implements ICfgScannerConfigBuilderInfo2Set {
private Configuration cfg;
private SoftReference<IScannerConfigBuilderInfo2Set> fContainer;
// private HashMap map;
CfgInfo(Configuration cfg){
this.cfg = cfg;
// init();
}
public CfgInfoContext[] getContexts() {
Map<CfgInfoContext, IScannerConfigBuilderInfo2> map = createMap();
return map.keySet().toArray(new CfgInfoContext[map.size()]);
}
public IScannerConfigBuilderInfo2 getInfo(CfgInfoContext context) {
return createMap().get(context);
// IScannerConfigBuilderInfo2 info = null;
// if(!isPerRcTypeDiscovery()){
// info = cfg.getScannerConfigInfo();
// if(info == null){
// info = ScannerConfigInfoFactory2.create(cfg, ManagedBuilderCorePlugin.getDefault().getPluginPreferences());
// }
// } else {
// Tool tool = (Tool)context.getTool();
// if(tool != null)
// info = tool.getScannerConfigInfo(context.getInputType());
//// else
//// info = getDefaultInfo();
// }
// return info;
}
public boolean isPerRcTypeDiscovery() {
return cfg.isPerRcTypeDiscovery();
}
private IScannerConfigBuilderInfo2Set getContainer() throws CoreException{
IScannerConfigBuilderInfo2Set container = fContainer != null ? fContainer.get() : null;
if(container == null){
if(!cfg.isPreference()){
ICConfigurationDescription cfgDes = ManagedBuildManager.getDescriptionForConfiguration(cfg);
if(cfgDes != null){
ICProjectDescription projDes = cfgDes.getProjectDescription();
if(projDes != null){
ContainerInfo cInfo = (ContainerInfo)projDes.getSessionProperty(CONTAINER_INFO_PROPERTY);
if(cInfo != null && cInfo.matches(projDes)){
container = cInfo.fContainer;
} else {
container = ScannerConfigProfileManager.createScannerConfigBuildInfo2Set(cfg.getOwner().getProject());
cInfo = new ContainerInfo(projDes, container);
projDes.setSessionProperty(CONTAINER_INFO_PROPERTY, cInfo);
}
}
}
if(container == null){
container = ScannerConfigProfileManager.createScannerConfigBuildInfo2Set(cfg.getOwner().getProject());
}
} else {
Preferences prefs = MakeCorePlugin.getDefault().getPluginPreferences();
container = ScannerConfigProfileManager.createScannerConfigBuildInfo2Set(prefs, false);
}
}
if(fContainer == null) {
fContainer = new SoftReference<IScannerConfigBuilderInfo2Set>(container);
}
return container;
}
private Map<CfgInfoContext, IScannerConfigBuilderInfo2> createMap(){
HashMap<CfgInfoContext, IScannerConfigBuilderInfo2> map = new HashMap<CfgInfoContext, IScannerConfigBuilderInfo2>();
try{
IScannerConfigBuilderInfo2Set container = getContainer();
boolean isPerRcType = cfg.isPerRcTypeDiscovery();
Map<InfoContext, IScannerConfigBuilderInfo2> baseMap = container.getInfoMap();
if(!isPerRcType){
// Discovery profile scope = configuration wide
CfgInfoContext c = new CfgInfoContext(cfg);
InfoContext baseContext = c.toInfoContext();
IScannerConfigBuilderInfo2 info = container.getInfo(baseContext);
if(info == null){
String id = cfg.getDiscoveryProfileId();
if(id == null)
id = CfgScannerConfigUtil.getFirstProfileId(cfg.getFilteredTools());
IScannerConfigBuilderInfo2 prefInfo = null;
if(!cfg.isPreference()){
IConfiguration prefCfg = ManagedBuildManager.getPreferenceConfiguration(false);
ICfgScannerConfigBuilderInfo2Set prefContainer = create(prefCfg);
prefInfo = prefContainer.getInfo(new CfgInfoContext(prefCfg));
}
if(prefInfo == null){
if(id != null)
info = container.createInfo(baseContext, id);
else
info = container.createInfo(baseContext);
} else {
if(id != null)
info = container.createInfo(baseContext, prefInfo, id);
else
info = container.createInfo(baseContext, prefInfo, prefInfo.getSelectedProfileId());
}
}
map.put(new CfgInfoContext(cfg), info);
} else {
// Discovery profile scope = per language
Map<CfgInfoContext, IScannerConfigBuilderInfo2> configMap = getConfigInfoMap(baseMap);
IResourceInfo[] rcInfos = cfg.getResourceInfos();
for (IResourceInfo rcInfo : rcInfos) {
ITool tools[];
if(rcInfo instanceof IFolderInfo) {
tools = ((IFolderInfo)rcInfo).getFilteredTools();
} else {
tools = ((IFileInfo)rcInfo).getToolsToInvoke();
}
for (ITool tool : tools) {
IInputType types[] = tool.getInputTypes();
if(types.length != 0){
for (IInputType inputType : types) {
CfgInfoContext context = new CfgInfoContext(rcInfo, tool, inputType);
context = CfgScannerConfigUtil.adjustPerRcTypeContext(context);
if(context != null && context.getResourceInfo() != null){
IScannerConfigBuilderInfo2 info = configMap.get(context);
if(info == null && !inputType.isExtensionElement() && inputType.getSuperClass() != null){
CfgInfoContext superContext = new CfgInfoContext(rcInfo, tool, inputType.getSuperClass());
superContext = CfgScannerConfigUtil.adjustPerRcTypeContext(superContext);
if(superContext != null && superContext.getResourceInfo() != null){
info = configMap.get(superContext);
}
// Scanner discovery options aren't settable on a file-per-file basis. Thus
// files with custom properties don't have a persisted entry in the config
// info map; we create an ephemeral entry instead. We need to assign that file
// the scanner profile that's used for non-custom files of the same
// inputType/tool (and configuration, of course). Unfortunately, identifying
// a match is inefficient, but in practice, projects don't have tons of
// customized files. See Bug 354194
String id = null;
for (Entry<CfgInfoContext, IScannerConfigBuilderInfo2> entry : configMap.entrySet()) {
CfgInfoContext cfgInfoCxt = entry.getKey();
if (match(cfgInfoCxt.getInputType(), context.getInputType()) &&
match(cfgInfoCxt.getTool(), context.getTool().getSuperClass()) &&
cfgInfoCxt.getConfiguration().equals(context.getConfiguration())) {
id = entry.getValue().getSelectedProfileId();
}
}
if (id == null) {
id = CfgScannerConfigUtil.getDefaultProfileId(context, true);
}
InfoContext baseContext = context.toInfoContext();
if(info == null){
if(id != null){
info = container.createInfo(baseContext, id);
} else {
info = container.createInfo(baseContext);
}
} else {
if(id != null){
info = container.createInfo(baseContext, info, id);
} else {
info = container.createInfo(baseContext, info);
}
}
// Make sure to remove the ephemeral info map entry from the
// container, otherwise it will not be ephemeral but rather a
// permanent and stagnant part of the project description. It was
// added to the container only so we could obtain an
// IScannerConfigBuilderInfo2. Now that we have the info object,
// revert the container. See Bug 354194. Note that the permanent
// entry for the project's root folder resource info gets created
// by us shortly after project creation; thus we have to make an
// exception for that rcinfo.
if (!(rcInfo instanceof IFolderInfo && rcInfo.getPath().isEmpty())) {
container.removeInfo(context.toInfoContext());
}
}
if(info != null){
map.put(context, info);
}
}
}
} else {
if(cfg.isPreference())
continue;
CfgInfoContext context = new CfgInfoContext(rcInfo, tool, null);
context = CfgScannerConfigUtil.adjustPerRcTypeContext(context);
if(context != null && context.getResourceInfo() != null){
IScannerConfigBuilderInfo2 info = configMap.get(context);
if(info == null){
String id = CfgScannerConfigUtil.getDefaultProfileId(context, true);
InfoContext baseContext = context.toInfoContext();
if(id != null){
info = container.createInfo(baseContext, id);
} else {
info = container.createInfo(baseContext);
}
}
if(info != null){
map.put(context, info);
}
}
}
}
}
if(!configMap.isEmpty()){
for (Entry<CfgInfoContext, IScannerConfigBuilderInfo2> entry : configMap.entrySet()) {
if(map.containsKey(entry.getKey()))
continue;
CfgInfoContext c = entry.getKey();
if(c.getResourceInfo() != null || c.getTool() != null || c.getInputType() != null){
InfoContext baseC = c.toInfoContext();
if(!baseC.isDefaultContext())
container.removeInfo(baseC);
}
}
}
}
} catch (CoreException e){
ManagedBuilderCorePlugin.log(e);
}
return map;
}
private Map<CfgInfoContext, IScannerConfigBuilderInfo2> getConfigInfoMap(Map<InfoContext, IScannerConfigBuilderInfo2> baseMap){
Map<CfgInfoContext, IScannerConfigBuilderInfo2> map = new HashMap<CfgInfoContext, IScannerConfigBuilderInfo2>();
for (Entry<InfoContext, IScannerConfigBuilderInfo2> entry : baseMap.entrySet()) {
InfoContext baseContext = entry.getKey();
CfgInfoContext c = CfgInfoContext.fromInfoContext(cfg, baseContext);
if(c != null){
IScannerConfigBuilderInfo2 info = entry.getValue();
map.put(c, info);
}
}
return map;
}
public Map<CfgInfoContext,IScannerConfigBuilderInfo2> getInfoMap() {
return createMap();
}
public void setPerRcTypeDiscovery(boolean on) {
cfg.setPerRcTypeDiscovery(on);
}
public IScannerConfigBuilderInfo2 applyInfo(CfgInfoContext context,
IScannerConfigBuilderInfo2 base) {
try {
IScannerConfigBuilderInfo2 newInfo;
IScannerConfigBuilderInfo2Set container = getContainer();
InfoContext baseContext = context.toInfoContext();
if(base != null){
newInfo = container.createInfo(baseContext, base);
} else {
if(!baseContext.isDefaultContext())
container.removeInfo(baseContext);
newInfo = getInfo(context);
}
return newInfo;
} catch (CoreException e) {
ManagedBuilderCorePlugin.log(e);
}
return null;
}
public IConfiguration getConfiguration() {
return cfg;
}
public boolean isProfileSupported(CfgInfoContext context,
String profileId) {
if(!isPerRcTypeDiscovery())
return true;
return CfgScannerConfigProfileManager.isPerFileProfile(profileId);
}
}
public static ICfgScannerConfigBuilderInfo2Set create(IConfiguration cfg){
Configuration c = (Configuration)cfg;
ICfgScannerConfigBuilderInfo2Set container = c.getCfgScannerConfigInfo();
if(container == null){
container = new CfgInfo(c);
c.setCfgScannerConfigInfo(container);
}
return container;
}
public static void save(BuildConfigurationData data, ICProjectDescription des, ICProjectDescription baseDescription, boolean force) throws CoreException{
ContainerInfo info = (ContainerInfo)des.getSessionProperty(CONTAINER_INFO_PROPERTY);
if(info != null){
if(info.matches(baseDescription)){
IScannerConfigBuilderInfo2Set baseContainer = info.fContainer;
baseContainer.save();
}
des.setSessionProperty(CONTAINER_INFO_PROPERTY, null);
} else if (force){
Configuration cfg = (Configuration)data.getConfiguration();
CfgInfo cfgInfo = new CfgInfo(cfg);
cfg.setCfgScannerConfigInfo(cfgInfo);
cfgInfo.getInfoMap();
cfgInfo.getContainer().save();
des.setSessionProperty(CONTAINER_INFO_PROPERTY, null);
}
}
public static void savePreference(IConfiguration cfg) throws CoreException{
ICfgScannerConfigBuilderInfo2Set container = ((Configuration)cfg).getCfgScannerConfigInfo();
if(container != null){
IScannerConfigBuilderInfo2Set baseContainer = ((CfgInfo)container).getContainer();
if(baseContainer != null){
baseContainer.save();
}
}
}
private static boolean match(ITool t1, ITool t2){
if (t1 == null || t2 == null)
return false;
if (t1.getId().equals(t2.getId())) {
return true;
}
return match(t1.getSuperClass(), t2.getSuperClass());
}
private static boolean match(IInputType i1, IInputType i2){
if (i1 == null || i2 == null)
return false;
if (i1.getId().equals(i2.getId())) {
return true;
}
return match(i1.getSuperClass(), i2.getSuperClass());
}
}