Index: plugin/src-test/com/intellij/struts2/BasicHighlightingTestCase.java =================================================================== --- plugin/src-test/com/intellij/struts2/BasicHighlightingTestCase.java (revision 82) +++ plugin/src-test/com/intellij/struts2/BasicHighlightingTestCase.java Wed Feb 27 19:03:40 CET 2008 @@ -24,6 +24,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.spring.SpringManager; import com.intellij.struts2.facet.StrutsFacet; import com.intellij.struts2.facet.StrutsFacetType; import com.intellij.struts2.facet.configuration.StrutsFileSet; @@ -77,6 +78,9 @@ myModuleTestFixture = moduleBuilder.getFixture(); myModule = myModuleTestFixture.getModule(); myFacet = createFacet(); + final SpringManager springManager = SpringManager.getInstance(myProject); + System.out.println("springManager = " + springManager); + } protected void configureModule(final T moduleBuilder) throws Exception { Index: plugin/src/com/intellij/struts2/dom/struts/impl/ActionClassConverterSpringContributor.java =================================================================== --- plugin/src/com/intellij/struts2/dom/struts/impl/ActionClassConverterSpringContributor.java Mon Feb 25 22:01:48 CET 2008 +++ plugin/src/com/intellij/struts2/dom/struts/impl/ActionClassConverterSpringContributor.java Mon Feb 25 22:01:48 CET 2008 @@ -0,0 +1,118 @@ +/* + * 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. + * + */ + +package com.intellij.struts2.dom.struts.impl; + +import com.intellij.codeInsight.lookup.LookupValueFactory; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.reference.PsiReferenceProviderBase; +import com.intellij.psi.xml.XmlAttributeValue; +import com.intellij.spring.SpringManager; +import com.intellij.spring.SpringModel; +import com.intellij.spring.model.SpringUtils; +import com.intellij.spring.model.xml.beans.SpringBeanPointer; +import com.intellij.struts2.dom.struts.action.ActionClassConverterContributor; +import com.intellij.util.xml.ConvertContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Extends <action> "class" resolving to Spring beans. + * + * @author Yann Cˇbron + */ +public class ActionClassConverterSpringContributor extends PsiReferenceProviderBase implements ActionClassConverterContributor { + + /** + * Checks if struts2-spring-plugin is present in current module. + * + * @param convertContext Current context. + * @return true if yes. + */ + public boolean isSuitable(@NotNull final ConvertContext convertContext) { + final PsiClass springIntegrationPlugin = convertContext.findClass( + "org.apache.struts2.spring.StrutsSpringObjectFactory", + null); + return springIntegrationPlugin != null; + } + + @NotNull + public PsiReference[] getReferencesByElement(final PsiElement psiElement) { + return new PsiReference[]{new SpringBeanReference((XmlAttributeValue) psiElement)}; + } + + + private static class SpringBeanReference extends PsiReferenceBase { + + private SpringBeanReference(final XmlAttributeValue element) { + super(element); + } + + public boolean isSoft() { + return true; + } + + public PsiElement resolve() { + final SpringModel model = getSpringModel(); + if (model == null) { + return null; + } + + final String beanName = myElement.getValue(); + final SpringBeanPointer springBean = SpringUtils.findBeanByReferenceName(model, beanName); + +// System.out.println(beanName + " springBean = " + springBean); + return springBean == null ? null : springBean.getBeanClass(); + } + + @Nullable + private SpringModel getSpringModel() { + final Module module = ModuleUtil.findModuleForPsiElement(myElement); + if (module == null) { + return null; + } + + return SpringManager.getInstance(module.getProject()).getCombinedModel(module); + } + + public Object[] getVariants() { + final List lookups = new ArrayList(); + final SpringModel model = getSpringModel(); + if (model != null) { + final Collection list = model.getAllCommonBeans(true); + + for (final SpringBeanPointer bean : list) { + final String beanName = bean.getName(); + final PsiFile psiFile = bean.getContainingFile(); + + if (psiFile != null && StringUtil.isNotEmpty(beanName)) { + //noinspection ConstantConditions + lookups.add(LookupValueFactory.createLookupValueWithHint(beanName, bean.getBeanIcon(), psiFile.getName())); + } + } + } + return lookups.toArray(new Object[lookups.size()]); + } + } + +} \ No newline at end of file Index: dom-api/src/com/intellij/struts2/dom/struts/action/ActionClassConverterContributor.java =================================================================== --- dom-api/src/com/intellij/struts2/dom/struts/action/ActionClassConverterContributor.java Mon Feb 25 21:53:42 CET 2008 +++ dom-api/src/com/intellij/struts2/dom/struts/action/ActionClassConverterContributor.java Mon Feb 25 21:53:42 CET 2008 @@ -0,0 +1,36 @@ +/* + * 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. + * + */ + +package com.intellij.struts2.dom.struts.action; + +import com.intellij.psi.impl.source.resolve.reference.PsiReferenceProvider; +import com.intellij.util.xml.ConvertContext; +import org.jetbrains.annotations.NotNull; + +/** + * @author Yann Cˇbron + */ +public interface ActionClassConverterContributor extends PsiReferenceProvider { + + /** + * Is this contributor suitable in the current resolving context. + * + * @param convertContext Current context. + * @return true if yes, false otherwise. + */ + boolean isSuitable(@NotNull final ConvertContext convertContext); + +} \ No newline at end of file Index: dom-api/src/com/intellij/struts2/dom/struts/action/Action.java =================================================================== --- dom-api/src/com/intellij/struts2/dom/struts/action/Action.java (revision 84) +++ dom-api/src/com/intellij/struts2/dom/struts/action/Action.java Mon Feb 25 21:56:33 CET 2008 @@ -41,10 +41,9 @@ GenericAttributeValue getName(); @Attribute(value = "class") - @ExtendClass(allowAbstract = false, allowInterface = false) + @Convert(ActionClassConverter.class) GenericAttributeValue getActionClass(); - @Attribute(value = "method") @Convert(ActionMethodConverter.class) GenericAttributeValue getMethod(); Index: plugin/src/com/intellij/struts2/StrutsProjectComponent.java =================================================================== --- plugin/src/com/intellij/struts2/StrutsProjectComponent.java (revision 101) +++ plugin/src/com/intellij/struts2/StrutsProjectComponent.java Mon Feb 25 21:35:35 CET 2008 @@ -20,6 +20,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.struts2.dom.struts.IncludeFileResolvingConverter; +import com.intellij.struts2.dom.struts.action.ActionClassConverter; +import com.intellij.struts2.dom.struts.action.ActionClassConverterContributor; import com.intellij.struts2.dom.struts.action.ResultTypeResolvingConverter; import com.intellij.struts2.dom.struts.action.StrutsPathReferenceConverter; import com.intellij.struts2.dom.struts.impl.*; @@ -54,6 +56,7 @@ public void initComponent() { addStrutsResultContributors(); + addActionClassConverters(); registerDomConverters(); } @@ -70,8 +73,23 @@ }); } + /** + * Adds all registered extension points for <action> "class" resolvers. + */ + private void addActionClassConverters() { + StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() { + + public void run() { + final ActionClassConverterContributor[] actionClassConverterContributors = Extensions.getExtensions(ActionClassConverter.EP_NAME); + ActionClassConverterImpl.addAdditionalProviders(actionClassConverterContributors); + } + }); + } + private void registerDomConverters() { final ConverterManager converterManager = domManager.getConverterManager(); + converterManager.registerConverterImplementation(ActionClassConverter.class, + new ActionClassConverterImpl()); converterManager.registerConverterImplementation(StrutsPackageExtendsResolveConverter.class, new StrutsPackageExtendsResolveConverterImpl()); converterManager.registerConverterImplementation(IncludeFileResolvingConverter.class, Index: plugin/src/com/intellij/struts2/dom/inspection/Struts2ModelInspection.java =================================================================== --- plugin/src/com/intellij/struts2/dom/inspection/Struts2ModelInspection.java (revision 82) +++ plugin/src/com/intellij/struts2/dom/inspection/Struts2ModelInspection.java Mon Feb 25 22:04:38 CET 2008 @@ -16,6 +16,7 @@ package com.intellij.struts2.dom.inspection; import com.intellij.struts2.dom.struts.StrutsRoot; +import com.intellij.struts2.dom.struts.action.ActionClassConverter; import com.intellij.util.xml.GenericDomValue; import com.intellij.util.xml.highlighting.BasicDomElementsInspection; import org.jetbrains.annotations.NonNls; @@ -32,8 +33,13 @@ super(StrutsRoot.class); } - // TODO hack for suppresing wildcard-resolving protected boolean shouldCheckResolveProblems(final GenericDomValue value) { + // TODO we roll our own checking for class + if (value.getConverter() instanceof ActionClassConverter) { + return false; + } + + // TODO hack for suppresing wildcard-resolving final String stringValue = value.getStringValue(); return stringValue == null || stringValue.indexOf('{') < 0; } Index: plugin/src/META-INF/struts2-spring.xml =================================================================== --- plugin/src/META-INF/struts2-spring.xml Mon Feb 25 22:01:48 CET 2008 +++ plugin/src/META-INF/struts2-spring.xml Mon Feb 25 22:01:48 CET 2008 @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file Index: plugin/src/com/intellij/struts2/dom/struts/impl/ActionClassConverterImpl.java =================================================================== --- plugin/src/com/intellij/struts2/dom/struts/impl/ActionClassConverterImpl.java Mon Feb 25 21:53:17 CET 2008 +++ plugin/src/com/intellij/struts2/dom/struts/impl/ActionClassConverterImpl.java Mon Feb 25 21:53:17 CET 2008 @@ -0,0 +1,117 @@ +/* + * 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. + * + */ + +package com.intellij.struts2.dom.struts.impl; + +import com.intellij.openapi.module.Module; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.xml.XmlElement; +import com.intellij.struts2.dom.struts.action.ActionClassConverter; +import com.intellij.struts2.dom.struts.action.ActionClassConverterContributor; +import com.intellij.util.ArrayUtil; +import com.intellij.util.xml.ConvertContext; +import com.intellij.util.xml.GenericDomValue; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Yann Cˇbron + */ +public class ActionClassConverterImpl extends ActionClassConverter { + + private static ActionClassConverterContributor[] ADDITIONAL_PROVIDERS = new ActionClassConverterContributor[0]; + + /** + * Adds the given providers. + * + * @param additionalProviders Additional providers to query. + */ + public static void addAdditionalProviders(final ActionClassConverterContributor[] additionalProviders) { + ADDITIONAL_PROVIDERS = ArrayUtil.mergeArrays(ADDITIONAL_PROVIDERS, + additionalProviders, + ActionClassConverterContributor.class); + } + + public PsiClass fromString(@Nullable @NonNls final String s, final ConvertContext context) { + if (s == null) { + return null; + } + + // resolve JAVA-class directly + final PsiClass psiClass = context.findClass(s, null); + if (psiClass != null) { + return psiClass; + } + + // first match in additional providers + final XmlElement element = context.getReferenceXmlElement(); + + for (final ActionClassConverterContributor actionClassConverterContributor : ADDITIONAL_PROVIDERS) { + if (actionClassConverterContributor.isSuitable(context)) { + final PsiReference[] add = actionClassConverterContributor.getReferencesByElement(element); + if (add.length == 1 && add[0].resolve() != null) { + return (PsiClass) add[0].resolve(); + } + } + } + + return null; + } + + public String toString(@Nullable final PsiClass psiClass, final ConvertContext context) { + return psiClass != null ? psiClass.getQualifiedName() : null; + } + + public String getErrorMessage(@Nullable final String s, final ConvertContext context) { + return "Cannot resolve Action class ''" + s + "''"; + } + + @NotNull + public PsiReference[] createReferences(final GenericDomValue psiClassGenericDomValue, + final PsiElement element, + final ConvertContext context) { + // 1. "normal" JAVA classes + final GlobalSearchScope scope = getResolveScope(psiClassGenericDomValue); + final JavaClassReferenceProvider javaClassReferenceProvider = new JavaClassReferenceProvider(scope); + + javaClassReferenceProvider.setOption(JavaClassReferenceProvider.INSTANTIATABLE, Boolean.TRUE); + javaClassReferenceProvider.setOption(JavaClassReferenceProvider.CONCRETE, Boolean.TRUE); + javaClassReferenceProvider.setOption(JavaClassReferenceProvider.NOT_INTERFACE, Boolean.TRUE); + javaClassReferenceProvider.setSoft(true); + PsiReference[] javaClassReferences = javaClassReferenceProvider.getReferencesByElement(element); + + // 2. additional resolvers (currently Spring only) + for (final ActionClassConverterContributor actionClassConverterContributor : ADDITIONAL_PROVIDERS) { + if (actionClassConverterContributor.isSuitable(context)) { + final PsiReference[] additionalReferences = actionClassConverterContributor.getReferencesByElement(element); + javaClassReferences = ArrayUtil.mergeArrays(javaClassReferences, additionalReferences, PsiReference.class); + } + } + + return javaClassReferences; + } + + private static GlobalSearchScope getResolveScope(final GenericDomValue genericdomvalue) { + final Module module = genericdomvalue.getModule(); + return module != null ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) : null; + } + +} \ No newline at end of file Index: dom-api/src/com/intellij/struts2/dom/struts/action/ActionClassConverter.java =================================================================== --- dom-api/src/com/intellij/struts2/dom/struts/action/ActionClassConverter.java Mon Feb 25 21:59:19 CET 2008 +++ dom-api/src/com/intellij/struts2/dom/struts/action/ActionClassConverter.java Mon Feb 25 21:59:19 CET 2008 @@ -0,0 +1,37 @@ +/* + * 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. + * + */ + +package com.intellij.struts2.dom.struts.action; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiClass; +import com.intellij.util.xml.Converter; +import com.intellij.util.xml.CustomReferenceConverter; + +/** + * Converter for <action> "class" attribute. + * + * @author Yann Cˇbron + */ +public abstract class ActionClassConverter extends Converter implements CustomReferenceConverter { + + /** + * References from this EP will be added automatically. + */ + public static ExtensionPointName EP_NAME = new ExtensionPointName( + "com.intellij.struts2.actionClassContributor"); + +} \ No newline at end of file Index: plugin/src/META-INF/plugin.xml =================================================================== --- plugin/src/META-INF/plugin.xml (revision 101) +++ plugin/src/META-INF/plugin.xml Tue Feb 26 19:05:58 CET 2008 @@ -24,6 +24,7 @@ JavaScript + com.intellij.spring - + + @@ -51,7 +55,7 @@ + implementation="com.intellij.struts2.structure.StrutsStructureViewBuilderProvider"/> @@ -64,9 +68,9 @@ + implementation="com.intellij.struts2.structure.ValidationStructureViewBuilderProvider"/> - +