/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
public final class LanguageFactory {
public static final String EXTENSION = "extension";
public static final String BY_EXTENSION = "by_extension";
private static LanguageFactory instance = new LanguageFactory();
public static String[] supportedLanguages;
static {
supportedLanguages = instance.languages.keySet().toArray(new String[instance.languages.size()]);
}
private Map<String, Language> languages = new HashMap<>();
private LanguageFactory() {
List<Language> languagesList = new ArrayList<>();
ServiceLoader<Language> languageLoader = ServiceLoader.load(Language.class);
Iterator<Language> iterator = languageLoader.iterator();
while (iterator.hasNext()) {
try {
Language language = iterator.next();
languagesList.add(language);
} catch (UnsupportedClassVersionError e) {
// Some languages require java8 and are therefore only available
// if java8 or later is used as runtime.
System.err.println("Ignoring language for CPD: " + e.toString());
}
}
// sort languages by terse name. Avoiding differences in the order of languages
// across JVM versions / OS.
Collections.sort(languagesList, new Comparator<Language>() {
@Override
public int compare(Language o1, Language o2) {
return o1.getTerseName().compareToIgnoreCase(o2.getTerseName());
}
});
// using a linked hash map to maintain insertion order
languages = new LinkedHashMap<>();
for (Language language : languagesList) {
languages.put(language.getTerseName().toLowerCase(Locale.ROOT), language);
}
}
public static Language createLanguage(String language) {
return createLanguage(language, new Properties());
}
public static Language createLanguage(String language, Properties properties) {
Language implementation;
if (BY_EXTENSION.equals(language)) {
implementation = instance.getLanguageByExtension(properties.getProperty(EXTENSION));
} else {
implementation = instance.languages.get(instance.languageAliases(language).toLowerCase());
}
if (implementation == null) {
// No proper implementation
// FIXME: We should log a warning, shouldn't we ?
implementation = new AnyLanguage(language);
}
implementation.setProperties(properties);
return implementation;
}
private String languageAliases(String language) {
// CPD and C language share the same parser
if ("c".equals(language)) {
return "cpp";
}
return language;
}
private Language getLanguageByExtension(String extension) {
Language result = null;
for (Language language : languages.values()) {
if (language.getExtensions().contains(extension)) {
result = language;
break;
}
}
return result;
}
}