Extending Struts Assistant

Hi, I'm extending Struts Assistant plugin for our company's needs, but I cannot get over problem with multiple 'struts-config.xml' files. Code completion works nearly perfect, but when
there are two config files each with action element with the same 'path' attribute value, I always get the first one found, no matter if it is from another Struts module.

So I adjusted findByName() method for my needs (as first parameter i provide List gained from StrutsModel.getActions()):

protected T findByName(@NotNull Collection]]> list, @NonNls @NotNull String name) {
Collections.reverse(list); // Reverse to ensure processing global struts-config.xml as the last one
try {
for (T element : list) {
if (name.equals(element.getPresentation().getElementName())) {
PsiDirectory elementConfigFileDir = element.getXmlTag().getContainingFile().getContainingDirectory();
if (isStrutsConfigForActiveFile(elementConfigFileDir)) {
return element;
catch (NullPointerException e) {
return null;

protected boolean isStrutsConfigForActiveFile(@NotNull PsiDirectory dir) {
myValueDir = myValue.getContainingFile().getContainingDirectory();
while (myValueDir != null) {
if (dir.equals(myValueDir)) {
return true;
myValueDir = myValueDir.getParentDirectory();
return false;

I always get the correct Action instance, but the completion list is never displayed, only "No suggestion". I stepped through the code in debugger, but the progress is the same as in original Struts Assistant plugin. Are there any rules that do not allow using PSI objects at certain places? Or is it matter of processing time to get completion list?

Thank for any kind of help, I am really desperate...

Josef Pavlas


Hi Josef,

first of all, standard Struts Assistant should support multiple struts
modules. How are they configured in your web.xml?
What kind of completion fails with your code?
As the thirst guess, I would suggest calling PsiFile.getOriginalFile() to
obtain "original" file that is not the same as containing file for
Try the following:
PsiFile psiFile = element.getXmlTag().getContainingFile();
if (psiFile.getOriginalFile() != null) {
psiFile = psiFile.getOriginalFile();
PsiDirectory elementConfigFileDir = psiFile.getContainingDirectory();


Hi Dmitry and thanks for reply.

In web.xml file inside element I have: config /WEB-INF/struts-config.xml config/public /WEB-INF/pages/public/struts-config-public.xml config/private /WEB-INF/pages/private/struts-config-private.xml Completion with standard StrutsAssistant (and with extended version too) works fine, unless I have 'action' element with the same 'path' attribute value (for example ]]>) in more than one struts-config-xx.xml file. The problem is I always get Action from struts-config-public.xml even if the edited file is located in "private" module (so I want to get Action from struts-config-private.xml).

I wrote method that gets List of all Action objects (StrutsModel.getMergedModel().getActions()) and I compare directory of it's containing file to the directory of file I am editing. Finally, the Action object from the 'nearest' struts-config-xx.xml file is the one I want to get. So far everything works fine, I get correct Action object, I fill array with PsiBeanProperty objects but in editor window I get no completion list, only "No suggestions" tooltip.

I tried debugging of original plugin and extended version, but I have no idea where could be problem - passing through methods and classes is the same (entire process of getting completion variants and showing the completion list in editor window).


Please file the problem to JIRA. Do you use IDEA 6.0 or EAP? I will fix it
in Selena EAP and let you know how it can be done.


The problem is fixed in Selena EAP:

New code from StrutsModelImpl:

public StrutsModel getStrutsModel(@Nullable final PsiElement psiElement) {
if (psiElement == null) {
return null;
PsiFile file = psiElement.getContainingFile();
if (file == null) {
return null;
if (file.getOriginalFile() != null) {
file = file.getOriginalFile();

final FileType fileType = file.getFileType();
if (fileType == StdFileTypes.XML) {
} else {
final Module module = ModuleUtil.findModuleForPsiElement(psiElement);
if (module != null) {
final VirtualFile virtualFile = file.getVirtualFile();
assert virtualFile != null;
final WebDirectoryElement dir =
WebDirectoryUtil.findParentWebDirectory(module.getProject(), virtualFile);
if (dir != null) {
final List]]> strutsModels = getAllStrutsModels(module);
String path = dir.getPath();
while (true) {
for (StrutsModel model: strutsModels) {
final WebDirectoryElement moduleRoot = model.getModuleRoot();
if (moduleRoot != null && path.equals(moduleRoot.getPath())) {
return model;
int lastSlash = path.lastIndexOf('/');
if (lastSlash == -1) {
path = path.substring(0, lastSlash);
return getCombinedStrutsModel(module);
return null;


I am using 6.0.5 - build 6180.

I really appreciate your help, thank you very much.


Please sign in to leave a comment.