/* * Copyright 2016 The authors * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.struts2.dom.struts.impl; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PropertyUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; /** * Helper methods for {@link ActionImpl}. * * @author Yann Cébron */ final class ActionUtil { private ActionUtil() { } /** * Does the given path match the Action's path (including support for wildcards and bang notation). * * @param actionPath Path of Action. * @param checkPath Path to check. * @return true if matched. */ static boolean matchesPath(@NotNull @NonNls final String actionPath, @NotNull @NonNls final String checkPath) { // strip everything behind "!" final int bangIdx = checkPath.indexOf('!'); final String strippedCheckPath = bangIdx == -1 ? checkPath : checkPath.substring(0, bangIdx); // do we have any wildcard-markers in our path? no --> exact compare if (actionPath.indexOf('*') == -1) { return Comparing.equal(strippedCheckPath, actionPath); } try { return Pattern.matches(StringUtil.replace(actionPath, "*", "[^/]*"), strippedCheckPath); } catch (PatternSyntaxException e) { return false; } } /** * Returns all suitable action methods for the given Action class. * * @param actionClass Action class to search for action methods. * @param methodName (Optional) Method name. * @return Methods suitable for action execution. */ static List<PsiMethod> findActionMethods(@NotNull final PsiClass actionClass, @Nullable final String methodName) { final Module module = ModuleUtilCore.findModuleForPsiElement(actionClass); if (module == null) { return Collections.emptyList(); } final GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false); final PsiClassType stringType = PsiType.getJavaLangString(actionClass.getManager(), scope); final PsiElementFactory psiElementFactory = JavaPsiFacade.getInstance(actionClass.getProject()).getElementFactory(); final PsiClassType resultType = psiElementFactory.createTypeByFQClassName("com.opensymphony.xwork2.Result", scope); final boolean searchForMethod = methodName != null; final List<PsiMethod> actionMethods = new SmartList<>(); final PsiMethod[] methods = searchForMethod ? actionClass.findMethodsByName(methodName, true) : actionClass.getAllMethods(); for (final PsiMethod psiMethod : methods) { if (psiMethod.isConstructor()) { continue; } // only public non-static concrete methods final PsiModifierList modifiers = psiMethod.getModifierList(); if (!modifiers.hasModifierProperty(PsiModifier.PUBLIC) || modifiers.hasModifierProperty(PsiModifier.STATIC) || modifiers.hasModifierProperty(PsiModifier.ABSTRACT)) { continue; } // no parameters if (psiMethod.getParameterList().getParametersCount() != 0) { continue; } // skip "toString()" final String psiMethodName = psiMethod.getName(); if (Comparing.equal(psiMethodName, "toString")) { continue; } // do not include simple getters (with underlying field) if (PropertyUtil.isSimplePropertyGetter(psiMethod) && actionClass.findFieldByName(PropertyUtil.getPropertyName(psiMethod), true) != null) { continue; } // return type "java.lang.String" or "com.opensymphony.xwork2.Result" final PsiType type = psiMethod.getReturnType(); if (type != null && type instanceof PsiClassType && (type.equals(stringType) || type.equals(resultType))) { // stop on first hit when searching for name if (searchForMethod) { return Collections.singletonList(psiMethod); } // do not add methods with same name from super-class final Condition<PsiMethod> nameCondition = method -> psiMethodName.equals(method.getName()); if (!ContainerUtil.exists(actionMethods, nameCondition)) { actionMethods.add(psiMethod); } } } return actionMethods; } }