You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2024/02/06 13:17:24 UTC

(struts-intellij-plugin) 01/01: Struts 2 moved to obsolete plugins

This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts-intellij-plugin.git

commit 8bb4fd35e2c46a7bb03c17fd264b31a883d98734
Author: Yuriy Artamonov <yu...@jetbrains.com>
AuthorDate: Sun May 7 19:22:23 2023 +0200

    Struts 2 moved to obsolete plugins
---
 .gitignore                                         |   42 +
 LICENSE.TXT                                        |  176 +++
 build.gradle.kts                                   |   58 +
 gradle.properties                                  |    3 +
 gradle/wrapper/gradle-wrapper.jar                  |  Bin 0 -> 60756 bytes
 gradle/wrapper/gradle-wrapper.properties           |    5 +
 gradlew                                            |  234 ++++
 gradlew.bat                                        |   89 ++
 settings.gradle.kts                                |    8 +
 src/main/gen/OgnlIcons.java                        |   18 +
 src/main/gen/OgnlTypes.java                        |  183 +++
 src/main/gen/lexer/_OgnlLexer.java                 | 1287 ++++++++++++++++++++
 src/main/gen/parser/OgnlParser.java                | 1006 +++++++++++++++
 src/main/gen/psi/OgnlBinaryExpression.java         |   35 +
 src/main/gen/psi/OgnlConditionalExpression.java    |   35 +
 src/main/gen/psi/OgnlExpression.java               |   30 +
 src/main/gen/psi/OgnlFqnTypeExpression.java        |   26 +
 src/main/gen/psi/OgnlIndexedExpression.java        |   32 +
 src/main/gen/psi/OgnlLambdaExpression.java         |   29 +
 src/main/gen/psi/OgnlLiteralExpression.java        |   29 +
 src/main/gen/psi/OgnlMapEntryElement.java          |   32 +
 src/main/gen/psi/OgnlMapExpression.java            |   32 +
 src/main/gen/psi/OgnlMethodCallExpression.java     |   32 +
 src/main/gen/psi/OgnlNewArrayExpression.java       |   32 +
 src/main/gen/psi/OgnlNewExpression.java            |   32 +
 src/main/gen/psi/OgnlParameterList.java            |   31 +
 src/main/gen/psi/OgnlParenthesizedExpression.java  |   29 +
 src/main/gen/psi/OgnlProjectionExpression.java     |   29 +
 src/main/gen/psi/OgnlReferenceExpression.java      |   29 +
 src/main/gen/psi/OgnlSelectionExpression.java      |   29 +
 src/main/gen/psi/OgnlSequenceExpression.java       |   29 +
 src/main/gen/psi/OgnlUnaryExpression.java          |   32 +
 .../gen/psi/OgnlVariableAssignmentExpression.java  |   32 +
 src/main/gen/psi/OgnlVariableExpression.java       |   26 +
 src/main/gen/psi/OgnlVisitor.java                  |  113 ++
 .../gen/psi/impl/OgnlBinaryExpressionImpl.java     |   63 +
 .../psi/impl/OgnlConditionalExpressionImpl.java    |   65 +
 src/main/gen/psi/impl/OgnlExpressionImpl.java      |   50 +
 .../gen/psi/impl/OgnlFqnTypeExpressionImpl.java    |   44 +
 .../gen/psi/impl/OgnlIndexedExpressionImpl.java    |   58 +
 .../gen/psi/impl/OgnlLambdaExpressionImpl.java     |   50 +
 .../gen/psi/impl/OgnlLiteralExpressionImpl.java    |   49 +
 src/main/gen/psi/impl/OgnlMapEntryElementImpl.java |   58 +
 src/main/gen/psi/impl/OgnlMapExpressionImpl.java   |   56 +
 .../gen/psi/impl/OgnlMethodCallExpressionImpl.java |   56 +
 .../gen/psi/impl/OgnlNewArrayExpressionImpl.java   |   58 +
 src/main/gen/psi/impl/OgnlNewExpressionImpl.java   |   56 +
 src/main/gen/psi/impl/OgnlParameterListImpl.java   |   54 +
 .../psi/impl/OgnlParenthesizedExpressionImpl.java  |   50 +
 .../gen/psi/impl/OgnlProjectionExpressionImpl.java |   50 +
 .../gen/psi/impl/OgnlReferenceExpressionImpl.java  |   50 +
 .../gen/psi/impl/OgnlSelectionExpressionImpl.java  |   50 +
 .../gen/psi/impl/OgnlSequenceExpressionImpl.java   |   50 +
 src/main/gen/psi/impl/OgnlUnaryExpressionImpl.java |   55 +
 .../impl/OgnlVariableAssignmentExpressionImpl.java |   55 +
 .../gen/psi/impl/OgnlVariableExpressionImpl.java   |   44 +
 src/main/grammar/apache2.txt                       |   17 +
 src/main/grammar/ognl.bnf                          |  317 +++++
 .../com/intellij/struts2/Struts2IconProvider.java  |   89 ++
 .../java/com/intellij/struts2/Struts2Icons.java    |   20 +
 .../struts2/Struts2PresentationProvider.java       |  150 +++
 .../struts2/Struts2ProblemFileHighlightFilter.java |   82 ++
 .../intellij/struts2/Struts2ResourceProvider.java  |   99 ++
 .../Struts2ValidationPresentationProvider.java     |   70 ++
 .../java/com/intellij/struts2/StrutsBundle.java    |   46 +
 .../java/com/intellij/struts2/StrutsConstants.java |  277 +++++
 .../StrutsFileTemplateGroupDescriptorFactory.java  |   83 ++
 .../struts2/StrutsFileTemplateProvider.java        |   67 +
 .../java/com/intellij/struts2/StrutsIcons.java     |  112 ++
 .../actions/create/CreateStrutsXmlAction.java      |   72 ++
 .../struts2/annotators/ActionAnnotatorBase.java    |  230 ++++
 .../struts2/annotators/ActionJavaAnnotator.java    |   64 +
 .../annotators/DomElementListCellRenderer.java     |   97 ++
 .../struts2/annotators/JspActionAnnotator.java     |  149 +++
 .../StrutsConventionImplicitUsageProvider.java     |  104 ++
 .../annotators/StrutsFileSetCheckingAnnotator.java |  216 ++++
 .../intellij/struts2/annotators/package-info.java  |   19 +
 .../struts2/dom/BeanPropertyPathConverterBase.java |   90 ++
 .../com/intellij/struts2/dom/ConverterUtil.java    |   95 ++
 .../struts2/dom/ExtendableClassConverter.java      |   91 ++
 .../intellij/struts2/dom/StrutsDomConstants.java   |   47 +
 .../dom/inspection/Struts2ModelInspection.java     |  198 +++
 .../inspection/Struts2ModelInspectionVisitor.java  |  150 +++
 .../dom/inspection/Struts2ModelValidator.java      |   86 ++
 .../struts2/dom/inspection/ValidatorBase.java      |   52 +
 .../inspection/ValidatorConfigModelInspection.java |   44 +
 .../dom/inspection/ValidatorModelInspection.java   |   46 +
 .../dom/inspection/ValidatorModelValidator.java    |  104 ++
 .../struts2/dom/inspection/package-info.java       |   19 +
 .../com/intellij/struts2/dom/params/Param.java     |   38 +
 .../struts2/dom/params/ParamNameConverter.java     |   49 +
 .../struts2/dom/params/ParamNameConverterImpl.java |   62 +
 .../struts2/dom/params/ParamValueConverter.java    |   56 +
 .../dom/params/ParamValueConvertersRegistry.java   |   39 +
 .../intellij/struts2/dom/params/ParamsElement.java |   45 +
 ...erceptorRefInStackParamNameCustomConverter.java |  148 +++
 .../custom/ResultParamNameCustomConverter.java     |  130 ++
 .../java/com/intellij/struts2/dom/struts/Bean.java |   54 +
 .../com/intellij/struts2/dom/struts/BeanScope.java |   46 +
 .../intellij/struts2/dom/struts/HasResultType.java |   47 +
 .../com/intellij/struts2/dom/struts/Include.java   |   40 +
 .../dom/struts/IncludeFileResolvingConverter.java  |   68 ++
 .../dom/struts/Struts2DomFileDescription.java      |   48 +
 .../intellij/struts2/dom/struts/StrutsRoot.java    |   65 +
 .../struts2/dom/struts/UnknownHandlerRef.java      |   34 +
 .../dom/struts/UnknownHandlerRefConverter.java     |   45 +
 .../struts2/dom/struts/UnknownHandlerStack.java    |   32 +
 .../intellij/struts2/dom/struts/action/Action.java |  151 +++
 .../dom/struts/action/ActionMethodConverter.java   |   88 ++
 .../action/ActionNameCustomReferenceConverter.java |  106 ++
 .../dom/struts/action/AllowedMethodsConverter.java |   83 ++
 .../struts/action/CreateActionMethodQuickFix.java  |   94 ++
 .../dom/struts/action/ExceptionMapping.java        |   42 +
 .../ExceptionMappingResultResolveConverter.java    |   83 ++
 .../intellij/struts2/dom/struts/action/Result.java |   61 +
 .../action/ResultTypeResolvingConverter.java       |   41 +
 .../action/StrutsPathReferenceConverter.java       |   24 +
 .../struts2/dom/struts/constant/Constant.java      |   40 +
 .../dom/struts/constant/ConstantNameConverter.java |   27 +
 .../struts/constant/ConstantNameConverterImpl.java |   48 +
 .../struts/constant/ConstantValueConverter.java    |   26 +
 .../constant/ConstantValueConverterImpl.java       |   49 +
 .../struts2/dom/struts/constant/package-info.java  |    4 +
 .../struts2/dom/struts/impl/ActionImpl.java        |  135 ++
 .../struts2/dom/struts/impl/ActionImplUtil.java    |  148 +++
 .../DefaultInterceptorRefResolveConverterImpl.java |   87 ++
 .../struts/impl/ExtendableClassConverterImpl.java  |  127 ++
 .../struts2/dom/struts/impl/GlobalResultImpl.java  |   48 +
 .../impl/IncludeFileResolvingConverterImpl.java    |  132 ++
 .../struts2/dom/struts/impl/InterceptorImpl.java   |   33 +
 .../dom/struts/impl/InterceptorRefImpl.java        |   38 +
 .../impl/InterceptorRefResolveConverterImpl.java   |   87 ++
 .../dom/struts/impl/InterceptorStackImpl.java      |   25 +
 .../struts2/dom/struts/impl/ResultImpl.java        |   55 +
 .../struts2/dom/struts/impl/ResultTypeImpl.java    |   31 +
 .../impl/ResultTypeResolvingConverterImpl.java     |   83 ++
 .../StrutsPackageExtendsResolveConverterImpl.java  |   93 ++
 .../struts2/dom/struts/impl/StrutsPackageImpl.java |  108 ++
 .../impl/UnknownHandlerRefConverterImpl.java       |   82 ++
 .../struts2/dom/struts/impl/package-info.java      |   19 +
 .../ActionChainOrRedirectResultContributor.java    |  155 +++
 .../impl/path/ActionPathResultContributor.java     |  190 +++
 .../impl/path/DispatchPathResultContributor.java   |   71 ++
 .../struts/impl/path/FileReferenceSetHelper.java   |  117 ++
 .../dom/struts/impl/path/ResultTypeResolver.java   |   82 ++
 .../path/StrutsPathReferenceConverterImpl.java     |   67 +
 .../struts/impl/path/StrutsResultContributor.java  |  140 +++
 .../struts2/dom/struts/impl/path/package-info.java |   19 +
 .../struts2/dom/struts/model/StrutsManager.java    |   96 ++
 .../dom/struts/model/StrutsManagerImpl.java        |   87 ++
 .../struts2/dom/struts/model/StrutsModel.java      |  100 ++
 .../dom/struts/model/StrutsModelFactory.java       |   94 ++
 .../struts2/dom/struts/model/StrutsModelImpl.java  |  142 +++
 .../struts2/dom/struts/model/package-info.java     |   19 +
 .../intellij/struts2/dom/struts/package-info.java  |   19 +
 .../dom/struts/strutspackage/DefaultActionRef.java |   39 +
 .../dom/struts/strutspackage/DefaultClassRef.java  |   38 +
 .../strutspackage/DefaultInterceptorRef.java       |   35 +
 .../DefaultInterceptorRefResolveConverter.java     |   42 +
 .../strutspackage/GlobalExceptionMapping.java      |   44 +
 ...obalExceptionMappingResultResolveConverter.java |   73 ++
 .../strutspackage/GlobalExceptionMappings.java     |   33 +
 .../dom/struts/strutspackage/GlobalResult.java     |   45 +
 .../dom/struts/strutspackage/GlobalResults.java    |   35 +
 .../dom/struts/strutspackage/Interceptor.java      |   37 +
 .../strutspackage/InterceptorOrStackBase.java      |   33 +
 .../dom/struts/strutspackage/InterceptorRef.java   |   35 +
 .../InterceptorRefResolveConverter.java            |   43 +
 .../dom/struts/strutspackage/InterceptorStack.java |   36 +
 .../dom/struts/strutspackage/Interceptors.java     |   37 +
 .../dom/struts/strutspackage/ResultType.java       |   50 +
 .../dom/struts/strutspackage/ResultTypes.java      |   38 +
 .../dom/struts/strutspackage/StrutsPackage.java    |  131 ++
 .../StrutsPackageExtendsResolveConverter.java      |   44 +
 .../StrutsPackageHierarchyWalker.java              |   59 +
 .../StrutsPackageWithinPackageScopeProvider.java   |   36 +
 .../com/intellij/struts2/dom/validator/Field.java  |   48 +
 .../struts2/dom/validator/FieldNameConverter.java  |   27 +
 .../struts2/dom/validator/FieldValidator.java      |   49 +
 .../intellij/struts2/dom/validator/Message.java    |   42 +
 .../intellij/struts2/dom/validator/Validator.java  |   42 +
 .../ValidatorConfigDomFileDescription.java         |   49 +
 .../dom/validator/ValidatorDomFileDescription.java |   47 +
 .../struts2/dom/validator/ValidatorManager.java    |   88 ++
 .../dom/validator/ValidatorManagerImpl.java        |  195 +++
 .../intellij/struts2/dom/validator/Validators.java |   49 +
 .../dom/validator/config/ValidatorConfig.java      |   41 +
 .../config/ValidatorConfigResolveConverter.java    |   39 +
 .../dom/validator/config/ValidatorsConfig.java     |   40 +
 .../dom/validator/impl/FieldNameConverterImpl.java |   71 ++
 .../dom/validator/impl/FieldValidatorImpl.java     |   34 +
 .../impl/ValidatorConfigResolveConverterImpl.java  |   59 +
 .../struts2/dom/validator/impl/ValidatorImpl.java  |   32 +
 .../struts2/dom/validator/package-info.java        |   19 +
 .../intellij/struts2/facet/Struts2LibraryType.java |   49 +
 .../com/intellij/struts2/facet/StrutsFacet.java    |   81 ++
 .../struts2/facet/StrutsFacetConfiguration.java    |  159 +++
 .../StrutsFacetLibrariesValidatorDescription.java  |   54 +
 .../intellij/struts2/facet/StrutsFacetType.java    |   71 ++
 .../struts2/facet/StrutsFrameworkDetector.java     |   68 ++
 .../facet/StrutsFrameworkSupportProvider.java      |  223 ++++
 .../com/intellij/struts2/facet/package-info.java   |    4 +
 .../java/com/intellij/struts2/facet/struts2.xml    |   31 +
 .../struts2/facet/ui/FeaturesConfigurationTab.form |   44 +
 .../struts2/facet/ui/FeaturesConfigurationTab.java |   72 ++
 .../struts2/facet/ui/FileSetConfigurationTab.form  |   21 +
 .../struts2/facet/ui/FileSetConfigurationTab.java  |  446 +++++++
 .../intellij/struts2/facet/ui/FileSetEditor.form   |   43 +
 .../intellij/struts2/facet/ui/FileSetEditor.java   |  178 +++
 .../struts2/facet/ui/StrutsConfigsSearcher.java    |   51 +
 .../intellij/struts2/facet/ui/StrutsFileSet.java   |  170 +++
 .../intellij/struts2/facet/ui/StrutsFilesTree.java |   83 ++
 .../struts2/facet/ui/StrutsVersionDetector.java    |   79 ++
 .../intellij/struts2/facet/ui/package-info.java    |    4 +
 .../FreeMarkerCssInlineStyleInjector.java          |   73 ++
 .../freemarker/FreeMarkerJavaScriptInjector.java   |   73 ++
 .../struts2/freemarker/FreeMarkerOgnlInjector.java |   82 ++
 .../FreeMarkerStrutsResultContributor.java         |   72 ++
 .../freemarker/FreemarkerInjectionConstants.java   |   45 +
 .../freemarker/Struts2GlobalVariableProvider.java  |  175 +++
 .../intellij/struts2/freemarker/package-info.java  |    4 +
 .../gotosymbol/GoToActionSymbolProvider.java       |   81 ++
 .../gotosymbol/GoToPackageSymbolProvider.java      |   90 ++
 .../gotosymbol/GotoRelatedActionProvider.java      |  107 ++
 .../intellij/struts2/gotosymbol/package-info.java  |   19 +
 .../intellij/struts2/graph/StrutsDataModel.java    |  207 ++++
 .../intellij/struts2/graph/StrutsNodeRenderer.java |   45 +
 .../struts2/graph/StrutsPresentationModel.java     |  168 +++
 .../intellij/struts2/graph/beans/ActionNode.java   |   41 +
 .../struts2/graph/beans/BasicStrutsEdge.java       |   82 ++
 .../struts2/graph/beans/BasicStrutsNode.java       |   82 ++
 .../intellij/struts2/graph/beans/ResultNode.java   |   59 +
 .../graph/fileEditor/Struts2GraphComponent.java    |  161 +++
 .../graph/fileEditor/Struts2GraphFileEditor.java   |  123 ++
 .../fileEditor/Struts2GraphFileEditorProvider.java |   91 ++
 .../com/intellij/struts2/graph/package-info.java   |   19 +
 .../struts2/groovy/ActionGroovyAnnotator.java      |   55 +
 .../code/CreateValidationXmlIntention.java         |  236 ++++
 .../struts2/jsp/TaglibCssInlineStyleInjector.java  |   77 ++
 .../struts2/jsp/TaglibJavaScriptInjector.java      |  117 ++
 .../intellij/struts2/jsp/TaglibOgnlInjector.java   |  110 ++
 .../inspection/HardcodedActionUrlInspection.java   |  299 +++++
 ...gnlStruts2JspVariableReferencesContributor.java |   58 +
 .../ConstantValueConverterClassContributor.java    |   34 +
 .../struts2/model/constant/StrutsConstant.java     |   53 +
 .../model/constant/StrutsConstantContributor.java  |   47 +
 .../model/constant/StrutsConstantHelper.java       |   86 ++
 .../struts2/model/constant/StrutsConstantKey.java  |   51 +
 .../model/constant/StrutsConstantManager.java      |   78 ++
 .../model/constant/StrutsConstantManagerImpl.java  |  276 +++++
 .../contributor/ConstantValueClassConverter.java   |  120 ++
 .../DelimitedStringValuesConverter.java            |   64 +
 .../constant/contributor/ResultTypeConverter.java  |   95 ++
 .../contributor/StringValuesConverter.java         |   49 +
 .../contributor/StrutsConstantContributorBase.java |   98 ++
 .../StrutsConventionPluginConstantContributor.java |   72 ++
 .../contributor/StrutsCoreConstantContributor.java |  150 +++
 .../StrutsOSGiPluginConstantContributor.java       |   51 +
 .../contributor/StrutsPackageConverter.java        |   74 ++
 .../StrutsRESTPluginConstantContributor.java       |   59 +
 .../StrutsSpringPluginConstantContributor.java     |   57 +
 .../intellij/struts2/model/jam/StrutsJamUtils.java |   51 +
 .../struts2/model/jam/StrutsSemContributor.java    |   64 +
 .../InterceptorJamReferenceConverter.java          |   77 ++
 .../jam/convention/JamDefaultInterceptorRef.java   |   66 +
 .../model/jam/convention/JamInterceptorRef.java    |   93 ++
 .../model/jam/convention/JamParentPackage.java     |  116 ++
 .../model/jam/convention/JamResultPath.java        |  170 +++
 .../jam/convention/StrutsConventionConstants.java  |   35 +
 .../struts2/model/jam/convention/package-info.java |    4 +
 .../intellij/struts2/model/jam/package-info.java   |    4 +
 .../java/com/intellij/struts2/ognl/OgnlFile.java   |   43 +
 .../com/intellij/struts2/ognl/OgnlFileType.java    |   66 +
 .../com/intellij/struts2/ognl/OgnlLanguage.java    |   52 +
 .../struts2/ognl/OgnlLanguageInjector.java         |  100 ++
 .../struts2/ognl/OgnlParserDefinition.java         |   94 ++
 .../intellij/struts2/ognl/OgnlTypedHandler.java    |  106 ++
 .../OgnlKeywordCompletionContributor.java          |  143 +++
 .../struts2/ognl/formatting/OgnlBlock.java         |  115 ++
 .../formatting/OgnlFormattingModelBuilder.java     |   72 ++
 .../struts2/ognl/highlight/OgnlBraceMatcher.java   |   53 +
 .../ognl/highlight/OgnlColorSettingsPage.java      |   98 ++
 .../struts2/ognl/highlight/OgnlHighlighter.java    |  141 +++
 .../ognl/highlight/OgnlHighlightingAnnotator.java  |   33 +
 .../ognl/highlight/OgnlHighlightingLexer.java      |   48 +
 .../struts2/ognl/highlight/OgnlQuoteHandler.java   |   29 +
 .../com/intellij/struts2/ognl/lexer/OgnlLexer.java |   34 +
 .../intellij/struts2/ognl/lexer/_OgnlLexer.flex    |  192 +++
 .../com/intellij/struts2/ognl/package-info.java    |   21 +
 .../com/intellij/struts2/ognl/psi/OgnlKeyword.java |   52 +
 .../struts2/ognl/psi/OgnlPsiCompositeElement.java  |   24 +
 .../intellij/struts2/ognl/psi/OgnlTokenGroups.java |   69 ++
 .../intellij/struts2/ognl/psi/OgnlTokenType.java   |   29 +
 .../ognl/psi/impl/OgnlFqnTypeExpressionBase.java   |   58 +
 .../ognl/psi/impl/OgnlPsiCompositeElementBase.java |   36 +
 .../struts2/ognl/psi/impl/OgnlPsiUtil.java         |  183 +++
 .../ognl/psi/impl/OgnlReferenceExpressionBase.java |   79 ++
 .../ognl/psi/impl/OgnlVariableExpressionBase.java  |   83 ++
 .../OgnlFqnTypeExpressionManipulator.java          |   48 +
 .../struts2/ognl/psi/resolve/OgnlResolveUtil.java  |   41 +
 .../OgnlDefaultVariableReferencesContributor.java  |   53 +
 .../resolve/variable/OgnlVariableReference.java    |   17 +
 .../OgnlVariableReferencesContributor.java         |   32 +
 .../spellchecker/OgnlSpellcheckingStrategy.java    |   42 +
 .../ognl/template/OgnlTemplateContextType.java     |   52 +
 .../java/com/intellij/struts2/package-info.java    |   19 +
 .../struts2/preview/Struts2UrlConverter.java       |   57 +
 .../ResultActionPropertyReferenceProvider.java     |  110 ++
 .../StaticStringValuesReferenceProvider.java       |   81 ++
 .../StrutsBootstrapTaglibReferenceContributor.java |   47 +
 ...trutsJQueryChartTaglibReferenceContributor.java |   65 +
 ...StrutsJQueryGridTaglibReferenceContributor.java |   87 ++
 ...rutsJQueryMobileTaglibReferenceContributor.java |   88 ++
 ...tsJQueryRichtextTaglibReferenceContributor.java |   88 ++
 .../StrutsJQueryTaglibReferenceContributor.java    |  200 +++
 ...StrutsJQueryTaglibReferenceContributorBase.java |  128 ++
 ...StrutsJQueryTreeTaglibReferenceContributor.java |   53 +
 .../reference/StrutsReferenceContributor.java      |  106 ++
 .../StrutsTaglibReferenceContributorBase.java      |  186 +++
 .../StrutsUITaglibReferenceContributor.java        |  252 ++++
 .../com/intellij/struts2/reference/TaglibUtil.java |   66 +
 .../WrappedPropertiesReferenceProvider.java        |   49 +
 .../common/BeanPropertyPathReference.java          |  164 +++
 .../common/BeanPropertyPathReferenceSet.java       |   80 ++
 .../reference/jsp/ActionLinkReferenceProvider.java |  264 ++++
 .../jsp/ActionMethodReferenceProvider.java         |  133 ++
 .../jsp/ActionPropertyReferenceProvider.java       |  113 ++
 .../reference/jsp/ActionReferenceInjector.java     |   58 +
 .../reference/jsp/ActionReferenceProvider.java     |  182 +++
 .../reference/jsp/NamespaceReferenceProvider.java  |  104 ++
 .../reference/jsp/ThemeReferenceProvider.java      |   60 +
 .../intellij/struts2/reference/package-info.java   |    4 +
 .../web/StrutsConstantValueReference.java          |  180 +++
 .../WebXmlStrutsConstantNameReferenceProvider.java |   72 ++
 ...WebXmlStrutsConstantValueReferenceProvider.java |   37 +
 .../struts2/reference/web/package-info.java        |    4 +
 .../Struts2BundledDictionaryProvider.java          |   32 +
 .../com/intellij/struts2/spellchecker/struts2.dic  |   48 +
 ...nstantValueConverterSpringClassContributor.java |   58 +
 .../ExtendableClassConverterSpringContributor.java |  165 +++
 .../BaseStructureViewBuilderProvider.java          |   83 ++
 .../structure/StructureViewTreeElement.java        |  113 ++
 .../struts2/structure/StructureViewTreeModel.java  |  125 ++
 .../StrutsStructureViewBuilderProvider.java        |   53 +
 .../structure/StrutsTreeDescriptionProvider.java   |   70 ++
 .../ValidationStructureViewBuilderProvider.java    |   52 +
 .../intellij/struts2/structure/package-info.java   |   19 +
 .../velocity/Struts2GlobalMacroProvider.java       |   60 +
 .../velocity/Struts2GlobalVariableProvider.java    |   82 ++
 .../velocity/VelocityStrutsResultContributor.java  |   74 ++
 src/main/resources/META-INF/ognl.xml               |   41 +
 src/main/resources/META-INF/plugin.xml             |  258 ++++
 src/main/resources/META-INF/struts2-freemarker.xml |   24 +
 src/main/resources/META-INF/struts2-groovy.xml     |   20 +
 src/main/resources/META-INF/struts2-spring.xml     |   10 +
 src/main/resources/META-INF/struts2-velocity.xml   |   22 +
 .../resources/fileTemplates/j2ee/struts.xml.ft     |    8 +
 .../resources/fileTemplates/j2ee/struts.xml.html   |    7 +
 .../resources/fileTemplates/j2ee/struts_2_1.xml.ft |    8 +
 .../fileTemplates/j2ee/struts_2_1.xml.html         |    7 +
 .../fileTemplates/j2ee/struts_2_1_7.xml.ft         |    8 +
 .../fileTemplates/j2ee/struts_2_1_7.xml.html       |    7 +
 .../resources/fileTemplates/j2ee/struts_2_3.xml.ft |    8 +
 .../fileTemplates/j2ee/struts_2_3.xml.html         |    7 +
 .../resources/fileTemplates/j2ee/struts_2_5.xml.ft |    8 +
 .../fileTemplates/j2ee/struts_2_5.xml.html         |    7 +
 .../resources/fileTemplates/j2ee/validator.xml.ft  |    8 +
 .../fileTemplates/j2ee/validator.xml.html          |    7 +
 src/main/resources/icons/action.svg                |   14 +
 src/main/resources/icons/action_small.svg          |   14 +
 src/main/resources/icons/edit_small.svg            |    6 +
 .../inspectionDescriptions/HardcodedActionUrl.html |   17 +
 .../Struts2ModelInspection.html                    |    5 +
 .../ValidatorConfigModelInspection.html            |    5 +
 .../ValidatorModelInspection.html                  |    5 +
 .../after.java.template                            |    7 +
 .../before.java.template                           |    7 +
 .../CreateValidationXmlIntention/description.html  |    6 +
 src/main/resources/liveTemplates/ognl-struts2.xml  |    8 +
 src/main/resources/liveTemplates/ognl.xml          |   19 +
 .../resources/messages/Struts2Bundle.properties    |   80 ++
 src/main/resources/resources/dtds/struts-2.0.dtd   |  140 +++
 src/main/resources/resources/dtds/struts-2.1.7.dtd |  141 +++
 src/main/resources/resources/dtds/struts-2.1.dtd   |  145 +++
 src/main/resources/resources/dtds/struts-2.3.dtd   |  152 +++
 src/main/resources/resources/dtds/struts-2.5.dtd   |  153 +++
 .../resources/dtds/xwork-validator-1.0.2.dtd       |   42 +
 .../resources/dtds/xwork-validator-1.0.3.dtd       |   44 +
 .../resources/dtds/xwork-validator-1.0.dtd         |   42 +
 .../resources/dtds/xwork-validator-config-1.0.dtd  |   19 +
 .../dtds/xwork-validator-config-struts-1.0.dtd     |   19 +
 .../dtds/xwork-validator-definition-1.0.dtd        |   21 +
 .../dtds/xwork-validator-struts-1.0.2.dtd          |   44 +
 .../resources/dtds/xwork-validator-struts-1.0.dtd  |   42 +
 .../lang/ognl/OgnlCodeInsightSanityTest.java       |  105 ++
 .../java/com/intellij/lang/ognl/OgnlTestUtils.java |   40 +
 .../intellij/lang/ognl/OgnlTypedHandlerTest.java   |   46 +
 .../ognl/completion/OgnlCompletionTestCase.java    |   40 +
 .../OgnlFqnTypeExpressionCompletionTest.java       |   80 ++
 .../ognl/completion/OgnlKeywordCompletionTest.java |   77 ++
 .../OgnlVariableExpressionCompletionTest.java      |   28 +
 .../lang/ognl/formatting/OgnlFormattingTest.java   |  109 ++
 .../ognl/highlight/OgnlHighlightingLexerTest.java  |   47 +
 .../intellij/lang/ognl/lexer/OgnlLexerTest.java    |   57 +
 .../parsing/ConditionalExpressionParsingTest.java  |   38 +
 .../ognl/parsing/ExpressionHolderParsingTest.java  |   35 +
 .../ognl/parsing/IndexedExpressionParsingTest.java |   46 +
 .../ognl/parsing/LambdaExpressionParsingTest.java  |   39 +
 .../ognl/parsing/MapExpressionParsingTest.java     |   46 +
 .../parsing/MethodCallExpressionParsingTest.java   |   43 +
 .../parsing/NewArrayExpressionParsingTest.java     |   41 +
 .../ognl/parsing/NewExpressionParsingTest.java     |   44 +
 .../lang/ognl/parsing/OgnlParsingTestCase.java     |   42 +
 .../ParenthesizedExpressionParsingTest.java        |   35 +
 .../ProjectionSelectionExpressionParsingTest.java  |   34 +
 .../parsing/SequenceExpressionParsingTest.java     |   39 +
 .../ognl/parsing/UnaryExpressionParsingTest.java   |   39 +
 .../VariableAssignmentExpressionParsingTest.java   |   31 +
 .../parsing/VariableExpressionParsingTest.java     |   31 +
 .../ognl/psi/ConditionalExpressionPsiTest.java     |   83 ++
 .../lang/ognl/psi/IndexedExpressionPsiTest.java    |   92 ++
 .../lang/ognl/psi/LambdaExpressionPsiTest.java     |   49 +
 .../lang/ognl/psi/LiteralExpressionPsiTest.java    |  132 ++
 .../lang/ognl/psi/MapExpressionPsiTest.java        |   86 ++
 .../lang/ognl/psi/MethodCallExpressionPsiTest.java |   94 ++
 .../lang/ognl/psi/NewArrayExpressionPsiTest.java   |   65 +
 .../lang/ognl/psi/NewExpressionPsiTest.java        |   71 ++
 .../ognl/psi/ParenthesizedExpressionPsiTest.java   |   92 ++
 .../lang/ognl/psi/ProjectionExpressionPsiTest.java |   44 +
 .../com/intellij/lang/ognl/psi/PsiTestCase.java    |   78 ++
 .../lang/ognl/psi/ReferenceExpressionPsiTest.java  |   70 ++
 .../lang/ognl/psi/SelectionExpressionPsiTest.java  |   64 +
 .../lang/ognl/psi/SequenceExpressionPsiTest.java   |   63 +
 .../lang/ognl/psi/UnaryExpressionPsiTest.java      |   81 ++
 .../psi/VariableAssignmentExpressionPsiTest.java   |   44 +
 .../lang/ognl/psi/VariableExpressionPsiTest.java   |   94 ++
 .../ArithmeticBinaryExpressionPsiTest.java         |   46 +
 .../BinaryExpressionPsiTestCase.java               |   77 ++
 .../BitwiseBooleanBinaryExpressionPsiTest.java     |   48 +
 .../BitwiseShiftBinaryExpressionPsiTest.java       |   48 +
 .../BooleanBinaryExpressionPsiTest.java            |   49 +
 .../ComparisonBinaryExpressionPsiTest.java         |   57 +
 .../EqualityBinaryExpressionPsiTest.java           |   40 +
 .../InNotInBinaryExpressionPsiTest.java            |   38 +
 .../InstanceOfBinaryExpressionPsiTest.java         |   31 +
 .../lang/ognl/template/OgnlLiveTemplatesTest.java  |   52 +
 .../struts2/BasicLightHighlightingTestCase.java    |  175 +++
 .../struts2/Struts2ProjectDescriptorBuilder.java   |  175 +++
 .../annotators/ActionJavaAnnotatorTest.java        |   75 ++
 .../struts2/annotators/AnnotatorTestUtils.java     |   66 +
 .../struts2/annotators/JspActionAnnotatorTest.java |   65 +
 .../StrutsConventionImplicitUsageProviderTest.java |  116 ++
 .../StrutsFileSetCheckingAnnotatorTest.java        |   51 +
 .../java/com/intellij/struts2/dom/DomStubTest.java |   93 ++
 .../intellij/struts2/dom/StrutsDomStubTest.java    |   52 +
 .../struts2/dom/struts/StrutsCompletionTest.java   |   93 ++
 .../dom/struts/StrutsHighlightingSpringTest.java   |  144 +++
 .../struts2/dom/struts/StrutsHighlightingTest.java |   84 ++
 .../struts2/dom/struts/StrutsIncludeTest.java      |   43 +
 .../struts2/dom/struts/StrutsIntentionTest.java    |   52 +
 .../struts/StrutsLightHighlightingTestCase.java    |   56 +
 .../dom/struts/StrutsResultResolvingTest.java      |  137 +++
 .../dom/struts/impl/ActionImplUtilTest.java        |   70 ++
 .../validator/ValidationFieldCompletionTest.java   |   36 +
 ...ValidationFieldValidatorTypeCompletionTest.java |   37 +
 .../dom/validator/ValidationHighlightingTest.java  |   37 +
 .../ValidationLightHighlightingTestCase.java       |   55 +
 .../validator/ValidatorConfigHighlightingTest.java |   40 +
 .../facet/ui/StrutsConfigsSearcherTest.java        |   53 +
 .../facet/ui/StrutsVersionDetectorTest.java        |   38 +
 .../freemarker/FreemarkerIntegrationTest.java      |   51 +
 .../struts2/gotosymbol/GoToSymbolProviderTest.java |   88 ++
 .../HardcodedActionUrlInspectionTest.java          |   95 ++
 .../struts2/jsp/ognl/Struts2OgnlJspTest.java       |   57 +
 .../StrutsConstantManagerNoCustomTest.java         |   66 +
 .../constant/StrutsConstantManagerTestCase.java    |   47 +
 ...rutsConstantManagerWithStrutsPluginXmlTest.java |   72 ++
 ...utsConstantManagerWithStrutsPropertiesTest.java |   48 +
 .../StrutsConstantManagerWithWebXmlTest.java       |   52 +
 .../jam/convention/JamConventionLightTestCase.java |   99 ++
 .../convention/JamDefaultInterceptorRefTest.java   |   57 +
 .../jam/convention/JamInterceptorRefTest.java      |   54 +
 .../model/jam/convention/JamParentPackageTest.java |   65 +
 .../model/jam/convention/JamResultPathTest.java    |   81 ++
 .../intellij/struts2/reference/TaglibUtilTest.java |   45 +
 .../jsp/ActionLinkReferenceProviderTest.java       |   99 ++
 .../jsp/ActionPropertyReferenceProviderTest.java   |   59 +
 .../reference/jsp/ActionReferenceProviderTest.java |   79 ++
 .../jsp/NamespaceReferenceProviderTest.java        |   51 +
 .../jsp/UITagsAttributesReferenceProviderTest.java |   63 +
 .../reference/struts/ResultActionPropertyTest.java |   36 +
 .../struts2/reference/web/WebXmlConstantTest.java  |   85 ++
 .../struts2/structure/StrutsStructureViewTest.java |   70 ++
 .../structure/ValidationStructureViewTest.java     |   67 +
 src/test/testData/configsSearcher/struts.xml       |    9 +
 .../MacroParametersResolveOnlyToParameters.ftl     |    1 +
 src/test/testData/freemarker/MyTestAction.java     |    4 +
 .../freemarker/StrutsActionToplevel-struts.xml     |   37 +
 .../testData/freemarker/StrutsActionToplevel.ftl   |    2 +
 .../testData/freemarker/StrutsCommonVariables.ftl  |    9 +
 .../testData/gutterJava/actionClass/MyAction.java  |    7 +
 .../com/MyValidationAction-validation.xml          |   13 +
 .../actionClass/com/MyValidationAction.java        |   19 +
 .../struts-actionClass-multiple_mappings.xml       |   23 +
 .../gutterJava/actionClass/struts-actionClass.xml  |   15 +
 .../gutterJava/actionClass/struts-validation.xml   |   16 +
 .../testData/gutterJsp/actionClass/MyAction.java   |    7 +
 .../jsp/test_gutter_action_attribute.jsp           |    3 +
 .../actionClass/jsp/test_gutter_name_attribute.jsp |    3 +
 .../gutterJsp/actionClass/struts-actionClass.xml   |   15 +
 .../hardcodedUrl/customActionExtension.jsp         |    1 +
 .../hardcodedUrl/customActionExtension_after.jsp   |    2 +
 .../jsp/inspection/hardcodedUrl/customTag.jsp      |    2 +
 .../inspection/hardcodedUrl/customTag_after.jsp    |    4 +
 .../jsp/inspection/hardcodedUrl/dynamic.jsp        |    1 +
 .../testData/jsp/inspection/hardcodedUrl/host.jsp  |    1 +
 .../jsp/inspection/hardcodedUrl/method.jsp         |    1 +
 .../jsp/inspection/hardcodedUrl/method_after.jsp   |    2 +
 .../jsp/inspection/hardcodedUrl/multiParams.jsp    |    1 +
 .../inspection/hardcodedUrl/multiParamsEscaped.jsp |    1 +
 .../hardcodedUrl/multiParamsEscaped_after.jsp      |    5 +
 .../inspection/hardcodedUrl/multiParams_after.jsp  |    5 +
 .../jsp/inspection/hardcodedUrl/namespace.jsp      |    1 +
 .../inspection/hardcodedUrl/namespace_after.jsp    |    2 +
 .../jsp/inspection/hardcodedUrl/oneParam.jsp       |    1 +
 .../jsp/inspection/hardcodedUrl/oneParam_after.jsp |    4 +
 .../jsp/inspection/hardcodedUrl/protocol.jsp       |    1 +
 .../jsp/inspection/hardcodedUrl/simple.jsp         |    1 +
 .../hardcodedUrl/simpleTaglibPrefixDefined.jsp     |    2 +
 .../simpleTaglibPrefixDefined_after.jsp            |    2 +
 .../jsp/inspection/hardcodedUrl/simple_after.jsp   |    2 +
 .../jsp/inspection/hardcodedUrl/struts.properties  |    2 +
 .../jsp/inspection/hardcodedUrl/struts.xml         |    9 +
 src/test/testData/jsp/ognl/WEB-INF/web.xml         |   14 +
 .../jsp/ognl/struts2-jsp-variables-completion.jsp  |    3 +
 .../testData/jsp/ognl/taglib-ognl-injection.jsp    |   14 +
 src/test/testData/lexer/nestedBraces.txt           |   11 +
 .../lexer/nestedBracesWithoutExpression.txt        |    7 +
 src/test/testData/lexer/nestedModuloAndCurly.txt   |    7 +
 src/test/testData/lexer/twoRightCurly.txt          |    6 +
 .../testData/model/constant/noCustom/dummy.xml     |    0
 .../testData/model/constant/noCustom/struts.xml    |    9 +
 .../model/constant/withPluginXml/struts.xml        |    9 +
 .../withStrutsProperties/struts.properties         |    3 +
 .../model/constant/withStrutsProperties/struts.xml |   13 +
 .../model/constant/withWebXml/WEB-INF/web.xml      |   23 +
 .../testData/model/constant/withWebXml/struts.xml  |   13 +
 .../defaultInterceptorRef/jam/package-info.java    |    2 +
 .../convention/defaultInterceptorRef/struts.xml    |   23 +
 .../testcompletion/package-info.java               |    2 +
 .../interceptorRef/completion/ActionSingle.java    |    8 +
 .../interceptorRef/jam/ActionSingle.java           |    8 +
 .../model/jam/convention/interceptorRef/struts.xml |   23 +
 .../jam/convention/parentPackage/jam/Action.java   |    8 +
 .../convention/parentPackage/jam/package-info.java |    2 +
 .../model/jam/convention/parentPackage/struts.xml  |   23 +
 .../parentPackage/testcompletion/Action.java       |    8 +
 .../parentPackage/testcompletion/package-info.java |    2 +
 .../resultPath/WEB-INF/customContent/test.jsp      |    1 +
 .../convention/resultPath/jam/ActionProperty.java  |    8 +
 .../jam/convention/resultPath/jam/ActionValue.java |    8 +
 .../jam/convention/resultPath/struts.properties    |    2 +
 .../resultPath/testcompletion/ActionProperty.java  |    8 +
 .../psi/conditionalExpression/ColonMissing.ognl    |    1 +
 .../psi/conditionalExpression/ColonMissing.txt     |   13 +
 .../psi/conditionalExpression/ElseMissing.ognl     |    1 +
 .../psi/conditionalExpression/ElseMissing.txt      |   15 +
 .../psi/conditionalExpression/ThenMissing.ognl     |    1 +
 .../psi/conditionalExpression/ThenMissing.txt      |   10 +
 .../psi/expressionHolder/MissingClosingBrace.ognl  |    1 +
 .../psi/expressionHolder/MissingClosingBrace.txt   |    7 +
 .../psi/expressionHolder/NoExpression.ognl         |    1 +
 .../testData/psi/expressionHolder/NoExpression.txt |    5 +
 .../psi/indexedExpression/AfterIdentifier.ognl     |    1 +
 .../psi/indexedExpression/AfterIdentifier.txt      |   10 +
 .../testData/psi/indexedExpression/AfterVar.ognl   |    1 +
 .../testData/psi/indexedExpression/AfterVar.txt    |   11 +
 .../AfterVarFollowedByProperty.ognl                |    1 +
 .../AfterVarFollowedByProperty.txt                 |   13 +
 .../AfterVarFollowedBySelection.ognl               |    1 +
 .../AfterVarFollowedBySelection.txt                |   18 +
 .../MissingClosingRightBracket.ognl                |    1 +
 .../MissingClosingRightBracket.txt                 |   11 +
 .../AfterBracketExpressionExpected.ognl            |    1 +
 .../AfterBracketExpressionExpected.txt             |    8 +
 .../AfterColonBracketExpected.ognl                 |    1 +
 .../lambdaExpression/AfterColonBracketExpected.txt |    7 +
 .../AfterExpressionClosingBracketExpected.ognl     |    1 +
 .../AfterExpressionClosingBracketExpected.txt      |   12 +
 .../psi/mapExpression/MissingColonAfterKey.ognl    |    1 +
 .../psi/mapExpression/MissingColonAfterKey.txt     |   16 +
 .../mapExpression/MissingKeyAfterFirstElement.ognl |    1 +
 .../mapExpression/MissingKeyAfterFirstElement.txt  |   22 +
 .../mapExpression/MissingMapEntryAfterComma.ognl   |    1 +
 .../mapExpression/MissingMapEntryAfterComma.txt    |   22 +
 .../psi/mapExpression/MissingValueAfterColon.ognl  |    1 +
 .../psi/mapExpression/MissingValueAfterColon.txt   |   18 +
 .../testData/psi/mapExpression/NoMapEntries.ognl   |    1 +
 .../testData/psi/mapExpression/NoMapEntries.txt    |   12 +
 .../MissingClosingParenthesesNoParameter.ognl      |    1 +
 .../MissingClosingParenthesesNoParameter.txt       |   11 +
 .../MissingClosingParenthesesOneParameter.ognl     |    1 +
 .../MissingClosingParenthesesOneParameter.txt      |   12 +
 .../MissingClosingParenthesesTwoParameters.ognl    |    1 +
 .../MissingClosingParenthesesTwoParameters.txt     |   15 +
 .../MissingExpressionInParameters.ognl             |    1 +
 .../MissingExpressionInParameters.txt              |   14 +
 .../newArrayExpression/MissingArrayExpression.ognl |    1 +
 .../newArrayExpression/MissingArrayExpression.txt  |   11 +
 .../MissingClosingRightBrace.ognl                  |    1 +
 .../MissingClosingRightBrace.txt                   |   13 +
 .../MissingSequenceClosingRightBrace.ognl          |    1 +
 .../MissingSequenceClosingRightBrace.txt           |   21 +
 .../psi/newExpression/ConstructorOrArray.ognl      |    1 +
 .../psi/newExpression/ConstructorOrArray.txt       |   10 +
 .../MissingClosingRightParenthesis.ognl            |    1 +
 .../MissingClosingRightParenthesis.txt             |   14 +
 .../psi/newExpression/MissingParameter.ognl        |    1 +
 .../psi/newExpression/MissingParameter.txt         |   13 +
 .../testData/psi/newExpression/TypeExpected.ognl   |    1 +
 .../testData/psi/newExpression/TypeExpected.txt    |    7 +
 .../MissingClosingRightParenthesis.ognl            |    1 +
 .../MissingClosingRightParenthesis.txt             |   13 +
 .../MissingClosingRightParenthesisNested.ognl      |    1 +
 .../MissingClosingRightParenthesisNested.txt       |   23 +
 .../ExpressionExpectedAfterSelectorType.ognl       |    1 +
 .../ExpressionExpectedAfterSelectorType.txt        |   13 +
 ...rTypeOrExpressionExpectedAfterOpeningBrace.ognl |    1 +
 ...orTypeOrExpressionExpectedAfterOpeningBrace.txt |   10 +
 .../ExpressionAfterCommaExpected.ognl              |    1 +
 .../ExpressionAfterCommaExpected.txt               |   11 +
 .../MissingClosingRightBrace.ognl                  |    1 +
 .../MissingClosingRightBrace.txt                   |   11 +
 .../SingleExpressionIsNotSequence.ognl             |    1 +
 .../SingleExpressionIsNotSequence.txt              |   10 +
 .../unaryExpression/MissingAfterBitwiseNegate.ognl |    1 +
 .../unaryExpression/MissingAfterBitwiseNegate.txt  |    7 +
 .../unaryExpression/MissingAfterNotKeyword.ognl    |    1 +
 .../psi/unaryExpression/MissingAfterNotKeyword.txt |    7 +
 .../UnaryNotOperatorBeforeVariable.ognl            |    1 +
 .../UnaryNotOperatorBeforeVariable.txt             |   19 +
 .../MissingExpression.ognl                         |    1 +
 .../MissingExpression.txt                          |   11 +
 .../MissingVariableIdentifier.ognl                 |    1 +
 .../MissingVariableIdentifier.txt                  |    6 +
 .../reference/jsp/action/ActionMethods.java        |   11 +
 .../action/jsp/action-completionvariants-bang.jsp  |    3 +
 .../jsp/action/jsp/action-completionvariants.jsp   |    3 +
 .../jsp/action-completionvariants_method.jsp       |    4 +
 .../jsp/action-completionvariants_namespace.jsp    |   19 +
 .../jsp/action/jsp/action-highlighting.jsp         |   37 +
 .../reference/jsp/action/struts-action.xml         |   26 +
 .../reference/jsp/actionLink/WEB-INF/web.xml       |   14 +
 ...tionLink-completionvariants-namespace_given.jsp |    1 +
 .../actionLink-completionvariants-no-namespace.jsp |    2 +
 .../jsp/actionLink/jsp/actionLink-highlighting.jsp |   20 +
 .../jsp/actionLink/jsp/actionLink-reference_1.jsp  |    1 +
 .../jsp/actionLink/jsp/actionLink-reference_2.jsp  |    1 +
 .../reference/jsp/actionLink/jsp/index.jsp         |    0
 .../reference/jsp/actionLink/struts-actionLink.xml |   19 +
 .../reference/jsp/actionproperty/MyAction.java     |   68 ++
 ...actionproperty-forminput-completionvariants.jsp |    6 +
 .../jsp/actionproperty-forminput-highlighting.jsp  |   74 ++
 ...perty-forminput-readonly-completionvariants.jsp |    6 +
 .../jsp/actionproperty-param-highlighting.jsp      |   33 +
 .../jsp/actionproperty/struts-actionproperty.xml   |   14 +
 .../namespace/jsp/namespace-completionvariants.jsp |    3 +
 .../jsp/namespace/jsp/namespace-highlighting.jsp   |   12 +
 .../reference/jsp/namespace/struts-namespace.xml   |   18 +
 .../reference/jsp/uitags/MyBundle.properties       |    1 +
 .../testData/reference/jsp/uitags/jsp/common.jsp   |   48 +
 .../testData/reference/jsp/uitags/jsp/paths.jsp    |   13 +
 .../testData/reference/jsp/uitags/jsp/specific.jsp |   88 ++
 .../reference/web/constant/WEB-INF/web.xml         |   68 ++
 .../web/constant/WEB-INF/web_name_completion.xml   |   19 +
 .../web/constant/WEB-INF/web_value_completion.xml  |   19 +
 .../constant/WEB-INF/web_value_completion_2.xml    |   19 +
 src/test/testData/structure/struts-structure.xml   |   23 +
 .../testData/structure/validation-structure.xml    |   22 +
 .../testData/strutsXml/completion/ActionClass.java |   45 +
 .../struts-completionvariants-action_method.xml    |   14 +
 .../struts-completionvariants-constant_name.xml    |   12 +
 ...-completionvariants-interceptor-ref-extends.xml |   50 +
 .../struts-completionvariants-interceptor-ref.xml  |   24 +
 .../struts-completionvariants-package_extends.xml  |   20 +
 .../struts-completionvariants-result_name.xml      |   18 +
 ...ts-completionvariants-result_type-extending.xml |   40 +
 .../struts-completionvariants-result_type.xml      |   24 +
 .../strutsXml/highlighting/MyAbstractClass.java    |    1 +
 .../testData/strutsXml/highlighting/MyClass.java   |   54 +
 .../strutsXml/highlighting/MyException.java        |    2 +
 .../strutsXml/highlighting/MyInterface.java        |    2 +
 .../strutsXml/highlighting/MyInterfaceImpl.java    |    2 +
 .../strutsXml/highlighting/MyNestedClass.java      |   22 +
 .../highlighting/struts-action-allowedMethods.xml  |   26 +
 .../strutsXml/highlighting/struts-constants.xml    |   40 +
 .../highlighting/struts-default-2_1_8.xml          |  324 +++++
 .../highlighting/struts-default-2_3_1.xml          |  306 +++++
 .../strutsXml/highlighting/struts-default.xml      |  315 +++++
 .../strutsXml/highlighting/struts-errors.xml       |   14 +
 .../highlighting/struts-exceptionmapping.xml       |  108 ++
 .../highlighting/struts-interceptor-ref.xml        |   33 +
 .../strutsXml/highlighting/struts-param.xml        |  192 +++
 .../strutsXml/highlighting/struts-simple.xml       |  216 ++++
 .../highlighting/struts-unknownhandlerstack.xml    |   20 +
 .../strutsXml/include/com/test/struts-sub.xml      |    8 +
 .../testData/strutsXml/include/struts-include.xml  |    8 +
 .../strutsXml/include/struts-notinfileset.xml      |   16 +
 src/test/testData/strutsXml/include/struts.xml     |   20 +
 .../testData/strutsXml/intentions/MyClass.java     |    2 +
 .../strutsXml/intentions/struts-action-method.xml  |   15 +
 src/test/testData/strutsXml/result/WEB-INF/web.xml |    8 +
 src/test/testData/strutsXml/result/jsp/index.jsp   |    1 +
 .../testData/strutsXml/result/jsp2/jsp2-index.jsp  |    1 +
 .../strutsXml/result/struts-actionRedirect.xml     |   61 +
 .../strutsXml/result/struts-actionchain.xml        |   81 ++
 .../strutsXml/result/struts-actionpath-fq.xml      |   54 +
 .../strutsXml/result/struts-actionpath.xml         |   86 ++
 .../result/struts-completionvariants-chain.xml     |   28 +
 .../strutsXml/result/struts-completionvariants.xml |   44 +
 .../strutsXml/result/struts-path-dispatcher.xml    |   90 ++
 .../strutsXml/result/struts-unknownResultType.xml  |   38 +
 .../resultActionProperty/ActionClass.java          |   19 +
 .../struts-resultActionProperty.xml                |   42 +
 .../testData/strutsXml/spring/MyAbstractClass.java |    1 +
 src/test/testData/strutsXml/spring/MyClass.java    |    7 +
 .../testData/strutsXml/spring/MyInterface.java     |    1 +
 src/test/testData/strutsXml/spring/spring.xml      |   19 +
 .../spring/struts-completionvariants-spring.xml    |   15 +
 .../struts-completionvariants-subclass-spring.xml  |   18 +
 .../testData/strutsXml/spring/struts-spring.xml    |   72 ++
 src/test/testData/stubs/struts-stubs.xml           |   21 +
 .../completion/field/com/MyAction-validation.xml   |   32 +
 .../completion/field/com/MyAction.java             |   39 +
 .../src/com/MyAction-validation.xml                |   32 +
 .../fieldValidatorType/src/com/MyAction.java       |   39 +
 .../config/validator-config-default.xml            |   21 +
 .../config/validator-config-simple.xml             |   18 +
 .../highlighting/com/MyAction-validation.xml       |   64 +
 .../validationXml/highlighting/com/MyAction.java   |   24 +
 740 files changed, 41380 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b63da45
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,42 @@
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 0000000..2bb9ad2
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,176 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..0345203
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,58 @@
+plugins {
+    id("java")
+    id("org.jetbrains.kotlin.jvm") version "1.8.21"
+    id("org.jetbrains.intellij") version "1.13.3"
+}
+
+group = "com.intellij"
+version = "2023.2"
+
+repositories {
+    mavenCentral()
+}
+
+java.sourceSets["main"].java {
+    srcDir("src/main/gen")
+}
+
+intellij {
+    version.set("2023.1.1")
+    type.set("IU") // Target IDE Platform
+
+    plugins.set(listOf(
+        "com.intellij.javaee",
+        "com.intellij.javaee.web",
+        "com.intellij.spring",
+        "com.intellij.freemarker",
+        "com.intellij.velocity",
+        "org.intellij.groovy",
+        "JavaScript",
+        "com.intellij.java-i18n"
+    ))
+}
+
+tasks {
+    // Set the JVM compatibility versions
+    withType<JavaCompile> {
+        sourceCompatibility = "17"
+        targetCompatibility = "17"
+    }
+    withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
+        kotlinOptions.jvmTarget = "17"
+    }
+
+    patchPluginXml {
+        sinceBuild.set("231")
+        untilBuild.set("232.*")
+    }
+
+    signPlugin {
+        certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
+        privateKey.set(System.getenv("PRIVATE_KEY"))
+        password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
+    }
+
+    publishPlugin {
+        token.set(System.getenv("PUBLISH_TOKEN"))
+    }
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..2bca45c
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,3 @@
+kotlin.stdlib.default.dependency=false
+# TODO temporary workaround for Kotlin 1.8.20+ (https://jb.gg/intellij-platform-kotlin-oom)
+kotlin.incremental.useClasspathSnapshot=false
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..249e583
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..fae0804
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..1b6c787
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original 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
+#
+#      https://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.
+#
+
+##############################################################################
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..ac1b06f
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..1c62927
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,8 @@
+pluginManagement {
+    repositories {
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
+
+rootProject.name = "struts2"
\ No newline at end of file
diff --git a/src/main/gen/OgnlIcons.java b/src/main/gen/OgnlIcons.java
new file mode 100644
index 0000000..449531f
--- /dev/null
+++ b/src/main/gen/OgnlIcons.java
@@ -0,0 +1,18 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.lang.ognl;
+
+import com.intellij.ui.IconManager;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * NOTE THIS FILE IS AUTO-GENERATED
+ * DO NOT EDIT IT BY HAND, run "Generate icon classes" configuration instead
+ */
+public final class OgnlIcons {
+  private static @NotNull Icon load(@NotNull String path, int cacheKey, int flags) {
+    return IconManager.getInstance().loadRasterizedIcon(path, OgnlIcons.class.getClassLoader(), cacheKey, flags);
+  }
+  /** 10x10 */ public static final @NotNull Icon Action_small = load("icons/action_small.svg", -592871696, 0);
+}
diff --git a/src/main/gen/OgnlTypes.java b/src/main/gen/OgnlTypes.java
new file mode 100644
index 0000000..b9e4c6c
--- /dev/null
+++ b/src/main/gen/OgnlTypes.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl;
+
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.PsiElement;
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.ognl.psi.OgnlTokenType;
+import com.intellij.lang.ognl.psi.impl.*;
+
+public interface OgnlTypes {
+
+  IElementType BINARY_EXPRESSION = new OgnlTokenType("BINARY_EXPRESSION");
+  IElementType CONDITIONAL_EXPRESSION = new OgnlTokenType("CONDITIONAL_EXPRESSION");
+  IElementType EXPRESSION = new OgnlTokenType("EXPRESSION");
+  IElementType FQN_TYPE_EXPRESSION = new OgnlTokenType("FQN_TYPE_EXPRESSION");
+  IElementType INDEXED_EXPRESSION = new OgnlTokenType("INDEXED_EXPRESSION");
+  IElementType LAMBDA_EXPRESSION = new OgnlTokenType("LAMBDA_EXPRESSION");
+  IElementType LITERAL_EXPRESSION = new OgnlTokenType("LITERAL_EXPRESSION");
+  IElementType MAP_ENTRY_ELEMENT = new OgnlTokenType("MAP_ENTRY_ELEMENT");
+  IElementType MAP_EXPRESSION = new OgnlTokenType("MAP_EXPRESSION");
+  IElementType METHOD_CALL_EXPRESSION = new OgnlTokenType("METHOD_CALL_EXPRESSION");
+  IElementType NEW_ARRAY_EXPRESSION = new OgnlTokenType("NEW_ARRAY_EXPRESSION");
+  IElementType NEW_EXPRESSION = new OgnlTokenType("NEW_EXPRESSION");
+  IElementType PARAMETER_LIST = new OgnlTokenType("PARAMETER_LIST");
+  IElementType PARENTHESIZED_EXPRESSION = new OgnlTokenType("PARENTHESIZED_EXPRESSION");
+  IElementType PROJECTION_EXPRESSION = new OgnlTokenType("PROJECTION_EXPRESSION");
+  IElementType REFERENCE_EXPRESSION = new OgnlTokenType("REFERENCE_EXPRESSION");
+  IElementType SELECTION_EXPRESSION = new OgnlTokenType("SELECTION_EXPRESSION");
+  IElementType SEQUENCE_EXPRESSION = new OgnlTokenType("SEQUENCE_EXPRESSION");
+  IElementType UNARY_EXPRESSION = new OgnlTokenType("UNARY_EXPRESSION");
+  IElementType VARIABLE_ASSIGNMENT_EXPRESSION = new OgnlTokenType("VARIABLE_ASSIGNMENT_EXPRESSION");
+  IElementType VARIABLE_EXPRESSION = new OgnlTokenType("VARIABLE_EXPRESSION");
+
+  IElementType AND = new OgnlTokenType("&");
+  IElementType AND_AND = new OgnlTokenType("&&");
+  IElementType AND_KEYWORD = new OgnlTokenType("and");
+  IElementType AT = new OgnlTokenType("@");
+  IElementType BAND_KEYWORD = new OgnlTokenType("band");
+  IElementType BIG_DECIMAL_LITERAL = new OgnlTokenType("BIG_DECIMAL_LITERAL");
+  IElementType BIG_INTEGER_LITERAL = new OgnlTokenType("BIG_INTEGER_LITERAL");
+  IElementType BOR_KEYWORD = new OgnlTokenType("bor");
+  IElementType CHARACTER_LITERAL = new OgnlTokenType("CHARACTER_LITERAL");
+  IElementType COLON = new OgnlTokenType(":");
+  IElementType COMMA = new OgnlTokenType(",");
+  IElementType DIVISION = new OgnlTokenType("/");
+  IElementType DOLLAR = new OgnlTokenType("$");
+  IElementType DOT = new OgnlTokenType(".");
+  IElementType DOUBLE_LITERAL = new OgnlTokenType("DOUBLE_LITERAL");
+  IElementType EQ = new OgnlTokenType("=");
+  IElementType EQUAL = new OgnlTokenType("==");
+  IElementType EQ_KEYWORD = new OgnlTokenType("eq");
+  IElementType EXPRESSION_END = new OgnlTokenType("EXPRESSION_END");
+  IElementType EXPRESSION_START = new OgnlTokenType("%{");
+  IElementType FALSE_KEYWORD = new OgnlTokenType("false");
+  IElementType GREATER = new OgnlTokenType(">");
+  IElementType GREATER_EQUAL = new OgnlTokenType(">=");
+  IElementType GT_EQ_KEYWORD = new OgnlTokenType("gte");
+  IElementType GT_KEYWORD = new OgnlTokenType("gt");
+  IElementType HASH = new OgnlTokenType("#");
+  IElementType IDENTIFIER = new OgnlTokenType("IDENTIFIER");
+  IElementType INSTANCEOF_KEYWORD = new OgnlTokenType("instanceof");
+  IElementType INTEGER_LITERAL = new OgnlTokenType("INTEGER_LITERAL");
+  IElementType IN_KEYWORD = new OgnlTokenType("in");
+  IElementType LBRACE = new OgnlTokenType("{");
+  IElementType LBRACKET = new OgnlTokenType("[");
+  IElementType LESS = new OgnlTokenType("<");
+  IElementType LESS_EQUAL = new OgnlTokenType("<=");
+  IElementType LPARENTH = new OgnlTokenType("(");
+  IElementType LT_EQ_KEYWORD = new OgnlTokenType("lte");
+  IElementType LT_KEYWORD = new OgnlTokenType("lt");
+  IElementType MINUS = new OgnlTokenType("-");
+  IElementType MODULO = new OgnlTokenType("%");
+  IElementType MULTIPLY = new OgnlTokenType("*");
+  IElementType NEGATE = new OgnlTokenType("!");
+  IElementType NEQ_KEYWORD = new OgnlTokenType("neq");
+  IElementType NEW_KEYWORD = new OgnlTokenType("new");
+  IElementType NOT = new OgnlTokenType("~");
+  IElementType NOT_EQUAL = new OgnlTokenType("!=");
+  IElementType NOT_IN_KEYWORD = new OgnlTokenType("not in");
+  IElementType NOT_KEYWORD = new OgnlTokenType("not");
+  IElementType NULL_KEYWORD = new OgnlTokenType("null");
+  IElementType OR = new OgnlTokenType("|");
+  IElementType OR_KEYWORD = new OgnlTokenType("or");
+  IElementType OR_OR = new OgnlTokenType("||");
+  IElementType PLUS = new OgnlTokenType("+");
+  IElementType QUESTION = new OgnlTokenType("?");
+  IElementType RBRACE = new OgnlTokenType("}");
+  IElementType RBRACKET = new OgnlTokenType("]");
+  IElementType RPARENTH = new OgnlTokenType(")");
+  IElementType SHIFT_LEFT = new OgnlTokenType("<<");
+  IElementType SHIFT_LEFT_KEYWORD = new OgnlTokenType("shl");
+  IElementType SHIFT_RIGHT = new OgnlTokenType(">>");
+  IElementType SHIFT_RIGHT_KEYWORD = new OgnlTokenType("shr");
+  IElementType SHIFT_RIGHT_LOGICAL = new OgnlTokenType(">>>");
+  IElementType SHIFT_RIGHT_LOGICAL_KEYWORD = new OgnlTokenType("ushr");
+  IElementType STRING_LITERAL = new OgnlTokenType("STRING_LITERAL");
+  IElementType TRUE_KEYWORD = new OgnlTokenType("true");
+  IElementType XOR = new OgnlTokenType("^");
+  IElementType XOR_KEYWORD = new OgnlTokenType("xor");
+
+  class Factory {
+    public static PsiElement createElement(ASTNode node) {
+      IElementType type = node.getElementType();
+      if (type == BINARY_EXPRESSION) {
+        return new OgnlBinaryExpressionImpl(node);
+      }
+      else if (type == CONDITIONAL_EXPRESSION) {
+        return new OgnlConditionalExpressionImpl(node);
+      }
+      else if (type == FQN_TYPE_EXPRESSION) {
+        return new OgnlFqnTypeExpressionImpl(node);
+      }
+      else if (type == INDEXED_EXPRESSION) {
+        return new OgnlIndexedExpressionImpl(node);
+      }
+      else if (type == LAMBDA_EXPRESSION) {
+        return new OgnlLambdaExpressionImpl(node);
+      }
+      else if (type == LITERAL_EXPRESSION) {
+        return new OgnlLiteralExpressionImpl(node);
+      }
+      else if (type == MAP_ENTRY_ELEMENT) {
+        return new OgnlMapEntryElementImpl(node);
+      }
+      else if (type == MAP_EXPRESSION) {
+        return new OgnlMapExpressionImpl(node);
+      }
+      else if (type == METHOD_CALL_EXPRESSION) {
+        return new OgnlMethodCallExpressionImpl(node);
+      }
+      else if (type == NEW_ARRAY_EXPRESSION) {
+        return new OgnlNewArrayExpressionImpl(node);
+      }
+      else if (type == NEW_EXPRESSION) {
+        return new OgnlNewExpressionImpl(node);
+      }
+      else if (type == PARAMETER_LIST) {
+        return new OgnlParameterListImpl(node);
+      }
+      else if (type == PARENTHESIZED_EXPRESSION) {
+        return new OgnlParenthesizedExpressionImpl(node);
+      }
+      else if (type == PROJECTION_EXPRESSION) {
+        return new OgnlProjectionExpressionImpl(node);
+      }
+      else if (type == REFERENCE_EXPRESSION) {
+        return new OgnlReferenceExpressionImpl(node);
+      }
+      else if (type == SELECTION_EXPRESSION) {
+        return new OgnlSelectionExpressionImpl(node);
+      }
+      else if (type == SEQUENCE_EXPRESSION) {
+        return new OgnlSequenceExpressionImpl(node);
+      }
+      else if (type == UNARY_EXPRESSION) {
+        return new OgnlUnaryExpressionImpl(node);
+      }
+      else if (type == VARIABLE_ASSIGNMENT_EXPRESSION) {
+        return new OgnlVariableAssignmentExpressionImpl(node);
+      }
+      else if (type == VARIABLE_EXPRESSION) {
+        return new OgnlVariableExpressionImpl(node);
+      }
+      throw new AssertionError("Unknown element type: " + type);
+    }
+  }
+}
diff --git a/src/main/gen/lexer/_OgnlLexer.java b/src/main/gen/lexer/_OgnlLexer.java
new file mode 100644
index 0000000..e9dec60
--- /dev/null
+++ b/src/main/gen/lexer/_OgnlLexer.java
@@ -0,0 +1,1287 @@
+// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+
+// Generated by JFlex 1.9.1 http://jflex.de/  (tweaked for IntelliJ platform)
+// source: _OgnlLexer.flex
+
+/* Generated code. Do not modify it. */
+package com.intellij.lang.ognl.lexer;
+
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.tree.IElementType;
+import java.util.*;
+import java.lang.reflect.Field;
+import org.jetbrains.annotations.NotNull;
+
+import com.intellij.psi.TokenType;
+import com.intellij.lang.ognl.OgnlTypes;
+
+
+public class _OgnlLexer implements FlexLexer {
+
+  /** This character denotes the end of file */
+  public static final int YYEOF = -1;
+
+  /** initial size of the lookahead buffer */
+  private static final int ZZ_BUFFERSIZE = 16384;
+
+  /** lexical states */
+  public static final int YYINITIAL = 0;
+  public static final int NESTED_BRACE = 2;
+  public static final int EXPR = 4;
+
+  /**
+   * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
+   * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
+   *                  at the beginning of a line
+   * l is of the form l = 2*k, k a non negative integer
+   */
+  private static final int ZZ_LEXSTATE[] = {
+     0,  0,  1,  1,  1, 1
+  };
+
+  /**
+   * Top-level table for translating characters to character classes
+   */
+  private static final int [] ZZ_CMAP_TOP = zzUnpackcmap_top();
+
+  private static final String ZZ_CMAP_TOP_PACKED_0 =
+    "\1\0\1\u0100\1\u0200\1\u0300\1\u0400\1\u0500\1\u0600\1\u0700"+
+    "\1\u0800\1\u0900\1\u0a00\1\u0b00\1\u0c00\1\u0d00\1\u0e00\1\u0f00"+
+    "\1\u1000\1\u0100\1\u1100\1\u1200\1\u1300\1\u0100\1\u1400\1\u1500"+
+    "\1\u1600\1\u1700\1\u1800\1\u1900\1\u1a00\1\u1b00\1\u0100\1\u1c00"+
+    "\1\u1d00\1\u1e00\12\u1f00\1\u2000\1\u2100\1\u2200\1\u1f00\1\u2300"+
+    "\1\u2400\2\u1f00\31\u0100\1\u2500\121\u0100\1\u2600\4\u0100\1\u2700"+
+    "\1\u0100\1\u2800\1\u2900\1\u2a00\1\u2b00\1\u2c00\1\u2d00\53\u0100"+
+    "\1\u2e00\41\u1f00\1\u0100\1\u2f00\1\u3000\1\u0100\1\u3100\1\u3200"+
+    "\1\u3300\1\u3400\1\u3500\1\u3600\1\u3700\1\u3800\1\u3900\1\u0100"+
+    "\1\u3a00\1\u3b00\1\u3c00\1\u3d00\1\u3e00\1\u3f00\1\u4000\1\u4100"+
+    "\1\u4200\1\u4300\1\u4400\1\u4500\1\u4600\1\u4700\1\u4800\1\u4900"+
+    "\1\u4a00\1\u4b00\1\u4c00\1\u4d00\1\u1f00\1\u4e00\1\u4f00\1\u5000"+
+    "\1\u5100\3\u0100\1\u5200\1\u5300\1\u5400\12\u1f00\4\u0100\1\u5500"+
+    "\17\u1f00\2\u0100\1\u5600\41\u1f00\2\u0100\1\u5700\1\u5800\2\u1f00"+
+    "\1\u5900\1\u5a00\27\u0100\1\u5b00\2\u0100\1\u5c00\1\u5d00\1\u5e00"+
+    "\1\u5f00\42\u1f00\1\u0100\1\u6000\1\u6100\11\u1f00\1\u6200\24\u1f00"+
+    "\1\u6300\1\u6400\1\u1f00\1\u6500\1\u6600\1\u6700\1\u6800\2\u1f00"+
+    "\1\u6900\5\u1f00\1\u6a00\1\u6b00\1\u6c00\5\u1f00\1\u6d00\1\u6e00"+
+    "\2\u1f00\1\u6f00\1\u1f00\1\u7000\14\u1f00\1\u7100\4\u1f00\246\u0100"+
+    "\1\u7200\20\u0100\1\u7300\1\u7400\25\u0100\1\u7500\34\u0100\1\u7600"+
+    "\14\u1f00\2\u0100\1\u7700\5\u1f00\23\u5d00\1\u7800\u0aec\u1f00\1\u7900"+
+    "\1\u7a00\u02fe\u1f00";
+
+  private static int [] zzUnpackcmap_top() {
+    int [] result = new int[4352];
+    int offset = 0;
+    offset = zzUnpackcmap_top(ZZ_CMAP_TOP_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackcmap_top(String packed, int offset, int [] result) {
+    int i = 0;       /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int count = packed.charAt(i++);
+      int value = packed.charAt(i++);
+      do result[j++] = value; while (--count > 0);
+    }
+    return j;
+  }
+
+
+  /**
+   * Second-level tables for translating characters to character classes
+   */
+  private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks();
+
+  private static final String ZZ_CMAP_BLOCKS_PACKED_0 =
+    "\11\0\1\1\1\2\1\3\1\1\1\2\16\0\4\3"+
+    "\1\4\1\5\1\6\1\7\1\10\1\11\1\12\1\13"+
+    "\1\14\1\15\1\16\1\17\1\20\1\21\1\22\1\23"+
+    "\1\24\11\25\1\26\1\3\1\27\1\30\1\31\1\32"+
+    "\1\33\1\34\1\35\2\34\1\36\2\34\1\37\22\34"+
+    "\1\40\1\41\1\42\1\43\1\0\1\3\1\44\1\45"+
+    "\1\46\1\47\1\50\1\51\1\52\1\53\1\54\2\34"+
+    "\1\55\1\34\1\56\1\57\1\34\1\60\1\61\1\62"+
+    "\1\63\1\64\1\34\1\65\1\66\2\34\1\67\1\70"+
+    "\1\71\1\72\41\0\2\3\4\0\4\3\1\34\2\3"+
+    "\1\0\7\3\1\34\4\3\1\34\5\3\27\34\1\3"+
+    "\37\34\1\3\u01ca\34\4\3\14\34\16\3\5\34\7\3"+
+    "\1\34\1\3\1\34\21\3\160\0\5\34\1\3\2\34"+
+    "\2\3\4\34\1\3\1\34\6\3\1\34\1\3\3\34"+
+    "\1\3\1\34\1\3\24\34\1\3\123\34\1\3\213\34"+
+    "\1\3\5\0\2\3\246\34\1\3\46\34\2\3\1\34"+
+    "\6\3\51\34\6\3\1\0\1\3\55\0\1\3\1\0"+
+    "\1\3\2\0\1\3\2\0\1\3\1\0\10\3\33\34"+
+    "\4\3\4\34\15\3\6\0\5\3\1\0\4\3\13\0"+
+    "\1\3\1\0\3\3\53\34\37\0\4\3\2\34\1\0"+
+    "\143\34\1\3\1\34\10\0\1\3\6\0\2\34\2\0"+
+    "\1\3\4\0\2\34\12\0\3\34\2\3\1\34\17\3"+
+    "\1\0\1\34\1\0\36\34\33\0\2\3\131\34\13\0"+
+    "\1\34\16\3\12\0\41\34\11\0\2\34\4\3\1\34"+
+    "\2\3\3\0\26\34\4\0\1\34\11\0\1\34\3\0"+
+    "\1\34\5\0\22\3\31\34\3\0\4\3\13\34\65\3"+
+    "\25\34\1\3\10\34\12\0\13\3\61\0\66\34\3\0"+
+    "\1\34\22\0\1\34\7\0\12\34\2\0\2\3\12\0"+
+    "\1\3\20\34\3\0\1\3\10\34\2\3\2\34\2\3"+
+    "\26\34\1\3\7\34\1\3\1\34\3\3\4\34\2\3"+
+    "\1\0\1\34\7\0\2\3\2\0\2\3\3\0\1\34"+
+    "\10\3\1\0\4\3\2\34\1\3\3\34\2\0\2\3"+
+    "\12\0\2\34\2\0\7\3\1\0\1\34\1\3\1\0"+
+    "\2\3\3\0\1\3\6\34\4\3\2\34\2\3\26\34"+
+    "\1\3\7\34\1\3\2\34\1\3\2\34\1\3\2\34"+
+    "\2\3\1\0\1\3\5\0\4\3\2\0\2\3\3\0"+
+    "\3\3\1\0\7\3\4\34\1\3\1\34\7\3\14\0"+
+    "\3\34\1\0\13\3\3\0\1\3\11\34\1\3\3\34"+
+    "\1\3\26\34\1\3\7\34\1\3\2\34\1\3\5\34"+
+    "\2\3\1\0\1\34\10\0\1\3\3\0\1\3\3\0"+
+    "\2\3\1\34\17\3\2\34\2\0\2\3\12\0\1\3"+
+    "\1\0\7\3\1\34\6\0\1\3\3\0\1\3\10\34"+
+    "\2\3\2\34\2\3\26\34\1\3\7\34\1\3\2\34"+
+    "\1\3\5\34\2\3\1\0\1\34\7\0\2\3\2\0"+
+    "\2\3\3\0\7\3\3\0\4\3\2\34\1\3\3\34"+
+    "\2\0\2\3\12\0\1\3\1\34\20\3\1\0\1\34"+
+    "\1\3\6\34\3\3\3\34\1\3\4\34\3\3\2\34"+
+    "\1\3\1\34\1\3\2\34\3\3\2\34\3\3\3\34"+
+    "\3\3\14\34\4\3\5\0\3\3\3\0\1\3\4\0"+
+    "\2\3\1\34\6\3\1\0\16\3\12\0\11\3\1\0"+
+    "\6\3\5\0\10\34\1\3\3\34\1\3\27\34\1\3"+
+    "\20\34\3\3\1\34\7\0\1\3\3\0\1\3\4\0"+
+    "\7\3\2\0\1\3\3\34\5\3\2\34\2\0\2\3"+
+    "\12\0\20\3\1\34\3\0\1\3\10\34\1\3\3\34"+
+    "\1\3\27\34\1\3\12\34\1\3\5\34\2\3\1\0"+
+    "\1\34\7\0\1\3\3\0\1\3\4\0\7\3\2\0"+
+    "\7\3\1\34\1\3\2\34\2\0\2\3\12\0\1\3"+
+    "\2\34\15\3\5\0\10\34\1\3\3\34\1\3\51\34"+
+    "\2\0\1\34\7\0\1\3\3\0\1\3\4\0\1\34"+
+    "\5\3\3\34\1\0\7\3\3\34\2\0\2\3\12\0"+
+    "\12\3\6\34\1\3\3\0\1\3\22\34\3\3\30\34"+
+    "\1\3\11\34\1\3\1\34\2\3\7\34\3\3\1\0"+
+    "\4\3\6\0\1\3\1\0\1\3\10\0\6\3\12\0"+
+    "\2\3\2\0\15\3\60\34\1\0\2\34\7\0\4\3"+
+    "\1\0\7\34\10\0\1\3\12\0\47\3\2\34\1\3"+
+    "\1\34\1\3\5\34\1\3\30\34\1\3\1\34\1\3"+
+    "\12\34\1\0\2\34\11\0\1\34\2\3\5\34\1\3"+
+    "\1\34\1\3\6\0\2\3\12\0\2\3\4\34\40\3"+
+    "\1\34\27\3\2\0\6\3\12\0\13\3\1\0\1\3"+
+    "\1\0\1\3\1\0\4\3\2\0\10\34\1\3\44\34"+
+    "\4\3\24\0\1\3\2\0\5\34\13\0\1\3\44\0"+
+    "\11\3\1\0\71\3\53\34\24\0\1\34\12\0\6\3"+
+    "\6\34\4\0\4\34\3\0\1\34\3\0\2\34\7\0"+
+    "\3\34\4\0\15\34\14\0\1\34\17\0\2\3\46\34"+
+    "\1\3\1\34\5\3\1\34\2\3\53\34\1\3\115\34"+
+    "\1\3\4\34\2\3\7\34\1\3\1\34\1\3\4\34"+
+    "\2\3\51\34\1\3\4\34\2\3\41\34\1\3\4\34"+
+    "\2\3\7\34\1\3\1\34\1\3\4\34\2\3\17\34"+
+    "\1\3\71\34\1\3\4\34\2\3\103\34\2\3\3\0"+
+    "\40\3\20\34\20\3\126\34\2\3\6\34\3\3\u016c\34"+
+    "\2\3\21\34\1\3\32\34\5\3\113\34\3\3\3\0"+
+    "\10\34\7\3\15\34\1\3\4\34\3\0\13\3\22\34"+
+    "\3\0\13\3\22\34\2\0\14\3\15\34\1\3\3\34"+
+    "\1\3\2\0\14\3\64\34\40\0\3\3\1\34\3\3"+
+    "\1\0\1\34\1\0\2\3\12\0\41\3\4\0\1\3"+
+    "\12\0\6\3\131\34\7\3\5\34\2\0\42\34\1\0"+
+    "\1\34\5\3\106\34\12\3\37\34\1\3\14\0\4\3"+
+    "\14\0\12\3\12\0\36\34\2\3\5\34\13\3\54\34"+
+    "\4\3\32\34\6\3\12\0\46\3\27\34\5\0\4\3"+
+    "\65\34\12\0\1\3\35\0\2\3\13\0\6\3\12\0"+
+    "\15\3\1\34\10\3\16\0\1\3\2\0\77\3\5\0"+
+    "\57\34\21\0\7\34\4\3\12\0\21\3\11\0\14\3"+
+    "\3\0\36\34\15\0\2\34\12\0\54\34\16\0\14\3"+
+    "\44\34\24\0\10\3\12\0\3\3\3\34\12\0\44\34"+
+    "\2\3\11\34\7\3\53\34\2\3\3\34\20\3\3\0"+
+    "\1\3\25\0\4\34\1\0\6\34\1\0\2\34\3\0"+
+    "\1\34\5\3\300\34\72\0\1\3\5\0\26\34\2\3"+
+    "\6\34\2\3\46\34\2\3\6\34\2\3\10\34\1\3"+
+    "\1\34\1\3\1\34\1\3\1\34\1\3\37\34\2\3"+
+    "\65\34\1\3\7\34\1\3\1\34\3\3\3\34\1\3"+
+    "\7\34\3\3\4\34\2\3\6\34\4\3\15\34\5\3"+
+    "\3\34\1\3\7\34\16\3\5\0\32\3\5\0\20\3"+
+    "\2\0\23\3\1\0\13\3\5\0\1\3\12\0\1\3"+
+    "\1\34\15\3\1\34\20\3\15\34\3\3\40\0\20\3"+
+    "\15\0\4\3\1\0\3\3\14\0\21\3\1\34\4\3"+
+    "\1\34\2\3\12\34\1\3\1\34\3\3\5\34\6\3"+
+    "\1\34\1\3\1\34\1\3\1\34\1\3\4\34\1\3"+
+    "\13\34\2\3\4\34\5\3\5\34\4\3\1\34\21\3"+
+    "\43\0\2\34\4\0\u0177\3\57\34\1\3\57\34\1\3"+
+    "\205\34\6\3\4\34\3\0\2\34\14\3\46\34\1\3"+
+    "\1\34\5\3\1\34\2\3\70\34\7\3\1\34\17\3"+
+    "\1\0\27\34\11\3\7\34\1\3\7\34\1\3\7\34"+
+    "\1\3\7\34\1\3\7\34\1\3\7\34\1\3\7\34"+
+    "\1\3\7\34\1\3\40\0\57\3\1\34\325\3\2\34"+
+    "\1\0\31\3\17\0\1\3\5\34\2\3\3\0\2\34"+
+    "\4\3\126\34\2\3\2\0\2\3\3\34\1\3\132\34"+
+    "\1\3\4\34\5\3\53\34\1\3\136\34\21\3\33\34"+
+    "\5\0\60\3\306\34\12\0\100\3\360\34\15\0\3\3"+
+    "\215\34\103\3\56\34\2\3\15\34\3\3\20\34\12\0"+
+    "\2\34\24\3\57\34\1\0\4\3\12\0\1\3\37\34"+
+    "\2\0\106\34\14\0\45\3\11\34\2\3\147\34\2\3"+
+    "\65\34\2\3\5\34\4\0\52\3\2\0\13\34\1\0"+
+    "\3\34\1\0\4\34\1\0\27\34\5\0\4\3\1\0"+
+    "\13\3\1\0\7\3\64\34\14\3\2\0\62\34\22\0"+
+    "\12\3\12\0\6\3\22\0\6\34\3\3\1\34\1\3"+
+    "\2\34\13\0\34\34\10\0\2\3\27\34\15\0\14\3"+
+    "\35\34\3\3\4\0\57\34\16\0\16\3\1\34\12\0"+
+    "\6\3\5\34\1\0\12\34\12\0\5\34\1\3\51\34"+
+    "\16\0\11\3\3\34\1\0\10\34\2\0\2\3\12\0"+
+    "\6\3\27\34\3\3\1\34\3\0\62\34\1\0\1\34"+
+    "\3\0\2\34\2\0\5\34\2\0\1\34\1\0\1\34"+
+    "\30\3\3\34\2\3\13\34\5\0\2\3\3\34\2\0"+
+    "\12\3\6\34\2\3\6\34\2\3\6\34\11\3\7\34"+
+    "\1\3\7\34\1\3\53\34\1\3\14\34\2\0\6\3"+
+    "\163\34\10\0\1\3\2\0\2\3\12\0\6\3\244\34"+
+    "\14\3\27\34\4\3\61\34\4\3\156\34\2\3\152\34"+
+    "\46\3\7\34\14\3\5\34\5\3\1\34\1\0\12\34"+
+    "\1\3\15\34\1\3\5\34\1\3\1\34\1\3\2\34"+
+    "\1\3\2\34\1\3\154\34\41\3\153\34\22\3\100\34"+
+    "\2\3\66\34\50\3\14\34\1\0\3\3\20\0\20\3"+
+    "\20\0\3\3\2\0\30\3\3\0\31\3\1\0\6\3"+
+    "\5\34\1\3\207\34\2\3\1\0\4\3\1\0\13\3"+
+    "\12\0\7\3\32\34\4\3\1\0\1\3\32\34\13\3"+
+    "\131\34\3\3\6\34\2\3\6\34\2\3\6\34\2\3"+
+    "\3\34\3\3\2\0\3\3\2\0\22\3\3\0\4\3"+
+    "\14\34\1\3\32\34\1\3\23\34\1\3\2\34\1\3"+
+    "\17\34\2\3\16\34\42\3\173\34\105\3\65\0\210\3"+
+    "\1\0\202\3\35\34\3\3\61\34\17\3\1\0\37\3"+
+    "\40\34\15\3\24\34\1\0\10\34\1\0\5\3\46\34"+
+    "\5\0\5\3\36\34\2\3\44\34\4\3\10\34\1\3"+
+    "\5\0\52\3\236\34\2\3\12\0\6\3\44\34\4\3"+
+    "\44\34\4\3\50\34\10\3\64\34\234\3\67\34\11\3"+
+    "\26\34\12\3\10\34\230\3\6\34\2\3\1\34\1\3"+
+    "\54\34\1\3\2\34\3\3\1\34\2\3\27\34\12\3"+
+    "\27\34\11\3\37\34\101\3\23\34\1\3\2\34\12\3"+
+    "\26\34\12\3\32\34\106\3\70\34\6\3\2\34\100\3"+
+    "\1\34\3\0\1\3\2\0\5\3\4\0\4\34\1\3"+
+    "\3\34\1\3\35\34\2\3\3\0\4\3\1\0\40\3"+
+    "\35\34\3\3\35\34\43\3\10\34\1\3\34\34\2\0"+
+    "\31\3\66\34\12\3\26\34\12\3\23\34\15\3\22\34"+
+    "\156\3\111\34\67\3\63\34\15\3\63\34\15\3\44\34"+
+    "\4\0\10\3\12\0\u0146\3\52\0\1\3\2\0\3\3"+
+    "\2\0\116\3\35\34\12\3\1\34\10\3\26\34\13\0"+
+    "\137\3\25\0\33\3\27\34\11\3\3\0\65\34\17\0"+
+    "\37\3\12\0\17\3\4\0\55\34\13\0\2\3\1\0"+
+    "\17\3\1\0\2\3\31\34\7\3\12\0\6\3\3\0"+
+    "\44\34\16\0\1\3\12\0\4\3\1\34\3\0\10\3"+
+    "\43\34\1\0\2\3\1\34\11\3\3\0\60\34\16\0"+
+    "\4\34\4\3\4\0\1\3\14\0\1\34\1\3\1\34"+
+    "\43\3\22\34\1\3\31\34\14\0\6\3\1\0\101\3"+
+    "\7\34\1\3\1\34\1\3\4\34\1\3\17\34\1\3"+
+    "\12\34\7\3\57\34\14\0\5\3\12\0\6\3\4\0"+
+    "\1\3\10\34\2\3\2\34\2\3\26\34\1\3\7\34"+
+    "\1\3\2\34\1\3\5\34\1\3\2\0\1\34\7\0"+
+    "\2\3\2\0\2\3\3\0\2\3\1\34\6\3\1\0"+
+    "\5\3\5\34\2\0\2\3\7\0\3\3\5\0\213\3"+
+    "\65\34\22\0\4\34\5\3\12\0\4\3\1\0\1\34"+
+    "\2\0\36\3\60\34\24\0\2\34\1\3\1\34\10\3"+
+    "\12\0\246\3\57\34\7\0\2\3\11\0\27\3\4\34"+
+    "\2\0\42\3\60\34\21\0\3\3\1\34\13\3\12\0"+
+    "\46\3\53\34\15\0\1\34\7\3\12\0\66\3\33\34"+
+    "\2\3\17\0\4\3\12\0\306\3\54\34\17\0\145\3"+
+    "\100\34\12\0\25\3\1\34\7\0\2\3\1\0\2\3"+
+    "\10\0\1\3\2\0\1\3\36\0\1\3\2\0\2\3"+
+    "\11\0\14\3\12\0\106\3\10\34\2\3\47\34\7\0"+
+    "\2\3\7\0\1\34\1\3\1\34\1\0\33\3\1\34"+
+    "\12\0\50\34\7\0\1\34\4\0\10\3\1\0\10\3"+
+    "\1\34\13\0\56\34\20\0\3\3\1\34\42\3\71\34"+
+    "\7\3\11\34\1\3\45\34\10\0\1\3\10\0\1\34"+
+    "\17\3\12\0\30\3\36\34\2\3\26\0\1\3\16\0"+
+    "\111\3\7\34\1\3\2\34\1\3\46\34\6\0\3\3"+
+    "\1\0\1\3\2\0\1\3\7\0\1\34\1\0\10\3"+
+    "\12\0\6\3\6\34\1\3\2\34\1\3\40\34\5\0"+
+    "\1\3\2\0\1\3\5\0\1\34\7\3\12\0\u0136\3"+
+    "\23\34\4\0\271\3\1\0\54\3\4\0\37\3\232\34"+
+    "\146\3\157\0\21\3\304\34\274\3\57\34\1\3\11\0"+
+    "\307\3\107\34\271\3\71\34\7\3\37\34\1\3\12\0"+
+    "\146\3\36\34\2\3\5\0\13\3\60\34\7\0\11\3"+
+    "\4\34\14\3\12\0\11\3\25\34\5\3\23\34\260\3"+
+    "\100\34\200\3\113\34\4\3\1\0\1\34\67\0\7\3"+
+    "\4\0\15\34\100\3\2\34\1\3\1\34\1\0\13\3"+
+    "\2\0\16\3\370\34\10\3\363\34\u01e3\0\52\3\11\0"+
+    "\367\3\37\34\61\3\3\34\21\3\4\34\10\3\u018c\34"+
+    "\4\3\153\34\5\3\15\34\3\3\11\34\7\3\12\34"+
+    "\3\3\2\0\1\3\4\0\301\3\5\0\3\3\26\0"+
+    "\2\3\7\0\36\3\4\0\224\3\3\0\273\3\125\34"+
+    "\1\3\107\34\1\3\2\34\2\3\1\34\2\3\2\34"+
+    "\2\3\4\34\1\3\14\34\1\3\1\34\1\3\7\34"+
+    "\1\3\101\34\1\3\4\34\2\3\10\34\1\3\7\34"+
+    "\1\3\34\34\1\3\4\34\1\3\5\34\1\3\1\34"+
+    "\3\3\7\34\1\3\u0154\34\2\3\31\34\1\3\31\34"+
+    "\1\3\37\34\1\3\31\34\1\3\37\34\1\3\31\34"+
+    "\1\3\37\34\1\3\31\34\1\3\37\34\1\3\31\34"+
+    "\1\3\10\34\2\3\151\0\4\3\62\0\10\3\1\0"+
+    "\16\3\1\0\26\3\5\0\1\3\17\0\120\3\7\0"+
+    "\1\3\21\0\2\3\7\0\1\3\2\0\1\3\5\0"+
+    "\325\3\55\34\3\3\7\0\7\34\2\3\12\0\4\3"+
+    "\1\34\u0171\3\54\34\16\0\5\3\1\0\305\34\13\3"+
+    "\7\0\51\3\104\34\7\0\1\34\4\3\12\0\u0156\3"+
+    "\1\0\117\3\4\34\1\3\33\34\1\3\2\34\1\3"+
+    "\1\34\2\3\1\34\1\3\12\34\1\3\4\34\1\3"+
+    "\1\34\1\3\1\34\6\3\1\34\4\3\1\34\1\3"+
+    "\1\34\1\3\1\34\1\3\3\34\1\3\2\34\1\3"+
+    "\1\34\2\3\1\34\1\3\1\34\1\3\1\34\1\3"+
+    "\1\34\1\3\1\34\1\3\2\34\1\3\1\34\2\3"+
+    "\4\34\1\3\7\34\1\3\4\34\1\3\4\34\1\3"+
+    "\1\34\1\3\12\34\1\3\21\34\5\3\3\34\1\3"+
+    "\5\34\1\3\21\34\u0134\3\12\0\6\3\327\34\7\0"+
+    "\42\3\65\34\13\3\336\34\2\3\u0182\34\16\3\u0131\34"+
+    "\37\3\36\34\342\3\113\0\266\3\1\0\36\3\140\0"+
+    "\200\3\360\0\20\3";
+
+  private static int [] zzUnpackcmap_blocks() {
+    int [] result = new int[31488];
+    int offset = 0;
+    offset = zzUnpackcmap_blocks(ZZ_CMAP_BLOCKS_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) {
+    int i = 0;       /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int count = packed.charAt(i++);
+      int value = packed.charAt(i++);
+      do result[j++] = value; while (--count > 0);
+    }
+    return j;
+  }
+
+  /**
+   * Translates DFA states to action switch labels.
+   */
+  private static final int [] ZZ_ACTION = zzUnpackAction();
+
+  private static final String ZZ_ACTION_PACKED_0 =
+    "\2\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7"+
+    "\1\10\1\11\1\12\1\13\1\14\1\15\1\16\1\17"+
+    "\1\20\1\21\2\22\1\23\1\24\1\25\1\26\1\27"+
+    "\1\30\1\31\1\32\1\33\1\34\15\31\1\35\1\36"+
+    "\1\37\1\7\1\40\1\41\2\4\1\42\1\43\2\11"+
+    "\1\44\1\0\1\44\1\45\1\46\1\47\1\50\1\51"+
+    "\1\52\3\31\1\53\1\31\1\54\1\55\1\56\3\31"+
+    "\1\57\4\31\1\60\1\61\1\44\1\62\1\63\1\31"+
+    "\1\64\1\31\1\65\1\31\1\66\1\67\1\70\1\71"+
+    "\1\31\1\72\1\73\2\31\1\74\1\75\2\31\1\0"+
+    "\1\76\1\77\1\100\1\101\1\31\1\0\1\31\1\102"+
+    "\3\31\1\103";
+
+  private static int [] zzUnpackAction() {
+    int [] result = new int[117];
+    int offset = 0;
+    offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackAction(String packed, int offset, int [] result) {
+    int i = 0;       /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int count = packed.charAt(i++);
+      int value = packed.charAt(i++);
+      do result[j++] = value; while (--count > 0);
+    }
+    return j;
+  }
+
+
+  /**
+   * Translates a state to a row index in the transition table
+   */
+  private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
+
+  private static final String ZZ_ROWMAP_PACKED_0 =
+    "\0\0\0\73\0\166\0\261\0\354\0\u0127\0\166\0\166"+
+    "\0\u0162\0\u019d\0\u01d8\0\166\0\166\0\166\0\166\0\166"+
+    "\0\166\0\u0213\0\166\0\u024e\0\u0289\0\166\0\u02c4\0\u02ff"+
+    "\0\u033a\0\166\0\166\0\u0375\0\166\0\166\0\166\0\u03b0"+
+    "\0\u03eb\0\u0426\0\u0461\0\u049c\0\u04d7\0\u0512\0\u054d\0\u0588"+
+    "\0\u05c3\0\u05fe\0\u0639\0\u0674\0\166\0\u06af\0\166\0\166"+
+    "\0\166\0\166\0\166\0\u06ea\0\166\0\166\0\166\0\u0725"+
+    "\0\u0760\0\u079b\0\u07d6\0\166\0\166\0\166\0\166\0\166"+
+    "\0\u0811\0\u084c\0\u0887\0\u08c2\0\u0375\0\u08fd\0\u0938\0\u0973"+
+    "\0\u09ae\0\u09e9\0\u0a24\0\u0a5f\0\u0375\0\u0a9a\0\u0ad5\0\u0b10"+
+    "\0\u0b4b\0\166\0\166\0\u0b86\0\166\0\u0375\0\u0bc1\0\u0375"+
+    "\0\u0bfc\0\u0375\0\u0c37\0\u0375\0\u0375\0\u0375\0\u0c72\0\u0cad"+
+    "\0\u0375\0\u0375\0\u0ce8\0\u0d23\0\u0375\0\u0375\0\u0d5e\0\u0d99"+
+    "\0\u0dd4\0\u0375\0\u0375\0\u0375\0\u0375\0\u0e0f\0\u0e4a\0\u0e85"+
+    "\0\166\0\u0ec0\0\u0efb\0\u0f36\0\u0375";
+
+  private static int [] zzUnpackRowMap() {
+    int [] result = new int[117];
+    int offset = 0;
+    offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackRowMap(String packed, int offset, int [] result) {
+    int i = 0;  /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length() - 1;
+    while (i < l) {
+      int high = packed.charAt(i++) << 16;
+      result[j++] = high | packed.charAt(i++);
+    }
+    return j;
+  }
+
+  /**
+   * The transition table of the DFA
+   */
+  private static final int [] ZZ_TRANS = zzUnpacktrans();
+
+  private static final String ZZ_TRANS_PACKED_0 =
+    "\1\3\2\4\1\3\1\4\1\5\1\6\1\7\1\10"+
+    "\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1\20"+
+    "\1\21\1\22\1\23\1\24\1\25\1\26\1\27\1\30"+
+    "\1\31\1\32\1\33\4\34\1\35\1\3\1\36\1\37"+
+    "\1\40\1\41\2\34\1\42\1\43\1\44\1\34\1\45"+
+    "\1\46\1\47\1\50\2\34\1\51\1\52\1\53\1\34"+
+    "\1\54\1\55\1\56\1\3\1\57\1\3\2\4\1\3"+
+    "\1\4\1\5\1\6\1\7\1\10\1\60\1\12\1\13"+
+    "\1\14\1\15\1\16\1\17\1\20\1\21\1\22\1\23"+
+    "\1\24\1\25\1\26\1\27\1\30\1\31\1\32\1\33"+
+    "\4\34\1\35\1\3\1\36\1\37\1\40\1\41\2\34"+
+    "\1\42\1\43\1\44\1\34\1\45\1\46\1\47\1\50"+
+    "\2\34\1\51\1\52\1\53\1\34\1\54\1\55\1\56"+
+    "\1\61\1\57\74\0\2\4\1\0\1\4\116\0\1\62"+
+    "\42\0\2\6\1\0\3\6\1\63\32\6\1\64\31\6"+
+    "\67\0\1\65\15\0\1\66\60\0\2\13\1\0\10\13"+
+    "\1\67\25\13\1\70\31\13\24\0\2\71\67\0\1\71"+
+    "\1\0\2\72\10\0\1\73\1\74\10\0\1\73\2\0"+
+    "\1\74\41\0\1\71\1\0\2\25\10\0\1\73\1\74"+
+    "\10\0\1\73\2\0\1\74\46\0\1\75\1\76\72\0"+
+    "\1\77\72\0\1\100\1\101\41\0\1\34\7\0\1\34"+
+    "\13\0\2\34\6\0\4\34\4\0\23\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\12\34"+
+    "\1\102\10\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\1\103\12\34\1\104\7\34\4\0"+
+    "\1\34\7\0\1\34\13\0\2\34\6\0\4\34\4\0"+
+    "\14\34\1\105\6\34\4\0\1\34\7\0\1\34\13\0"+
+    "\2\34\6\0\4\34\4\0\1\106\22\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\17\34"+
+    "\1\107\3\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\12\34\1\110\10\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\17\34"+
+    "\1\111\3\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\4\34\1\112\6\34\1\113\4\34"+
+    "\1\114\2\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\15\34\1\115\5\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\7\34"+
+    "\1\116\13\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\15\34\1\117\5\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\16\34"+
+    "\1\120\4\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\13\34\1\121\7\34\74\0\1\122"+
+    "\2\0\2\6\1\0\70\6\2\13\1\0\70\13\24\0"+
+    "\2\71\7\0\1\123\1\73\6\0\1\123\2\0\1\73"+
+    "\44\0\1\71\1\0\2\72\10\0\1\73\11\0\1\73"+
+    "\41\0\1\124\1\0\1\124\2\0\2\124\7\0\1\123"+
+    "\7\0\1\123\56\0\1\125\41\0\1\34\7\0\1\34"+
+    "\13\0\2\34\6\0\4\34\4\0\3\34\1\126\17\34"+
+    "\4\0\1\34\7\0\1\34\13\0\2\34\6\0\4\34"+
+    "\4\0\12\34\1\127\10\34\4\0\1\34\7\0\1\34"+
+    "\13\0\2\34\6\0\4\34\4\0\15\34\1\130\5\34"+
+    "\4\0\1\34\7\0\1\34\13\0\2\34\6\0\4\34"+
+    "\4\0\11\34\1\131\11\34\4\0\1\34\7\0\1\34"+
+    "\13\0\2\34\6\0\4\34\4\0\4\34\1\132\16\34"+
+    "\4\0\1\34\7\0\1\34\13\0\2\34\6\0\4\34"+
+    "\4\0\16\34\1\133\4\34\4\0\1\34\7\0\1\34"+
+    "\13\0\2\34\6\0\4\34\4\0\4\34\1\134\16\34"+
+    "\4\0\1\34\7\0\1\34\13\0\2\34\6\0\4\34"+
+    "\4\0\14\34\1\135\4\34\1\136\1\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\17\34"+
+    "\1\137\3\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\11\34\1\140\11\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\11\34"+
+    "\1\141\3\34\1\142\5\34\4\0\1\34\7\0\1\34"+
+    "\13\0\2\34\6\0\4\34\4\0\20\34\1\143\2\34"+
+    "\4\0\1\34\7\0\1\34\13\0\2\34\6\0\4\34"+
+    "\4\0\7\34\1\144\13\34\4\0\1\34\7\0\1\34"+
+    "\13\0\2\34\6\0\4\34\4\0\15\34\1\145\5\34"+
+    "\30\0\2\124\7\0\1\123\7\0\1\123\25\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\3\34"+
+    "\1\146\17\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\16\34\1\147\4\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\17\34"+
+    "\1\150\3\34\4\0\1\34\3\0\1\151\3\0\1\34"+
+    "\13\0\2\34\6\0\4\34\4\0\23\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\11\34"+
+    "\1\152\11\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\4\34\1\153\16\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\15\34"+
+    "\1\154\5\34\4\0\1\34\7\0\1\34\13\0\2\34"+
+    "\6\0\4\34\4\0\4\34\1\155\16\34\4\0\1\34"+
+    "\7\0\1\34\13\0\2\34\6\0\4\34\4\0\1\156"+
+    "\22\34\60\0\1\157\16\0\1\34\7\0\1\34\13\0"+
+    "\2\34\6\0\4\34\4\0\12\34\1\160\10\34\62\0"+
+    "\1\161\14\0\1\34\7\0\1\34\13\0\2\34\6\0"+
+    "\4\34\4\0\2\34\1\162\20\34\4\0\1\34\7\0"+
+    "\1\34\13\0\2\34\6\0\4\34\4\0\4\34\1\163"+
+    "\16\34\4\0\1\34\7\0\1\34\13\0\2\34\6\0"+
+    "\4\34\4\0\13\34\1\164\7\34\4\0\1\34\7\0"+
+    "\1\34\13\0\2\34\6\0\4\34\4\0\5\34\1\165"+
+    "\15\34\4\0";
+
+  private static int [] zzUnpacktrans() {
+    int [] result = new int[3953];
+    int offset = 0;
+    offset = zzUnpacktrans(ZZ_TRANS_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpacktrans(String packed, int offset, int [] result) {
+    int i = 0;       /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int count = packed.charAt(i++);
+      int value = packed.charAt(i++);
+      value--;
+      do result[j++] = value; while (--count > 0);
+    }
+    return j;
+  }
+
+
+  /* error codes */
+  private static final int ZZ_UNKNOWN_ERROR = 0;
+  private static final int ZZ_NO_MATCH = 1;
+  private static final int ZZ_PUSHBACK_2BIG = 2;
+
+  /* error messages for the codes above */
+  private static final String[] ZZ_ERROR_MSG = {
+    "Unknown internal scanner error",
+    "Error: could not match input",
+    "Error: pushback value was too large"
+  };
+
+  /**
+   * ZZ_ATTRIBUTE[aState] contains the attributes of state {@code aState}
+   */
+  private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
+
+  private static final String ZZ_ATTRIBUTE_PACKED_0 =
+    "\2\0\1\11\3\1\2\11\3\1\6\11\1\1\1\11"+
+    "\2\1\1\11\3\1\2\11\1\1\3\11\15\1\1\11"+
+    "\1\1\5\11\1\1\3\11\2\1\1\0\1\1\5\11"+
+    "\21\1\2\11\1\1\1\11\23\1\1\0\5\1\1\0"+
+    "\1\1\1\11\4\1";
+
+  private static int [] zzUnpackAttribute() {
+    int [] result = new int[117];
+    int offset = 0;
+    offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
+    return result;
+  }
+
+  private static int zzUnpackAttribute(String packed, int offset, int [] result) {
+    int i = 0;       /* index in packed string  */
+    int j = offset;  /* index in unpacked array */
+    int l = packed.length();
+    while (i < l) {
+      int count = packed.charAt(i++);
+      int value = packed.charAt(i++);
+      do result[j++] = value; while (--count > 0);
+    }
+    return j;
+  }
+
+  /** the input device */
+  private java.io.Reader zzReader;
+
+  /** the current state of the DFA */
+  private int zzState;
+
+  /** the current lexical state */
+  private int zzLexicalState = YYINITIAL;
+
+  /** this buffer contains the current text to be matched and is
+      the source of the yytext() string */
+  private CharSequence zzBuffer = "";
+
+  /** the textposition at the last accepting state */
+  private int zzMarkedPos;
+
+  /** the current text position in the buffer */
+  private int zzCurrentPos;
+
+  /** startRead marks the beginning of the yytext() string in the buffer */
+  private int zzStartRead;
+
+  /** endRead marks the last character in the buffer, that has been read
+      from input */
+  private int zzEndRead;
+
+  /** zzAtEOF == true <=> the scanner is at the EOF */
+  private boolean zzAtEOF;
+
+  /** Number of newlines encountered up to the start of the matched text. */
+  @SuppressWarnings("unused")
+  private int yyline;
+
+  /** Number of characters from the last newline up to the start of the matched text. */
+  @SuppressWarnings("unused")
+  protected int yycolumn;
+
+  /** Number of characters up to the start of the matched text. */
+  @SuppressWarnings("unused")
+  private long yychar;
+
+  /** Whether the scanner is currently at the beginning of a line. */
+  @SuppressWarnings("unused")
+  private boolean zzAtBOL = true;
+
+  /** Whether the user-EOF-code has already been executed. */
+  private boolean zzEOFDone;
+
+  /* user code: */
+  public _OgnlLexer(){
+    this((java.io.Reader)null);
+  }
+
+  private static final class State {
+    final int lBraceCount;
+    final int state;
+
+    private State(int state, int lBraceCount) {
+        this.state = state;
+        this.lBraceCount = lBraceCount;
+    }
+
+    @Override
+    public String toString() {
+        return "yystate = " + state + (lBraceCount == 0 ? "" : "lBraceCount = " + lBraceCount);
+    }
+  }
+
+  private final Stack<State> myStateStack = new Stack<>();
+  private int myLeftBraceCount;
+
+  protected void resetInternal() {
+    myLeftBraceCount = 0;
+    myStateStack.clear();
+  }
+
+  private void pushState(int newState) {
+    myStateStack.push(new State(yystate(), myLeftBraceCount));
+    myLeftBraceCount = 0;
+    yybegin(newState);
+  }
+
+  private void popState() {
+    if (myStateStack.empty()) return;
+
+    State state = myStateStack.pop();
+    myLeftBraceCount = state.lBraceCount;
+    yybegin(state.state);
+  }
+
+
+  /**
+   * Creates a new scanner
+   *
+   * @param   in  the java.io.Reader to read input from.
+   */
+  public _OgnlLexer(java.io.Reader in) {
+    this.zzReader = in;
+  }
+
+
+  /** Returns the maximum size of the scanner buffer, which limits the size of tokens. */
+  private int zzMaxBufferLen() {
+    return Integer.MAX_VALUE;
+  }
+
+  /**  Whether the scanner buffer can grow to accommodate a larger token. */
+  private boolean zzCanGrow() {
+    return true;
+  }
+
+  /**
+   * Translates raw input code points to DFA table row
+   */
+  private static int zzCMap(int input) {
+    int offset = input & 255;
+    return offset == input ? ZZ_CMAP_BLOCKS[offset] : ZZ_CMAP_BLOCKS[ZZ_CMAP_TOP[input >> 8] | offset];
+  }
+
+  public final int getTokenStart() {
+    return zzStartRead;
+  }
+
+  public final int getTokenEnd() {
+    return getTokenStart() + yylength();
+  }
+
+  public void reset(CharSequence buffer, int start, int end, int initialState) {
+    zzBuffer = buffer;
+    zzCurrentPos = zzMarkedPos = zzStartRead = start;
+    zzAtEOF  = false;
+    zzAtBOL = true;
+    zzEndRead = end;
+    yybegin(initialState);
+  }
+
+  /**
+   * Refills the input buffer.
+   *
+   * @return      {@code false}, iff there was new input.
+   *
+   * @exception   java.io.IOException  if any I/O-Error occurs
+   */
+  private boolean zzRefill() throws java.io.IOException {
+    return true;
+  }
+
+
+  /**
+   * Returns the current lexical state.
+   */
+  public final int yystate() {
+    return zzLexicalState;
+  }
+
+
+  /**
+   * Enters a new lexical state
+   *
+   * @param newState the new lexical state
+   */
+  public final void yybegin(int newState) {
+    zzLexicalState = newState;
+  }
+
+
+  /**
+   * Returns the text matched by the current regular expression.
+   */
+  public final CharSequence yytext() {
+    return zzBuffer.subSequence(zzStartRead, zzMarkedPos);
+  }
+
+
+  /**
+   * Returns the character at position {@code pos} from the
+   * matched text.
+   *
+   * It is equivalent to yytext().charAt(pos), but faster
+   *
+   * @param pos the position of the character to fetch.
+   *            A value from 0 to yylength()-1.
+   *
+   * @return the character at position pos
+   */
+  public final char yycharat(int pos) {
+    return zzBuffer.charAt(zzStartRead+pos);
+  }
+
+
+  /**
+   * Returns the length of the matched text region.
+   */
+  public final int yylength() {
+    return zzMarkedPos-zzStartRead;
+  }
+
+
+  /**
+   * Reports an error that occurred while scanning.
+   *
+   * In a wellformed scanner (no or only correct usage of
+   * yypushback(int) and a match-all fallback rule) this method
+   * will only be called with things that "Can't Possibly Happen".
+   * If this method is called, something is seriously wrong
+   * (e.g. a JFlex bug producing a faulty scanner etc.).
+   *
+   * Usual syntax/scanner level error handling should be done
+   * in error fallback rules.
+   *
+   * @param   errorCode  the code of the errormessage to display
+   */
+  private void zzScanError(int errorCode) {
+    String message;
+    try {
+      message = ZZ_ERROR_MSG[errorCode];
+    }
+    catch (ArrayIndexOutOfBoundsException e) {
+      message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
+    }
+
+    throw new Error(message);
+  }
+
+
+  /**
+   * Pushes the specified amount of characters back into the input stream.
+   *
+   * They will be read again by then next call of the scanning method
+   *
+   * @param number  the number of characters to be read again.
+   *                This number must not be greater than yylength()!
+   */
+  public void yypushback(int number)  {
+    if ( number > yylength() )
+      zzScanError(ZZ_PUSHBACK_2BIG);
+
+    zzMarkedPos -= number;
+  }
+
+
+  /**
+   * Contains user EOF-code, which will be executed exactly once,
+   * when the end of file is reached
+   */
+  private void zzDoEOF() {
+    if (!zzEOFDone) {
+      zzEOFDone = true;
+    
+  resetInternal();
+    }
+  }
+
+
+  /**
+   * Resumes scanning until the next regular expression is matched,
+   * the end of input is encountered or an I/O-Error occurs.
+   *
+   * @return      the next token
+   * @exception   java.io.IOException  if any I/O-Error occurs
+   */
+  public IElementType advance() throws java.io.IOException
+  {
+    int zzInput;
+    int zzAction;
+
+    // cached fields:
+    int zzCurrentPosL;
+    int zzMarkedPosL;
+    int zzEndReadL = zzEndRead;
+    CharSequence zzBufferL = zzBuffer;
+
+    int [] zzTransL = ZZ_TRANS;
+    int [] zzRowMapL = ZZ_ROWMAP;
+    int [] zzAttrL = ZZ_ATTRIBUTE;
+
+    while (true) {
+      zzMarkedPosL = zzMarkedPos;
+
+      zzAction = -1;
+
+      zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
+
+      zzState = ZZ_LEXSTATE[zzLexicalState];
+
+      // set up zzAction for empty match case:
+      int zzAttributes = zzAttrL[zzState];
+      if ( (zzAttributes & 1) == 1 ) {
+        zzAction = zzState;
+      }
+
+
+      zzForAction: {
+        while (true) {
+
+          if (zzCurrentPosL < zzEndReadL) {
+            zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL);
+            zzCurrentPosL += Character.charCount(zzInput);
+          }
+          else if (zzAtEOF) {
+            zzInput = YYEOF;
+            break zzForAction;
+          }
+          else {
+            // store back cached positions
+            zzCurrentPos  = zzCurrentPosL;
+            zzMarkedPos   = zzMarkedPosL;
+            boolean eof = zzRefill();
+            // get translated positions and possibly new buffer
+            zzCurrentPosL  = zzCurrentPos;
+            zzMarkedPosL   = zzMarkedPos;
+            zzBufferL      = zzBuffer;
+            zzEndReadL     = zzEndRead;
+            if (eof) {
+              zzInput = YYEOF;
+              break zzForAction;
+            }
+            else {
+              zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL);
+              zzCurrentPosL += Character.charCount(zzInput);
+            }
+          }
+          int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMap(zzInput) ];
+          if (zzNext == -1) break zzForAction;
+          zzState = zzNext;
+
+          zzAttributes = zzAttrL[zzState];
+          if ( (zzAttributes & 1) == 1 ) {
+            zzAction = zzState;
+            zzMarkedPosL = zzCurrentPosL;
+            if ( (zzAttributes & 8) == 8 ) break zzForAction;
+          }
+
+        }
+      }
+
+      // store back cached position
+      zzMarkedPos = zzMarkedPosL;
+
+      if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
+        zzAtEOF = true;
+            zzDoEOF();
+        return null;
+      }
+      else {
+        switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+          case 1:
+            { return TokenType.BAD_CHARACTER;
+            }
+          // fall through
+          case 68: break;
+          case 2:
+            { return TokenType.WHITE_SPACE;
+            }
+          // fall through
+          case 69: break;
+          case 3:
+            { return OgnlTypes.NEGATE;
+            }
+          // fall through
+          case 70: break;
+          case 4:
+            { return OgnlTypes.STRING_LITERAL;
+            }
+          // fall through
+          case 71: break;
+          case 5:
+            { return OgnlTypes.HASH;
+            }
+          // fall through
+          case 72: break;
+          case 6:
+            { return OgnlTypes.DOLLAR;
+            }
+          // fall through
+          case 73: break;
+          case 7:
+            { return OgnlTypes.MODULO;
+            }
+          // fall through
+          case 74: break;
+          case 8:
+            { return OgnlTypes.AND;
+            }
+          // fall through
+          case 75: break;
+          case 9:
+            { return OgnlTypes.CHARACTER_LITERAL;
+            }
+          // fall through
+          case 76: break;
+          case 10:
+            { return OgnlTypes.LPARENTH;
+            }
+          // fall through
+          case 77: break;
+          case 11:
+            { return OgnlTypes.RPARENTH;
+            }
+          // fall through
+          case 78: break;
+          case 12:
+            { return OgnlTypes.MULTIPLY;
+            }
+          // fall through
+          case 79: break;
+          case 13:
+            { return OgnlTypes.PLUS;
+            }
+          // fall through
+          case 80: break;
+          case 14:
+            { return OgnlTypes.COMMA;
+            }
+          // fall through
+          case 81: break;
+          case 15:
+            { return OgnlTypes.MINUS;
+            }
+          // fall through
+          case 82: break;
+          case 16:
+            { return OgnlTypes.DOT;
+            }
+          // fall through
+          case 83: break;
+          case 17:
+            { return OgnlTypes.DIVISION;
+            }
+          // fall through
+          case 84: break;
+          case 18:
+            { return OgnlTypes.INTEGER_LITERAL;
+            }
+          // fall through
+          case 85: break;
+          case 19:
+            { return OgnlTypes.COLON;
+            }
+          // fall through
+          case 86: break;
+          case 20:
+            { return OgnlTypes.LESS;
+            }
+          // fall through
+          case 87: break;
+          case 21:
+            { return OgnlTypes.EQ;
+            }
+          // fall through
+          case 88: break;
+          case 22:
+            { return OgnlTypes.GREATER;
+            }
+          // fall through
+          case 89: break;
+          case 23:
+            { return OgnlTypes.QUESTION;
+            }
+          // fall through
+          case 90: break;
+          case 24:
+            { return OgnlTypes.AT;
+            }
+          // fall through
+          case 91: break;
+          case 25:
+            { return OgnlTypes.IDENTIFIER;
+            }
+          // fall through
+          case 92: break;
+          case 26:
+            { return OgnlTypes.LBRACKET;
+            }
+          // fall through
+          case 93: break;
+          case 27:
+            { return OgnlTypes.RBRACKET;
+            }
+          // fall through
+          case 94: break;
+          case 28:
+            { return OgnlTypes.XOR;
+            }
+          // fall through
+          case 95: break;
+          case 29:
+            { myLeftBraceCount++;
+  pushState(NESTED_BRACE);
+  return OgnlTypes.LBRACE;
+            }
+          // fall through
+          case 96: break;
+          case 30:
+            { return OgnlTypes.OR;
+            }
+          // fall through
+          case 97: break;
+          case 31:
+            { return OgnlTypes.NOT;
+            }
+          // fall through
+          case 98: break;
+          case 32:
+            { popState();
+  if (myLeftBraceCount == 0)  {
+    return OgnlTypes.EXPRESSION_END;
+  }
+
+  myLeftBraceCount--;
+  return OgnlTypes.RBRACE;
+            }
+          // fall through
+          case 99: break;
+          case 33:
+            { return OgnlTypes.NOT_EQUAL;
+            }
+          // fall through
+          case 100: break;
+          case 34:
+            { pushState(EXPR);
+  return OgnlTypes.EXPRESSION_START;
+            }
+          // fall through
+          case 101: break;
+          case 35:
+            { return OgnlTypes.AND_AND;
+            }
+          // fall through
+          case 102: break;
+          case 36:
+            { return OgnlTypes.DOUBLE_LITERAL;
+            }
+          // fall through
+          case 103: break;
+          case 37:
+            { return OgnlTypes.BIG_INTEGER_LITERAL;
+            }
+          // fall through
+          case 104: break;
+          case 38:
+            { return OgnlTypes.SHIFT_LEFT;
+            }
+          // fall through
+          case 105: break;
+          case 39:
+            { return OgnlTypes.LESS_EQUAL;
+            }
+          // fall through
+          case 106: break;
+          case 40:
+            { return OgnlTypes.EQUAL;
+            }
+          // fall through
+          case 107: break;
+          case 41:
+            { return OgnlTypes.GREATER_EQUAL;
+            }
+          // fall through
+          case 108: break;
+          case 42:
+            { return OgnlTypes.SHIFT_RIGHT;
+            }
+          // fall through
+          case 109: break;
+          case 43:
+            { return OgnlTypes.EQ_KEYWORD;
+            }
+          // fall through
+          case 110: break;
+          case 44:
+            { return OgnlTypes.GT_KEYWORD;
+            }
+          // fall through
+          case 111: break;
+          case 45:
+            { return OgnlTypes.IN_KEYWORD;
+            }
+          // fall through
+          case 112: break;
+          case 46:
+            { return OgnlTypes.LT_KEYWORD;
+            }
+          // fall through
+          case 113: break;
+          case 47:
+            { return OgnlTypes.OR_KEYWORD;
+            }
+          // fall through
+          case 114: break;
+          case 48:
+            { return OgnlTypes.OR_OR;
+            }
+          // fall through
+          case 115: break;
+          case 49:
+            { return OgnlTypes.BIG_DECIMAL_LITERAL;
+            }
+          // fall through
+          case 116: break;
+          case 50:
+            { return OgnlTypes.SHIFT_RIGHT_LOGICAL;
+            }
+          // fall through
+          case 117: break;
+          case 51:
+            { return OgnlTypes.AND_KEYWORD;
+            }
+          // fall through
+          case 118: break;
+          case 52:
+            { return OgnlTypes.BOR_KEYWORD;
+            }
+          // fall through
+          case 119: break;
+          case 53:
+            { return OgnlTypes.GT_EQ_KEYWORD;
+            }
+          // fall through
+          case 120: break;
+          case 54:
+            { return OgnlTypes.LT_EQ_KEYWORD;
+            }
+          // fall through
+          case 121: break;
+          case 55:
+            { return OgnlTypes.NEQ_KEYWORD;
+            }
+          // fall through
+          case 122: break;
+          case 56:
+            { return OgnlTypes.NEW_KEYWORD;
+            }
+          // fall through
+          case 123: break;
+          case 57:
+            { return OgnlTypes.NOT_KEYWORD;
+            }
+          // fall through
+          case 124: break;
+          case 58:
+            { return OgnlTypes.SHIFT_LEFT_KEYWORD;
+            }
+          // fall through
+          case 125: break;
+          case 59:
+            { return OgnlTypes.SHIFT_RIGHT_KEYWORD;
+            }
+          // fall through
+          case 126: break;
+          case 60:
+            { return OgnlTypes.XOR_KEYWORD;
+            }
+          // fall through
+          case 127: break;
+          case 61:
+            { return OgnlTypes.BAND_KEYWORD;
+            }
+          // fall through
+          case 128: break;
+          case 62:
+            { return OgnlTypes.NULL_KEYWORD;
+            }
+          // fall through
+          case 129: break;
+          case 63:
+            { return OgnlTypes.TRUE_KEYWORD;
+            }
+          // fall through
+          case 130: break;
+          case 64:
+            { return OgnlTypes.SHIFT_RIGHT_LOGICAL_KEYWORD;
+            }
+          // fall through
+          case 131: break;
+          case 65:
+            { return OgnlTypes.FALSE_KEYWORD;
+            }
+          // fall through
+          case 132: break;
+          case 66:
+            { return OgnlTypes.NOT_IN_KEYWORD;
+            }
+          // fall through
+          case 133: break;
+          case 67:
+            { return OgnlTypes.INSTANCEOF_KEYWORD;
+            }
+          // fall through
+          case 134: break;
+          default:
+            zzScanError(ZZ_NO_MATCH);
+          }
+      }
+    }
+  }
+
+
+}
diff --git a/src/main/gen/parser/OgnlParser.java b/src/main/gen/parser/OgnlParser.java
new file mode 100644
index 0000000..741c85a
--- /dev/null
+++ b/src/main/gen/parser/OgnlParser.java
@@ -0,0 +1,1006 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.parser;
+
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiBuilder.Marker;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import static com.intellij.lang.parser.GeneratedParserUtilBase.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.tree.TokenSet;
+import com.intellij.lang.PsiParser;
+import com.intellij.lang.LightPsiParser;
+
+@SuppressWarnings({"SimplifiableIfStatement", "UnusedAssignment"})
+public class OgnlParser implements PsiParser, LightPsiParser {
+
+  public ASTNode parse(IElementType t, PsiBuilder b) {
+    parseLight(t, b);
+    return b.getTreeBuilt();
+  }
+
+  public void parseLight(IElementType t, PsiBuilder b) {
+    boolean r;
+    b = adapt_builder_(t, b, this, EXTENDS_SETS_);
+    Marker m = enter_section_(b, 0, _COLLAPSE_, null);
+    r = parse_root_(t, b);
+    exit_section_(b, 0, m, t, r, true, TRUE_CONDITION);
+  }
+
+  protected boolean parse_root_(IElementType t, PsiBuilder b) {
+    return parse_root_(t, b, 0);
+  }
+
+  static boolean parse_root_(IElementType t, PsiBuilder b, int l) {
+    return root(b, l + 1);
+  }
+
+  public static final TokenSet[] EXTENDS_SETS_ = new TokenSet[] {
+    create_token_set_(BINARY_EXPRESSION, CONDITIONAL_EXPRESSION, EXPRESSION, FQN_TYPE_EXPRESSION,
+      INDEXED_EXPRESSION, LAMBDA_EXPRESSION, LITERAL_EXPRESSION, MAP_EXPRESSION,
+      METHOD_CALL_EXPRESSION, NEW_ARRAY_EXPRESSION, NEW_EXPRESSION, PARENTHESIZED_EXPRESSION,
+      PROJECTION_EXPRESSION, REFERENCE_EXPRESSION, SELECTION_EXPRESSION, SEQUENCE_EXPRESSION,
+      UNARY_EXPRESSION, VARIABLE_ASSIGNMENT_EXPRESSION, VARIABLE_EXPRESSION),
+  };
+
+  /* ********************************************************** */
+  // '[' expression? ']' sequenceExpression?
+  static boolean arrayConstructorExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "arrayConstructorExpression")) return false;
+    if (!nextTokenIs(b, LBRACKET)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeToken(b, LBRACKET);
+    p = r; // pin = 1
+    r = r && report_error_(b, arrayConstructorExpression_1(b, l + 1));
+    r = p && report_error_(b, consumeToken(b, RBRACKET)) && r;
+    r = p && arrayConstructorExpression_3(b, l + 1) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // expression?
+  private static boolean arrayConstructorExpression_1(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "arrayConstructorExpression_1")) return false;
+    expression(b, l + 1, -1);
+    return true;
+  }
+
+  // sequenceExpression?
+  private static boolean arrayConstructorExpression_3(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "arrayConstructorExpression_3")) return false;
+    sequenceExpression(b, l + 1);
+    return true;
+  }
+
+  /* ********************************************************** */
+  // plusMinusOperations |
+  //                            divideMultiplyOperations |
+  //                            bitwiseBooleanOperations |
+  //                            instanceOfOperation |
+  //                            shiftOperations |
+  //                            booleanOperations |
+  //                            equalityOperations |
+  //                            relationalOperations |
+  //                            setOperations
+  static boolean binaryOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "binaryOperations")) return false;
+    boolean r;
+    Marker m = enter_section_(b, l, _NONE_, null, "<operator>");
+    r = plusMinusOperations(b, l + 1);
+    if (!r) r = divideMultiplyOperations(b, l + 1);
+    if (!r) r = bitwiseBooleanOperations(b, l + 1);
+    if (!r) r = instanceOfOperation(b, l + 1);
+    if (!r) r = shiftOperations(b, l + 1);
+    if (!r) r = booleanOperations(b, l + 1);
+    if (!r) r = equalityOperations(b, l + 1);
+    if (!r) r = relationalOperations(b, l + 1);
+    if (!r) r = setOperations(b, l + 1);
+    exit_section_(b, l, m, r, false, null);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // "|" | "^" | "&" | "band" | "bor" | "xor"
+  static boolean bitwiseBooleanOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "bitwiseBooleanOperations")) return false;
+    boolean r;
+    r = consumeToken(b, OR);
+    if (!r) r = consumeToken(b, XOR);
+    if (!r) r = consumeToken(b, AND);
+    if (!r) r = consumeToken(b, BAND_KEYWORD);
+    if (!r) r = consumeToken(b, BOR_KEYWORD);
+    if (!r) r = consumeToken(b, XOR_KEYWORD);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // '!' | "~"
+  static boolean bitwiseOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "bitwiseOperations")) return false;
+    if (!nextTokenIs(b, "", NEGATE, NOT)) return false;
+    boolean r;
+    r = consumeToken(b, NEGATE);
+    if (!r) r = consumeToken(b, NOT);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // "true" | "false"
+  static boolean booleanLiteralExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "booleanLiteralExpression")) return false;
+    if (!nextTokenIs(b, "", FALSE_KEYWORD, TRUE_KEYWORD)) return false;
+    boolean r;
+    r = consumeToken(b, TRUE_KEYWORD);
+    if (!r) r = consumeToken(b, FALSE_KEYWORD);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // "&&" | "||" |
+  //                               "and" | "or" |
+  //                               "not"
+  static boolean booleanOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "booleanOperations")) return false;
+    boolean r;
+    r = consumeToken(b, AND_AND);
+    if (!r) r = consumeToken(b, OR_OR);
+    if (!r) r = consumeToken(b, AND_KEYWORD);
+    if (!r) r = consumeToken(b, OR_KEYWORD);
+    if (!r) r = consumeToken(b, NOT_KEYWORD);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // ':' expression
+  static boolean conditionalExpressionTail(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "conditionalExpressionTail")) return false;
+    if (!nextTokenIs(b, COLON)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeToken(b, COLON);
+    p = r; // pin = 1
+    r = r && expression(b, l + 1, -1);
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  /* ********************************************************** */
+  // '(' parameterList ')'
+  static boolean constructorExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "constructorExpression")) return false;
+    if (!nextTokenIs(b, LPARENTH)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeToken(b, LPARENTH);
+    p = r; // pin = 1
+    r = r && report_error_(b, parameterList(b, l + 1));
+    r = p && consumeToken(b, RPARENTH) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  /* ********************************************************** */
+  // '*' | '/' | '%'
+  static boolean divideMultiplyOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "divideMultiplyOperations")) return false;
+    boolean r;
+    r = consumeToken(b, MULTIPLY);
+    if (!r) r = consumeToken(b, DIVISION);
+    if (!r) r = consumeToken(b, MODULO);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // "==" | "!=" |
+  //                                "eq" | "neq"
+  static boolean equalityOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "equalityOperations")) return false;
+    boolean r;
+    r = consumeToken(b, EQUAL);
+    if (!r) r = consumeToken(b, NOT_EQUAL);
+    if (!r) r = consumeToken(b, EQ_KEYWORD);
+    if (!r) r = consumeToken(b, NEQ_KEYWORD);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // expression (',' expression)+
+  static boolean expressionSequenceRequired(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "expressionSequenceRequired")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = expression(b, l + 1, -1);
+    p = r; // pin = 1
+    r = r && expressionSequenceRequired_1(b, l + 1);
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // (',' expression)+
+  private static boolean expressionSequenceRequired_1(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "expressionSequenceRequired_1")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = expressionSequenceRequired_1_0(b, l + 1);
+    while (r) {
+      int c = current_position_(b);
+      if (!expressionSequenceRequired_1_0(b, l + 1)) break;
+      if (!empty_element_parsed_guard_(b, "expressionSequenceRequired_1", c)) break;
+    }
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // ',' expression
+  private static boolean expressionSequenceRequired_1_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "expressionSequenceRequired_1_0")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeToken(b, COMMA);
+    p = r; // pin = 1
+    r = r && expression(b, l + 1, -1);
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  /* ********************************************************** */
+  // IDENTIFIER ('.' IDENTIFIER)*
+  public static boolean fqnTypeExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "fqnTypeExpression")) return false;
+    if (!nextTokenIs(b, IDENTIFIER)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, FQN_TYPE_EXPRESSION, null);
+    r = consumeToken(b, IDENTIFIER);
+    p = r; // pin = 1
+    r = r && fqnTypeExpression_1(b, l + 1);
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // ('.' IDENTIFIER)*
+  private static boolean fqnTypeExpression_1(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "fqnTypeExpression_1")) return false;
+    while (true) {
+      int c = current_position_(b);
+      if (!fqnTypeExpression_1_0(b, l + 1)) break;
+      if (!empty_element_parsed_guard_(b, "fqnTypeExpression_1", c)) break;
+    }
+    return true;
+  }
+
+  // '.' IDENTIFIER
+  private static boolean fqnTypeExpression_1_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "fqnTypeExpression_1_0")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeTokens(b, 1, DOT, IDENTIFIER);
+    p = r; // pin = 1
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  /* ********************************************************** */
+  // "instanceof"
+  static boolean instanceOfOperation(PsiBuilder b, int l) {
+    return consumeToken(b, INSTANCEOF_KEYWORD);
+  }
+
+  /* ********************************************************** */
+  // expression ':' expression
+  public static boolean mapEntryElement(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "mapEntryElement")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, MAP_ENTRY_ELEMENT, "<map entry>");
+    r = expression(b, l + 1, -1);
+    p = r; // pin = 1
+    r = r && report_error_(b, consumeToken(b, COLON));
+    r = p && expression(b, l + 1, -1) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  /* ********************************************************** */
+  // [] mapEntryElement (',' mapEntryElement)*
+  static boolean mapExpressionSequence(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "mapExpressionSequence")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = mapExpressionSequence_0(b, l + 1);
+    p = r; // pin = 1
+    r = r && report_error_(b, mapEntryElement(b, l + 1));
+    r = p && mapExpressionSequence_2(b, l + 1) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // []
+  private static boolean mapExpressionSequence_0(PsiBuilder b, int l) {
+    return true;
+  }
+
+  // (',' mapEntryElement)*
+  private static boolean mapExpressionSequence_2(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "mapExpressionSequence_2")) return false;
+    while (true) {
+      int c = current_position_(b);
+      if (!mapExpressionSequence_2_0(b, l + 1)) break;
+      if (!empty_element_parsed_guard_(b, "mapExpressionSequence_2", c)) break;
+    }
+    return true;
+  }
+
+  // ',' mapEntryElement
+  private static boolean mapExpressionSequence_2_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "mapExpressionSequence_2_0")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeToken(b, COMMA);
+    p = r; // pin = 1
+    r = r && mapEntryElement(b, l + 1);
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  /* ********************************************************** */
+  // '#@' fqnTypeExpression '@{'
+  static boolean mapTypeExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "mapTypeExpression")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeToken(b, "#@");
+    p = r; // pin = 1
+    r = r && report_error_(b, fqnTypeExpression(b, l + 1));
+    r = p && consumeToken(b, "@{") && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  /* ********************************************************** */
+  // INTEGER_LITERAL | BIG_INTEGER_LITERAL | DOUBLE_LITERAL | BIG_DECIMAL_LITERAL
+  static boolean numberLiteralExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "numberLiteralExpression")) return false;
+    boolean r;
+    r = consumeToken(b, INTEGER_LITERAL);
+    if (!r) r = consumeToken(b, BIG_INTEGER_LITERAL);
+    if (!r) r = consumeToken(b, DOUBLE_LITERAL);
+    if (!r) r = consumeToken(b, BIG_DECIMAL_LITERAL);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // expression? (',' expression)*
+  public static boolean parameterList(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "parameterList")) return false;
+    boolean r;
+    Marker m = enter_section_(b, l, _NONE_, PARAMETER_LIST, "<parameter list>");
+    r = parameterList_0(b, l + 1);
+    r = r && parameterList_1(b, l + 1);
+    exit_section_(b, l, m, r, false, null);
+    return r;
+  }
+
+  // expression?
+  private static boolean parameterList_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "parameterList_0")) return false;
+    expression(b, l + 1, -1);
+    return true;
+  }
+
+  // (',' expression)*
+  private static boolean parameterList_1(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "parameterList_1")) return false;
+    while (true) {
+      int c = current_position_(b);
+      if (!parameterList_1_0(b, l + 1)) break;
+      if (!empty_element_parsed_guard_(b, "parameterList_1", c)) break;
+    }
+    return true;
+  }
+
+  // ',' expression
+  private static boolean parameterList_1_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "parameterList_1_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeToken(b, COMMA);
+    r = r && expression(b, l + 1, -1);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // '+' | '-'
+  static boolean plusMinusOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "plusMinusOperations")) return false;
+    if (!nextTokenIs(b, "", MINUS, PLUS)) return false;
+    boolean r;
+    r = consumeToken(b, PLUS);
+    if (!r) r = consumeToken(b, MINUS);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // '{' expression '}'
+  public static boolean projectionExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "projectionExpression")) return false;
+    if (!nextTokenIs(b, LBRACE)) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeToken(b, LBRACE);
+    r = r && expression(b, l + 1, -1);
+    r = r && consumeToken(b, RBRACE);
+    exit_section_(b, m, PROJECTION_EXPRESSION, r);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // '<'  | "<="  | '>'  | ">=" |
+  //                                  "lt" | "lte" | "gt" | "gte"
+  static boolean relationalOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "relationalOperations")) return false;
+    boolean r;
+    r = consumeToken(b, LESS);
+    if (!r) r = consumeToken(b, LESS_EQUAL);
+    if (!r) r = consumeToken(b, GREATER);
+    if (!r) r = consumeToken(b, GREATER_EQUAL);
+    if (!r) r = consumeToken(b, LT_KEYWORD);
+    if (!r) r = consumeToken(b, LT_EQ_KEYWORD);
+    if (!r) r = consumeToken(b, GT_KEYWORD);
+    if (!r) r = consumeToken(b, GT_EQ_KEYWORD);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // EXPRESSION_START rootElement EXPRESSION_END
+  static boolean root(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "root")) return false;
+    if (!nextTokenIs(b, EXPRESSION_START)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeToken(b, EXPRESSION_START);
+    p = r; // pin = 1
+    r = r && report_error_(b, rootElement(b, l + 1));
+    r = p && consumeToken(b, EXPRESSION_END) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  /* ********************************************************** */
+  // expression
+  static boolean rootElement(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "rootElement")) return false;
+    boolean r;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = expression(b, l + 1, -1);
+    exit_section_(b, l, m, r, false, rootRecover_parser_);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // !(EXPRESSION_END)
+  static boolean rootRecover(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "rootRecover")) return false;
+    boolean r;
+    Marker m = enter_section_(b, l, _NOT_);
+    r = !consumeToken(b, EXPRESSION_END);
+    exit_section_(b, l, m, r, false, null);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // '{' ('?' | '^' | '$') expression '}'
+  public static boolean selectionExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "selectionExpression")) return false;
+    if (!nextTokenIs(b, LBRACE)) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeToken(b, LBRACE);
+    r = r && selectionExpression_1(b, l + 1);
+    r = r && expression(b, l + 1, -1);
+    r = r && consumeToken(b, RBRACE);
+    exit_section_(b, m, SELECTION_EXPRESSION, r);
+    return r;
+  }
+
+  // '?' | '^' | '$'
+  private static boolean selectionExpression_1(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "selectionExpression_1")) return false;
+    boolean r;
+    r = consumeToken(b, QUESTION);
+    if (!r) r = consumeToken(b, XOR);
+    if (!r) r = consumeToken(b, DOLLAR);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // "not in" | "in"
+  static boolean setOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "setOperations")) return false;
+    if (!nextTokenIs(b, "", IN_KEYWORD, NOT_IN_KEYWORD)) return false;
+    boolean r;
+    r = consumeToken(b, NOT_IN_KEYWORD);
+    if (!r) r = consumeToken(b, IN_KEYWORD);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // "<<" | ">>" | ">>>" |
+  //                             "shl" | "shr" | "ushr"
+  static boolean shiftOperations(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "shiftOperations")) return false;
+    boolean r;
+    r = consumeToken(b, SHIFT_LEFT);
+    if (!r) r = consumeToken(b, SHIFT_RIGHT);
+    if (!r) r = consumeToken(b, SHIFT_RIGHT_LOGICAL);
+    if (!r) r = consumeToken(b, SHIFT_LEFT_KEYWORD);
+    if (!r) r = consumeToken(b, SHIFT_RIGHT_KEYWORD);
+    if (!r) r = consumeToken(b, SHIFT_RIGHT_LOGICAL_KEYWORD);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // STRING_LITERAL | CHARACTER_LITERAL
+  static boolean textLiteralExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "textLiteralExpression")) return false;
+    if (!nextTokenIs(b, "", CHARACTER_LITERAL, STRING_LITERAL)) return false;
+    boolean r;
+    r = consumeToken(b, STRING_LITERAL);
+    if (!r) r = consumeToken(b, CHARACTER_LITERAL);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // bitwiseOperations |
+  //                           '+' | '-' | "not"
+  static boolean unaryOperator(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "unaryOperator")) return false;
+    boolean r;
+    r = bitwiseOperations(b, l + 1);
+    if (!r) r = consumeToken(b, PLUS);
+    if (!r) r = consumeToken(b, MINUS);
+    if (!r) r = consumeToken(b, NOT_KEYWORD);
+    return r;
+  }
+
+  /* ********************************************************** */
+  // Expression root: expression
+  // Operator priority table:
+  // 0: PREFIX(unaryExpression)
+  // 1: ATOM(lambdaExpression)
+  // 2: ATOM(mapExpression)
+  // 3: ATOM(sequenceExpression)
+  // 4: ATOM(parenthesizedExpression)
+  // 5: ATOM(variableAssignmentExpression)
+  // 6: BINARY(conditionalExpression)
+  // 7: BINARY(binaryExpression)
+  // 8: ATOM(newArrayExpression)
+  // 9: ATOM(newExpression)
+  // 10: POSTFIX(methodCallExpression)
+  // 11: ATOM(indexedExpression)
+  // 12: ATOM(referenceExpression)
+  // 13: ATOM(variableExpression)
+  // 14: ATOM(literalExpression)
+  public static boolean expression(PsiBuilder b, int l, int g) {
+    if (!recursion_guard_(b, l, "expression")) return false;
+    addVariant(b, "<expression>");
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, "<expression>");
+    r = unaryExpression(b, l + 1);
+    if (!r) r = lambdaExpression(b, l + 1);
+    if (!r) r = mapExpression(b, l + 1);
+    if (!r) r = sequenceExpression(b, l + 1);
+    if (!r) r = parenthesizedExpression(b, l + 1);
+    if (!r) r = variableAssignmentExpression(b, l + 1);
+    if (!r) r = newArrayExpression(b, l + 1);
+    if (!r) r = newExpression(b, l + 1);
+    if (!r) r = indexedExpression(b, l + 1);
+    if (!r) r = referenceExpression(b, l + 1);
+    if (!r) r = variableExpression(b, l + 1);
+    if (!r) r = literalExpression(b, l + 1);
+    p = r;
+    r = r && expression_0(b, l + 1, g);
+    exit_section_(b, l, m, null, r, p, null);
+    return r || p;
+  }
+
+  public static boolean expression_0(PsiBuilder b, int l, int g) {
+    if (!recursion_guard_(b, l, "expression_0")) return false;
+    boolean r = true;
+    while (true) {
+      Marker m = enter_section_(b, l, _LEFT_, null);
+      if (g < 6 && consumeTokenSmart(b, QUESTION)) {
+        r = report_error_(b, expression(b, l, 6));
+        r = conditionalExpressionTail(b, l + 1) && r;
+        exit_section_(b, l, m, CONDITIONAL_EXPRESSION, r, true, null);
+      }
+      else if (g < 7 && binaryOperations(b, l + 1)) {
+        r = expression(b, l, 7);
+        exit_section_(b, l, m, BINARY_EXPRESSION, r, true, null);
+      }
+      else if (g < 10 && leftMarkerIs(b, REFERENCE_EXPRESSION) && methodCallExpression_0(b, l + 1)) {
+        r = true;
+        exit_section_(b, l, m, METHOD_CALL_EXPRESSION, r, true, null);
+      }
+      else {
+        exit_section_(b, l, m, null, false, false, null);
+        break;
+      }
+    }
+    return r;
+  }
+
+  public static boolean unaryExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "unaryExpression")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, null);
+    r = unaryOperator(b, l + 1);
+    p = r;
+    r = p && expression(b, l, 0);
+    exit_section_(b, l, m, UNARY_EXPRESSION, r, p, null);
+    return r || p;
+  }
+
+  // ':' '[' expression "]"
+  public static boolean lambdaExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "lambdaExpression")) return false;
+    if (!nextTokenIsSmart(b, COLON)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, null);
+    r = consumeTokensSmart(b, 1, COLON, LBRACKET);
+    p = r; // pin = 1
+    r = r && report_error_(b, expression(b, l + 1, -1));
+    r = p && consumeToken(b, RBRACKET) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // ('#{' | mapTypeExpression) mapExpressionSequence '}'
+  public static boolean mapExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "mapExpression")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _COLLAPSE_, MAP_EXPRESSION, "<map expression>");
+    r = mapExpression_0(b, l + 1);
+    p = r; // pin = 1
+    r = r && report_error_(b, mapExpressionSequence(b, l + 1));
+    r = p && consumeToken(b, RBRACE) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // '#{' | mapTypeExpression
+  private static boolean mapExpression_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "mapExpression_0")) return false;
+    boolean r;
+    r = consumeTokenSmart(b, "#{");
+    if (!r) r = mapTypeExpression(b, l + 1);
+    return r;
+  }
+
+  // '{' expressionSequenceRequired '}'
+  public static boolean sequenceExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "sequenceExpression")) return false;
+    if (!nextTokenIsSmart(b, LBRACE)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, SEQUENCE_EXPRESSION, null);
+    r = consumeTokenSmart(b, LBRACE);
+    p = r; // pin = 1
+    r = r && report_error_(b, expressionSequenceRequired(b, l + 1));
+    r = p && consumeToken(b, RBRACE) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // '(' expression ')'
+  public static boolean parenthesizedExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "parenthesizedExpression")) return false;
+    if (!nextTokenIsSmart(b, LPARENTH)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, PARENTHESIZED_EXPRESSION, null);
+    r = consumeTokenSmart(b, LPARENTH);
+    p = r; // pin = 1
+    r = r && report_error_(b, expression(b, l + 1, -1));
+    r = p && consumeToken(b, RPARENTH) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // '#' IDENTIFIER '=' expression
+  public static boolean variableAssignmentExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "variableAssignmentExpression")) return false;
+    if (!nextTokenIsSmart(b, HASH)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, VARIABLE_ASSIGNMENT_EXPRESSION, null);
+    r = consumeTokensSmart(b, 3, HASH, IDENTIFIER, EQ);
+    p = r; // pin = 3
+    r = r && expression(b, l + 1, -1);
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // "new" fqnTypeExpression arrayConstructorExpression
+  public static boolean newArrayExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "newArrayExpression")) return false;
+    if (!nextTokenIsSmart(b, NEW_KEYWORD)) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeTokenSmart(b, NEW_KEYWORD);
+    r = r && fqnTypeExpression(b, l + 1);
+    r = r && arrayConstructorExpression(b, l + 1);
+    exit_section_(b, m, NEW_ARRAY_EXPRESSION, r);
+    return r;
+  }
+
+  // "new" fqnTypeExpression constructorExpression
+  public static boolean newExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "newExpression")) return false;
+    if (!nextTokenIsSmart(b, NEW_KEYWORD)) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, NEW_EXPRESSION, null);
+    r = consumeTokenSmart(b, NEW_KEYWORD);
+    p = r; // pin = 1
+    r = r && report_error_(b, fqnTypeExpression(b, l + 1));
+    r = p && constructorExpression(b, l + 1) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // '(' parameterList ')'
+  private static boolean methodCallExpression_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "methodCallExpression_0")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_);
+    r = consumeTokenSmart(b, LPARENTH);
+    p = r; // pin = '\('
+    r = r && report_error_(b, parameterList(b, l + 1));
+    r = p && consumeToken(b, RPARENTH) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // (referenceExpression | variableExpression) '[' expression ']'
+  //                       ('.' IDENTIFIER)*
+  //                       ('.'  selectionExpression | projectionExpression)?
+  public static boolean indexedExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "indexedExpression")) return false;
+    boolean r, p;
+    Marker m = enter_section_(b, l, _NONE_, INDEXED_EXPRESSION, "<indexed expression>");
+    r = indexedExpression_0(b, l + 1);
+    r = r && consumeToken(b, LBRACKET);
+    p = r; // pin = 2
+    r = r && report_error_(b, expression(b, l + 1, -1));
+    r = p && report_error_(b, consumeToken(b, RBRACKET)) && r;
+    r = p && report_error_(b, indexedExpression_4(b, l + 1)) && r;
+    r = p && indexedExpression_5(b, l + 1) && r;
+    exit_section_(b, l, m, r, p, null);
+    return r || p;
+  }
+
+  // referenceExpression | variableExpression
+  private static boolean indexedExpression_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "indexedExpression_0")) return false;
+    boolean r;
+    r = referenceExpression(b, l + 1);
+    if (!r) r = variableExpression(b, l + 1);
+    return r;
+  }
+
+  // ('.' IDENTIFIER)*
+  private static boolean indexedExpression_4(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "indexedExpression_4")) return false;
+    while (true) {
+      int c = current_position_(b);
+      if (!indexedExpression_4_0(b, l + 1)) break;
+      if (!empty_element_parsed_guard_(b, "indexedExpression_4", c)) break;
+    }
+    return true;
+  }
+
+  // '.' IDENTIFIER
+  private static boolean indexedExpression_4_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "indexedExpression_4_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeTokensSmart(b, 0, DOT, IDENTIFIER);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // ('.'  selectionExpression | projectionExpression)?
+  private static boolean indexedExpression_5(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "indexedExpression_5")) return false;
+    indexedExpression_5_0(b, l + 1);
+    return true;
+  }
+
+  // '.'  selectionExpression | projectionExpression
+  private static boolean indexedExpression_5_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "indexedExpression_5_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = indexedExpression_5_0_0(b, l + 1);
+    if (!r) r = projectionExpression(b, l + 1);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // '.'  selectionExpression
+  private static boolean indexedExpression_5_0_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "indexedExpression_5_0_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeTokenSmart(b, DOT);
+    r = r && selectionExpression(b, l + 1);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // (variableExpression | ('@')? IDENTIFIER)
+  //                         ('.' IDENTIFIER)* ('@' IDENTIFIER)?
+  //                         ('.'  selectionExpression)?
+  //                         ('.'  projectionExpression )?
+  public static boolean referenceExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression")) return false;
+    boolean r;
+    Marker m = enter_section_(b, l, _COLLAPSE_, REFERENCE_EXPRESSION, "<reference expression>");
+    r = referenceExpression_0(b, l + 1);
+    r = r && referenceExpression_1(b, l + 1);
+    r = r && referenceExpression_2(b, l + 1);
+    r = r && referenceExpression_3(b, l + 1);
+    r = r && referenceExpression_4(b, l + 1);
+    exit_section_(b, l, m, r, false, null);
+    return r;
+  }
+
+  // variableExpression | ('@')? IDENTIFIER
+  private static boolean referenceExpression_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = variableExpression(b, l + 1);
+    if (!r) r = referenceExpression_0_1(b, l + 1);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // ('@')? IDENTIFIER
+  private static boolean referenceExpression_0_1(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_0_1")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = referenceExpression_0_1_0(b, l + 1);
+    r = r && consumeToken(b, IDENTIFIER);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // ('@')?
+  private static boolean referenceExpression_0_1_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_0_1_0")) return false;
+    consumeTokenSmart(b, AT);
+    return true;
+  }
+
+  // ('.' IDENTIFIER)*
+  private static boolean referenceExpression_1(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_1")) return false;
+    while (true) {
+      int c = current_position_(b);
+      if (!referenceExpression_1_0(b, l + 1)) break;
+      if (!empty_element_parsed_guard_(b, "referenceExpression_1", c)) break;
+    }
+    return true;
+  }
+
+  // '.' IDENTIFIER
+  private static boolean referenceExpression_1_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_1_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeTokensSmart(b, 0, DOT, IDENTIFIER);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // ('@' IDENTIFIER)?
+  private static boolean referenceExpression_2(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_2")) return false;
+    referenceExpression_2_0(b, l + 1);
+    return true;
+  }
+
+  // '@' IDENTIFIER
+  private static boolean referenceExpression_2_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_2_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeTokensSmart(b, 0, AT, IDENTIFIER);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // ('.'  selectionExpression)?
+  private static boolean referenceExpression_3(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_3")) return false;
+    referenceExpression_3_0(b, l + 1);
+    return true;
+  }
+
+  // '.'  selectionExpression
+  private static boolean referenceExpression_3_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_3_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeTokenSmart(b, DOT);
+    r = r && selectionExpression(b, l + 1);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // ('.'  projectionExpression )?
+  private static boolean referenceExpression_4(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_4")) return false;
+    referenceExpression_4_0(b, l + 1);
+    return true;
+  }
+
+  // '.'  projectionExpression
+  private static boolean referenceExpression_4_0(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "referenceExpression_4_0")) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeTokenSmart(b, DOT);
+    r = r && projectionExpression(b, l + 1);
+    exit_section_(b, m, null, r);
+    return r;
+  }
+
+  // '#' IDENTIFIER
+  public static boolean variableExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "variableExpression")) return false;
+    if (!nextTokenIsSmart(b, HASH)) return false;
+    boolean r;
+    Marker m = enter_section_(b);
+    r = consumeTokensSmart(b, 0, HASH, IDENTIFIER);
+    exit_section_(b, m, VARIABLE_EXPRESSION, r);
+    return r;
+  }
+
+  // numberLiteralExpression |
+  //                       textLiteralExpression |
+  //                       booleanLiteralExpression |
+  //                       "null"
+  public static boolean literalExpression(PsiBuilder b, int l) {
+    if (!recursion_guard_(b, l, "literalExpression")) return false;
+    boolean r;
+    Marker m = enter_section_(b, l, _NONE_, LITERAL_EXPRESSION, "<literal expression>");
+    r = numberLiteralExpression(b, l + 1);
+    if (!r) r = textLiteralExpression(b, l + 1);
+    if (!r) r = booleanLiteralExpression(b, l + 1);
+    if (!r) r = consumeTokenSmart(b, NULL_KEYWORD);
+    exit_section_(b, l, m, r, false, null);
+    return r;
+  }
+
+  static final Parser rootRecover_parser_ = new Parser() {
+    public boolean parse(PsiBuilder b, int l) {
+      return rootRecover(b, l + 1);
+    }
+  };
+}
diff --git a/src/main/gen/psi/OgnlBinaryExpression.java b/src/main/gen/psi/OgnlBinaryExpression.java
new file mode 100644
index 0000000..8dddbd7
--- /dev/null
+++ b/src/main/gen/psi/OgnlBinaryExpression.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlBinaryExpression extends OgnlExpression {
+
+  @NotNull
+  OgnlExpression getLeft();
+
+  @Nullable
+  OgnlExpression getRight();
+
+  @NotNull
+  OgnlTokenType getOperator();
+
+}
diff --git a/src/main/gen/psi/OgnlConditionalExpression.java b/src/main/gen/psi/OgnlConditionalExpression.java
new file mode 100644
index 0000000..52be3cd
--- /dev/null
+++ b/src/main/gen/psi/OgnlConditionalExpression.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlConditionalExpression extends OgnlExpression {
+
+  @NotNull
+  OgnlExpression getCondition();
+
+  @Nullable
+  OgnlExpression getThen();
+
+  @Nullable
+  OgnlExpression getElse();
+
+}
diff --git a/src/main/gen/psi/OgnlExpression.java b/src/main/gen/psi/OgnlExpression.java
new file mode 100644
index 0000000..8efe65c
--- /dev/null
+++ b/src/main/gen/psi/OgnlExpression.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiType;
+
+public interface OgnlExpression extends OgnlPsiCompositeElement {
+
+  @Nullable
+  PsiType getType();
+
+}
diff --git a/src/main/gen/psi/OgnlFqnTypeExpression.java b/src/main/gen/psi/OgnlFqnTypeExpression.java
new file mode 100644
index 0000000..88a0d22
--- /dev/null
+++ b/src/main/gen/psi/OgnlFqnTypeExpression.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlFqnTypeExpression extends OgnlExpression {
+
+}
diff --git a/src/main/gen/psi/OgnlIndexedExpression.java b/src/main/gen/psi/OgnlIndexedExpression.java
new file mode 100644
index 0000000..e38130a
--- /dev/null
+++ b/src/main/gen/psi/OgnlIndexedExpression.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlIndexedExpression extends OgnlExpression {
+
+  @NotNull
+  OgnlExpression getReferenceQualifier();
+
+  @Nullable
+  OgnlExpression getIndexExpression();
+
+}
diff --git a/src/main/gen/psi/OgnlLambdaExpression.java b/src/main/gen/psi/OgnlLambdaExpression.java
new file mode 100644
index 0000000..ef32614
--- /dev/null
+++ b/src/main/gen/psi/OgnlLambdaExpression.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlLambdaExpression extends OgnlExpression {
+
+  @Nullable
+  OgnlExpression getExpression();
+
+}
diff --git a/src/main/gen/psi/OgnlLiteralExpression.java b/src/main/gen/psi/OgnlLiteralExpression.java
new file mode 100644
index 0000000..aad2156
--- /dev/null
+++ b/src/main/gen/psi/OgnlLiteralExpression.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlLiteralExpression extends OgnlExpression {
+
+  @Nullable
+  Object getConstantValue();
+
+}
diff --git a/src/main/gen/psi/OgnlMapEntryElement.java b/src/main/gen/psi/OgnlMapEntryElement.java
new file mode 100644
index 0000000..c96f13a
--- /dev/null
+++ b/src/main/gen/psi/OgnlMapEntryElement.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlMapEntryElement extends OgnlPsiCompositeElement {
+
+  @NotNull
+  OgnlExpression getKeyExpression();
+
+  @Nullable
+  OgnlExpression getValueExpression();
+
+}
diff --git a/src/main/gen/psi/OgnlMapExpression.java b/src/main/gen/psi/OgnlMapExpression.java
new file mode 100644
index 0000000..ffaaaa2
--- /dev/null
+++ b/src/main/gen/psi/OgnlMapExpression.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlMapExpression extends OgnlExpression {
+
+  @NotNull
+  List<OgnlMapEntryElement> getMapEntryElementList();
+
+  @Nullable
+  OgnlFqnTypeExpression getMapType();
+
+}
diff --git a/src/main/gen/psi/OgnlMethodCallExpression.java b/src/main/gen/psi/OgnlMethodCallExpression.java
new file mode 100644
index 0000000..256909f
--- /dev/null
+++ b/src/main/gen/psi/OgnlMethodCallExpression.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlMethodCallExpression extends OgnlExpression {
+
+  @Nullable
+  OgnlParameterList getParameterList();
+
+  @Nullable
+  OgnlExpression getMethod();
+
+}
diff --git a/src/main/gen/psi/OgnlNewArrayExpression.java b/src/main/gen/psi/OgnlNewArrayExpression.java
new file mode 100644
index 0000000..de1470a
--- /dev/null
+++ b/src/main/gen/psi/OgnlNewArrayExpression.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlNewArrayExpression extends OgnlExpression {
+
+  @NotNull
+  OgnlExpression getObjectType();
+
+  @Nullable
+  OgnlExpression getConstructorExpression();
+
+}
diff --git a/src/main/gen/psi/OgnlNewExpression.java b/src/main/gen/psi/OgnlNewExpression.java
new file mode 100644
index 0000000..9a1c4f2
--- /dev/null
+++ b/src/main/gen/psi/OgnlNewExpression.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlNewExpression extends OgnlExpression {
+
+  @Nullable
+  OgnlParameterList getParameterList();
+
+  @Nullable
+  OgnlFqnTypeExpression getObjectType();
+
+}
diff --git a/src/main/gen/psi/OgnlParameterList.java b/src/main/gen/psi/OgnlParameterList.java
new file mode 100644
index 0000000..2dabd1d
--- /dev/null
+++ b/src/main/gen/psi/OgnlParameterList.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlParameterList extends OgnlPsiCompositeElement {
+
+  @NotNull
+  List<OgnlExpression> getParametersList();
+
+  int getParameterCount();
+
+}
diff --git a/src/main/gen/psi/OgnlParenthesizedExpression.java b/src/main/gen/psi/OgnlParenthesizedExpression.java
new file mode 100644
index 0000000..27ebcec
--- /dev/null
+++ b/src/main/gen/psi/OgnlParenthesizedExpression.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlParenthesizedExpression extends OgnlExpression {
+
+  @Nullable
+  OgnlExpression getExpression();
+
+}
diff --git a/src/main/gen/psi/OgnlProjectionExpression.java b/src/main/gen/psi/OgnlProjectionExpression.java
new file mode 100644
index 0000000..2e85a93
--- /dev/null
+++ b/src/main/gen/psi/OgnlProjectionExpression.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlProjectionExpression extends OgnlExpression {
+
+  @NotNull
+  OgnlExpression getProjectionExpression();
+
+}
diff --git a/src/main/gen/psi/OgnlReferenceExpression.java b/src/main/gen/psi/OgnlReferenceExpression.java
new file mode 100644
index 0000000..9275dff
--- /dev/null
+++ b/src/main/gen/psi/OgnlReferenceExpression.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlReferenceExpression extends OgnlExpression {
+
+  @NotNull
+  List<OgnlExpression> getExpressionList();
+
+}
diff --git a/src/main/gen/psi/OgnlSelectionExpression.java b/src/main/gen/psi/OgnlSelectionExpression.java
new file mode 100644
index 0000000..fb7e309
--- /dev/null
+++ b/src/main/gen/psi/OgnlSelectionExpression.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlSelectionExpression extends OgnlExpression {
+
+  @NotNull
+  OgnlExpression getSelectorExpression();
+
+}
diff --git a/src/main/gen/psi/OgnlSequenceExpression.java b/src/main/gen/psi/OgnlSequenceExpression.java
new file mode 100644
index 0000000..4ee460d
--- /dev/null
+++ b/src/main/gen/psi/OgnlSequenceExpression.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlSequenceExpression extends OgnlExpression {
+
+  @NotNull
+  List<OgnlExpression> getElementsList();
+
+}
diff --git a/src/main/gen/psi/OgnlUnaryExpression.java b/src/main/gen/psi/OgnlUnaryExpression.java
new file mode 100644
index 0000000..237b00d
--- /dev/null
+++ b/src/main/gen/psi/OgnlUnaryExpression.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlUnaryExpression extends OgnlExpression {
+
+  @Nullable
+  OgnlExpression getExpression();
+
+  @NotNull
+  OgnlTokenType getUnaryOperator();
+
+}
diff --git a/src/main/gen/psi/OgnlVariableAssignmentExpression.java b/src/main/gen/psi/OgnlVariableAssignmentExpression.java
new file mode 100644
index 0000000..c264457
--- /dev/null
+++ b/src/main/gen/psi/OgnlVariableAssignmentExpression.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlVariableAssignmentExpression extends OgnlExpression {
+
+  @NotNull
+  String getVariableName();
+
+  @Nullable
+  OgnlExpression getAssignment();
+
+}
diff --git a/src/main/gen/psi/OgnlVariableExpression.java b/src/main/gen/psi/OgnlVariableExpression.java
new file mode 100644
index 0000000..f852bd8
--- /dev/null
+++ b/src/main/gen/psi/OgnlVariableExpression.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElement;
+
+public interface OgnlVariableExpression extends OgnlExpression {
+
+}
diff --git a/src/main/gen/psi/OgnlVisitor.java b/src/main/gen/psi/OgnlVisitor.java
new file mode 100644
index 0000000..0465189
--- /dev/null
+++ b/src/main/gen/psi/OgnlVisitor.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi;
+
+import org.jetbrains.annotations.*;
+import com.intellij.psi.PsiElementVisitor;
+
+public class OgnlVisitor extends PsiElementVisitor {
+
+  public void visitBinaryExpression(@NotNull OgnlBinaryExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitConditionalExpression(@NotNull OgnlConditionalExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitExpression(@NotNull OgnlExpression o) {
+    visitPsiCompositeElement(o);
+  }
+
+  public void visitFqnTypeExpression(@NotNull OgnlFqnTypeExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitIndexedExpression(@NotNull OgnlIndexedExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitLambdaExpression(@NotNull OgnlLambdaExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitLiteralExpression(@NotNull OgnlLiteralExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitMapEntryElement(@NotNull OgnlMapEntryElement o) {
+    visitPsiCompositeElement(o);
+  }
+
+  public void visitMapExpression(@NotNull OgnlMapExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitMethodCallExpression(@NotNull OgnlMethodCallExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitNewArrayExpression(@NotNull OgnlNewArrayExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitNewExpression(@NotNull OgnlNewExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitParameterList(@NotNull OgnlParameterList o) {
+    visitPsiCompositeElement(o);
+  }
+
+  public void visitParenthesizedExpression(@NotNull OgnlParenthesizedExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitProjectionExpression(@NotNull OgnlProjectionExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitReferenceExpression(@NotNull OgnlReferenceExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitSelectionExpression(@NotNull OgnlSelectionExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitSequenceExpression(@NotNull OgnlSequenceExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitUnaryExpression(@NotNull OgnlUnaryExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitVariableAssignmentExpression(@NotNull OgnlVariableAssignmentExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitVariableExpression(@NotNull OgnlVariableExpression o) {
+    visitExpression(o);
+  }
+
+  public void visitPsiCompositeElement(@NotNull OgnlPsiCompositeElement o) {
+    visitElement(o);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlBinaryExpressionImpl.java b/src/main/gen/psi/impl/OgnlBinaryExpressionImpl.java
new file mode 100644
index 0000000..b92c4fe
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlBinaryExpressionImpl.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlBinaryExpressionImpl extends OgnlExpressionImpl implements OgnlBinaryExpression {
+
+  public OgnlBinaryExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitBinaryExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public OgnlExpression getLeft() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.get(0);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getRight() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.size() < 2 ? null : p1.get(1);
+  }
+
+  @NotNull
+  public OgnlTokenType getOperator() {
+    return OgnlPsiUtil.getOperator(this);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlConditionalExpressionImpl.java b/src/main/gen/psi/impl/OgnlConditionalExpressionImpl.java
new file mode 100644
index 0000000..2105da2
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlConditionalExpressionImpl.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlConditionalExpressionImpl extends OgnlExpressionImpl implements OgnlConditionalExpression {
+
+  public OgnlConditionalExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitConditionalExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public OgnlExpression getCondition() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.get(0);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getThen() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.size() < 2 ? null : p1.get(1);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getElse() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.size() < 3 ? null : p1.get(2);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlExpressionImpl.java b/src/main/gen/psi/impl/OgnlExpressionImpl.java
new file mode 100644
index 0000000..9a82d06
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlExpressionImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+import com.intellij.psi.PsiType;
+
+public abstract class OgnlExpressionImpl extends OgnlPsiCompositeElementBase implements OgnlExpression {
+
+  public OgnlExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Nullable
+  public PsiType getType() {
+    return OgnlPsiUtil.getType(this);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlFqnTypeExpressionImpl.java b/src/main/gen/psi/impl/OgnlFqnTypeExpressionImpl.java
new file mode 100644
index 0000000..0ed4ede
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlFqnTypeExpressionImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlFqnTypeExpressionImpl extends OgnlFqnTypeExpressionBase implements OgnlFqnTypeExpression {
+
+  public OgnlFqnTypeExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitFqnTypeExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlIndexedExpressionImpl.java b/src/main/gen/psi/impl/OgnlIndexedExpressionImpl.java
new file mode 100644
index 0000000..ed36109
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlIndexedExpressionImpl.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlIndexedExpressionImpl extends OgnlExpressionImpl implements OgnlIndexedExpression {
+
+  public OgnlIndexedExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitIndexedExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public OgnlExpression getReferenceQualifier() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.get(0);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getIndexExpression() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.size() < 2 ? null : p1.get(1);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlLambdaExpressionImpl.java b/src/main/gen/psi/impl/OgnlLambdaExpressionImpl.java
new file mode 100644
index 0000000..ea3939b
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlLambdaExpressionImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlLambdaExpressionImpl extends OgnlExpressionImpl implements OgnlLambdaExpression {
+
+  public OgnlLambdaExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitLambdaExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getExpression() {
+    return findChildByClass(OgnlExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlLiteralExpressionImpl.java b/src/main/gen/psi/impl/OgnlLiteralExpressionImpl.java
new file mode 100644
index 0000000..177e2d7
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlLiteralExpressionImpl.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlLiteralExpressionImpl extends OgnlExpressionImpl implements OgnlLiteralExpression {
+
+  public OgnlLiteralExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitLiteralExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Nullable
+  public Object getConstantValue() {
+    return OgnlPsiUtil.getConstantValue(this);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlMapEntryElementImpl.java b/src/main/gen/psi/impl/OgnlMapEntryElementImpl.java
new file mode 100644
index 0000000..e1c6e86
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlMapEntryElementImpl.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlMapEntryElementImpl extends OgnlPsiCompositeElementBase implements OgnlMapEntryElement {
+
+  public OgnlMapEntryElementImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitMapEntryElement(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public OgnlExpression getKeyExpression() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.get(0);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getValueExpression() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.size() < 2 ? null : p1.get(1);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlMapExpressionImpl.java b/src/main/gen/psi/impl/OgnlMapExpressionImpl.java
new file mode 100644
index 0000000..034ee59
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlMapExpressionImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlMapExpressionImpl extends OgnlExpressionImpl implements OgnlMapExpression {
+
+  public OgnlMapExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitMapExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public List<OgnlMapEntryElement> getMapEntryElementList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlMapEntryElement.class);
+  }
+
+  @Override
+  @Nullable
+  public OgnlFqnTypeExpression getMapType() {
+    return findChildByClass(OgnlFqnTypeExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlMethodCallExpressionImpl.java b/src/main/gen/psi/impl/OgnlMethodCallExpressionImpl.java
new file mode 100644
index 0000000..cc80c23
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlMethodCallExpressionImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlMethodCallExpressionImpl extends OgnlExpressionImpl implements OgnlMethodCallExpression {
+
+  public OgnlMethodCallExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitMethodCallExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @Nullable
+  public OgnlParameterList getParameterList() {
+    return findChildByClass(OgnlParameterList.class);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getMethod() {
+    return findChildByClass(OgnlExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlNewArrayExpressionImpl.java b/src/main/gen/psi/impl/OgnlNewArrayExpressionImpl.java
new file mode 100644
index 0000000..68dbdd4
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlNewArrayExpressionImpl.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlNewArrayExpressionImpl extends OgnlExpressionImpl implements OgnlNewArrayExpression {
+
+  public OgnlNewArrayExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitNewArrayExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public OgnlExpression getObjectType() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.get(0);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getConstructorExpression() {
+    List<OgnlExpression> p1 = PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+    return p1.size() < 2 ? null : p1.get(1);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlNewExpressionImpl.java b/src/main/gen/psi/impl/OgnlNewExpressionImpl.java
new file mode 100644
index 0000000..378176c
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlNewExpressionImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlNewExpressionImpl extends OgnlExpressionImpl implements OgnlNewExpression {
+
+  public OgnlNewExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitNewExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @Nullable
+  public OgnlParameterList getParameterList() {
+    return findChildByClass(OgnlParameterList.class);
+  }
+
+  @Override
+  @Nullable
+  public OgnlFqnTypeExpression getObjectType() {
+    return findChildByClass(OgnlFqnTypeExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlParameterListImpl.java b/src/main/gen/psi/impl/OgnlParameterListImpl.java
new file mode 100644
index 0000000..496e86b
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlParameterListImpl.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlParameterListImpl extends OgnlPsiCompositeElementBase implements OgnlParameterList {
+
+  public OgnlParameterListImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitParameterList(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public List<OgnlExpression> getParametersList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+  }
+
+  public int getParameterCount() {
+    return OgnlPsiUtil.getParameterCount(this);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlParenthesizedExpressionImpl.java b/src/main/gen/psi/impl/OgnlParenthesizedExpressionImpl.java
new file mode 100644
index 0000000..e934ef4
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlParenthesizedExpressionImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlParenthesizedExpressionImpl extends OgnlExpressionImpl implements OgnlParenthesizedExpression {
+
+  public OgnlParenthesizedExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitParenthesizedExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getExpression() {
+    return findChildByClass(OgnlExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlProjectionExpressionImpl.java b/src/main/gen/psi/impl/OgnlProjectionExpressionImpl.java
new file mode 100644
index 0000000..dc31e57
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlProjectionExpressionImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlProjectionExpressionImpl extends OgnlExpressionImpl implements OgnlProjectionExpression {
+
+  public OgnlProjectionExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitProjectionExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public OgnlExpression getProjectionExpression() {
+    return findNotNullChildByClass(OgnlExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlReferenceExpressionImpl.java b/src/main/gen/psi/impl/OgnlReferenceExpressionImpl.java
new file mode 100644
index 0000000..9386fb3
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlReferenceExpressionImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlReferenceExpressionImpl extends OgnlReferenceExpressionBase implements OgnlReferenceExpression {
+
+  public OgnlReferenceExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitReferenceExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public List<OgnlExpression> getExpressionList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlSelectionExpressionImpl.java b/src/main/gen/psi/impl/OgnlSelectionExpressionImpl.java
new file mode 100644
index 0000000..42f56c2
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlSelectionExpressionImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlSelectionExpressionImpl extends OgnlExpressionImpl implements OgnlSelectionExpression {
+
+  public OgnlSelectionExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitSelectionExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public OgnlExpression getSelectorExpression() {
+    return findNotNullChildByClass(OgnlExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlSequenceExpressionImpl.java b/src/main/gen/psi/impl/OgnlSequenceExpressionImpl.java
new file mode 100644
index 0000000..d07a5dd
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlSequenceExpressionImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlSequenceExpressionImpl extends OgnlExpressionImpl implements OgnlSequenceExpression {
+
+  public OgnlSequenceExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitSequenceExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @NotNull
+  public List<OgnlExpression> getElementsList() {
+    return PsiTreeUtil.getChildrenOfTypeAsList(this, OgnlExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlUnaryExpressionImpl.java b/src/main/gen/psi/impl/OgnlUnaryExpressionImpl.java
new file mode 100644
index 0000000..4be737b
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlUnaryExpressionImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlUnaryExpressionImpl extends OgnlExpressionImpl implements OgnlUnaryExpression {
+
+  public OgnlUnaryExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitUnaryExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getExpression() {
+    return findChildByClass(OgnlExpression.class);
+  }
+
+  @NotNull
+  public OgnlTokenType getUnaryOperator() {
+    return OgnlPsiUtil.getUnaryOperator(this);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlVariableAssignmentExpressionImpl.java b/src/main/gen/psi/impl/OgnlVariableAssignmentExpressionImpl.java
new file mode 100644
index 0000000..59d8eac
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlVariableAssignmentExpressionImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlVariableAssignmentExpressionImpl extends OgnlExpressionImpl implements OgnlVariableAssignmentExpression {
+
+  public OgnlVariableAssignmentExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitVariableAssignmentExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+  @NotNull
+  public String getVariableName() {
+    return OgnlPsiUtil.getVariableName(this);
+  }
+
+  @Override
+  @Nullable
+  public OgnlExpression getAssignment() {
+    return findChildByClass(OgnlExpression.class);
+  }
+
+}
diff --git a/src/main/gen/psi/impl/OgnlVariableExpressionImpl.java b/src/main/gen/psi/impl/OgnlVariableExpressionImpl.java
new file mode 100644
index 0000000..bb88355
--- /dev/null
+++ b/src/main/gen/psi/impl/OgnlVariableExpressionImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
+package com.intellij.lang.ognl.psi.impl;
+
+import java.util.List;
+import org.jetbrains.annotations.*;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.util.PsiTreeUtil;
+import static com.intellij.lang.ognl.OgnlTypes.*;
+import com.intellij.lang.ognl.psi.*;
+
+public class OgnlVariableExpressionImpl extends OgnlVariableExpressionBase implements OgnlVariableExpression {
+
+  public OgnlVariableExpressionImpl(ASTNode node) {
+    super(node);
+  }
+
+  public void accept(@NotNull OgnlVisitor visitor) {
+    visitor.visitVariableExpression(this);
+  }
+
+  public void accept(@NotNull PsiElementVisitor visitor) {
+    if (visitor instanceof OgnlVisitor) accept((OgnlVisitor)visitor);
+    else super.accept(visitor);
+  }
+
+}
diff --git a/src/main/grammar/apache2.txt b/src/main/grammar/apache2.txt
new file mode 100644
index 0000000..190fec4
--- /dev/null
+++ b/src/main/grammar/apache2.txt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2018 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.
+ */
+
+
+// Generated from ognl.bnf, do not modify
\ No newline at end of file
diff --git a/src/main/grammar/ognl.bnf b/src/main/grammar/ognl.bnf
new file mode 100644
index 0000000..ef532d5
--- /dev/null
+++ b/src/main/grammar/ognl.bnf
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2017 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.
+ */
+{
+  classHeader="apache2.txt"
+
+  psiImplUtilClass="com.intellij.lang.ognl.psi.impl.OgnlPsiUtil"
+
+  parserClass="com.intellij.lang.ognl.parser.OgnlParser"
+
+  implements="com.intellij.lang.ognl.psi.OgnlPsiCompositeElement"
+  extends="com.intellij.lang.ognl.psi.impl.OgnlPsiCompositeElementBase"
+
+  psiClassPrefix="Ognl"
+  psiImplClassSuffix="Impl"
+  psiPackage="com.intellij.lang.ognl.psi"
+  psiImplPackage="com.intellij.lang.ognl.psi.impl"
+
+  elementTypeHolderClass="com.intellij.lang.ognl.OgnlTypes"
+  elementTypePrefix=""
+  elementTypeClass="com.intellij.lang.ognl.psi.OgnlTokenType"
+  tokenTypeClass="com.intellij.lang.ognl.psi.OgnlTokenType"
+
+  extends(".*(Expression|Literal)")="expression"
+
+  tokens = [
+    EXPRESSION_START="%{"
+    EXPRESSION_END="}"
+
+    DOT="."
+    COMMA=","
+    COLON=":"
+
+    LPARENTH="("
+    RPARENTH=")"
+    LBRACKET="["
+    RBRACKET="]"
+    LBRACE="{"
+    RBRACE="}"
+
+    AT="@"
+    QUESTION="?"
+    DOLLAR="$"
+    HASH="#"
+
+    PLUS="+"
+    MINUS="-"
+    MULTIPLY="*"
+    DIVISION="/"
+    MODULO="%"
+
+    NEGATE="!"
+    NOT_EQUAL="!="
+    EQUAL="=="
+    EQ="="
+    LESS="<"
+    LESS_EQUAL="<="
+    GREATER=">"
+    GREATER_EQUAL=">="
+
+    EQ_KEYWORD="eq"
+    NEQ_KEYWORD="neq"
+    LT_KEYWORD="lt"
+    LT_EQ_KEYWORD="lte"
+    GT_KEYWORD="gt"
+    GT_EQ_KEYWORD="gte"
+
+    AND_AND="&&"
+    OR_OR="||"
+    AND_KEYWORD="and"
+    OR_KEYWORD="or"
+    NOT_KEYWORD="not"
+
+    OR="|"
+    XOR="^"
+    AND="&"
+    NOT="~"
+
+    BAND_KEYWORD="band"
+    BOR_KEYWORD="bor"
+    XOR_KEYWORD="xor"
+
+    NEW_KEYWORD="new"
+    TRUE_KEYWORD="true"
+    FALSE_KEYWORD="false"
+    NULL_KEYWORD="null"
+
+    INSTANCEOF_KEYWORD="instanceof"
+    NOT_IN_KEYWORD="not in"
+    IN_KEYWORD="in"
+
+    SHIFT_LEFT="<<"
+    SHIFT_RIGHT=">>"
+    SHIFT_RIGHT_LOGICAL=">>>"
+
+    SHIFT_LEFT_KEYWORD="shl"
+    SHIFT_RIGHT_KEYWORD="shr"
+    SHIFT_RIGHT_LOGICAL_KEYWORD="ushr"
+  ]
+}
+
+root ::= EXPRESSION_START rootElement EXPRESSION_END { pin=1 }
+private rootRecover ::= !(EXPRESSION_END)
+private rootElement ::= expression {recoverWhile="rootRecover"}
+
+expression ::= unaryExpression |
+               lambdaExpression |
+               mapExpression |
+               sequenceExpression |
+               parenthesizedExpression |
+               variableAssignmentExpression |
+               conditionalExpression |
+               binaryExpression |
+               newArrayExpression |
+               newExpression |
+               methodCallExpression |
+               indexedExpression |
+               referenceExpression |
+               variableExpression |
+               literalExpression
+{
+  methods=[
+    getType
+  ]
+}
+
+private numberLiteralExpression ::= INTEGER_LITERAL | BIG_INTEGER_LITERAL | DOUBLE_LITERAL | BIG_DECIMAL_LITERAL
+private booleanLiteralExpression ::= "true" | "false"
+private textLiteralExpression ::= STRING_LITERAL | CHARACTER_LITERAL  // TODO detect missing closing quote/tick
+literalExpression ::= numberLiteralExpression |
+                      textLiteralExpression |
+                      booleanLiteralExpression |
+                      "null" {
+  methods=[
+    getConstantValue
+  ]
+}
+
+projectionExpression ::= '{' expression '}'
+{
+  methods=[
+    projectionExpression="expression"
+  ]
+}
+selectionExpression ::= '{' ('?' | '^' | '$') expression '}'
+{
+  methods=[
+    selectorExpression="expression"
+  ]
+}
+
+referenceExpression ::= (variableExpression | ('@')? IDENTIFIER)
+                        ('.' IDENTIFIER)* ('@' IDENTIFIER)?
+                        ('.'  selectionExpression)?
+                        ('.'  projectionExpression )?
+{
+  mixin="com.intellij.lang.ognl.psi.impl.OgnlReferenceExpressionBase"
+}
+
+variableExpression ::= '#' IDENTIFIER {
+  mixin="com.intellij.lang.ognl.psi.impl.OgnlVariableExpressionBase"
+}
+
+variableAssignmentExpression ::= '#' IDENTIFIER '=' expression {
+  methods=[
+    getVariableName
+    assignment="expression"
+  ]
+  pin=3
+}
+
+parameterList ::= expression? (',' expression)* {
+  methods=[
+    parametersList="expression"
+    getParameterCount
+  ]
+}
+methodCallExpression ::= referenceExpression '(' parameterList ')'  {
+  methods=[
+    method="expression"
+  ]
+  pin(".*")="'\('"
+}
+
+private expressionSequenceRequired ::= expression (',' expression)+  { pin(".*")=1 }
+sequenceExpression ::= '{' expressionSequenceRequired '}' {
+  methods=[
+    elementsList="expression"
+  ]
+  pin=1
+}
+
+mapEntryElement ::= expression ':' expression {
+  methods=[
+    expression=""
+    keyExpression="expression[0]"
+    valueExpression="expression[1]"
+  ]
+  name="map entry"
+  pin=1
+}
+private mapExpressionSequence ::= [] mapEntryElement (',' mapEntryElement)* {pin(".*")=1}
+private mapTypeExpression ::= '#@' fqnTypeExpression '@{' {
+  pin=1
+}
+mapExpression ::= ('#{' | mapTypeExpression) mapExpressionSequence '}' {
+  methods=[
+    mapType="fqnTypeExpression"
+  ]
+  pin=1
+}
+
+lambdaExpression ::= ':' '[' expression "]" {
+  pin=1
+}
+
+indexedExpression ::= (referenceExpression | variableExpression) '[' expression ']'
+                      ('.' IDENTIFIER)*
+                      ('.'  selectionExpression | projectionExpression)? {
+  methods=[
+    expression=""
+    referenceQualifier="expression[0]"
+    indexExpression="expression[1]"
+  ]
+  pin=2
+}
+
+parenthesizedExpression ::= '(' expression ')' { pin=1 }
+
+// binary ----------------------------------------------------------------
+private plusMinusOperations ::= '+' | '-'
+private divideMultiplyOperations ::=  '*' | '/' | '%'
+private booleanOperations ::= "&&" | "||" |
+                              "and" | "or" |
+                              "not"
+private bitwiseBooleanOperations ::=  "|" | "^" | "&" | "band" | "bor" | "xor"
+private equalityOperations ::= "==" | "!=" |
+                               "eq" | "neq"
+private relationalOperations ::= '<'  | "<="  | '>'  | ">=" |
+                                 "lt" | "lte" | "gt" | "gte"
+private shiftOperations ::= "<<" | ">>" | ">>>" |
+                            "shl" | "shr" | "ushr"
+private instanceOfOperation ::= "instanceof"
+private setOperations ::= "not in" | "in"
+private binaryOperations ::=
+                           plusMinusOperations |
+                           divideMultiplyOperations |
+                           bitwiseBooleanOperations |
+                           instanceOfOperation |
+                           shiftOperations |
+                           booleanOperations |
+                           equalityOperations |
+                           relationalOperations |
+                           setOperations
+                           { name="operator" }
+binaryExpression ::= expression binaryOperations expression {
+  methods=[
+    expression=""
+    left="expression[0]"
+    right="expression[1]"
+    getOperator
+  ]
+}
+
+private bitwiseOperations ::= '!' | "~"
+private unaryOperator ::= bitwiseOperations |
+                          '+' | '-' | "not"
+unaryExpression ::= unaryOperator expression {
+  methods=[
+    getUnaryOperator
+  ]
+}
+
+private conditionalExpressionTail ::= ':' expression {pin=1}
+conditionalExpression ::= expression '?' expression conditionalExpressionTail {
+  methods=[
+    expression=""
+    condition="expression[0]"
+    then="expression[1]"
+    else="expression[2]"
+  ]
+}
+
+private constructorExpression ::= '(' parameterList ')' {pin=1}
+newExpression ::= "new" fqnTypeExpression constructorExpression {
+  methods=[
+    objectType="fqnTypeExpression"
+  ]
+  pin=1
+}
+
+private arrayConstructorExpression ::= '[' expression? ']' sequenceExpression? {pin=1}
+newArrayExpression ::= "new" fqnTypeExpression arrayConstructorExpression {
+  methods=[
+    expression=""
+    objectType="expression[0]"
+    constructorExpression="expression[1]"
+  ]
+}
+
+
+// common
+fqnTypeExpression ::= IDENTIFIER ('.' IDENTIFIER)* {
+  pin(".*")=1
+  mixin="com.intellij.lang.ognl.psi.impl.OgnlFqnTypeExpressionBase"
+}
diff --git a/src/main/java/com/intellij/struts2/Struts2IconProvider.java b/src/main/java/com/intellij/struts2/Struts2IconProvider.java
new file mode 100644
index 0000000..1cf4c4e
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/Struts2IconProvider.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2014 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;
+
+import com.intellij.ide.IconProvider;
+import com.intellij.jam.model.util.JamCommonUtil;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiModifier;
+import com.intellij.psi.impl.PsiClassImplUtil;
+import com.intellij.struts2.dom.struts.model.StrutsManager;
+import com.intellij.struts2.dom.struts.model.StrutsModel;
+import com.intellij.struts2.facet.StrutsFacet;
+import com.intellij.ui.LayeredIcon;
+import com.intellij.ui.scale.JBUIScale;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * Provides icons for Struts-related code. <br/>Original code posted by Sascha Weinreuter.
+ *
+ * @author Yann C&eacute;bron
+ */
+public class Struts2IconProvider extends IconProvider {
+
+  @Override
+  @Nullable
+  public Icon getIcon(@NotNull final PsiElement element, final int flags) {
+
+    if (!(element instanceof PsiClass psiClass)) {
+      return null;
+    }
+
+    // IconProvider queries non-physical PSI as well (e.g. completion items); check validity
+    if (!element.isPhysical() ||
+        !element.isValid()) {
+      return null;
+    }
+
+    // no icons when no facet present
+    final Module module = ModuleUtilCore.findModuleForPsiElement(element);
+    if (module == null) {
+      return null;
+    }
+
+    final StrutsFacet strutsFacet = StrutsFacet.getInstance(module);
+    if (strutsFacet == null) {
+      return null;
+    }
+
+    // handle suitable JAVA classes --> overlay icon
+    if (psiClass.isInterface() ||
+        psiClass.isEnum() ||
+        !psiClass.hasModifierProperty(PsiModifier.PUBLIC) ||
+        psiClass.hasModifierProperty(PsiModifier.ABSTRACT) ||
+        !JamCommonUtil.isPlainJavaFile(psiClass.getContainingFile())) {
+      return null;
+    }
+
+    final StrutsModel strutsModel = StrutsManager.getInstance(psiClass.getProject()).getCombinedModel(module);
+    if (strutsModel == null ||
+        !strutsModel.isActionClass(psiClass)) {
+      return null;
+    }
+
+    final LayeredIcon layeredIcon = new LayeredIcon(2);
+    final Icon original = PsiClassImplUtil.getClassIcon(flags, psiClass);
+    layeredIcon.setIcon(original, 0);
+    layeredIcon.setIcon(Struts2Icons.Action_small, 1, StrutsIcons.OVERLAY_X_OFFSET, StrutsIcons.OVERLAY_Y_OFFSET);
+    return JBUIScale.scaleIcon(layeredIcon);
+  }
+}
diff --git a/src/main/java/com/intellij/struts2/Struts2Icons.java b/src/main/java/com/intellij/struts2/Struts2Icons.java
new file mode 100644
index 0000000..5a7b8a1
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/Struts2Icons.java
@@ -0,0 +1,20 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.struts2;
+
+import com.intellij.ui.IconManager;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * NOTE THIS FILE IS AUTO-GENERATED
+ * DO NOT EDIT IT BY HAND, run "Generate icon classes" configuration instead
+ */
+public final class Struts2Icons {
+  private static @NotNull Icon load(@NotNull String path, int cacheKey, int flags) {
+    return IconManager.getInstance().loadRasterizedIcon(path, Struts2Icons.class.getClassLoader(), cacheKey, flags);
+  }
+  /** 16x16 */ public static final @NotNull Icon Action = load("icons/action.svg", 1640284181, 0);
+  /** 10x10 */ public static final @NotNull Icon Action_small = load("icons/action_small.svg", -592871696, 0);
+  /** 10x10 */ public static final @NotNull Icon Edit_small = load("icons/edit_small.svg", 1635832574, 0);
+}
diff --git a/src/main/java/com/intellij/struts2/Struts2PresentationProvider.java b/src/main/java/com/intellij/struts2/Struts2PresentationProvider.java
new file mode 100644
index 0000000..2c3a962
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/Struts2PresentationProvider.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2019 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;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.presentation.PresentationProvider;
+import com.intellij.psi.PsiClass;
+import com.intellij.struts2.dom.struts.Include;
+import com.intellij.struts2.dom.struts.StrutsRoot;
+import com.intellij.struts2.dom.struts.action.ExceptionMapping;
+import com.intellij.struts2.dom.struts.action.Result;
+import com.intellij.struts2.dom.struts.strutspackage.*;
+import com.intellij.util.xml.DomUtil;
+import com.intellij.util.xml.GenericAttributeValue;
+
+import javax.swing.*;
+
+/**
+ * Provides icon/name for Struts DOM elements.
+ *
+ * @author Yann C&eacute;bron
+ */
+public class Struts2PresentationProvider extends PresentationProvider {
+
+  @Override
+  public Icon getIcon(final Object o) {
+
+    if (o instanceof DefaultInterceptorRef) {
+      return StrutsIcons.DEFAULT_INTERCEPTOR_REF;
+    }
+
+    if (o instanceof DefaultActionRef) {
+      return StrutsIcons.DEFAULT_ACTION_REF;
+    }
+
+    if (o instanceof DefaultClassRef) {
+      return StrutsIcons.DEFAULT_CLASS_REF;
+    }
+
+    if (o instanceof GlobalResult) {
+      return StrutsIcons.GLOBAL_RESULT;
+    }
+
+    if (o instanceof GlobalExceptionMapping) {
+      return StrutsIcons.GLOBAL_EXCEPTION_MAPPING;
+    }
+
+    if (o instanceof ExceptionMapping) {
+      return AllIcons.Nodes.ExceptionClass;
+    }
+
+    if (o instanceof StrutsRoot) {
+      return StrutsIcons.STRUTS_CONFIG_FILE;
+    }
+
+    if (o instanceof StrutsPackage) {
+      return StrutsIcons.STRUTS_PACKAGE;
+    }
+
+    if (o instanceof InterceptorRef) {
+      final InterceptorOrStackBase interceptorOrStackBase = ((InterceptorRef) o).getName().getValue();
+      if (interceptorOrStackBase instanceof Interceptor) {
+        return AllIcons.Nodes.Plugin;
+      }
+      if (interceptorOrStackBase instanceof InterceptorStack) {
+        return AllIcons.Nodes.Pluginobsolete;
+      }
+    }
+
+    if (o instanceof ResultType resultType) {
+      final GenericAttributeValue<Boolean> resultTypeDefault = resultType.getDefault();
+      if (DomUtil.hasXml(resultTypeDefault) &&
+          resultTypeDefault.getValue() == Boolean.TRUE) {
+        return StrutsIcons.RESULT_TYPE_DEFAULT;
+      }
+      return AllIcons.Debugger.Console;
+    }
+
+    return null;
+  }
+
+  @Override
+  public String getName(final Object o) {
+
+    if (o instanceof Result) {
+      return ((Result) o).getNameOrDefault();
+    }
+
+    if (o instanceof StrutsRoot) {
+      return DomUtil.getFile(((StrutsRoot) o)).getName();
+    }
+
+    if (o instanceof ExceptionMapping) {
+      final PsiClass exceptionClass = ((ExceptionMapping) o).getExceptionClass().getValue();
+      if (exceptionClass != null) {
+        return exceptionClass.getName();
+      }
+      return ((ExceptionMapping) o).getName().getStringValue();
+    }
+
+    if (o instanceof GlobalExceptionMapping) {
+      final PsiClass exceptionClass = ((GlobalExceptionMapping) o).getExceptionClass().getValue();
+      if (exceptionClass != null) {
+        return exceptionClass.getName();
+      }
+      return ((GlobalExceptionMapping) o).getName().getStringValue();
+    }
+
+    if (o instanceof InterceptorRef) {
+      return ((InterceptorRef) o).getName().getStringValue();
+    }
+
+    if (o instanceof DefaultInterceptorRef) {
+      return ((DefaultInterceptorRef) o).getName().getStringValue();
+    }
+
+    if (o instanceof Include) {
+      return ((Include) o).getFile().getStringValue();
+    }
+
+    if (o instanceof GlobalResult) {
+      final String globalResultName = ((GlobalResult) o).getName().getStringValue();
+      return globalResultName != null ? globalResultName : Result.DEFAULT_NAME;
+    }
+
+    if (o instanceof DefaultActionRef) {
+      return ((DefaultActionRef) o).getName().getStringValue();
+    }
+
+    if (o instanceof DefaultClassRef) {
+      return ((DefaultClassRef) o).getDefaultClass().getStringValue();
+    }
+
+    return null;
+  }
+
+}
diff --git a/src/main/java/com/intellij/struts2/Struts2ProblemFileHighlightFilter.java b/src/main/java/com/intellij/struts2/Struts2ProblemFileHighlightFilter.java
new file mode 100644
index 0000000..3ecbfb0
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/Struts2ProblemFileHighlightFilter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2013 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;
+
+import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.openapi.application.ReadAction;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.struts2.dom.struts.model.StrutsManager;
+import com.intellij.struts2.dom.validator.ValidatorManager;
+import com.intellij.struts2.facet.StrutsFacet;
+
+/**
+ * Include {@code struts.xml}-files configured in filesets and all {@code *-validation.xml}-files
+ * for project view error highlighting.
+ * <p/>
+ * TODO include errors provided by DOM-inspections
+ *
+ * @author Yann C&eacute;bron
+ */
+public class Struts2ProblemFileHighlightFilter implements Condition<VirtualFile> {
+
+  private final Project project;
+
+  public Struts2ProblemFileHighlightFilter(final Project project) {
+    this.project = project;
+  }
+
+  @Override
+  public boolean value(final VirtualFile virtualFile) {
+    if (!FileTypeRegistry.getInstance().isFileOfType(virtualFile, XmlFileType.INSTANCE)) {
+      return false;
+    }
+
+    final Module module = ModuleUtilCore.findModuleForFile(virtualFile, project);
+    if (module == null) {
+      return false;
+    }
+
+    if (StrutsFacet.getInstance(module) == null) {
+      return false;
+    }
+
+    final boolean isStrutsXml = ReadAction.compute(() -> {
+      final StrutsManager strutsManager = StrutsManager.getInstance(project);
+
+      final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
+      return psiFile instanceof XmlFile &&
+             strutsManager.isStruts2ConfigFile((XmlFile)psiFile) &&
+             strutsManager.getModelByFile((XmlFile)psiFile) != null;
+    });
+    if (isStrutsXml) {
+      return true;
+    }
+
+    return ReadAction.compute(() -> {
+      final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
+      return psiFile instanceof XmlFile
+             && ValidatorManager.getInstance(project).isValidatorsFile((XmlFile)psiFile);
+    });
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/Struts2ResourceProvider.java b/src/main/java/com/intellij/struts2/Struts2ResourceProvider.java
new file mode 100644
index 0000000..0d45d63
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/Struts2ResourceProvider.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 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;
+
+import com.intellij.javaee.ResourceRegistrar;
+import com.intellij.javaee.StandardResourceProvider;
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * Provides "External resources" (DTDs).
+ *
+ * @author Dmitry Avdeev
+ */
+final class Struts2ResourceProvider implements StandardResourceProvider {
+  @NonNls
+  private static final String DTD_PATH = "/resources/dtds/";
+
+  @Override
+  public void registerResources(final ResourceRegistrar registrar) {
+    addDTDResource(StrutsConstants.STRUTS_2_0_DTD_URI,
+                   StrutsConstants.STRUTS_2_0_DTD_ID,
+                   "struts-2.0.dtd", registrar);
+
+    addDTDResource(StrutsConstants.STRUTS_2_1_DTD_URI,
+                   StrutsConstants.STRUTS_2_1_DTD_ID,
+                   "struts-2.1.dtd", registrar);
+
+    addDTDResource(StrutsConstants.STRUTS_2_1_7_DTD_URI,
+                   StrutsConstants.STRUTS_2_1_7_DTD_ID,
+                   "struts-2.1.7.dtd", registrar);
+
+    addDTDResource(StrutsConstants.STRUTS_2_3_DTD_URI,
+                   StrutsConstants.STRUTS_2_3_DTD_ID,
+                   "struts-2.3.dtd", registrar);
+
+    addDTDResource(StrutsConstants.STRUTS_2_5_DTD_URI,
+                   StrutsConstants.STRUTS_2_5_DTD_ID,
+                   "struts-2.5.dtd", registrar);
+
+
+    addDTDResource(StrutsConstants.VALIDATOR_1_00_DTD_URI,
+                   StrutsConstants.VALIDATOR_1_00_DTD_ID,
+                   "xwork-validator-1.0.dtd", registrar);
+    addDTDResource(StrutsConstants.VALIDATOR_1_00_STRUTS_DTD_URI,
+                   StrutsConstants.VALIDATOR_1_00_STRUTS_DTD_ID,
+                   "xwork-validator-struts-1.0.dtd", registrar);
+
+    addDTDResource(StrutsConstants.VALIDATOR_1_02_DTD_URI,
+                   StrutsConstants.VALIDATOR_1_02_DTD_ID,
+                   "xwork-validator-1.0.2.dtd", registrar);
+    addDTDResource(StrutsConstants.VALIDATOR_1_02_STRUTS_DTD_URI,
+                   StrutsConstants.VALIDATOR_1_02_STRUTS_DTD_ID,
+                   "xwork-validator-struts-1.0.2.dtd", registrar);
+
+    addDTDResource(StrutsConstants.VALIDATOR_1_03_DTD_URI,
+                   StrutsConstants.VALIDATOR_1_03_DTD_ID,
+                   "xwork-validator-1.0.3.dtd", registrar);
+
+    addDTDResource(StrutsConstants.VALIDATOR_CONFIG_DTD_URI,
+                   StrutsConstants.VALIDATOR_CONFIG_DTD_ID,
+                   "xwork-validator-config-1.0.dtd", registrar);
+    addDTDResource(StrutsConstants.VALIDATOR_CONFIG_STRUTS_DTD_URI,
+                   StrutsConstants.VALIDATOR_CONFIG_STRUTS_DTD_ID,
+                   "xwork-validator-config-struts-1.0.dtd", registrar);
+    addDTDResource(StrutsConstants.VALIDATOR_DEFINITION_DTD_URI,
+                   StrutsConstants.VALIDATOR_DEFINITION_DTD_ID,
+                   "xwork-validator-definition-1.0.dtd", registrar);
+  }
+
+  /**
+   * Adds a DTD resource from local DTD resource path.
+   *
+   * @param uri       Resource URI.
+   * @param id        Resource ID.
+   * @param localFile DTD filename.
+   * @param registrar Resource registrar.
+   */
+  private static void addDTDResource(@NonNls final String uri,
+                                     @NonNls final String id,
+                                     @NonNls final String localFile,
+                                     final ResourceRegistrar registrar) {
+    registrar.addStdResource(uri, DTD_PATH + localFile, Struts2ResourceProvider.class);
+    registrar.addStdResource(id, DTD_PATH + localFile, Struts2ResourceProvider.class);
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/Struts2ValidationPresentationProvider.java b/src/main/java/com/intellij/struts2/Struts2ValidationPresentationProvider.java
new file mode 100644
index 0000000..415226e
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/Struts2ValidationPresentationProvider.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 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;
+
+import com.intellij.ide.presentation.PresentationProvider;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.struts2.dom.validator.Field;
+import com.intellij.struts2.dom.validator.FieldValidator;
+import com.intellij.struts2.dom.validator.Message;
+import com.intellij.struts2.dom.validator.Validators;
+import com.intellij.struts2.dom.validator.config.ValidatorConfig;
+import com.intellij.util.xml.DomUtil;
+
+import javax.swing.*;
+
+/**
+ * Presentation icon/name for Validation DOM elements.
+ *
+ * @author Yann C&eacute;bron
+ */
+public class Struts2ValidationPresentationProvider extends PresentationProvider {
+
+  @Override
+  public Icon getIcon(final Object o) {
+
+    if (o instanceof Validators) {
+      return StrutsIcons.VALIDATION_CONFIG_FILE;
+    }
+
+    return null;
+  }
+
+  @Override
+  public String getName(final Object o) {
+
+    if (o instanceof Validators) {
+      return DomUtil.getFile(((Validators) o)).getName();
+    }
+
+    if (o instanceof Field) {
+      return ((Field) o).getName().getStringValue();
+    }
+
+    if (o instanceof FieldValidator) {
+      final ValidatorConfig validatorConfig = ((FieldValidator) o).getType().getValue();
+      return validatorConfig != null ? validatorConfig.getName().getStringValue() : null;
+    }
+
+    if (o instanceof Message) {
+      final String key = ((Message) o).getKey().getStringValue();
+      return StringUtil.isNotEmpty(key) ? key : ((Message) o).getValue();
+    }
+
+    return null;
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/StrutsBundle.java b/src/main/java/com/intellij/struts2/StrutsBundle.java
new file mode 100644
index 0000000..db18f1d
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/StrutsBundle.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2013 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;
+
+import com.intellij.DynamicBundle;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.PropertyKey;
+
+import java.util.function.Supplier;
+
+/**
+ * MessageResource provider.
+ *
+ * @author Yann C&eacute;bron
+ */
+public final class StrutsBundle extends DynamicBundle {
+
+  public static @Nls String message(@NotNull @PropertyKey(resourceBundle = PATH_TO_BUNDLE) String key, Object @NotNull ... params) {
+    return ourInstance.getMessage(key, params);
+  }
+
+  @NotNull
+  public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = PATH_TO_BUNDLE) String key, Object @NotNull ... params) {
+    return ourInstance.getLazyMessage(key, params);
+  }
+
+  private static final String PATH_TO_BUNDLE = "messages.Struts2Bundle";
+  private static final StrutsBundle ourInstance = new StrutsBundle();
+
+  private StrutsBundle() {
+    super(PATH_TO_BUNDLE);
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/StrutsConstants.java b/src/main/java/com/intellij/struts2/StrutsConstants.java
new file mode 100644
index 0000000..265e901
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/StrutsConstants.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2013 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;
+
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * Plugin-wide constants.
+ *
+ * @author Yann C&eacute;bron
+ */
+@SuppressWarnings("SpellCheckingInspection")
+public final class StrutsConstants {
+
+  private StrutsConstants() {
+  }
+
+  @NonNls
+  public static final String STRUTS_2_0_FILTER_CLASS = "org.apache.struts2.dispatcher.FilterDispatcher";
+
+  @NonNls
+  public static final String STRUTS_2_1_FILTER_CLASS = "org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter";
+
+  @NonNls
+  public static final String XWORK_ACTION_CLASS = "com.opensymphony.xwork2.Action";
+
+  /**
+   * Spring object factory.
+   */
+  @NonNls
+  public static final String SPRING_OBJECT_FACTORY_CLASS = "org.apache.struts2.spring.StrutsSpringObjectFactory";
+
+  /**
+   * Default filename for Struts configuration file.
+   */
+  @NonNls
+  public static final String STRUTS_XML_DEFAULT_FILENAME = "struts.xml";
+
+  /**
+   * struts.xml 2.0 URI.
+   */
+  @NonNls
+  public static final String STRUTS_2_0_DTD_URI = "http://struts.apache.org/dtds/struts-2.0.dtd";
+
+  /**
+   * struts.xml 2.0 ID.
+   */
+  @NonNls
+  public static final String STRUTS_2_0_DTD_ID = "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN";
+
+  /**
+   * struts.xml 2.1 URI.
+   */
+  @NonNls
+  public static final String STRUTS_2_1_DTD_URI = "http://struts.apache.org/dtds/struts-2.1.dtd";
+
+  /**
+   * struts.xml 2.1 ID.
+   */
+  @NonNls
+  public static final String STRUTS_2_1_DTD_ID = "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN";
+
+  /**
+   * struts.xml 2.1.7 URI.
+   */
+  @NonNls
+  public static final String STRUTS_2_1_7_DTD_URI = "http://struts.apache.org/dtds/struts-2.1.7.dtd";
+
+  /**
+   * struts.xml 2.1.7 ID.
+   */
+  @NonNls
+  public static final String STRUTS_2_1_7_DTD_ID = "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN";
+
+  /**
+   * struts.xml 2.3 URI.
+   */
+  @NonNls
+  public static final String STRUTS_2_3_DTD_URI = "http://struts.apache.org/dtds/struts-2.3.dtd";
+
+  /**
+   * struts.xml 2.3 ID.
+   */
+  @NonNls
+  public static final String STRUTS_2_3_DTD_ID = "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN";
+
+
+  @NonNls
+  public static final String STRUTS_2_5_DTD_URI = "http://struts.apache.org/dtds/struts-2.5.dtd";
+  @NonNls
+  public static final String STRUTS_2_5_DTD_ID = "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN";
+
+  /**
+   * All struts.xml DTD-IDs/URIs.
+   */
+  @NonNls
+  public static final String[] STRUTS_DTDS = {
+    STRUTS_2_0_DTD_URI, STRUTS_2_0_DTD_ID,
+    STRUTS_2_1_DTD_URI, STRUTS_2_1_DTD_ID,
+    STRUTS_2_1_7_DTD_URI, STRUTS_2_1_7_DTD_ID,
+    STRUTS_2_3_DTD_URI, STRUTS_2_3_DTD_ID,
+    STRUTS_2_5_DTD_URI, STRUTS_2_5_DTD_ID
+  };
+
+  @NonNls
+  public static final String VALIDATOR_1_00_DTD_URI = "http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd";
+  @NonNls
+  public static final String VALIDATOR_1_00_DTD_ID = "-//OpenSymphony Group//XWork Validator 1.0//EN";
+  @NonNls
+  public static final String VALIDATOR_1_00_STRUTS_DTD_URI = "http://struts.apache.org/dtds/xwork-validator-1.0.dtd";
+  @NonNls
+  public static final String VALIDATOR_1_00_STRUTS_DTD_ID = "-//Apache Struts//XWork Validator 1.0//EN";
+
+  @NonNls
+  public static final String VALIDATOR_1_02_DTD_URI = "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd";
+  @NonNls
+  public static final String VALIDATOR_1_02_DTD_ID = "-//OpenSymphony Group//XWork Validator 1.0.2//EN";
+  @NonNls
+  public static final String VALIDATOR_1_02_STRUTS_DTD_URI = "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd";
+  @NonNls
+  public static final String VALIDATOR_1_02_STRUTS_DTD_ID = "-//Apache Struts//XWork Validator 1.0.2//EN";
+
+  @NonNls
+  public static final String VALIDATOR_1_03_DTD_URI = "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd";
+  @NonNls
+  public static final String VALIDATOR_1_03_DTD_ID = "-//Apache Struts//XWork Validator 1.0.3//EN";
+
+  /**
+   * All XXX-validation.xml DTD-IDs/URIs.
+   */
+  @NonNls
+  public static final String[] VALIDATOR_DTDS = {
+    VALIDATOR_1_00_DTD_URI, VALIDATOR_1_00_DTD_ID,
+    VALIDATOR_1_00_STRUTS_DTD_URI, VALIDATOR_1_00_STRUTS_DTD_ID,
+    VALIDATOR_1_02_DTD_URI, VALIDATOR_1_02_DTD_ID,
+    VALIDATOR_1_02_STRUTS_DTD_URI, VALIDATOR_1_02_STRUTS_DTD_ID,
+    VALIDATOR_1_03_DTD_URI, VALIDATOR_1_03_DTD_ID
+  };
+
+  @NonNls
+  public static final String VALIDATOR_CONFIG_DTD_URI = "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd";
+  @NonNls
+  public static final String VALIDATOR_CONFIG_DTD_ID = "-//OpenSymphony Group//XWork Validator Config 1.0//EN";
+  @NonNls
+  public static final String VALIDATOR_CONFIG_STRUTS_DTD_URI = "http://struts.apache.org/dtds/xwork-validator-config-1.0.dtd";
+  @NonNls
+  public static final String VALIDATOR_CONFIG_STRUTS_DTD_ID = "-//Apache Struts//XWork Validator Config 1.0//EN";
+
+
+  @NonNls
+  public static final String VALIDATOR_DEFINITION_DTD_URI = "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd";
+  @NonNls
+  public static final String VALIDATOR_DEFINITION_DTD_ID = "-//Apache Struts//XWork Validator Definition 1.0//EN";
+
+  @NonNls
+  public static final String[] VALIDATOR_CONFIG_DTDS = {
+    VALIDATOR_CONFIG_DTD_URI, VALIDATOR_CONFIG_DTD_ID,
+    VALIDATOR_CONFIG_STRUTS_DTD_URI, VALIDATOR_CONFIG_STRUTS_DTD_ID,
+    VALIDATOR_DEFINITION_DTD_URI, VALIDATOR_DEFINITION_DTD_ID
+  };
+
+  /**
+   * Struts UI taglib URI.
+   */
+  @NonNls
+  public static final String TAGLIB_STRUTS_UI_URI = "/struts-tags";
+
+  /**
+   * Struts UI taglib default prefix.
+   */
+  @NonNls
+  public static final String TAGLIB_STRUTS_UI_PREFIX = "s";
+
+  /**
+   * Struts UI taglib CSS-attributes.
+   */
+  @NonNls
+  public static final String[] TAGLIB_STRUTS_UI_CSS_ATTRIBUTES =
+    new String[]{"buttonCssStyle", "cssErrorStyle", "cssStyle", "doubleCssStyle"};
+
+  /**
+   * Struts jQuery-plugin taglib URI.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_PLUGIN_URI = "/struts-jquery-tags";
+
+  /**
+   * Struts jQuery-plugin taglib default prefix.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_PLUGIN_PREFIX = "sj";
+
+  /**
+   * Struts jQuery-plugin richtext taglib URI.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_RICHTEXT_PLUGIN_URI = "/struts-jquery-richtext-tags";
+
+  /**
+   * Struts jQuery-plugin richtext taglib default prefix.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_RICHTEXT_PLUGIN_PREFIX = "sjr";
+
+  /**
+   * Struts jQuery-plugin chart taglib URI.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_CHART_PLUGIN_URI = "/struts-jquery-chart-tags";
+
+  /**
+   * Struts jQuery-plugin chart taglib default prefix.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_CHART_PLUGIN_PREFIX = "sjc";
+
+  /**
+   * Struts jQuery-plugin tree taglib URI.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_TREE_PLUGIN_URI = "/struts-jquery-tree-tags";
+
+  /**
+   * Struts jQuery-plugin tree taglib default prefix.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_TREE_PLUGIN_PREFIX = "sjt";
+
+  /**
+   * Struts jQuery-plugin grid taglib URI.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_GRID_PLUGIN_URI = "/struts-jquery-grid-tags";
+
+  /**
+   * Struts jQuery-plugin grid taglib default prefix.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_GRID_PLUGIN_PREFIX = "sjg";
+
+  /**
+   * Struts jQuery-plugin mobile taglib URI.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_MOBILE_PLUGIN_URI = "/struts-jquery-mobile-tags";
+
+  /**
+   * Struts jQuery-plugin mobile taglib default prefix.
+   */
+  @NonNls
+  public static final String TAGLIB_JQUERY_MOBILE_PLUGIN_PREFIX = "sjm";
+
+  /**
+   * Struts bootstrap-plugin taglib URI.
+   */
+  @NonNls
+  public static final String TAGLIB_BOOTSTRAP_PLUGIN_URI = "/struts-bootstrap-tags";
+
+  /**
+   * Struts bootstrap-plugin taglib default prefix.
+   */
+  @NonNls
+  public static final String TAGLIB_BOOTSTRAP_PLUGIN_PREFIX = "sb";
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/StrutsFileTemplateGroupDescriptorFactory.java b/src/main/java/com/intellij/struts2/StrutsFileTemplateGroupDescriptorFactory.java
new file mode 100644
index 0000000..e8cbe92
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/StrutsFileTemplateGroupDescriptorFactory.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import com.intellij.ide.fileTemplates.FileTemplateDescriptor;
+import com.intellij.ide.fileTemplates.FileTemplateGroupDescriptor;
+import com.intellij.ide.fileTemplates.FileTemplateGroupDescriptorFactory;
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * Provides templates for struts.xml/validator.xml files.
+ *
+ * @author Yann C&eacute;bron
+ */
+public class StrutsFileTemplateGroupDescriptorFactory implements FileTemplateGroupDescriptorFactory {
+
+  /**
+   * Template for {@code 2.0.x}.
+   */
+  @NonNls
+  public static final String STRUTS_2_0_XML = "struts.xml";
+
+  /**
+   * Template for {@code 2.1.x}.
+   */
+  @NonNls
+  public static final String STRUTS_2_1_XML = "struts_2_1.xml";
+
+  /**
+   * Template for {@code >=2.1.7}.
+   */
+  @NonNls
+  public static final String STRUTS_2_1_7_XML = "struts_2_1_7.xml";
+
+  /**
+   * Template for {@code >=2.3}.
+   */
+  public static final String STRUTS_2_3_XML = "struts_2_3.xml";
+
+  /**
+   * Template for {@code >=2.5}.
+   */
+  public static final String STRUTS_2_5_XML = "struts_2_5.xml";
+
+  /**
+   * Template for {@code validation.xml}.  TODO cannot name "validation.xml" due to SA using this template name.
+   */
+  public static final String VALIDATION_XML = "validator.xml";
+
+  @Override
+  public FileTemplateGroupDescriptor getFileTemplatesDescriptor() {
+    final FileTemplateGroupDescriptor group = new FileTemplateGroupDescriptor(StrutsBundle.message("struts2"),
+                                                                              Struts2Icons.Action);
+    group.addTemplate(new FileTemplateDescriptor(STRUTS_2_0_XML,
+                                                 StrutsIcons.STRUTS_CONFIG_FILE));
+    group.addTemplate(new FileTemplateDescriptor(STRUTS_2_1_XML,
+                                                 StrutsIcons.STRUTS_CONFIG_FILE));
+    group.addTemplate(new FileTemplateDescriptor(STRUTS_2_1_7_XML,
+                                                 StrutsIcons.STRUTS_CONFIG_FILE));
+    group.addTemplate(new FileTemplateDescriptor(STRUTS_2_3_XML,
+                                                 StrutsIcons.STRUTS_CONFIG_FILE));
+    group.addTemplate(new FileTemplateDescriptor(STRUTS_2_5_XML,
+                                                 StrutsIcons.STRUTS_CONFIG_FILE));
+
+    group.addTemplate(new FileTemplateDescriptor(VALIDATION_XML,
+                                                 StrutsIcons.VALIDATION_CONFIG_FILE));
+    return group;
+  }
+
+}
diff --git a/src/main/java/com/intellij/struts2/StrutsFileTemplateProvider.java b/src/main/java/com/intellij/struts2/StrutsFileTemplateProvider.java
new file mode 100644
index 0000000..b641863
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/StrutsFileTemplateProvider.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.ide.fileTemplates.FileTemplateManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.struts2.facet.ui.StrutsVersionDetector;
+import com.intellij.util.text.VersionComparatorUtil;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Yann C&eacute;bron
+ */
+public class StrutsFileTemplateProvider {
+
+  private final String myVersionName;
+  private final boolean my21orNewer;
+
+  public StrutsFileTemplateProvider(Module module) {
+    myVersionName = StrutsVersionDetector.detectStrutsVersion(module);
+    my21orNewer = isNewerThan("2.1");
+  }
+
+  @NotNull
+  public FileTemplate determineFileTemplate(Project project) {
+    String template;
+    if (isNewerThan("2.5")) {
+      template = StrutsFileTemplateGroupDescriptorFactory.STRUTS_2_5_XML;
+    }
+    else if (isNewerThan("2.3")) {
+      template = StrutsFileTemplateGroupDescriptorFactory.STRUTS_2_3_XML;
+    }
+    else if (my21orNewer) {
+      template = isNewerThan("2.1.7") ?
+                 StrutsFileTemplateGroupDescriptorFactory.STRUTS_2_1_7_XML :
+                 StrutsFileTemplateGroupDescriptorFactory.STRUTS_2_1_XML;
+    }
+    else {
+      template = StrutsFileTemplateGroupDescriptorFactory.STRUTS_2_0_XML;
+    }
+
+    final FileTemplateManager fileTemplateManager = FileTemplateManager.getInstance(project);
+    return fileTemplateManager.getJ2eeTemplate(template);
+  }
+
+  public boolean is21orNewer() {
+    return my21orNewer;
+  }
+
+  private boolean isNewerThan(String versionName) {
+    return VersionComparatorUtil.compare(myVersionName, versionName) > 0;
+  }
+}
diff --git a/src/main/java/com/intellij/struts2/StrutsIcons.java b/src/main/java/com/intellij/struts2/StrutsIcons.java
new file mode 100644
index 0000000..3b669d2
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/StrutsIcons.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2014 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;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.ui.LayeredIcon;
+import com.intellij.ui.scale.JBUIScale;
+
+import javax.swing.*;
+
+/**
+ * All icons.
+ *
+ * @author Yann C&eacute;bron
+ */
+public final class StrutsIcons {
+  /**
+   * Icon for struts.xml files.
+   */
+  public static final LayeredIcon STRUTS_CONFIG_FILE = new LayeredIcon(2);
+
+  /**
+   * Icon for validation.xml files.
+   */
+  public static final LayeredIcon VALIDATION_CONFIG_FILE = new LayeredIcon(2);
+
+
+  public static final LayeredIcon ACTION_CLASS = new LayeredIcon(2);
+
+  public static final LayeredIcon STRUTS_VARIABLE = new LayeredIcon(2);
+
+  public static final LayeredIcon STRUTS_PACKAGE = new LayeredIcon(2);
+
+  /**
+   * Vertical offset for small overlay icons.
+   */
+  static final int OVERLAY_Y_OFFSET = JBUIScale.scale(7);
+
+  /**
+   * Horizontal offset for small overlay icons.
+   */
+  static final int OVERLAY_X_OFFSET = JBUIScale.scale(8);
+
+  private StrutsIcons() {
+  }
+
+  /**
+   * Overlay icon for "default" elements.
+   */
+  private static final Icon OVERLAY_DEFAULT = AllIcons.Actions.Checked;
+
+  public static final LayeredIcon RESULT_TYPE_DEFAULT = new LayeredIcon(2);
+
+  public static final LayeredIcon GLOBAL_RESULT = new LayeredIcon(2);
+  public static final LayeredIcon GLOBAL_EXCEPTION_MAPPING = new LayeredIcon(2);
+
+  public static final LayeredIcon DEFAULT_ACTION_REF = new LayeredIcon(2);
+  public static final LayeredIcon DEFAULT_CLASS_REF = new LayeredIcon(2);
+  public static final LayeredIcon DEFAULT_INTERCEPTOR_REF = new LayeredIcon(2);
+
+  // generic reference providers
+  public static final Icon THEME = AllIcons.Gutter.Colors;
+
+  static {
+    STRUTS_CONFIG_FILE.setIcon(StdFileTypes.XML.getIcon(), 0);
+    STRUTS_CONFIG_FILE.setIcon(Struts2Icons.Action_small, 1, OVERLAY_X_OFFSET, OVERLAY_Y_OFFSET);
+
+    VALIDATION_CONFIG_FILE.setIcon(StdFileTypes.XML.getIcon(), 0);
+    VALIDATION_CONFIG_FILE.setIcon(Struts2Icons.Edit_small, 1, OVERLAY_X_OFFSET, OVERLAY_Y_OFFSET);
+
+    ACTION_CLASS.setIcon(AllIcons.Nodes.Class, 0);
+    ACTION_CLASS.setIcon(Struts2Icons.Action_small, 1, OVERLAY_X_OFFSET, OVERLAY_Y_OFFSET);
+
+    STRUTS_VARIABLE.setIcon(AllIcons.Nodes.Variable, 0);
+    STRUTS_VARIABLE.setIcon(Struts2Icons.Action_small, 1, OVERLAY_X_OFFSET, OVERLAY_Y_OFFSET);
+
+    STRUTS_PACKAGE.setIcon(AllIcons.Nodes.Folder, 0);
+    STRUTS_PACKAGE.setIcon(Struts2Icons.Action_small, 1, OVERLAY_X_OFFSET, OVERLAY_Y_OFFSET);
+
+    createGlobalIcon(GLOBAL_RESULT, AllIcons.Vcs.Arrow_right);
+    createGlobalIcon(GLOBAL_EXCEPTION_MAPPING, AllIcons.Nodes.ExceptionClass);
+
+    createDefaultIcon(DEFAULT_ACTION_REF, Struts2Icons.Action);
+    createDefaultIcon(DEFAULT_CLASS_REF, AllIcons.Nodes.Class);
+    createDefaultIcon(DEFAULT_INTERCEPTOR_REF, AllIcons.Nodes.Plugin);
+    createDefaultIcon(RESULT_TYPE_DEFAULT, AllIcons.Debugger.Console);
+  }
+
+  private static void createGlobalIcon(final LayeredIcon icon, final Icon baseIcon) {
+    icon.setIcon(baseIcon, 0);
+    icon.setIcon(AllIcons.General.Web, 1, OVERLAY_X_OFFSET, OVERLAY_Y_OFFSET);
+  }
+
+  private static void createDefaultIcon(final LayeredIcon icon, final Icon baseIcon) {
+    icon.setIcon(baseIcon, 0);
+    icon.setIcon(OVERLAY_DEFAULT, 1, OVERLAY_X_OFFSET, OVERLAY_Y_OFFSET);
+  }
+}
diff --git a/src/main/java/com/intellij/struts2/actions/create/CreateStrutsXmlAction.java b/src/main/java/com/intellij/struts2/actions/create/CreateStrutsXmlAction.java
new file mode 100644
index 0000000..5827a5c
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/actions/create/CreateStrutsXmlAction.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2013 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.actions.create;
+
+import com.intellij.ide.actions.CreateFileAction;
+import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.ide.fileTemplates.FileTemplateUtil;
+import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.PlatformCoreDataKeys;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.StrutsFileTemplateProvider;
+import com.intellij.struts2.StrutsIcons;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Yann C&eacute;bron
+ */
+final class CreateStrutsXmlAction extends CreateFileAction {
+  public CreateStrutsXmlAction() {
+    super(StrutsBundle.messagePointer("create.config.new.file"),
+          StrutsBundle.messagePointer("create.config.new.file.description"),
+          StrutsIcons.STRUTS_CONFIG_FILE);
+  }
+
+  @Override
+  protected boolean isAvailable(final DataContext dataContext) {
+    if (!super.isAvailable(dataContext)) {
+      return false;
+    }
+
+    final Module module = PlatformCoreDataKeys.MODULE.getData(dataContext);
+    return module != null && JavaPsiFacade.getInstance(module.getProject()).findPackage("org.apache.struts2") != null;
+  }
+
+  @Override
+  protected PsiElement @NotNull [] create(@NotNull final String newName, final @NotNull PsiDirectory directory) throws Exception {
+    @NonNls final String fileName = getFileName(newName);
+
+    final Module module = ModuleUtilCore.findModuleForPsiElement(directory);
+    StrutsFileTemplateProvider templateProvider = new StrutsFileTemplateProvider(module);
+    final FileTemplate strutsXmlTemplate = templateProvider.determineFileTemplate(directory.getProject());
+    final PsiElement file = FileTemplateUtil.createFromTemplate(strutsXmlTemplate,
+                                                                fileName,
+                                                                null,
+                                                                directory);
+    return new PsiElement[]{file};
+  }
+
+  @Override
+  protected String getDefaultExtension() {
+    return XmlFileType.DEFAULT_EXTENSION;
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/annotators/ActionAnnotatorBase.java b/src/main/java/com/intellij/struts2/annotators/ActionAnnotatorBase.java
new file mode 100644
index 0000000..a911c67
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/annotators/ActionAnnotatorBase.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2013 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.annotators;
+
+import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
+import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;
+import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
+import com.intellij.icons.AllIcons;
+import com.intellij.navigation.GotoRelatedItem;
+import com.intellij.openapi.editor.markup.GutterIconRenderer;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.openapi.paths.PathReference;
+import com.intellij.psi.*;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.struts2.Struts2Icons;
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.StrutsIcons;
+import com.intellij.struts2.dom.struts.action.Action;
+import com.intellij.struts2.dom.struts.action.Result;
+import com.intellij.struts2.dom.struts.model.StrutsManager;
+import com.intellij.struts2.dom.struts.model.StrutsModel;
+import com.intellij.struts2.dom.validator.ValidatorManager;
+import com.intellij.struts2.facet.StrutsFacet;
+import com.intellij.util.NotNullFunction;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.xml.DomElement;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.*;
+
+/**
+ * Base class for annotating Action-Classes.
+ * Provides gutter icon/Go To Related File-navigation to &lt;action&gt; declaration(s) in struts.xml,
+ * corresponding {@code validation.xml}-files and navigation to result(s) from action methods.
+ *
+ * @author Yann C&eacute;bron
+ */
+public abstract class ActionAnnotatorBase extends RelatedItemLineMarkerProvider {
+  private static DomElementListCellRenderer<Action> getActionRenderer() {
+    return new DomElementListCellRenderer<>(StrutsBundle.message("annotators.action.no.name")) {
+      @Override
+      @NotNull
+      @NonNls
+      public String getAdditionalLocation(final Action action) {
+        return action != null ? "[" + action.getNamespace() + "] " : "";
+      }
+    };
+  }
+
+  private static final NotNullFunction<PathReference, Collection<? extends PsiElement>> PATH_REFERENCE_CONVERTER =
+    pathReference -> {
+      final PsiElement resolve = pathReference.resolve();
+      return resolve != null ? Collections.singleton(resolve) : Collections.emptyList();
+    };
+
+  private static final NotNullFunction<PathReference, Collection<? extends GotoRelatedItem>> PATH_REFERENCE_GOTO_RELATED_ITEM_PROVIDER =
+    pathReference -> {
+      final PsiElement resolve = pathReference.resolve();
+      return resolve != null ? Collections.singleton(new GotoRelatedItem(resolve) {
+        @Override
+        public Icon getCustomIcon() {
+          return pathReference.getIcon();
+        }
+
+        @Override
+        public String getCustomName() {
+          return pathReference.getPath();
+        }
+      }) : Collections.emptyList();
+    };
+
+  /**
+   * Determine the Action-PsiClass.
+   *
+   * @param psiElement Passed from annotator.
+   * @return null if PsiClass cannot be determined or is not suitable.
+   */
+  @Nullable
+  protected abstract PsiClass getActionPsiClass(@NotNull final PsiElement psiElement);
+
+  @Override
+  protected void collectNavigationMarkers(final @NotNull PsiElement element,
+                                          final @NotNull Collection<? super RelatedItemLineMarkerInfo<?>> lineMarkerInfos) {
+    if (!(element instanceof PsiIdentifier)) return;
+    final PsiClass clazz = getActionPsiClass(element.getParent());
+    if (clazz == null || clazz.getNameIdentifier() != element) {
+      return;
+    }
+
+    // do not run on non-public, abstract classes or interfaces
+    if (clazz.isInterface() ||
+        clazz.isAnnotationType() ||
+        !clazz.hasModifierProperty(PsiModifier.PUBLIC) ||
+        clazz.hasModifierProperty(PsiModifier.ABSTRACT)) {
+      return;
+    }
+
+    // short exit if Struts Facet not present
+    final Module module = ModuleUtilCore.findModuleForPsiElement(clazz);
+    if (module == null ||
+        StrutsFacet.getInstance(module) == null) {
+      return;
+    }
+
+    final StrutsManager strutsManager = StrutsManager.getInstance(element.getProject());
+    final StrutsModel strutsModel = strutsManager.getCombinedModel(module);
+    if (strutsModel == null) {
+      return;
+    }
+
+    installValidationTargets(element, lineMarkerInfos, clazz);
+
+    final List<Action> actions = strutsModel.findActionsByClass(clazz);
+    if (actions.isEmpty()) {
+      return;
+    }
+
+    installActionTargets(element, lineMarkerInfos, actions);
+    installActionMethods(lineMarkerInfos, clazz, actions);
+  }
+
+  /**
+   * Annotate action class to {@code <action>}-declarations.
+   *
+   * @param element         Class element to annotate.
+   * @param lineMarkerInfos Current line markers.
+   * @param actions         Corresponding Actions.
+   */
+  private static void installActionTargets(final PsiElement element,
+                                           final Collection<? super RelatedItemLineMarkerInfo<?>> lineMarkerInfos,
+                                           final List<? extends Action> actions) {
+    final String tooltip = actions.size() == 1 ? StrutsBundle.message("annotators.action.goto.tooltip.single") :
+        StrutsBundle.message("annotators.action.goto.tooltip");
+    final NavigationGutterIconBuilder<DomElement> gutterIconBuilder =
+        NavigationGutterIconBuilder.create(Struts2Icons.Action, NavigationGutterIconBuilder.DEFAULT_DOM_CONVERTOR,
+                                           NavigationGutterIconBuilder.DOM_GOTO_RELATED_ITEM_PROVIDER)
+                                   .setAlignment(GutterIconRenderer.Alignment.LEFT)
+                                   .setPopupTitle(StrutsBundle.message("annotators.action.goto.declaration"))
+                                   .setTargets(actions)
+                                   .setTooltipTitle(tooltip)
+                                   .setCellRenderer(ActionAnnotatorBase::getActionRenderer);
+    lineMarkerInfos.add(gutterIconBuilder.createLineMarkerInfo(element));
+  }
+
+  /**
+   * Annotate action-methods of this class with result(s).
+   *
+   * @param lineMarkerInfos Current line markers.
+   * @param clazz           Class to annotate.
+   * @param actions         Corresponding Actions.
+   */
+  private static void installActionMethods(final Collection<? super RelatedItemLineMarkerInfo<?>> lineMarkerInfos,
+                                           final PsiClass clazz,
+                                           final List<? extends Action> actions) {
+    final Map<PsiMethod, Set<PathReference>> pathReferenceMap = new HashMap<>();
+    for (final Action action : actions) {
+      final PsiMethod method = action.searchActionMethod();
+      if (method == null || !clazz.equals(method.getContainingClass())) {
+        continue;
+      }
+
+      final Set<PathReference> pathReferences = new HashSet<>();
+      final List<Result> results = action.getResults();
+      for (Result result : results) {
+        ContainerUtil.addIfNotNull(pathReferences, result.getValue());
+      }
+
+      Set<PathReference> toStore = pathReferenceMap.computeIfAbsent(method, __ -> new HashSet<>());
+      toStore.addAll(pathReferences);
+      pathReferenceMap.put(method, toStore);
+    }
+
+    for (final Map.Entry<PsiMethod, Set<PathReference>> entries : pathReferenceMap.entrySet()) {
+      final NavigationGutterIconBuilder<PathReference> gutterIconBuilder =
+          NavigationGutterIconBuilder.create(AllIcons.Actions.Forward, PATH_REFERENCE_CONVERTER,
+                                             PATH_REFERENCE_GOTO_RELATED_ITEM_PROVIDER)
+                                     .setAlignment(GutterIconRenderer.Alignment.LEFT)
+                                     .setPopupTitle(StrutsBundle.message("annotators.action.goto.result"))
+                                     .setTargets(entries.getValue())
+                                     .setTooltipTitle(StrutsBundle.message("annotators.action.goto.result.tooltip"));
+
+      PsiMethod method = entries.getKey();
+      PsiIdentifier identifier = method.getNameIdentifier();
+      if (identifier != null) {
+        lineMarkerInfos.add(gutterIconBuilder.createLineMarkerInfo(identifier));
+      }
+    }
+  }
+
+  /**
+   * Related {@code validation.xml} files.
+   *
+   * @param element         Class element to annotate.
+   * @param lineMarkerInfos Current line markers.
+   * @param clazz           Class to find validation files for.
+   */
+  private static void installValidationTargets(final PsiElement element,
+                                               final Collection<? super RelatedItemLineMarkerInfo<?>> lineMarkerInfos,
+                                               final PsiClass clazz) {
+    final List<XmlFile> files = ValidatorManager.getInstance(element.getProject()).findValidationFilesFor(clazz);
+    if (files.isEmpty()) {
+      return;
+    }
+
+    final NavigationGutterIconBuilder<PsiElement> validatorBuilder =
+        NavigationGutterIconBuilder.create(StrutsIcons.VALIDATION_CONFIG_FILE)
+                                   .setAlignment(GutterIconRenderer.Alignment.LEFT)
+                                   .setTargets(files)
+                                   .setPopupTitle(StrutsBundle.message("annotators.action.goto.validation"))
+                                   .setTooltipTitle(StrutsBundle.message("annotators.action.goto.validation.tooltip"));
+    lineMarkerInfos.add(validatorBuilder.createLineMarkerInfo(element));
+  }
+
+}
diff --git a/src/main/java/com/intellij/struts2/annotators/ActionJavaAnnotator.java b/src/main/java/com/intellij/struts2/annotators/ActionJavaAnnotator.java
new file mode 100644
index 0000000..391bf70
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/annotators/ActionJavaAnnotator.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 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.annotators;
+
+import com.intellij.ide.highlighter.JavaFileType;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.struts2.Struts2Icons;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * Annotator for JAVA-Action-classes.
+ * Provides gutter icon navigation to &lt;action&gt; declaration(s).
+ *
+ * @author Yann C&eacute;bron
+ */
+public class ActionJavaAnnotator extends ActionAnnotatorBase {
+
+  @Override
+  public String getId() {
+    return "ActionJavaAnnotator";
+  }
+
+  @Override
+  public String getName() {
+    return "Action (Java)";
+  }
+
+  @Nullable
+  @Override
+  public Icon getIcon() {
+    return Struts2Icons.Action;
+  }
+
+  @Override
+  protected PsiClass getActionPsiClass(@NotNull final PsiElement psiElement) {
+    if (!(psiElement instanceof PsiClass)) {
+      return null;
+    }
+
+    // do not run on classes within JSPs
+    if (psiElement.getContainingFile().getFileType() != JavaFileType.INSTANCE) {
+      return null;
+    }
+
+    return (PsiClass)psiElement;
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/annotators/DomElementListCellRenderer.java b/src/main/java/com/intellij/struts2/annotators/DomElementListCellRenderer.java
new file mode 100644
index 0000000..77b81dd
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/annotators/DomElementListCellRenderer.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2007 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.annotators;
+
+import com.intellij.ide.util.PsiElementListCellRenderer;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.xml.DomElement;
+import com.intellij.util.xml.DomManager;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * Renderer for "GoTo"-gutter-popups.
+ *
+ * @param <T> Navigation target DOM element type.
+ * @author Dmitry Avdeev
+ * @author Yann C&eacute;bron
+ */
+abstract class DomElementListCellRenderer<T extends DomElement> extends PsiElementListCellRenderer<XmlTag> {
+
+  private final String unknownElementText;
+
+  protected DomElementListCellRenderer(@Nls final String unknownElementText) {
+    this.unknownElementText = unknownElementText;
+  }
+
+  /**
+   * Gets an additional location string.
+   *
+   * @param domElement Target navigation element.
+   * @return Empty String if not suitable.
+   */
+  @NotNull
+  @NonNls
+  public abstract String getAdditionalLocation(final T domElement);
+
+  @Override
+  public String getElementText(final XmlTag element) {
+    final DomElement domElement = getDomElement(element);
+    if (domElement == null) {
+      return element.getName();
+    }
+
+    final String elementName = domElement.getPresentation().getElementName();
+    return elementName == null ? unknownElementText : elementName;
+  }
+
+  @Override
+  protected String getContainerText(final XmlTag element, final String name) {
+    final String containingFile = " (" + element.getContainingFile().getName() + ')';
+
+    final T domElement = getDomElement(element);
+    if (domElement == null) {
+      return containingFile;
+    }
+
+    return getAdditionalLocation(domElement) + containingFile;
+  }
+
+  @Override
+  protected Icon getIcon(final PsiElement element) {
+    final DomElement domElement = getDomElement((XmlTag) element);
+    if (domElement != null) {
+      final Icon icon = domElement.getPresentation().getIcon();
+      if (icon != null) {
+        return icon;
+      }
+    }
+
+    return super.getIcon(element);
+  }
+
+  @SuppressWarnings({"unchecked"})
+  @Nullable
+  private T getDomElement(@NotNull final XmlTag tag) {
+    return (T) DomManager.getDomManager(tag.getProject()).getDomElement(tag);
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/annotators/JspActionAnnotator.java b/src/main/java/com/intellij/struts2/annotators/JspActionAnnotator.java
new file mode 100644
index 0000000..f81a01c
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/annotators/JspActionAnnotator.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2015 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.annotators;
+
+import com.intellij.codeInsight.daemon.LineMarkerInfo;
+import com.intellij.codeInsight.daemon.LineMarkerProviderDescriptor;
+import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
+import com.intellij.openapi.editor.markup.GutterIconRenderer;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.openapi.util.NotNullLazyValue;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.psi.xml.XmlToken;
+import com.intellij.struts2.Struts2Icons;
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.StrutsConstants;
+import com.intellij.struts2.StrutsIcons;
+import com.intellij.struts2.dom.struts.action.Action;
+import com.intellij.struts2.dom.struts.model.StrutsManager;
+import com.intellij.struts2.dom.struts.model.StrutsModel;
+import com.intellij.struts2.facet.StrutsFacet;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.xml.util.XmlTagUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Annotates custom tags with "action" attribute.
+ *
+ * @author Yann C&eacute;bron
+ */
+public final class JspActionAnnotator extends LineMarkerProviderDescriptor {
+  @NonNls
+  private static final String ACTION_ATTRIBUTE_NAME = "action";
+
+  @NonNls
+  private static final String[] TAGS_WITH_ACTION_ATTRIBUTE = {"action", "form", "reset", "submit", "url"};
+
+  @Override
+  public String getId() {
+    return "JspActionAnnotator";
+  }
+
+  @NotNull
+  @Override
+  public String getName() {
+    return "Action (JSP)";
+  }
+
+  @Override
+  public @NotNull Icon getIcon() {
+    return Struts2Icons.Action;
+  }
+
+  @Override
+  public LineMarkerInfo<?> getLineMarkerInfo(final @NotNull PsiElement psiElement) {
+    return null;
+  }
+
+  @Override
+  public void collectSlowLineMarkers(final @NotNull List<? extends PsiElement> psiElements,
+                                     final @NotNull Collection<? super LineMarkerInfo<?>> lineMarkerInfos) {
+    if (psiElements.isEmpty()) {
+      return;
+    }
+
+    for (final PsiElement element : psiElements) {
+      annotate(element, lineMarkerInfos);
+    }
+  }
+
+  private static void annotate(@NotNull final PsiElement element,
+                               final @NotNull Collection<? super LineMarkerInfo<?>> lineMarkerInfos) {
+    if (!(element instanceof XmlTag xmlTag)) {
+      return;
+    }
+
+    // any of our tags?
+    final String tagName = xmlTag.getLocalName();
+    if (Arrays.binarySearch(TAGS_WITH_ACTION_ATTRIBUTE, tagName) < 0) {
+      return;
+    }
+
+    if (!Objects.equals(xmlTag.getNamespace(), StrutsConstants.TAGLIB_STRUTS_UI_URI)) {
+      return;
+    }
+
+    // short exit when Struts 2 facet not present
+    final Module module = ModuleUtilCore.findModuleForPsiElement(element);
+    if (module == null) {
+      return;
+    }
+
+    if (StrutsFacet.getInstance(module) == null) {
+      return;
+    }
+
+    // special case for <action>
+    final String actionPath = Objects.equals(tagName, ACTION_ATTRIBUTE_NAME) ?
+                              xmlTag.getAttributeValue("name") :
+                              xmlTag.getAttributeValue(ACTION_ATTRIBUTE_NAME);
+    if (actionPath == null) {
+      return;
+    }
+
+    final StrutsModel strutsModel = StrutsManager.getInstance(element.getProject()).getCombinedModel(module);
+    if (strutsModel == null) {
+      return;
+    }
+
+    final String namespace = xmlTag.getAttributeValue("namespace");
+    final List<Action> actions = strutsModel.findActionsByName(actionPath, namespace);
+    if (actions.isEmpty()) {
+      return;
+    }
+
+    // resolve to action method should be exactly 1
+    final NavigationGutterIconBuilder<PsiElement> gutterIconBuilder =
+        NavigationGutterIconBuilder.create(StrutsIcons.ACTION_CLASS).
+            setAlignment(GutterIconRenderer.Alignment.LEFT).
+            setTooltipText(StrutsBundle.message("annotators.jsp.goto.action.method")).
+            setEmptyPopupText(StrutsBundle.message("annotators.jsp.goto.action.method.not.found")).
+            setTargets(NotNullLazyValue.lazy(() -> ContainerUtil.mapNotNull(actions, Action::searchActionMethod)));
+
+    XmlToken identifier = XmlTagUtil.getStartTagNameElement(xmlTag);
+    if (identifier != null) {
+      lineMarkerInfos.add(gutterIconBuilder.createLineMarkerInfo(identifier));
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/annotators/StrutsConventionImplicitUsageProvider.java b/src/main/java/com/intellij/struts2/annotators/StrutsConventionImplicitUsageProvider.java
new file mode 100644
index 0000000..35d5ca4
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/annotators/StrutsConventionImplicitUsageProvider.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2013 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.annotators;
+
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.codeInsight.daemon.ImplicitUsageProvider;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.struts2.StrutsConstants;
+import com.intellij.struts2.model.jam.convention.StrutsConventionConstants;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Yann C&eacute;bron
+ */
+public class StrutsConventionImplicitUsageProvider implements ImplicitUsageProvider {
+
+  @Override
+  public boolean isImplicitUsage(@NotNull PsiElement element) {
+    if (element instanceof PsiClass) {
+      return isConventionActionClass((PsiClass)element);
+    }
+
+    if (element instanceof PsiMethod psiMethod) {
+      if (!checkMethod(psiMethod)) {
+        return false;
+      }
+
+      return isAnnotatedWithAction(psiMethod) ||
+             isConventionActionClass(psiMethod.getContainingClass());
+    }
+    return false;
+  }
+
+  @Override
+  public boolean isImplicitRead(@NotNull PsiElement element) {
+    return false;
+  }
+
+  @Override
+  public boolean isImplicitWrite(@NotNull PsiElement element) {
+    return false;
+  }
+
+  private static boolean checkMethod(PsiMethod psiMethod) {
+    return psiMethod.hasModifierProperty(PsiModifier.PUBLIC) &&
+           !psiMethod.isConstructor() &&
+           !psiMethod.hasModifierProperty(PsiModifier.STATIC) &&
+           !psiMethod.hasModifierProperty(PsiModifier.ABSTRACT);
+  }
+
+  private static boolean isAnnotatedWithAction(PsiModifierListOwner psiModifierListOwner) {
+    return AnnotationUtil.isAnnotated(psiModifierListOwner, StrutsConventionConstants.ACTION, 0);
+  }
+
+  private static boolean isConventionActionClass(@Nullable PsiClass psiClass) {
+    if (psiClass == null ||
+        psiClass.isInterface() ||
+        psiClass.isEnum() ||
+        psiClass.isAnnotationType() ||
+        !psiClass.hasModifierProperty(PsiModifier.PUBLIC) ||
+        psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+      return false;
+    }
+
+    if (isAnnotatedWithAction(psiClass)) {
+      return true;
+    }
+
+    if (AnnotationUtil.isAnnotated(psiClass, StrutsConventionConstants.ACTIONS, 0)) {
+      return true;
+    }
+
+    if (!isConventionPluginPresent(psiClass)) {
+      return false;
+    }
+
+    if (StringUtil.endsWith(psiClass.getName(), "Action")) {
+      return true;
+    }
+
+    return InheritanceUtil.isInheritor(psiClass, StrutsConstants.XWORK_ACTION_CLASS);
+  }
+
+  private static boolean isConventionPluginPresent(PsiElement element) {
+    final PsiClass conventionService = JavaPsiFacade.getInstance(element.getProject()).
+      findClass(StrutsConventionConstants.CONVENTIONS_SERVICE, element.getResolveScope());
+    return conventionService != null;
+  }
+}
diff --git a/src/main/java/com/intellij/struts2/annotators/StrutsFileSetCheckingAnnotator.java b/src/main/java/com/intellij/struts2/annotators/StrutsFileSetCheckingAnnotator.java
new file mode 100644
index 0000000..8f051d5
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/annotators/StrutsFileSetCheckingAnnotator.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2013 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.annotators;
+
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
+import com.intellij.lang.annotation.AnnotationHolder;
+import com.intellij.lang.annotation.Annotator;
+import com.intellij.lang.annotation.HighlightSeverity;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
+import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.PopupStep;
+import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
+import com.intellij.openapi.util.EmptyRunnable;
+import com.intellij.openapi.util.Iconable;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.jsp.JspFile;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.struts2.Struts2Icons;
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.StrutsIcons;
+import com.intellij.struts2.dom.struts.model.StrutsManager;
+import com.intellij.struts2.facet.StrutsFacet;
+import com.intellij.struts2.facet.ui.StrutsFileSet;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.indexing.BuildableRootsChangeRescanningInfo;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * Checks if {@code struts.xml} is registered in any of the file sets in the current module.
+ *
+ * @author Yann C&eacute;bron
+ */
+public class StrutsFileSetCheckingAnnotator implements Annotator {
+
+  @Override
+  public void annotate(@NotNull final PsiElement psiElement, @NotNull final AnnotationHolder holder) {
+    if (!(psiElement instanceof XmlFile xmlFile)) {
+      return;
+    }
+
+    if (psiElement instanceof JspFile) {
+      return;
+    }
+
+    final Module module = ModuleUtilCore.findModuleForPsiElement(psiElement);
+    if (module == null) {
+      return;
+    }
+
+    // do not run when facet not enabled
+    if (StrutsFacet.getInstance(module) == null) {
+      return;
+    }
+
+    final Project project = psiElement.getProject();
+
+    final StrutsManager strutsManager = StrutsManager.getInstance(project);
+    if (!strutsManager.isStruts2ConfigFile(xmlFile)) {
+      return;
+    }
+
+    final VirtualFile currentVirtualFile = xmlFile.getVirtualFile();
+    assert currentVirtualFile != null;
+
+    final Set<StrutsFileSet> allConfigFileSets = strutsManager.getAllConfigFileSets(module);
+    for (final StrutsFileSet configFileSet : allConfigFileSets) {
+      if (configFileSet.hasFile(currentVirtualFile)) {
+        return;
+      }
+    }
+
+    final boolean fileSetAvailable = allConfigFileSets.size() != 0;
+
+    IntentionAction fix;
+    if (fileSetAvailable) {
+      fix = new AddToFileSetFix(xmlFile.getName());
+    }
+    else {
+      fix = new IntentionAction() {
+        @Override
+        @NotNull
+        public String getText() {
+          return StrutsBundle.message("annotators.fileset.edit.facet.settings");
+        }
+
+        @Override
+        @NotNull
+        public String getFamilyName() {
+          return StrutsBundle.message("intentions.family.name");
+        }
+
+        @Override
+        public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile psiFile) {
+          return true;
+        }
+
+        @Override
+        public void invoke(@NotNull final Project project,
+                           final Editor editor,
+                           final PsiFile psiFile) throws IncorrectOperationException {
+          final StrutsFacet strutsFacet = StrutsFacet.getInstance(module);
+          assert strutsFacet != null;
+          ModulesConfigurator.showFacetSettingsDialog(strutsFacet, null);
+        }
+
+        @Override
+        public boolean startInWriteAction() {
+          return false;
+        }
+      };
+    }
+    holder.newAnnotation(HighlightSeverity.WARNING,
+                                     fileSetAvailable ?
+                                     StrutsBundle.message("annotators.fileset.file.not.registered") :
+                                     StrutsBundle.message("annotators.fileset.no.file.sets"))
+        .range(xmlFile)
+    .fileLevel().withFix(fix).create();
+  }
+
+
+  /**
+   * Adds the current struts.xml file to an existing file set.
+   */
+  private static final class AddToFileSetFix extends BaseIntentionAction implements Iconable {
+
+    private AddToFileSetFix(final String filename) {
+      setText(StrutsBundle.message("annotators.fileset.fix.add.to.fileset", filename));
+    }
+
+    @Override
+    @NotNull
+    public String getFamilyName() {
+      return StrutsBundle.message("intentions.family.name");
+    }
+
+    @Override
+    public Icon getIcon(final int flags) {
+      return Struts2Icons.Action;
+    }
+
+    @Override
+    public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
+      return true;
+    }
+
+    @Override
+    public void invoke(@NotNull final Project project,
+                       final Editor editor,
+                       final PsiFile file) throws IncorrectOperationException {
+      final StrutsFacet strutsFacet = StrutsFacet.getInstance(file);
+      assert strutsFacet != null;
+
+      final Set<StrutsFileSet> strutsFileSets = strutsFacet.getConfiguration().getFileSets();
+      final BaseListPopupStep<StrutsFileSet> step =
+        new BaseListPopupStep<>(StrutsBundle.message("annotators.fileset.fix.choose.fileset"),
+                                new ArrayList<>(strutsFileSets)) {
+
+          @Override
+          public Icon getIconFor(final StrutsFileSet aValue) {
+            return StrutsIcons.STRUTS_CONFIG_FILE;
+          }
+
+          @Override
+          public PopupStep onChosen(final StrutsFileSet selectedValue, final boolean finalChoice) {
+            selectedValue.addFile(file.getVirtualFile());
+            ApplicationManager.getApplication()
+              .runWriteAction(() -> {
+                Module module = strutsFacet.getModule();
+                BuildableRootsChangeRescanningInfo info = BuildableRootsChangeRescanningInfo.newInstance().addModule(module);
+                Module[] dependencies = ModuleRootManager.getInstance(module).getDependencies();
+                for (Module dependency : dependencies) {
+                  info.addModule(dependency);
+                }
+                ProjectRootManagerEx.getInstanceEx(project).makeRootsChange(EmptyRunnable.getInstance(), info);
+              });
+
+            // re-highlight (remove annotation)
+            DaemonCodeAnalyzer.getInstance(project).restart();
+
+            return super.onChosen(selectedValue, finalChoice);
+          }
+        };
+      JBPopupFactory.getInstance()
+        .createListPopup(step)
+        .showInBestPositionFor(editor);
+    }
+  }
+}
diff --git a/src/main/java/com/intellij/struts2/annotators/package-info.java b/src/main/java/com/intellij/struts2/annotators/package-info.java
new file mode 100644
index 0000000..6f3020e
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/annotators/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2007 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.
+ */
+
+/**
+ * Provides editor gutter mark navigation and other functionality.
+ */
+package com.intellij.struts2.annotators;
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/BeanPropertyPathConverterBase.java b/src/main/java/com/intellij/struts2/dom/BeanPropertyPathConverterBase.java
new file mode 100644
index 0000000..721b2b3
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/BeanPropertyPathConverterBase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2013 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;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.beanProperties.BeanProperty;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.xml.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DOM-Converter for resolving path to (nested) bean property.
+ * <p/>
+ * See {@code BeanPropertyPathReference}.
+ *
+ * @author Yann C&eacute;bron
+ */
+public abstract class BeanPropertyPathConverterBase extends Converter<List<BeanProperty>>
+    implements CustomReferenceConverter<List<BeanProperty>> {
+
+  /**
+   * Returns the class to search bean properties for.
+   *
+   * @param domElement Parent element.
+   * @return Class or {@code null} if not determinable.
+   */
+  @Nullable
+  protected abstract PsiClass findBeanPropertyClass(@NotNull final DomElement domElement);
+
+  @Override
+  public String toString(@Nullable final List<BeanProperty> beanProperties, final ConvertContext convertContext) {
+    return null;
+  }
+
+  @Override
+  public List<BeanProperty> fromString(@Nullable final String s, final ConvertContext convertContext) {
+    if (s == null) {
+      return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    final GenericAttributeValue<List<BeanProperty>> value =
+        (GenericAttributeValue<List<BeanProperty>>) convertContext.getInvocationElement();
+
+    final PsiReference[] references = createReferences(value, value.getXmlAttributeValue(), convertContext);
+    final ArrayList<BeanProperty> list = new ArrayList<>(references.length);
+    for (final PsiReference reference : references) {
+      final PsiElement resolve = reference.resolve();
+      if (resolve instanceof PsiMethod method) { // can be non-PsiMethod via ParamNameCustomConverter
+        final BeanProperty beanProperty = BeanProperty.createBeanProperty(method);
+        ContainerUtil.addIfNotNull(list, beanProperty);
+      }
+    }
+    return list;
+  }
+
+  /**
+   * Gets the enclosing Tag-DomElement.
+   *
+   * @param context Current context.
+   * @return Parent element or {@code null} if none found (should not happen in valid XML).
+   */
+  @Nullable
+  protected static DomElement findEnclosingTag(final ConvertContext context) {
+    final DomElement current = context.getInvocationElement();
+    final DomElement parent = current.getParent();
+    return parent != null ? parent.getParent() : null;
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/ConverterUtil.java b/src/main/java/com/intellij/struts2/dom/ConverterUtil.java
new file mode 100644
index 0000000..be094a3
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/ConverterUtil.java
@@ -0,0 +1,95 @@
+/*
+ * 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;
+
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.struts2.dom.struts.model.StrutsManager;
+import com.intellij.struts2.dom.struts.model.StrutsModel;
+import com.intellij.struts2.dom.struts.strutspackage.StrutsPackage;
+import com.intellij.util.xml.ConvertContext;
+import com.intellij.util.xml.DomUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.regex.Pattern;
+
+/**
+ * Utility methods for DOM-Converters.
+ *
+ * @author Yann C&eacute;bron
+ */
+public final class ConverterUtil {
+
+  // "{0}" through "{9}"
+  private static final Pattern WILDCARD_PATTERN = Pattern.compile("\\{\\d}");
+
+  private ConverterUtil() {
+  }
+
+  /**
+   * Gets the StrutsModel for the current context (=file).
+   *
+   * @param context Invoking context.
+   * @return {@code null} if no StrutsModel found by current file (e.g. not in any fileset).
+   */
+  @Nullable
+  public static StrutsModel getStrutsModel(final ConvertContext context) {
+    final XmlFile xmlFile = context.getFile();
+    return StrutsManager.getInstance(xmlFile.getProject()).getModelByFile(xmlFile);
+  }
+
+  /**
+   * Gets the StrutsModel for the current context (=file) or combined model for current module.
+   *
+   * @param context Invoking context.
+   * @return {@code null} if no StrutsModel found in current file/module.
+   */
+  @Nullable
+  public static StrutsModel getStrutsModelOrCombined(final ConvertContext context) {
+    final StrutsModel modelByFile = getStrutsModel(context);
+    if (modelByFile != null) {
+      return modelByFile;
+    }
+
+    return StrutsManager.getInstance(context.getFile().getProject()).getCombinedModel(context.getModule());
+  }
+
+  /**
+   * Returns the current (parent) {@code <package>} element.
+   *
+   * @param context Invoking context.
+   * @return Parent package.
+   */
+  @NotNull
+  public static StrutsPackage getCurrentStrutsPackage(final ConvertContext context) {
+    final StrutsPackage strutsPackage = DomUtil.getParentOfType(context.getInvocationElement(),
+                                                                StrutsPackage.class,
+                                                                true);
+    assert strutsPackage != null : context.getInvocationElement();
+    return strutsPackage;
+  }
+
+  /**
+   * Returns whether the value contains a wildcard-reference.
+   *
+   * @param value Value to check for wildcard pattern.
+   * @return {@code true} if contains wildcard value.
+   */
+  public static boolean hasWildcardReference(@Nullable final String value) {
+    return value != null && WILDCARD_PATTERN.matcher(value).find();
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/ExtendableClassConverter.java b/src/main/java/com/intellij/struts2/dom/ExtendableClassConverter.java
new file mode 100644
index 0000000..a1f140e
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/ExtendableClassConverter.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015 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;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.util.xml.ConvertContext;
+import com.intellij.util.xml.Converter;
+import com.intellij.util.xml.CustomReferenceConverter;
+import com.intellij.util.xml.ExtendClass;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Converter for "class" attribute. Must be used in conjunction with {@link ExtendClass} to
+ * determine valid references (interface allowed, non-public class allowed, ..).
+ *
+ * @author Yann C&eacute;bron
+ */
+public abstract class ExtendableClassConverter extends Converter<PsiClass>
+    implements CustomReferenceConverter<PsiClass> {
+
+  /**
+   * Stores the reference type display name(s).
+   */
+  public static final Key<String[]> REFERENCES_TYPES = Key.create("STRUTS2_REFERENCE_TYPES");
+
+  /**
+   * References from this EP will be added automatically.
+   */
+  public static final ExtensionPointName<ExtendableClassConverterContributor> EP_NAME =
+    new ExtensionPointName<>("com.intellij.struts2.classContributor");
+
+
+  /**
+   * Contributes results to {@link ExtendableClassConverter}.
+   * <p/>
+   * If the provided reference implements {@link com.intellij.codeInspection.LocalQuickFixProvider}
+   * its fixes will be added automatically.
+   *
+   * @author Yann C&eacute;bron
+   */
+  public abstract static class ExtendableClassConverterContributor {
+
+    /**
+     * Returns this contributor's type name for display in messages.
+     *
+     * @return Type name.
+     */
+    @NotNull
+    public abstract String getTypeName();
+
+    /**
+     * Is this contributor suitable in the current resolving context.
+     *
+     * @param convertContext Current context.
+     * @return true if yes, false otherwise.
+     */
+    public abstract boolean isSuitable(@NotNull final ConvertContext convertContext);
+
+    /**
+     * Creates references if this contributor is suitable.
+     *
+     * @param convertContext Current context.
+     * @param psiElement     Reference element.
+     * @param extendClass    Extend class definition for this element.
+     * @return References.
+     */
+    public abstract PsiReference @NotNull [] getReferences(@NotNull final ConvertContext convertContext,
+                                                           @NotNull final PsiElement psiElement,
+                                                           @NotNull final ExtendClass extendClass);
+
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/StrutsDomConstants.java b/src/main/java/com/intellij/struts2/dom/StrutsDomConstants.java
new file mode 100644
index 0000000..0c042f6
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/StrutsDomConstants.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011 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;
+
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * DOM-related constants.
+ *
+ * @author Yann C&eacute;bron
+ */
+public final class StrutsDomConstants {
+
+  private StrutsDomConstants() {
+  }
+
+  /**
+   * DOM-Namespace-Key for struts.xml
+   */
+  @NonNls
+  public static final String STRUTS_NAMESPACE_KEY = "struts namespace";
+
+  /**
+   * DOM-Namespace-Key for validation.xml
+   */
+  @NonNls
+  public static final String VALIDATOR_NAMESPACE_KEY = "validator namespace";
+
+  /**
+   * DOM-Namespace-Key for validator-config.xml
+   */
+  @NonNls
+  public static final String VALIDATOR_CONFIG_NAMESPACE_KEY = "validator config namespace";
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelInspection.java b/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelInspection.java
new file mode 100644
index 0000000..f318593
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelInspection.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2013 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.inspection;
+
+import com.intellij.codeInspection.options.OptPane;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.dom.ConverterUtil;
+import com.intellij.struts2.dom.ExtendableClassConverter;
+import com.intellij.struts2.dom.params.ParamNameConverter;
+import com.intellij.struts2.dom.params.ParamsElement;
+import com.intellij.struts2.dom.struts.HasResultType;
+import com.intellij.struts2.dom.struts.StrutsRoot;
+import com.intellij.struts2.dom.struts.action.Action;
+import com.intellij.struts2.dom.struts.action.ActionMethodConverter;
+import com.intellij.struts2.dom.struts.action.Result;
+import com.intellij.struts2.dom.struts.action.StrutsPathReferenceConverter;
+import com.intellij.struts2.dom.struts.impl.path.ResultTypeResolver;
+import com.intellij.struts2.dom.struts.model.StrutsManager;
+import com.intellij.struts2.dom.struts.strutspackage.ResultType;
+import com.intellij.struts2.facet.ui.StrutsFileSet;
+import com.intellij.util.io.URLUtil;
+import com.intellij.util.xml.*;
+import com.intellij.util.xml.highlighting.BasicDomElementsInspection;
+import com.intellij.util.xml.highlighting.DomElementAnnotationHolder;
+import com.intellij.util.xml.highlighting.DomHighlightingHelper;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+import static com.intellij.codeInspection.options.OptPane.checkbox;
+import static com.intellij.codeInspection.options.OptPane.pane;
+
+/**
+ * Default DOM-Model inspection for struts.xml files.
+ *
+ * @author Yann C&eacute;bron
+ */
+public class Struts2ModelInspection extends BasicDomElementsInspection<StrutsRoot> {
+
+  /**
+   * @noinspection PublicField
+   */
+  public boolean ignoreExtendableClass;
+
+  public Struts2ModelInspection() {
+    super(StrutsRoot.class);
+  }
+
+  @Override
+  public @NotNull OptPane getOptionsPane() {
+    return pane(
+      checkbox("ignoreExtendableClass", StrutsBundle.message("inspections.struts2.model.do.not.check.extendable.class")));
+  }
+
+  /**
+   * Only inspect struts.xml files configured in fileset.
+   *
+   * @param strutsRootDomFileElement Root element of file to inspect.
+   * @param holder                   Holder.
+   */
+  @Override
+  public void checkFileElement(final @NotNull DomFileElement<StrutsRoot> strutsRootDomFileElement,
+                               final @NotNull DomElementAnnotationHolder holder) {
+    final Module module = strutsRootDomFileElement.getModule();
+    if (module == null) {
+      return;
+    }
+
+    final XmlFile xmlFile = strutsRootDomFileElement.getFile();
+    final VirtualFile virtualFile = xmlFile.getVirtualFile();
+
+    final Set<StrutsFileSet> fileSets = StrutsManager.getInstance(xmlFile.getProject()).getAllConfigFileSets(module);
+    for (final StrutsFileSet strutsFileSet : fileSets) {
+      if (strutsFileSet.hasFile(virtualFile)) {
+        super.checkFileElement(strutsRootDomFileElement, holder);
+        break;
+      }
+    }
+  }
+
+  @Override
+  protected boolean shouldCheckResolveProblems(final GenericDomValue value) {
+    final Converter converter = value.getConverter();
+
+    // we roll our own checking for "class" in Struts2ModelInspectionVisitor
+    if (converter instanceof ExtendableClassConverter) {
+      return false;
+    }
+
+    // hack for STRPL-85: suppress <param>-highlighting within <result> for certain result-types
+    if (converter instanceof ParamNameConverter) {
+      final Result result = DomUtil.getParentOfType(value, Result.class, false);
+      if (result != null) {
+        final ResultType resultType = result.getEffectiveResultType();
+        if (resultType == null) {
+          return false; // error
+        }
+
+        final String resultTypeValue = resultType.getName().getStringValue();
+        if (resultTypeValue != null && ResultTypeResolver.isChainOrRedirectType(resultTypeValue)) {
+          return false;
+        }
+      }
+    }
+
+    final String stringValue = value.getStringValue();
+
+    // suppress <action> "method" when using wildcards
+    if (converter instanceof ActionMethodConverter &&
+        ConverterUtil.hasWildcardReference(stringValue)) {
+      return false;
+    }
+
+    // suppress <result> path
+    if (converter instanceof StrutsPathReferenceConverter) {
+
+      if (stringValue == null) {
+        return false;
+      }
+
+      // nested <param>-tags are present
+      if (!((ParamsElement)value).getParams().isEmpty()) {
+        return false;
+      }
+
+      // unsupported result-type
+      final ResultType resultType = ((HasResultType)value).getEffectiveResultType();
+      if (resultType == null) {
+        return false;
+      }
+
+      if (!ResultTypeResolver.hasResultTypeContributor(resultType.getName().getStringValue())) {
+        return false;
+      }
+
+      // suppress paths with wildcard reference
+      if (ConverterUtil.hasWildcardReference(stringValue)) {
+        final Action action = DomUtil.getParentOfType(value, Action.class, true);
+        return action != null && !action.isWildcardMapping();
+      }
+
+      // "${actionProperty}"
+      if (StringUtil.startsWith(stringValue, "${")) {
+        return false;
+      }
+
+      // global URLs
+      if (URLUtil.containsScheme(stringValue)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  @Override
+  protected void checkDomElement(final @NotNull DomElement element,
+                                 final @NotNull DomElementAnnotationHolder holder,
+                                 final @NotNull DomHighlightingHelper helper) {
+    final int oldSize = holder.getSize();
+
+    element.accept(new Struts2ModelInspectionVisitor(holder, ignoreExtendableClass));
+
+    if (oldSize == holder.getSize()) {
+      super.checkDomElement(element, holder, helper);
+    }
+  }
+
+  @Override
+  public String @NotNull [] getGroupPath() {
+    return new String[]{StrutsBundle.message("inspections.group.path.name"), getGroupDisplayName()};
+  }
+
+  @Override
+  @NotNull
+  @NonNls
+  public String getShortName() {
+    return "Struts2ModelInspection";
+  }
+}
diff --git a/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelInspectionVisitor.java b/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelInspectionVisitor.java
new file mode 100644
index 0000000..703f4b6
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelInspectionVisitor.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2019 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.inspection;
+
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.LocalQuickFixProvider;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.xml.XmlElement;
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.dom.ConverterUtil;
+import com.intellij.struts2.dom.ExtendableClassConverter;
+import com.intellij.struts2.dom.struts.Bean;
+import com.intellij.struts2.dom.struts.action.Action;
+import com.intellij.struts2.dom.struts.action.Result;
+import com.intellij.struts2.dom.struts.strutspackage.DefaultClassRef;
+import com.intellij.struts2.dom.struts.strutspackage.Interceptor;
+import com.intellij.struts2.dom.struts.strutspackage.ResultType;
+import com.intellij.struts2.dom.struts.strutspackage.StrutsPackage;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.containers.MultiMap;
+import com.intellij.util.xml.*;
+import com.intellij.util.xml.highlighting.DomElementAnnotationHolder;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Provides extended highlighting for various elements.
+ *
+ * @author Yann C&eacute;bron
+ */
+class Struts2ModelInspectionVisitor implements DomElementVisitor {
+
+  private final DomElementAnnotationHolder holder;
+  private final boolean myIgnoreExtendableClass;
+
+  Struts2ModelInspectionVisitor(final DomElementAnnotationHolder holder,
+                                boolean ignoreExtendableClass) {
+    this.holder = holder;
+    myIgnoreExtendableClass = ignoreExtendableClass;
+  }
+
+  @Override
+  public void visitDomElement(final DomElement element) {
+  }
+
+  public void visitAction(final Action action) {
+    final GenericAttributeValue<PsiClass> actionClass = action.getActionClass();
+    if (action.isWildcardMapping() &&
+        ConverterUtil.hasWildcardReference(actionClass.getStringValue())) {
+      return;
+    }
+
+    checkExtendableClassConverter(actionClass);
+
+    // default DOM duplicate highlighting works only for "plain" @NameValue
+    MultiMap<String, Result> duplicatedResultNames = MultiMap.create();
+    for (Result result : action.getResults()) {
+      duplicatedResultNames.putValue(result.getNameOrDefault(), result);
+    }
+
+    for (Map.Entry<String, Collection<Result>> entry : duplicatedResultNames.entrySet()) {
+      if (entry.getValue().size() == 1) continue;
+
+      for (Result result : entry.getValue()) {
+        holder.createProblem(result.getName(), XmlDomBundle.message("dom.inspections.identity",
+                                                                    ElementPresentationManager.getTypeNameForObject(result)));
+      }
+    }
+  }
+
+  public void visitBean(final Bean bean) {
+    checkExtendableClassConverter(bean.getBeanClass());
+  }
+
+  public void visitDefaultClassRef(final DefaultClassRef defaultClassRef) {
+    checkExtendableClassConverter(defaultClassRef.getDefaultClass());
+  }
+
+  public void visitInterceptor(final Interceptor interceptor) {
+    checkExtendableClassConverter(interceptor.getInterceptorClass());
+  }
+
+  public void visitResultType(final ResultType resultType) {
+    checkExtendableClassConverter(resultType.getResultTypeClass());
+  }
+
+  public void visitStrutsPackage(final StrutsPackage strutsPackage) {
+    final String namespace = strutsPackage.getNamespace().getStringValue();
+    if (namespace != null && !StringUtil.startsWithChar(namespace, '/')) {
+      holder.createProblem(strutsPackage.getNamespace(),
+                           StrutsBundle.message("dom.highlighting.struts.package.must.start.with.slash"));
+    }
+  }
+
+  private void checkExtendableClassConverter(final GenericAttributeValue clazzAttributeValue) {
+    if (myIgnoreExtendableClass) return;
+
+    final XmlElement xmlElement = DomUtil.getValueElement(clazzAttributeValue);
+    if (xmlElement == null) {
+      return;
+    }
+
+    final PsiReference[] psiReferences = xmlElement.getReferences();
+    for (final PsiReference psiReference : psiReferences) {
+      final PsiElement resolveElement = psiReference.resolve();
+      if (resolveElement instanceof PsiClass) {
+        return;
+      }
+    }
+
+    final String[] referenceTypesUserData = clazzAttributeValue.getUserData(ExtendableClassConverter.REFERENCES_TYPES);
+    final String referenceTypes = referenceTypesUserData != null ?
+                                  StringUtil.join(referenceTypesUserData, "|") :
+                                  StrutsBundle.message("dom.extendable.class.converter.type.class");
+
+    final String message = StrutsBundle.message("dom.extendable.class.converter.cannot.resolve",
+                                                referenceTypes,
+                                                clazzAttributeValue.getStringValue());
+
+    // merge all available QuickFixes (create class/package(s)..)
+    LocalQuickFix[] quickFixes = LocalQuickFix.EMPTY_ARRAY;
+    for (final PsiReference psiReference : psiReferences) {
+      if (psiReference instanceof LocalQuickFixProvider) {
+        final LocalQuickFix[] fixes = ((LocalQuickFixProvider)psiReference).getQuickFixes();
+        if (fixes != null) {
+          quickFixes = ArrayUtil.mergeArrays(fixes, quickFixes);
+        }
+      }
+    }
+
+    holder.createProblem(clazzAttributeValue, message, quickFixes);
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelValidator.java b/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelValidator.java
new file mode 100644
index 0000000..3cf63ca
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/inspection/Struts2ModelValidator.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2015 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.inspection;
+
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.openapi.compiler.CompileContext;
+import com.intellij.openapi.compiler.util.InspectionValidatorUtil;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.dom.struts.model.StrutsManager;
+import com.intellij.struts2.dom.struts.model.StrutsModel;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.FactoryMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Validator for struts.xml files when running "Build Project".
+ *
+ * @author Yann C&eacute;bron
+ */
+final class Struts2ModelValidator extends ValidatorBase {
+  public Struts2ModelValidator() {
+    super("Struts 2 Model Validator", StrutsBundle.message("inspections.struts2.model.validator"),
+          StrutsBundle.message("inspections.struts2.model.validator.progress"));
+  }
+
+  @Override
+  public Collection<VirtualFile> getFilesToProcess(final Project project, final CompileContext context) {
+    final StrutsManager strutsManager = StrutsManager.getInstance(project);
+    final PsiManager psiManager = PsiManager.getInstance(project);
+
+    // cache validation settings per module
+    final Map<Module, Boolean> enabledForModule =
+      FactoryMap.create(module1 -> isEnabledForModule(module1));
+
+    final Set<VirtualFile> files = new HashSet<>();
+    for (final VirtualFile file : context.getCompileScope().getFiles(XmlFileType.INSTANCE, false)) {
+      final Module module = context.getModuleByFile(file);
+      if (module != null &&
+          enabledForModule.get(module)) {
+        final PsiFile psiFile = psiManager.findFile(file);
+        if (psiFile instanceof XmlFile) {
+          final StrutsModel model = strutsManager.getModelByFile((XmlFile)psiFile);
+          if (model != null) {
+            for (final XmlFile configFile : model.getConfigFiles()) {
+              ContainerUtil.addIfNotNull(files, configFile.getVirtualFile());
+            }
+          }
+        }
+      }
+    }
+
+    InspectionValidatorUtil.expandCompileScopeIfNeeded(files, context);
+    return files;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Class<? extends LocalInspectionTool> @NotNull [] getInspectionToolClasses(CompileContext context) {
+    return new Class[]{Struts2ModelInspection.class};
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/inspection/ValidatorBase.java b/src/main/java/com/intellij/struts2/dom/inspection/ValidatorBase.java
new file mode 100644
index 0000000..9de4036
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/inspection/ValidatorBase.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 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.inspection;
+
+import com.intellij.compiler.options.ValidationConfiguration;
+import com.intellij.openapi.compiler.CompileScope;
+import com.intellij.openapi.compiler.util.InspectionValidator;
+import com.intellij.openapi.module.Module;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Base-class for validators.
+ *
+ * @author Yann C&eacute;bron
+ */
+abstract class ValidatorBase extends InspectionValidator {
+
+  protected ValidatorBase(@NonNls @NotNull String id, @NotNull String description,
+                          @NotNull String progressIndicatorText) {
+    super(id, description, progressIndicatorText);
+  }
+
+  protected final boolean isEnabledForModule(final Module module) {
+    return ValidationConfiguration.getInstance(module.getProject()).isSelected(getId());
+  }
+
+  @Override
+  public final boolean isAvailableOnScope(@NotNull final CompileScope scope) {
+    for (final Module module : scope.getAffectedModules()) {
+      if (isEnabledForModule(module)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/inspection/ValidatorConfigModelInspection.java b/src/main/java/com/intellij/struts2/dom/inspection/ValidatorConfigModelInspection.java
new file mode 100644
index 0000000..4be99ec
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/inspection/ValidatorConfigModelInspection.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 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.inspection;
+
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.dom.validator.config.ValidatorsConfig;
+import com.intellij.util.xml.highlighting.BasicDomElementsInspection;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Yann C&eacute;bron
+ */
+public class ValidatorConfigModelInspection extends BasicDomElementsInspection<ValidatorsConfig> {
+
+  public ValidatorConfigModelInspection() {
+    super(ValidatorsConfig.class);
+  }
+
+  @Override
+  public String @NotNull [] getGroupPath() {
+    return new String[]{StrutsBundle.message("inspections.group.path.name"), getGroupDisplayName()};
+  }
+
+  @Override
+  @NotNull
+  @NonNls
+  public String getShortName() {
+    return "ValidatorConfigModelInspection";
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/inspection/ValidatorModelInspection.java b/src/main/java/com/intellij/struts2/dom/inspection/ValidatorModelInspection.java
new file mode 100644
index 0000000..0f80423
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/inspection/ValidatorModelInspection.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012 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.inspection;
+
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.dom.validator.Validators;
+import com.intellij.util.xml.highlighting.BasicDomElementsInspection;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Default DOM-Model inspection for validator.xml files.
+ *
+ * @author Yann C&eacute;bron
+ */
+public class ValidatorModelInspection extends BasicDomElementsInspection<Validators> {
+
+  public ValidatorModelInspection() {
+    super(Validators.class);
+  }
+
+  @Override
+  public String @NotNull [] getGroupPath() {
+    return new String[]{StrutsBundle.message("inspections.group.path.name"), getGroupDisplayName()};
+  }
+
+  @Override
+  @NotNull
+  @NonNls
+  public String getShortName() {
+    return "ValidatorModelInspection";
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/inspection/ValidatorModelValidator.java b/src/main/java/com/intellij/struts2/dom/inspection/ValidatorModelValidator.java
new file mode 100644
index 0000000..19fdd1f
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/inspection/ValidatorModelValidator.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2015 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.inspection;
+
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.ide.highlighter.XmlFileType;
+import com.intellij.openapi.compiler.CompileContext;
+import com.intellij.openapi.compiler.util.InspectionValidatorUtil;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.module.ModuleUtilCore;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.struts2.StrutsBundle;
+import com.intellij.struts2.dom.validator.ValidatorManager;
+import com.intellij.struts2.facet.StrutsFacet;
+import com.intellij.util.containers.FactoryMap;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Validator for validation.xml/validators.xml files when running "Build Project".
+ *
+ * @author Yann C&eacute;bron
+ */
+final class ValidatorModelValidator extends ValidatorBase {
+  @NonNls
+  private static final String FILENAME_EXTENSION_VALIDATION_XML = "-validation.xml";
+
+  public ValidatorModelValidator() {
+    super("Struts 2 Validation Model Validator", StrutsBundle.message("inspections.validator.model.validator"),
+          StrutsBundle.message("inspections.validator.model.validator.progress")
+    );
+  }
+
+  @Override
+  public Collection<VirtualFile> getFilesToProcess(final Project project, final CompileContext context) {
+    final PsiManager psiManager = PsiManager.getInstance(project);
+    final ValidatorManager validatorManager = ValidatorManager.getInstance(project);
+
+    // cache S2facet/validation settings per module
+    final Map<Module, Boolean> enabledForModule =
+      FactoryMap.create(module1 -> isEnabledForModule(module1) &&
+                                   StrutsFacet.getInstance(module1) != null);
+
+    // collect all validation.xml files located in sources of S2-modules
+    final Set<VirtualFile> files = new HashSet<>();
+    for (final VirtualFile file : context.getProjectCompileScope().getFiles(XmlFileType.INSTANCE, true)) {
+      if (StringUtil.endsWith(file.getName(), FILENAME_EXTENSION_VALIDATION_XML)) {
+        final PsiFile psiFile = psiManager.findFile(file);
+        if (psiFile instanceof XmlFile &&
+            validatorManager.isValidatorsFile((XmlFile)psiFile)) {
+          final Module module = ModuleUtilCore.findModuleForFile(file, project);
+          if (module != null &&
+              enabledForModule.get(module)) {
+            files.add(file);
+          }
+        }
+      }
+    }
+
+    // add validator-config.xml if not default one from xwork.jar
+    final Set<VirtualFile> descriptorFiles = new HashSet<>();
+    for (final Module module : ModuleManager.getInstance(project).getModules()) {
+      if (enabledForModule.get(module)) {
+        final PsiFile psiFile = validatorManager.getValidatorConfigFile(module);
+        if (psiFile != null &&
+            validatorManager.isCustomValidatorConfigFile(psiFile)) {
+          InspectionValidatorUtil.addFile(descriptorFiles, psiFile);
+        }
+      }
+    }
+    files.addAll(InspectionValidatorUtil.expandCompileScopeIfNeeded(descriptorFiles, context));
+
+    return files;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Class<? extends LocalInspectionTool> @NotNull [] getInspectionToolClasses(CompileContext context) {
+    return new Class[]{ValidatorModelInspection.class, ValidatorConfigModelInspection.class};
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/inspection/package-info.java b/src/main/java/com/intellij/struts2/dom/inspection/package-info.java
new file mode 100644
index 0000000..5deb1c5
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/inspection/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2008 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.
+ */
+
+/**
+ * DOM-model inspections and validators.
+ */
+package com.intellij.struts2.dom.inspection;
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/params/Param.java b/src/main/java/com/intellij/struts2/dom/params/Param.java
new file mode 100644
index 0000000..bd39153
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/params/Param.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2013 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.params;
+
+import com.intellij.ide.presentation.Presentation;
+import com.intellij.psi.impl.beanProperties.BeanProperty;
+import com.intellij.util.xml.*;
+
+import java.util.List;
+
+/**
+ * {@code param}
+ *
+ * @author Yann C&eacute;bron
+ */
+@Presentation(typeName = "Parameter", icon = "AllIcons.Actions.Properties")
+@Convert(ParamValueConverter.class)
+public interface Param extends DomElement, GenericDomValue<String> {
+
+  @Attribute(value = "name")
+  @Required
+  @NameValue
+  @Convert(ParamNameConverter.class)
+  GenericAttributeValue<List<BeanProperty>> getName();
+}
diff --git a/src/main/java/com/intellij/struts2/dom/params/ParamNameConverter.java b/src/main/java/com/intellij/struts2/dom/params/ParamNameConverter.java
new file mode 100644
index 0000000..35bd93e
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/params/ParamNameConverter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 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.params;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.xml.XmlAttributeValue;
+import com.intellij.struts2.dom.BeanPropertyPathConverterBase;
+import com.intellij.util.xml.DomElement;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Converter for {@link Param#getName()}.
+ * <p/>
+ * Based on Spring plugin.
+ *
+ * @author Yann C&eacute;bron
+ */
+public abstract class ParamNameConverter extends BeanPropertyPathConverterBase {
+
+  public static final ExtensionPointName<ParamNameCustomConverter> EP_NAME =
+    new ExtensionPointName<>("com.intellij.struts2.paramNameCustomConverter");
+
+  /**
+   * Provides custom "name" resolving. Replaces the basic bean property resolving.
+   */
+  public abstract static class ParamNameCustomConverter {
+
+    /**
+     * Returns custom references or empty array if not applicable.
+     *
+     * @param nameAttributeValue    "name" attribute.
+     */
+    public abstract PsiReference @NotNull [] getCustomReferences(final XmlAttributeValue nameAttributeValue, final DomElement paramsElement);
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/params/ParamNameConverterImpl.java b/src/main/java/com/intellij/struts2/dom/params/ParamNameConverterImpl.java
new file mode 100644
index 0000000..3bfd180
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/params/ParamNameConverterImpl.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 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.params;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.beanProperties.BeanProperty;
+import com.intellij.psi.xml.XmlAttributeValue;
+import com.intellij.struts2.reference.common.BeanPropertyPathReferenceSet;
+import com.intellij.util.xml.ConvertContext;
+import com.intellij.util.xml.DomElement;
+import com.intellij.util.xml.GenericDomValue;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * @author Yann C&eacute;bron
+ */
+public class ParamNameConverterImpl extends ParamNameConverter {
+
+  @Override
+  protected PsiClass findBeanPropertyClass(@NotNull final DomElement domElement) {
+    return ((ParamsElement) domElement).getParamsClass();
+  }
+
+  @Override
+  public PsiReference @NotNull [] createReferences(final GenericDomValue<List<BeanProperty>> listGenericDomValue,
+                                                   final PsiElement psiElement,
+                                                   final ConvertContext convertContext) {
+    final DomElement paramsElement = findEnclosingTag(convertContext);
+    if (paramsElement == null) {
+      return PsiReference.EMPTY_ARRAY;
+    }
+
+    for (ParamNameCustomConverter customConverter : EP_NAME.getExtensionList()) {
+      final PsiReference[] customReferences = customConverter.getCustomReferences((XmlAttributeValue) psiElement,
+                                                                                  paramsElement);
+      if (customReferences.length > 0) {
+        return customReferences;
+      }
+    }
+
+    final PsiClass rootPsiClass = findBeanPropertyClass(paramsElement);
+    return new BeanPropertyPathReferenceSet(psiElement, rootPsiClass, false).getPsiReferences();
+  }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/intellij/struts2/dom/params/ParamValueConverter.java b/src/main/java/com/intellij/struts2/dom/params/ParamValueConverter.java
new file mode 100644
index 0000000..de49735
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/params/ParamValueConverter.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 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.params;
+
+import com.intellij.psi.PsiType;
+import com.intellij.psi.impl.beanProperties.BeanProperty;
+import com.intellij.util.xml.Converter;
+import com.intellij.util.xml.GenericDomValue;
+import com.intellij.util.xml.WrappingConverter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * @author Yann C&eacute;bron
+ * @see ParamValueConvertersRegistry
+ */
+public class ParamValueConverter extends WrappingConverter {
+
+  @Nullable
+  @Override
+  public Converter getConverter(@NotNull GenericDomValue domElement) {
+    final Param param = domElement.getParentOfType(Param.class, false);
+    if (param == null) {
+      return null;
+    }
+
+    // skip values containing expressions
+    final String text = domElement.getRawText();
+    if (text == null || text.contains("${")) {
+      return null;
+    }
+
+    final List<BeanProperty> beanProperties = param.getName().getValue();
+    if (beanProperties == null || beanProperties.isEmpty()) {
+      return null;
+    }
+
+    final BeanProperty property = beanProperties.get(beanProperties.size() - 1);
+    final PsiType type = property.getPropertyType();
+    return ParamValueConvertersRegistry.getInstance().getConverter(domElement, type);
+  }
+}
diff --git a/src/main/java/com/intellij/struts2/dom/params/ParamValueConvertersRegistry.java b/src/main/java/com/intellij/struts2/dom/params/ParamValueConvertersRegistry.java
new file mode 100644
index 0000000..4e51e91
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/params/ParamValueConvertersRegistry.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2013 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.params;
+
+import com.intellij.util.xml.converters.values.GenericDomValueConvertersRegistry;
+
+/**
+ * Registry of all converters used by {@link ParamValueConverter}.
+ *
+ * @author Yann C&eacute;bron
+ */
+public final class ParamValueConvertersRegistry extends GenericDomValueConvertersRegistry {
+
+  private static final ParamValueConvertersRegistry INSTANCE = new ParamValueConvertersRegistry();
+
+  public static ParamValueConvertersRegistry getInstance() {
+    return INSTANCE;
+  }
+
+  private ParamValueConvertersRegistry() {
+    registerBuiltinValueConverters();
+  }
+
+  private void registerBuiltinValueConverters() {
+    registerDefaultConverters();
+  }
+}
diff --git a/src/main/java/com/intellij/struts2/dom/params/ParamsElement.java b/src/main/java/com/intellij/struts2/dom/params/ParamsElement.java
new file mode 100644
index 0000000..ba60b9e
--- /dev/null
+++ b/src/main/java/com/intellij/struts2/dom/params/ParamsElement.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013 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.params;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.util.xml.DomElement;
+import com.intellij.util.xml.SubTagList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
... 37094 lines suppressed ...