blob: f400410bfca513dafa37ea541c87c57f5c27f16b [file] [log] [blame]
/*
* Copyright (c) 2010-2020 BSI Business Systems Integration AG.
* 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
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
*/
package org.eclipse.scout.sdk.core.s.structured;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.eclipse.scout.sdk.core.model.api.Flags.isAbstract;
import static org.eclipse.scout.sdk.core.model.api.Flags.isDeprecated;
import static org.eclipse.scout.sdk.core.model.api.Flags.isEnum;
import static org.eclipse.scout.sdk.core.model.api.Flags.isInterface;
import static org.eclipse.scout.sdk.core.s.util.ScoutTypeComparators.orderAnnotationComparator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import org.eclipse.scout.sdk.core.apidef.IClassNameSupplier;
import org.eclipse.scout.sdk.core.log.SdkLog;
import org.eclipse.scout.sdk.core.model.api.Flags;
import org.eclipse.scout.sdk.core.model.api.IField;
import org.eclipse.scout.sdk.core.model.api.IJavaElement;
import org.eclipse.scout.sdk.core.model.api.IMethod;
import org.eclipse.scout.sdk.core.model.api.IMethodParameter;
import org.eclipse.scout.sdk.core.model.api.IType;
import org.eclipse.scout.sdk.core.model.api.PropertyBean;
import org.eclipse.scout.sdk.core.s.ISdkConstants;
import org.eclipse.scout.sdk.core.s.apidef.IScoutApi;
import org.eclipse.scout.sdk.core.s.util.ScoutTypeComparators;
import org.eclipse.scout.sdk.core.util.CompositeObject;
import org.eclipse.scout.sdk.core.util.Strings;
public class StructuredType implements IStructuredType {
private static final Pattern PROPERTY_BEAN_REGEX = Pattern.compile("^(get|set|is|add|remove|clear|delete)(.*)$");
private static final Pattern START_HANDLER_REGEX = Pattern.compile("^start(.*)$");
private static final Pattern METHOD_INNER_TYPE_GETTER_REGEX = Pattern.compile("^get(.*)$");
private static final Predicate<IType> CLASS_FILTER = type -> {
if (Strings.isBlank(type.elementName())) {
return false; // anonymous type
}
var flags = type.flags();
return !isAbstract(flags) && !isInterface(flags) && !isDeprecated(flags);
};
private final IType m_type;
private final IScoutApi m_scoutApi;
private final EnumSet<Categories> m_enabledCategories;
private final EnumSet<Categories> m_visitedCategories;
private final Map<Categories, List<? extends IJavaElement>> m_elements;
protected StructuredType(IType type, EnumSet<Categories> enabledCategories) {
m_type = type;
m_scoutApi = type.javaEnvironment().api(IScoutApi.class).orElse(null);
m_enabledCategories = EnumSet.copyOf(enabledCategories);
m_visitedCategories = EnumSet.noneOf(Categories.class);
m_elements = new EnumMap<>(Categories.class);
// initially put all into unknown categories
var fields = type.fields().stream().collect(toList());
var enums = type.innerTypes().withFlags(Flags.AccEnum).stream().collect(toList());
var methods = type.methods().stream().collect(toList());
var types = type.innerTypes().stream().filter(element -> !isEnum(element.flags())).collect(toList());
m_elements.put(Categories.FIELD_UNKNOWN, fields);
m_elements.put(Categories.ENUM, enums);
m_elements.put(Categories.METHOD_UNCATEGORIZED, methods);
m_elements.put(Categories.TYPE_UNCATEGORIZED, types);
}
public Optional<IScoutApi> scoutApi() {
return Optional.ofNullable(m_scoutApi);
}
public static IStructuredType of(IType type) {
var enabled = EnumSet.of(Categories.FIELD_LOGGER, Categories.FIELD_STATIC, Categories.FIELD_MEMBER, Categories.FIELD_UNKNOWN, Categories.METHOD_CONSTRUCTOR, Categories.METHOD_CONFIG_PROPERTY,
Categories.METHOD_CONFIG_EXEC, Categories.METHOD_FORM_DATA_BEAN, Categories.METHOD_OVERRIDDEN, Categories.METHOD_START_HANDLER, Categories.METHOD_INNER_TYPE_GETTER, Categories.METHOD_LOCAL_BEAN, Categories.METHOD_UNCATEGORIZED,
Categories.TYPE_FORM_FIELD, Categories.TYPE_COLUMN, Categories.TYPE_CODE, Categories.TYPE_FORM, Categories.TYPE_TABLE, Categories.TYPE_TREE, Categories.TYPE_CALENDAR,
Categories.TYPE_CALENDAR_ITEM_PROVIDER, Categories.TYPE_WIZARD, Categories.TYPE_WIZARD_STEP, Categories.TYPE_MENU, Categories.TYPE_VIEW_BUTTON, Categories.TYPE_KEYSTROKE,
Categories.TYPE_COMPOSER_ATTRIBUTE, Categories.TYPE_COMPOSER_ENTRY, Categories.TYPE_FORM_HANDLER, Categories.TYPE_UNCATEGORIZED);
return new StructuredType(type, enabled);
}
private static CompositeObject createPropertyMethodKey(IMethod method) {
if (method != null) {
var matcher = PROPERTY_BEAN_REGEX.matcher(method.elementName());
if (matcher.find()) {
var getSetOrder = 20;
if (PropertyBean.GETTER_PREFIX.equalsIgnoreCase(matcher.group(1))) {
getSetOrder = 1;
}
else if (PropertyBean.GETTER_BOOL_PREFIX.equalsIgnoreCase(matcher.group(1))) {
getSetOrder = 2;
}
else if (PropertyBean.SETTER_PREFIX.equalsIgnoreCase(matcher.group(1))) {
getSetOrder = 3;
}
else if ("add".equalsIgnoreCase(matcher.group(1))) {
getSetOrder = 4;
}
else if ("remove".equalsIgnoreCase(matcher.group(1))) {
getSetOrder = 5;
}
else if ("clear".equalsIgnoreCase(matcher.group(1))) {
getSetOrder = 6;
}
else if ("delete".equalsIgnoreCase(matcher.group(1))) {
getSetOrder = 7;
}
var propName = matcher.group(2);
return new CompositeObject(propName, getSetOrder, method.elementName(), method.parameters().stream().count(), method);
}
}
return null;
}
private static IMethod getOverwrittenMethod(IMethod method) {
var refSig = method.identifier();
return method.requireDeclaringType().methods()
.withSuperClasses(true).stream()
.filter(element -> !method.equals(element) && refSig.equals(element.identifier()))
.findAny()
.orElse(null);
}
protected static CompositeObject createConstructorKey(Collection<IMethodParameter> list) {
if (list == null) {
return new CompositeObject(0, "");
}
var b = list.stream().map(p -> p.dataType().name()).collect(joining());
return new CompositeObject(list.size(), b);
}
/**
* Creates and gets a {@link Predicate} that evaluates to {@code true} for all {@link IType}s that are
* {@code instanceof} the given fully qualified name.
*
* @param type
* The fully qualified type name the candidates must be {@code instanceof}.
* @return The created {@link Predicate}
*/
public static Predicate<IType> instanceOf(String type) {
return candidate -> candidate.isInstanceOf(type);
}
public IType getType() {
return m_type;
}
protected List<? extends IJavaElement> getElementsInternal(Categories category) {
cache(category);
return m_elements.get(category);
}
@Override
public List<IJavaElement> getElements(Categories category) {
return new ArrayList<>(getElementsInternal(category));
}
@Override
@SuppressWarnings("unchecked")
public <T extends IJavaElement> List<T> getElements(Categories category, Class<T> clazz) {
var elements = getElementsInternal(category);
if (elements == null) {
return emptyList();
}
return elements.stream()
.map(e -> (T) e)
.collect(toList());
}
@Override
public IJavaElement getSiblingMethodFieldGetter(String methodName) {
return getSibling(methodName, Categories.METHOD_INNER_TYPE_GETTER);
}
protected IJavaElement getSibling(String siblingName, Categories... categories) {
for (var cat : categories) {
var references = getElementsInternal(cat);
if (references != null && !references.isEmpty()) {
for (IJavaElement reference : references) {
if (reference.elementName().compareTo(siblingName) > 0) {
return reference;
}
}
return references.get(references.size() - 1);
}
var sibling = getSibling(cat);
if (sibling != null) {
return sibling;
}
}
return null;
}
@Override
public IJavaElement getSibling(Categories category) {
var search = false;
var methodCategories = Categories.values();
for (var methodCategory : methodCategories) {
cache(methodCategory);
if (search) {
var elements = getElementsInternal(methodCategory);
if (elements != null && !elements.isEmpty()) {
return elements.get(0);
}
}
else if (methodCategory == category) {
search = true;
}
}
return null;
}
protected final void cache(Categories category) {
if (m_enabledCategories.contains(category) && !m_visitedCategories.contains(category)) {
List<IJavaElement> unknownMethods = new ArrayList<>(m_elements.get(Categories.METHOD_UNCATEGORIZED));
List<IJavaElement> unknownTypes = new ArrayList<>(m_elements.get(Categories.TYPE_UNCATEGORIZED));
switch (category) {
case FIELD_LOGGER:
case FIELD_STATIC:
case FIELD_MEMBER:
visitFields(new ArrayList<>(m_elements.get(Categories.FIELD_UNKNOWN)));
m_visitedCategories.add(Categories.FIELD_LOGGER);
m_visitedCategories.add(Categories.FIELD_STATIC);
m_visitedCategories.add(Categories.FIELD_MEMBER);
break;
case METHOD_CONSTRUCTOR:
visitMethodConstructors(unknownMethods);
m_visitedCategories.add(Categories.METHOD_CONSTRUCTOR);
m_elements.put(Categories.METHOD_UNCATEGORIZED, unknownMethods);
break;
case METHOD_CONFIG_PROPERTY:
visitMethodConfigProperty(unknownMethods);
m_visitedCategories.add(Categories.METHOD_CONFIG_PROPERTY);
m_elements.put(Categories.METHOD_UNCATEGORIZED, unknownMethods);
break;
case METHOD_CONFIG_EXEC:
visitMethodConfigExec(unknownMethods);
m_visitedCategories.add(Categories.METHOD_CONFIG_EXEC);
m_elements.put(Categories.METHOD_UNCATEGORIZED, unknownMethods);
break;
case METHOD_FORM_DATA_BEAN:
m_visitedCategories.add(Categories.METHOD_FORM_DATA_BEAN);
visitMethodFormDataBean(unknownMethods);
m_elements.put(Categories.METHOD_UNCATEGORIZED, unknownMethods);
break;
case METHOD_OVERRIDDEN:
visitMethodOverridden(unknownMethods);
m_visitedCategories.add(Categories.METHOD_OVERRIDDEN);
m_elements.put(Categories.METHOD_UNCATEGORIZED, unknownMethods);
break;
case METHOD_START_HANDLER:
visitMethodStartHandler(unknownMethods);
m_visitedCategories.add(Categories.METHOD_START_HANDLER);
m_elements.put(Categories.METHOD_UNCATEGORIZED, unknownMethods);
break;
case METHOD_INNER_TYPE_GETTER:
visitMethodInnerTypeGetter(unknownMethods);
m_visitedCategories.add(Categories.METHOD_INNER_TYPE_GETTER);
m_elements.put(Categories.METHOD_UNCATEGORIZED, unknownMethods);
break;
case METHOD_LOCAL_BEAN:
visitMethodLocalBean(unknownMethods);
m_visitedCategories.add(Categories.METHOD_LOCAL_BEAN);
m_elements.put(Categories.METHOD_UNCATEGORIZED, unknownMethods);
break;
case TYPE_FORM_FIELD:
visitTypeFormFields(unknownTypes);
m_visitedCategories.add(Categories.TYPE_FORM_FIELD);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_COLUMN:
visitTypeColumns(unknownTypes);
m_visitedCategories.add(Categories.TYPE_COLUMN);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_CODE:
visitTypeCodes(unknownTypes);
m_visitedCategories.add(Categories.TYPE_CODE);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_FORM:
visitTypeForms(unknownTypes);
m_visitedCategories.add(Categories.TYPE_FORM);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_TABLE:
visitTypeTables(unknownTypes);
m_visitedCategories.add(Categories.TYPE_TABLE);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_TREE:
visitTypeTrees(unknownTypes);
m_visitedCategories.add(Categories.TYPE_TREE);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_CALENDAR:
visitTypeCalendar(unknownTypes);
m_visitedCategories.add(Categories.TYPE_CALENDAR);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_CALENDAR_ITEM_PROVIDER:
visitTypeCalendarItemProvider(unknownTypes);
m_visitedCategories.add(Categories.TYPE_CALENDAR_ITEM_PROVIDER);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_WIZARD:
visitTypeWizards(unknownTypes);
m_visitedCategories.add(Categories.TYPE_WIZARD);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_WIZARD_STEP:
visitTypeWizardSteps(unknownTypes);
m_visitedCategories.add(Categories.TYPE_WIZARD_STEP);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_MENU:
visitTypeMenus(unknownTypes);
m_visitedCategories.add(Categories.TYPE_MENU);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_VIEW_BUTTON:
visitTypeViewButtons(unknownTypes);
m_visitedCategories.add(Categories.TYPE_VIEW_BUTTON);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_KEYSTROKE:
visitTypeKeystrokes(unknownTypes);
m_visitedCategories.add(Categories.TYPE_KEYSTROKE);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_COMPOSER_ATTRIBUTE:
visitTypeComposerAttribute(unknownTypes);
m_visitedCategories.add(Categories.TYPE_COMPOSER_ATTRIBUTE);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_COMPOSER_ENTRY:
visitTypeDataModelEntry(unknownTypes);
m_visitedCategories.add(Categories.TYPE_COMPOSER_ENTRY);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
case TYPE_FORM_HANDLER:
visitTypeFormHandlers(unknownTypes);
m_visitedCategories.add(Categories.TYPE_FORM_HANDLER);
m_elements.put(Categories.TYPE_UNCATEGORIZED, unknownTypes);
break;
default:
break;
}
}
}
/**
* can be overwritten. Overwrites must ensure to super call after processing the working set.
*/
protected void visitFields(List<IJavaElement> workingSet) {
List<IJavaElement> loggers = new ArrayList<>(2);
List<IJavaElement> statics = new ArrayList<>();
List<IJavaElement> members = new ArrayList<>();
var logger = scoutApi().map(IScoutApi::Logger).map(IClassNameSupplier::fqn);
for (var it = workingSet.iterator(); it.hasNext();) {
var f = (IField) it.next();
// static
if ((f.flags() & Flags.AccStatic) != 0) {
var fieldDataType = f.dataType().reference();
if (logger.isPresent() && logger.get().equals(fieldDataType)) {
loggers.add(f);
}
else {
statics.add(f);
}
}
else {
members.add(f);
}
it.remove();
}
m_elements.put(Categories.FIELD_LOGGER, loggers);
m_elements.put(Categories.FIELD_STATIC, statics);
m_elements.put(Categories.FIELD_MEMBER, members);
m_elements.put(Categories.FIELD_UNKNOWN, workingSet);
}
protected void visitMethodConstructors(Iterable<IJavaElement> workingSet) {
Map<CompositeObject, IJavaElement> constructors = new TreeMap<>();
for (var it = workingSet.iterator(); it.hasNext();) {
var method = (IMethod) it.next();
if (method.isConstructor()) {
var key = createConstructorKey(method.parameters().stream().collect(toList()));
constructors.put(key, method);
it.remove();
}
}
m_elements.put(Categories.METHOD_CONSTRUCTOR, new ArrayList<>(constructors.values()));
}
protected void visitMethodConfigExec(Iterable<IJavaElement> workingSet) {
visitMethodWithPrefix(workingSet, "exec", Categories.METHOD_CONFIG_EXEC);
}
protected void visitMethodConfigProperty(Iterable<IJavaElement> workingSet) {
visitMethodWithPrefix(workingSet, "getConfigured", Categories.METHOD_CONFIG_PROPERTY);
}
protected void visitMethodWithPrefix(Iterable<IJavaElement> workingSet, String prefix, Categories category) {
Map<CompositeObject, IJavaElement> methods = new TreeMap<>();
for (var it = workingSet.iterator(); it.hasNext();) {
var method = (IMethod) it.next();
var visitedMethod = method;
while (visitedMethod != null) {
var methodName = visitedMethod.elementName();
if (methodName.length() > prefix.length() && methodName.startsWith(prefix)) {
var key = new CompositeObject(method.elementName(), method.parameters().stream().count(), method);
methods.put(key, method);
it.remove();
break;
}
visitedMethod = getOverwrittenMethod(visitedMethod);
}
}
m_elements.put(category, new ArrayList<>(methods.values()));
}
protected void visitMethodFormDataBean(Iterable<IJavaElement> workingSet) {
Map<CompositeObject, IJavaElement> methods = new TreeMap<>();
var scoutApi = scoutApi();
if (scoutApi.isPresent()) {
var api = scoutApi.get();
var formDataFqn = api.FormData().fqn();
for (var it = workingSet.iterator(); it.hasNext();) {
var method = (IMethod) it.next();
if (method.annotations().withName(formDataFqn).existsAny()) {
var methodKey = createPropertyMethodKey(method);
if (methodKey != null) {
methods.put(methodKey, method);
it.remove();
}
else {
SdkLog.warning("could not parse property method '{}'.", method.elementName());
}
}
}
}
m_elements.put(Categories.METHOD_FORM_DATA_BEAN, new ArrayList<>(methods.values()));
}
protected void visitMethodOverridden(Iterable<IJavaElement> workingSet) {
Map<CompositeObject, IJavaElement> overriddenMethods = new TreeMap<>();
for (var it = workingSet.iterator(); it.hasNext();) {
var method = (IMethod) it.next();
if (getOverwrittenMethod(method) != null) {
var key = new CompositeObject(method.elementName(), method.parameters().stream().count(), method);
overriddenMethods.put(key, method);
it.remove();
}
}
m_elements.put(Categories.METHOD_OVERRIDDEN, new ArrayList<>(overriddenMethods.values()));
}
protected void visitMethodStartHandler(Iterable<IJavaElement> workingSet) {
Map<CompositeObject, IJavaElement> startHandlerMethods = new TreeMap<>();
for (var it = workingSet.iterator(); it.hasNext();) {
var method = (IMethod) it.next();
var matcher = START_HANDLER_REGEX.matcher(method.elementName());
if (matcher.find()) {
var fieldName = matcher.group(1);
if (getType().innerTypes().withRecursiveInnerTypes(true).withSimpleName(fieldName + ISdkConstants.SUFFIX_FORM_HANDLER).existsAny()) {
var key = new CompositeObject(method.elementName(), method.parameters().stream().count(), method);
startHandlerMethods.put(key, method);
it.remove();
}
}
}
m_elements.put(Categories.METHOD_START_HANDLER, new ArrayList<>(startHandlerMethods.values()));
}
protected void visitMethodInnerTypeGetter(Iterable<IJavaElement> workingSet) {
Map<CompositeObject, IJavaElement> fieldGetterMethods = new TreeMap<>();
for (var it = workingSet.iterator(); it.hasNext();) {
var method = (IMethod) it.next();
var matcher = METHOD_INNER_TYPE_GETTER_REGEX.matcher(method.elementName());
if (matcher.find()) {
var fieldName = matcher.group(1);
if (getType().innerTypes().withRecursiveInnerTypes(true).withSimpleName(fieldName).existsAny()) {
var key = new CompositeObject(method.elementName(), method.parameters().stream().count(), method);
fieldGetterMethods.put(key, method);
it.remove();
}
}
}
m_elements.put(Categories.METHOD_INNER_TYPE_GETTER, new ArrayList<>(fieldGetterMethods.values()));
}
protected void visitMethodLocalBean(Iterable<IJavaElement> workingSet) {
Map<CompositeObject, IJavaElement> localPropertyMethods = new TreeMap<>();
for (var it = workingSet.iterator(); it.hasNext();) {
var method = (IMethod) it.next();
var key = createPropertyMethodKey(method);
if (key != null) {
localPropertyMethods.put(key, method);
it.remove();
}
}
m_elements.put(Categories.METHOD_LOCAL_BEAN, new ArrayList<>(localPropertyMethods.values()));
}
protected void visitMethodUncategorized(Iterable<IMethod> workingSet) {
Map<CompositeObject, IJavaElement> methods = new TreeMap<>();
for (var it = workingSet.iterator(); it.hasNext();) {
var method = it.next();
var key = new CompositeObject(method.elementName(), method.parameters().stream().count(), method);
methods.put(key, method);
it.remove();
}
m_elements.put(Categories.METHOD_UNCATEGORIZED, new ArrayList<>(methods.values()));
}
protected void visitTypeFormFields(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IFormField, Categories.TYPE_FORM_FIELD, orderAnnotationComparator(false));
}
protected void visitTypeColumns(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IColumn, Categories.TYPE_COLUMN, orderAnnotationComparator(false));
}
protected void visitTypeCodes(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::ICode, Categories.TYPE_CODE, orderAnnotationComparator(false));
}
protected void visitTypeForms(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IForm, Categories.TYPE_FORM, orderAnnotationComparator(false));
}
protected void visitTypeTables(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::ITable, Categories.TYPE_TABLE, orderAnnotationComparator(false));
}
protected void visitTypeTrees(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::ITree, Categories.TYPE_TREE, orderAnnotationComparator(false));
}
protected void visitTypeCalendar(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::ICalendar, Categories.TYPE_CALENDAR, orderAnnotationComparator(false));
}
protected void visitTypeCalendarItemProvider(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::ICalendarItemProvider, Categories.TYPE_CALENDAR_ITEM_PROVIDER, orderAnnotationComparator(false));
}
protected void visitTypeWizards(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IWizard, Categories.TYPE_WIZARD, orderAnnotationComparator(false));
}
protected void visitTypeWizardSteps(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IWizardStep, Categories.TYPE_WIZARD_STEP, orderAnnotationComparator(false));
}
protected void visitTypeMenus(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IMenu, Categories.TYPE_MENU, orderAnnotationComparator(false));
}
protected void visitTypeViewButtons(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IViewButton, Categories.TYPE_VIEW_BUTTON, orderAnnotationComparator(false));
}
protected void visitTypeKeystrokes(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IKeyStroke, Categories.TYPE_KEYSTROKE, ScoutTypeComparators.BY_NAME);
}
protected void visitTypeComposerAttribute(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IDataModelAttribute, Categories.TYPE_COMPOSER_ATTRIBUTE, ScoutTypeComparators.BY_NAME);
}
protected void visitTypeDataModelEntry(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IDataModelEntity, Categories.TYPE_COMPOSER_ENTRY, ScoutTypeComparators.BY_NAME);
}
protected void visitTypeFormHandlers(Iterable<IJavaElement> workingSet) {
consumeType(workingSet, IScoutApi::IFormHandler, Categories.TYPE_FORM_HANDLER, ScoutTypeComparators.BY_NAME);
}
protected void consumeType(Iterable<IJavaElement> workingSet, Function<IScoutApi, IClassNameSupplier> typeInterface, Categories category, Comparator<IType> comparator) {
Set<IType> types = new TreeSet<>(comparator);
var scoutApi = scoutApi().orElse(null);
if (scoutApi != null) {
var fqn = typeInterface.apply(scoutApi).fqn();
var filter = CLASS_FILTER.and(instanceOf(fqn));
var it = workingSet.iterator();
while (it.hasNext()) {
var candidate = (IType) it.next();
if (filter.test(candidate)) {
types.add(candidate);
it.remove();
}
}
}
m_elements.put(category, new ArrayList<>(types));
}
}