/*******************************************************************************
* Copyright (c) 2007 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
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.internal.tcmodification.extension;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.managedbuilder.internal.core.IRealBuildObjectAssociation;
import org.eclipse.cdt.managedbuilder.internal.tcmodification.ObjectTypeBasedStorage;
import org.eclipse.core.runtime.IConfigurationElement;
public class MatchObjectElement {
public static String ELEMENT_NAME = "matchObject"; //$NON-NLS-1$
private static String ATTR_OBJECT_TYPE = "objectType"; //$NON-NLS-1$
private static String ATTR_OBJECT_IDS = "objectIds"; //$NON-NLS-1$
private static String ELEMENT_PATTERN = "pattern"; //$NON-NLS-1$
private static String ATTR_PATTERN_TYPE_SEARCH_SCOPE = "searchScope"; //$NON-NLS-1$
private static String ATTR_PATTERN_TYPE_ID_TYPE = "objectIdsType"; //$NON-NLS-1$
private static String DELIMITER = ";"; //$NON-NLS-1$
private int fObjectType;
private PatternElement[] fPatterns;
private int fHash;
public static class TypeToStringAssociation {
private int fType;
private String fString;
private static ObjectTypeBasedStorage<TypeToStringAssociation> fTypeAssociationStorage = new ObjectTypeBasedStorage<TypeToStringAssociation>();
private static Map<String, TypeToStringAssociation> fStringAssociationStorage = new HashMap<String, TypeToStringAssociation>();
public static TypeToStringAssociation TOOL = new TypeToStringAssociation(IRealBuildObjectAssociation.OBJECT_TOOL, "tool"); //$NON-NLS-1$
public static TypeToStringAssociation TOOLCHAIN = new TypeToStringAssociation(IRealBuildObjectAssociation.OBJECT_TOOLCHAIN, "toolChain"); //$NON-NLS-1$
public static TypeToStringAssociation CONFIGURATION = new TypeToStringAssociation(IRealBuildObjectAssociation.OBJECT_CONFIGURATION, "configuration"); //$NON-NLS-1$
public static TypeToStringAssociation BUILDER = new TypeToStringAssociation(IRealBuildObjectAssociation.OBJECT_BUILDER, "builder"); //$NON-NLS-1$
private TypeToStringAssociation(int type, String string){
fType = type;
fString = string;
fTypeAssociationStorage.set(type, this);
fStringAssociationStorage.put(fString, this);
}
public int getType(){
return fType;
}
public String getString(){
return fString;
}
public static TypeToStringAssociation getAssociation(String str){
return fStringAssociationStorage.get(str);
}
public static TypeToStringAssociation getAssociation(int type){
return fTypeAssociationStorage.get(type);
}
}
private static class PatternTypeKey {
private int fType;
PatternTypeKey(PatternElement el){
fType = el.getCompleteOredTypeValue();
}
@Override
public boolean equals(Object obj) {
if(obj == this)
return true;
if(!(obj instanceof PatternTypeKey))
return false;
return fType == ((PatternTypeKey)obj).fType;
}
@Override
public int hashCode() {
return fType;
}
}
public class PatternElement {
private HashSet<String> fIds;
private int fHashPE;
private int fType;
private static final int SEARCH_TYPE_MASK = 0xff;
private static final int SEARCH_TYPE_OFFSET = 0;
public static final int TYPE_SEARCH_EXTENSION_OBJECT = 1 << SEARCH_TYPE_OFFSET;
public static final int TYPE_SEARCH_ALL_EXTENSION_SUPERCLASSES = 1 << 1 + SEARCH_TYPE_OFFSET;
private static final int DEFAULT_PATTERN_SEARCH_TYPE = TYPE_SEARCH_EXTENSION_OBJECT;
private static final String EXTENSION_OBJECT = "EXTENSION_OBJECT"; //$NON-NLS-1$
private static final String ALL_EXTENSION_SUPERCLASSES = "ALL_EXTENSION_SUPERCLASSES"; //$NON-NLS-1$
private static final int ID_TYPE_MASK = 0xff00;
private static final int ID_TYPE_OFFSET = 8;
public static final int TYPE_ID_EXACT_MATCH = 1 << ID_TYPE_OFFSET;
public static final int TYPE_ID_REGEXP = 1 << 1 + ID_TYPE_OFFSET;
private static final int DEFAULT_PATTERN_ID_TYPE = TYPE_ID_EXACT_MATCH;
private static final String EXACT_MATCH = "EXACT_MATCH"; //$NON-NLS-1$
private static final String REGEGP = "REGEXP"; //$NON-NLS-1$
PatternElement(IConfigurationElement el, int defaultSearchType, int defaultIdType){
String tmp = el.getAttribute(ATTR_OBJECT_IDS);
fIds = new HashSet<String>(Arrays.asList(CDataUtil.stringToArray(tmp, DELIMITER)));
int type = 0;
tmp = el.getAttribute(ATTR_PATTERN_TYPE_SEARCH_SCOPE);
if(tmp == null) {
type = defaultSearchType;
} else {
if(EXTENSION_OBJECT.equals(tmp)){
type = TYPE_SEARCH_EXTENSION_OBJECT;
} else if (ALL_EXTENSION_SUPERCLASSES.equals(tmp)){
type = TYPE_SEARCH_ALL_EXTENSION_SUPERCLASSES;
} else {
throw new IllegalArgumentException();
}
}
tmp = el.getAttribute(ATTR_PATTERN_TYPE_ID_TYPE);
if(tmp == null) {
type |= defaultIdType;
} else {
if(EXACT_MATCH.equals(tmp)){
type |= TYPE_ID_EXACT_MATCH;
} else if (REGEGP.equals(tmp)){
type |= TYPE_ID_REGEXP;
} else {
throw new IllegalArgumentException();
}
}
fType = type;
}
private PatternElement(HashSet<String> ids, int type){
fIds = ids;
fType = type;
}
public String[] getIds(){
return fIds.toArray(new String[fIds.size()]);
}
@Override
public boolean equals(Object obj) {
if(obj == this)
return true;
if(!(obj instanceof PatternElement))
return false;
PatternElement other = (PatternElement)obj;
if(other.fIds.size() != fIds.size())
return false;
return other.fIds.containsAll(fIds);
}
@Override
public int hashCode() {
if(fHashPE == 0){
fHashPE = fIds.hashCode();
}
return fHashPE;
}
public PatternElement merge(PatternElement el) throws IllegalArgumentException {
if(el.fType != fType)
throw new IllegalArgumentException();
HashSet<String> set = new HashSet<String>();
set.addAll(fIds);
set.addAll(el.fIds);
return new PatternElement(set, fType);
}
public int getSearchType(){
return fType & SEARCH_TYPE_MASK;
}
public int getIdType(){
return fType & ID_TYPE_MASK;
}
public int getCompleteOredTypeValue(){
return fType;
}
}
public MatchObjectElement(IConfigurationElement element) throws IllegalArgumentException {
TypeToStringAssociation assoc = TypeToStringAssociation.getAssociation(element.getAttribute(ATTR_OBJECT_TYPE));
if(assoc == null)
throw new IllegalArgumentException();
fObjectType = assoc.getType();
Map<PatternTypeKey, PatternElement> patternMap = new HashMap<PatternTypeKey, PatternElement>();
int defaultSearchType = PatternElement.DEFAULT_PATTERN_SEARCH_TYPE;
int defaultIdType = PatternElement.DEFAULT_PATTERN_ID_TYPE;
if(element.getAttribute(ATTR_OBJECT_IDS) != null){
PatternElement el = new PatternElement(element, defaultSearchType, defaultIdType);
patternMap.put(new PatternTypeKey(el), el);
defaultSearchType = el.getSearchType();
defaultIdType = el.getIdType();
}
IConfigurationElement patternsChildren[] = element.getChildren(ELEMENT_PATTERN);
if(patternsChildren.length != 0){
for(int i = 0; i < patternsChildren.length; i++){
PatternElement el = new PatternElement(patternsChildren[i], defaultSearchType, defaultIdType);
PatternTypeKey key = new PatternTypeKey(el);
PatternElement cur = patternMap.get(key);
if(cur != null){
patternMap.put(key, cur.merge(el));
} else {
patternMap.put(key, el);
}
}
}
if(patternMap.size() == 0) {
throw new IllegalArgumentException();
}
fPatterns = patternMap.values().toArray(new PatternElement[patternMap.size()]);
}
public int getObjectType(){
return fObjectType;
}
@Override
public boolean equals(Object obj) {
if(obj == this)
return true;
if(!(obj instanceof MatchObjectElement))
return false;
MatchObjectElement other = (MatchObjectElement)obj;
if(fObjectType != other.fObjectType)
return false;
return Arrays.equals(other.fPatterns, fPatterns);
}
@Override
public int hashCode() {
if(fHash == 0){
int hash = fObjectType;
for(int i = 0; i < fPatterns.length; i++){
hash += fPatterns[i].hashCode();
}
fHash = hash;
}
return fHash;
}
public PatternElement[] getPatterns(){
return fPatterns.clone();
}
}