| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.netbeans.modules.maven.j2ee; |
| |
| import com.sun.source.tree.Tree; |
| import com.sun.source.tree.Tree.Kind; |
| import com.sun.source.util.TreePath; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.EnumSet; |
| import java.util.List; |
| import java.util.Set; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.type.TypeKind; |
| import javax.lang.model.type.TypeMirror; |
| import org.netbeans.api.java.classpath.ClassPath; |
| import org.netbeans.api.java.source.CompilationInfo; |
| import org.netbeans.api.project.FileOwnerQuery; |
| import org.netbeans.api.project.Project; |
| import org.netbeans.modules.java.hints.spi.AbstractHint; |
| import org.netbeans.modules.maven.api.NbMavenProject; |
| import org.netbeans.spi.editor.hints.ErrorDescription; |
| import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; |
| import org.netbeans.spi.editor.hints.Fix; |
| import org.openide.filesystems.FileObject; |
| import org.openide.filesystems.FileUtil; |
| import org.openide.util.NbBundle; |
| import static org.netbeans.modules.maven.j2ee.Bundle.*; |
| |
| |
| /** |
| * Warn user when Java EE APIs are missing. |
| */ |
| public class MissingJavaEEForUnitTestExecutionHint extends AbstractHint { |
| |
| private static final Set<Tree.Kind> TREE_KINDS = |
| EnumSet.<Tree.Kind>of(Kind.MEMBER_SELECT, Kind.IDENTIFIER); |
| |
| public MissingJavaEEForUnitTestExecutionHint() { |
| super(true, true, AbstractHint.HintSeverity.ERROR); |
| } |
| |
| @Override |
| @NbBundle.Messages("MissingJavaEEForUnitTestExecutionHint_Description=Find out whether Java EE API is available on project classpath. Java EE API is necessary for successful test execution. This hint also warns about incorrect usage of javaee-web-api artifact - that artifact is suitable only for compilation but not for test execution because body of all API methods was removed from the bytecode.") |
| public String getDescription() { |
| return MissingJavaEEForUnitTestExecutionHint_Description(); |
| } |
| |
| @Override |
| public Set<Kind> getTreeKinds() { |
| return TREE_KINDS; |
| } |
| |
| @Override |
| public List<org.netbeans.spi.editor.hints.ErrorDescription> run(CompilationInfo info, TreePath treePath) { |
| Element el = info.getTrees().getElement(treePath); |
| if (el == null) { |
| return null; |
| } |
| //Logger.getAnonymousLogger().log(Level.SEVERE, "---"+el+" "+(treePath.getLeaf() != null ? treePath.getLeaf().getKind() : "no kind")); |
| if (el.asType() == null || !el.asType().getKind().equals(TypeKind.DECLARED)) { |
| return null; |
| } |
| if (!isEEType(info, el.asType())) { |
| return null; |
| } |
| |
| String name = el.asType().toString(); |
| FileObject testFile = info.getFileObject(); |
| Project prj = FileOwnerQuery.getOwner(testFile); |
| if (prj == null) { |
| return null; |
| } |
| NbMavenProject mp = prj.getLookup().lookup(NbMavenProject.class); |
| if (mp == null) { |
| // handles only Maven projects; Ant projects solves this issue differently |
| return null; |
| } |
| |
| List<String> testRoots = mp.getMavenProject().getTestCompileSourceRoots(); |
| String path = FileUtil.getFileDisplayName(testFile); |
| boolean unitTest = false; |
| for (String testRoot : testRoots) { |
| if (path.startsWith(testRoot)) { |
| unitTest = true; |
| break; |
| } |
| } |
| if (!unitTest) { |
| // relevant only for unit tests which are going to be executed |
| return null; |
| } |
| ClassPath cp = ClassPath.getClassPath(testFile, ClassPath.EXECUTE); |
| if (cp == null) { |
| return null; |
| } |
| boolean javaeeJar = false; |
| boolean gfServer = false; |
| for (FileObject cpRoot : cp.getRoots()) { |
| FileObject fo = FileUtil.getArchiveFile(cpRoot); |
| if (fo == null) { |
| continue; |
| } |
| if (fo.getNameExt().toLowerCase().contains("javaee-web-api-7.0") || // NOI18N |
| fo.getNameExt().toLowerCase().contains("javaee-api-7.0") || |
| fo.getNameExt().toLowerCase().contains("javaee-web-api-8.0") || |
| fo.getNameExt().toLowerCase().contains("javaee-api-8.0")) { // NOI18N |
| javaeeJar = true; |
| } |
| |
| if (fo.getNameExt().toLowerCase().contains("glassfish-embedded-static-shell") || // NOI18N |
| fo.getNameExt().toLowerCase().contains("glassfish-embedded-all")) { // NOI18N |
| // GF is on project classpath; everything should be OK |
| return null; |
| } |
| } |
| try { |
| cp.getClassLoader(true).loadClass(name); // NOI18N |
| return null; |
| } catch (ClassFormatError tt) { |
| // OK, show hint to add JavaEE API |
| } catch (ClassNotFoundException tt) { |
| // #196713 - ignore this exception; it can happen for example when project classes are not compiled |
| return null; |
| } |
| |
| Tree t = treePath.getLeaf(); |
| return Collections.<ErrorDescription>singletonList( |
| ErrorDescriptionFactory.createErrorDescription( |
| getSeverity().toEditorSeverity(), |
| getDisplayName(javaeeJar), |
| new ArrayList<Fix>(), |
| info.getFileObject(), |
| (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), t), |
| (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), t))); |
| } |
| |
| private boolean isEEType(CompilationInfo info, TypeMirror type) { |
| if (type == null) { |
| return false; |
| } |
| if (isEEType(type)) { |
| return true; |
| } |
| List<? extends TypeMirror> l = info.getTypes().directSupertypes(type); |
| for (TypeMirror m : l) { |
| if (isEEType(info, m)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean isEEType(TypeMirror type) { |
| if (type == null) { |
| return false; |
| } |
| String name = type.toString(); |
| return (name.startsWith("javax.")); // NOI18N |
| } |
| |
| @Override |
| public String getId() { |
| return "MissingJavaEEForUnitTestExecutionHint"; // NOI18N |
| } |
| |
| @Override |
| public String getDisplayName() { |
| return getDisplayName(false); |
| } |
| |
| @NbBundle.Messages({ |
| "MissingJavaEEForUnitTestExecutionHint_DisplayName2=Java EE API is missing on project classpath (javaee-web-api artifact cannot be used for test execution).", |
| "MissingJavaEEForUnitTestExecutionHint_DisplayName=Java EE API is missing on project classpath." |
| }) |
| public String getDisplayName(boolean javaeeJar) { |
| if (javaeeJar) { |
| return MissingJavaEEForUnitTestExecutionHint_DisplayName2(); |
| } else { |
| return MissingJavaEEForUnitTestExecutionHint_DisplayName(); |
| } |
| } |
| |
| @Override |
| public void cancel() { |
| } |
| |
| } |