diff --git a/java.j2seplatform/nbproject/project.xml b/java.j2seplatform/nbproject/project.xml --- a/java.j2seplatform/nbproject/project.xml +++ b/java.j2seplatform/nbproject/project.xml @@ -87,6 +87,15 @@ 1 + + + + org.netbeans.modules.java.project + + + + 1 + 1.20 diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SELibrarySourceForBinaryQuery.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SELibrarySourceForBinaryQuery.java --- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SELibrarySourceForBinaryQuery.java +++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SELibrarySourceForBinaryQuery.java @@ -52,6 +52,7 @@ import org.netbeans.api.java.queries.SourceForBinaryQuery; import org.netbeans.api.project.libraries.Library; import org.netbeans.api.project.libraries.LibraryManager; +import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2; import org.openide.ErrorManager; import org.openide.filesystems.FileObject; @@ -160,9 +161,15 @@ if (this.lib.getContent(J2SELibraryTypeProvider.VOLUME_TYPE_CLASSPATH).contains(entry)) { List result = new ArrayList(); for (URL u : lib.getContent(J2SELibraryTypeProvider.VOLUME_TYPE_SRC)) { - FileObject sourceRootURL = URLMapper.findFileObject(u); - if (sourceRootURL!=null) { - result.add (sourceRootURL); + FileObject sourceRoot = URLMapper.findFileObject(u); + if (sourceRoot != null) { + FileObject fo2 = JavadocAndSourceRootDetection.findSourcesRoot(sourceRoot, false); + if (fo2 != null) { + sourceRoot = fo2; + } + } + if (sourceRoot!=null) { + result.add (sourceRoot); } } this.cache = result.toArray(new FileObject[result.size()]); diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.form b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.form --- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.form +++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.form @@ -9,6 +9,7 @@ + diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java --- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java +++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java @@ -62,6 +62,7 @@ import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileFilter; import org.netbeans.api.project.ant.FileChooser; +import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; import org.netbeans.spi.project.libraries.LibraryCustomizerContext; import org.openide.DialogDisplayer; import org.openide.ErrorManager; @@ -374,7 +375,7 @@ if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { try { lastFolder = chooser.getCurrentDirectory(); - addFiles (chooser.getSelectedPaths(), area != null ? area.getLocation() : null); + addFiles (chooser.getSelectedPaths(), area != null ? area.getLocation() : null, this.volumeType); } catch (MalformedURLException mue) { ErrorManager.getDefault().notify(mue); } catch (IOException ex) { @@ -405,7 +406,7 @@ // } - private void addFiles (String[] fileNames, URL libraryLocation) throws MalformedURLException { + private void addFiles (String[] fileNames, URL libraryLocation, String volume) throws MalformedURLException { int firstIndex = this.model.getSize(); for (int i = 0; i < fileNames.length; i++) { File f = new File(fileNames[i]); @@ -419,6 +420,7 @@ new File(URI.create(area.getLocation().toExternalForm())).getParentFile(), f.getPath())); } } + checkFile(realFile, volume); if (FileUtil.isArchiveFile(realFile.toURI().toURL())) { uri = LibrariesSupport.getArchiveRoot(uri); } else if (!uri.toString().endsWith("/")){ @@ -431,6 +433,7 @@ model.addResource(uri); } else { assert f.isAbsolute() : f.getPath(); + checkFile(f, volume); URL url = FileUtil.normalizeFile(f).toURI().toURL(); if (FileUtil.isArchiveFile(url)) { url = FileUtil.getArchiveRoot(url); @@ -438,14 +441,6 @@ url = new URL(url.toExternalForm()+"/"); } model.addResource(url); - } - if (this.volumeType.equals(J2SELibraryTypeProvider.VOLUME_TYPE_JAVADOC) - && !JavadocForBinaryQueryLibraryImpl.isValidLibraryJavadocRoot ( - LibrariesSupport.resolveLibraryEntryURI(libraryLocation, uri).toURL())) { - DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message( - NbBundle.getMessage(J2SEVolumeCustomizer.class,"TXT_InvalidJavadocRoot", f.getPath()), - NotifyDescriptor.ERROR_MESSAGE)); - continue; } } int lastIndex = this.model.getSize()-1; @@ -459,6 +454,31 @@ if (this.volumeType.equals(J2SELibraryTypeProvider.VOLUME_TYPE_CLASSPATH)) { if (impl != null) { impl.setContent(J2SELibraryTypeProvider.VOLUME_TYPE_MAVEN_POM, Collections.emptyList()); + } + } + } + + private void checkFile(File f, String volume) { + FileObject fo = FileUtil.toFileObject(f); + if (volume.equals(J2SELibraryTypeProvider.VOLUME_TYPE_JAVADOC)) { + if (fo != null) { + if (fo.isData()) { + fo = FileUtil.getArchiveRoot(fo); + } + if (JavadocAndSourceRootDetection.findJavadocRoot(fo, true) == null) { + DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message( + NbBundle.getMessage(J2SEVolumeCustomizer.class,"TXT_InvalidJavadocRoot", f.getPath()), + NotifyDescriptor.ERROR_MESSAGE)); + } + } + } else if (volume.equals(J2SELibraryTypeProvider.VOLUME_TYPE_SRC)) { + if (fo != null) { + if (fo.isData()) { + fo = FileUtil.getArchiveRoot(fo); + } + if (JavadocAndSourceRootDetection.findSourcesRoot(fo, true) == null) { + // TODO: warn user that no source root was found + } } } } diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/JavadocForBinaryQueryLibraryImpl.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/JavadocForBinaryQueryLibraryImpl.java --- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/JavadocForBinaryQueryLibraryImpl.java +++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/JavadocForBinaryQueryLibraryImpl.java @@ -52,6 +52,7 @@ import org.netbeans.api.java.queries.JavadocForBinaryQuery; import org.netbeans.api.project.libraries.Library; import org.netbeans.api.project.libraries.LibraryManager; +import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; import org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation; import org.openide.ErrorManager; import org.openide.util.WeakListeners; @@ -90,7 +91,7 @@ if (this.cachedRoots == null) { List result = new ArrayList(); for (URL u : lib.getContent(J2SELibraryTypeProvider.VOLUME_TYPE_JAVADOC)) { - result.add (getIndexFolder(u)); + result.add (getIndexFolder(u, false)); } this.cachedRoots = result.toArray(new URL[result.size()]); } @@ -179,60 +180,27 @@ /** - * Tests if the query accepts the root as valid JavadocRoot, - * the query accepts the JavaDoc root, if it can find the index-files - * or index-all.html in the root. - * @param rootURL the javadoc root - * @return true if the root is a valid Javadoc root - */ - static boolean isValidLibraryJavadocRoot (final URL rootURL) { - assert rootURL != null && rootURL.toExternalForm().endsWith("/"); - final FileObject root = URLMapper.findFileObject(rootURL); - if (root == null) { - return false; - } - return findIndexFolder (root,1) != null; - } - - /** * Search for the actual root of the Javadoc containing the index-all.html or * index-files. In case when it is not able to find it, it returns the given Javadoc folder/file. * @param URL Javadoc folder/file * @return URL either the URL of folder containg the index or the given parameter if the index was not found. */ - private static URL getIndexFolder (URL rootURL) { - if (rootURL == null) { + private static URL getIndexFolder (URL rootURL, boolean strict) { + FileObject fo = URLMapper.findFileObject(rootURL); + if (fo != null) { + fo = JavadocAndSourceRootDetection.findJavadocRoot(fo, false); + if (fo != null) { + URL url2 = URLMapper.findURL(fo, URLMapper.EXTERNAL); + if (url2 != null) { + return url2; + } + } + } + if (strict) { return null; - } - FileObject root = URLMapper.findFileObject(rootURL); - if (root == null) { - return rootURL; - } - FileObject result = findIndexFolder (root,1); - try { - return result == null ? rootURL : result.getURL(); - } catch (FileStateInvalidException e) { - ErrorManager.getDefault().notify(e); + } else { return rootURL; } } - private static FileObject findIndexFolder (FileObject fo, int depth) { - if (depth > MAX_DEPTH) { - return null; - } - if (fo.getFileObject("index-files",null)!=null || fo.getFileObject("index-all.html",null)!=null) { //NOI18N - return fo; - } - for (FileObject child : fo.getChildren()) { - if (child.isFolder()) { - FileObject result = findIndexFolder(child, depth+1); - if (result != null) { - return result; - } - } - } - return null; - } - } diff --git a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/DefaultClassPathProvider.java b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/DefaultClassPathProvider.java --- a/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/DefaultClassPathProvider.java +++ b/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/platformdefinition/DefaultClassPathProvider.java @@ -43,7 +43,6 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; -import java.io.*; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.net.URL; @@ -53,7 +52,6 @@ import java.util.Set; import java.util.Iterator; import java.util.HashSet; -import java.util.StringTokenizer; import java.util.WeakHashMap; import java.util.Collections; import org.netbeans.api.java.classpath.ClassPath; @@ -66,9 +64,8 @@ import org.netbeans.spi.java.classpath.ClassPathImplementation; import org.netbeans.spi.java.classpath.ClassPathFactory; import org.netbeans.spi.java.classpath.support.ClassPathSupport; -import org.netbeans.modules.classfile.ClassFile; -import org.netbeans.modules.classfile.ClassName; import org.netbeans.spi.java.classpath.PathResourceImplementation; +import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; import org.openide.ErrorManager; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileStateInvalidException; @@ -80,16 +77,10 @@ */ public class DefaultClassPathProvider implements ClassPathProvider { - /** Name of package keyword. */ - private static final String PACKAGE = "package"; //NOI18N /**Java file extension */ private static final String JAVA_EXT = "java"; //NOI18N /**Class file extension*/ private static final String CLASS_EXT = "class"; //NOI18N - - private static final int TYPE_JAVA = 1; - - private static final int TYPE_CLASS = 2; private /*WeakHash*/Map> sourceRootsCache = new WeakHashMap>(); private /*WeakHash*/Map> sourceClasPathsCache = new WeakHashMap>(); @@ -194,7 +185,7 @@ Reference foRef = this.sourceRootsCache.get (file); FileObject execRoot = null; if (foRef == null || (execRoot = foRef.get()) == null ) { - execRoot = getRootForFile (file, TYPE_CLASS); + execRoot = JavadocAndSourceRootDetection.findPackageRoot(file); if (execRoot == null) { return null; } @@ -215,336 +206,6 @@ } return null; } - - private static FileObject getRootForFile (final FileObject fo, int type) { - String pkg; - if (type == TYPE_JAVA) { - pkg = findJavaPackage (fo); - } - else { - pkg = findClassPackage (fo); - } - FileObject packageRoot = null; - if (pkg == null) { - packageRoot = fo.getParent(); - } - else { - List elements = new ArrayList (); - for (StringTokenizer tk = new StringTokenizer(pkg,"."); tk.hasMoreTokens();) { - elements.add(tk.nextToken()); - } - FileObject tmp = fo; - for (int i=elements.size()-1; i>=0; i--) { - String name = elements.get(i); - tmp = tmp.getParent(); - if (tmp == null || !tmp.getName().equals(name)) { - tmp = fo; - break; - } - } - packageRoot = tmp.getParent(); - } - return packageRoot; - } - - - /** - * Find java package in side .class file. - * - * @return package or null if not found - */ - private static final String findClassPackage (FileObject file) { - try { - InputStream in = file.getInputStream(); - try { - ClassFile cf = new ClassFile(in,false); - ClassName cn = cf.getName(); - return cn.getPackage(); - } finally { - in.close (); - } - } catch (FileNotFoundException fnf) { - //Ignore it - // The file was removed after checking it for isValid - } catch (IOException e) { - ErrorManager.getDefault().notify(e); - } - return null; - } - - /** - * Find java package in side .java file. - * - * @return package or null if not found - */ - private static String findJavaPackage(FileObject file) { - String pkg = ""; // NOI18N - boolean packageKnown = false; - - // Try to find the package name and then infer a directory to mount. - BufferedReader rd = null; - - try { - int pckgPos; // found package position - - rd = new BufferedReader(new SourceReader(file.getInputStream())); - - // Check for unicode byte watermarks. - rd.mark(2); - char[] cbuf = new char[2]; - rd.read(cbuf, 0, 2); - - if (cbuf[0] == 255 && cbuf[1] == 254) { - rd.close(); - rd = new BufferedReader(new SourceReader(file.getInputStream(), "Unicode")); // NOI18N - } else { - rd.reset(); - } - - while (!packageKnown) { - String line = rd.readLine(); - if (line == null) { - packageKnown = true; // i.e. valid termination of search, default pkg - //break; - return pkg; - } - - pckgPos = line.indexOf(PACKAGE); - if (pckgPos == -1) { - continue; - } - StringTokenizer tok = new StringTokenizer(line, " \t;"); // NOI18N - boolean gotPackage = false; - while (tok.hasMoreTokens()) { - String theTok = tok.nextToken (); - if (gotPackage) { - // Hopefully the package name, but first a sanity check... - StringTokenizer ptok = new StringTokenizer(theTok, "."); // NOI18N - boolean ok = ptok.hasMoreTokens(); - while (ptok.hasMoreTokens()) { - String component = ptok.nextToken(); - if (component.length() == 0) { - ok = false; - break; - } - if (!Character.isJavaIdentifierStart(component.charAt(0))) { - ok = false; - break; - } - for (int pos = 1; pos < component.length(); pos++) { - if (!Character.isJavaIdentifierPart(component.charAt(pos))) { - ok = false; - break; - } - } - } - if (ok) { - pkg = theTok; - packageKnown = true; - //break; - return pkg; - } else { - // Keep on looking for valid package statement. - gotPackage = false; - continue; - } - } else if (theTok.equals (PACKAGE)) { - gotPackage = true; - } else if (theTok.equals ("{")) { // NOI18N - // Most likely we can stop if hit opening brace of class def. - // Usually people leave spaces around it. - packageKnown = true; // valid end of search, default pkg - // break; - return pkg; - } - } - } - } catch (FileNotFoundException fnf) { - //Ignore it - //The file was probably removed after it was checked for isValid - } - catch (IOException e1) { - ErrorManager.getDefault().notify(e1); - } finally { - try { - if (rd != null) { - rd.close(); - } - } catch (IOException e2) { - ErrorManager.getDefault().notify(e2); - } - } - - return null; - } - - /** - * Filtered reader for Java sources - it simply excludes - * comments and some useless whitespaces from the original stream. - */ - public static class SourceReader extends InputStreamReader { - private int preRead = -1; - private boolean inString = false; - private boolean backslashLast = false; - private boolean separatorLast = false; - static private final char separators[] = {'.'}; // dot is enough here... - static private final char whitespaces[] = {' ', '\t', '\r', '\n'}; - - public SourceReader(InputStream in) { - super(in); - } - - public SourceReader(InputStream in, String encoding) throws UnsupportedEncodingException { - super(in, encoding); - } - - /** Reads chars from input reader and filters them. */ - public int read(char[] data, int pos, int len) throws IOException { - int numRead = 0; - int c; - char[] onechar = new char[1]; - - while (numRead < len) { - if (preRead != -1) { - c = preRead; - preRead = -1; - } else { - c = super.read(onechar, 0, 1); - if (c == -1) { // end of stream reached - return (numRead > 0) ? numRead : -1; - } - c = onechar[0]; - } - - if (c == '/' && !inString) { // a comment could start here - preRead = super.read(onechar, 0, 1); - if (preRead == 1) { - preRead = onechar[0]; - } - if (preRead != '*' && preRead != '/') { // it's not a comment - data[pos++] = (char) c; - numRead++; - if (preRead == -1) { // end of stream reached - return numRead; - } - } else { // we have run into the comment - skip it - if (preRead == '*') { // comment started with /* - preRead = -1; - do { - c = moveToChar('*'); - if (c == 0) { - c = super.read(onechar, 0, 1); - if (c == 1) { - c = onechar[0]; - } - if (c == '*') { - preRead = c; - } - } - } while (c != '/' && c != -1); - } else { // comment started with // - preRead = -1; - c = moveToChar('\n'); - if (c == 0) { - preRead = '\n'; - } - } - if (c == -1) { // end of stream reached - return -1; - } - } - } else { // normal valid character - if (!inString) { // not inside a string " ... " - if (isWhitespace(c)) { // reduce some whitespaces - while (true) { - preRead = super.read(onechar, 0, 1); - if (preRead == -1) { // end of stream reached - return (numRead > 0) ? numRead : -1; - } - preRead = onechar[0]; - - if (isSeparator(preRead)) { - c = preRead; - preRead = -1; - break; - } else if (!isWhitespace(preRead)) { - if (separatorLast) { - c = preRead; - preRead = -1; - } - break; - } - } - } - - if (c == '\"' || c == '\'') { - inString = true; - separatorLast = false; - } else { - separatorLast = isSeparator(c); - } - } else { // we are just in a string - if (c == '\"' || c == '\'') { - if (!backslashLast) { - inString = false; - } else { - backslashLast = false; - } - } else { - backslashLast = (c == '\\'); - } - } - - data[pos++] = (char) c; - numRead++; - } - } - return numRead; - } - - private int moveToChar(int c) throws IOException { - int cc; - char[] onechar = new char[1]; - - if (preRead != -1) { - cc = preRead; - preRead = -1; - } else { - cc = super.read(onechar, 0, 1); - if (cc == 1) { - cc = onechar[0]; - } - } - - while (cc != -1 && cc != c) { - cc = super.read(onechar, 0, 1); - if (cc == 1) { - cc = onechar[0]; - } - } - - return (cc == -1) ? -1 : 0; - } - - static private boolean isSeparator(int c) { - for (int i=0; i < separators.length; i++) { - if (c == separators[i]) { - return true; - } - } - return false; - } - - static private boolean isWhitespace(int c) { - for (int i=0; i < whitespaces.length; i++) { - if (c == whitespaces[i]) { - return true; - } - } - return false; - } - } // End of class SourceReader. - private static class RecursionException extends IllegalStateException {} diff --git a/java.j2seproject/nbproject/project.xml b/java.j2seproject/nbproject/project.xml --- a/java.j2seproject/nbproject/project.xml +++ b/java.j2seproject/nbproject/project.xml @@ -148,7 +148,7 @@ 1 - 1.19 + 1.20 diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/customizer/ClassPathUiSupport.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/customizer/ClassPathUiSupport.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/customizer/ClassPathUiSupport.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/customizer/ClassPathUiSupport.java @@ -53,8 +53,12 @@ import org.netbeans.api.project.libraries.LibrariesCustomizer; import org.netbeans.api.project.libraries.Library; import org.netbeans.modules.java.j2seproject.classpath.ClassPathSupport; +import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; import org.netbeans.spi.java.project.support.ui.EditJarSupport; import org.netbeans.spi.project.support.ant.AntProjectHelper; +import org.netbeans.spi.project.support.ant.PropertyUtils; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; import org.openide.util.NbCollections; /** @@ -147,6 +151,33 @@ if (eji != null) { item.setJavadocFilePath(eji.getJavadocFile()); item.setSourceFilePath(eji.getSourceFile()); + if (eji.getJavadocFile() != null) { + String val = helper.getStandardPropertyEvaluator().evaluate(eji.getJavadocFile()); + File f = PropertyUtils.resolveFile(FileUtil.toFile(helper.getProjectDirectory()), val); + FileObject fo = FileUtil.toFileObject(f); + if (fo != null) { + if (fo.isData()) { + fo = FileUtil.getArchiveRoot(fo); + } + if (JavadocAndSourceRootDetection.findJavadocRoot(fo, true) == null) { + // TODO: warn user that no Javadoc was found + } + } + } + if (eji.getSourceFile() != null) { + String val = helper.getStandardPropertyEvaluator().evaluate(eji.getSourceFile()); + File f = PropertyUtils.resolveFile(FileUtil.toFile(helper.getProjectDirectory()), val); + FileObject fo = FileUtil.toFileObject(f); + if (fo != null) { + if (fo.isData()) { + fo = FileUtil.getArchiveRoot(fo); + } + if (JavadocAndSourceRootDetection.findSourcesRoot(fo, true) == null) { + // TODO: warn user that no source root was found + } + } + } + } } if (item.getType() == ClassPathSupport.Item.TYPE_LIBRARY) { diff --git a/java.project/manifest.mf b/java.project/manifest.mf --- a/java.project/manifest.mf +++ b/java.project/manifest.mf @@ -3,6 +3,6 @@ OpenIDE-Module-Layer: org/netbeans/modules/java/project/layer.xml OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/project/Bundle.properties OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker -OpenIDE-Module-Specification-Version: 1.19 +OpenIDE-Module-Specification-Version: 1.20 AutoUpdate-Show-In-Client: false diff --git a/java.project/nbproject/project.xml b/java.project/nbproject/project.xml --- a/java.project/nbproject/project.xml +++ b/java.project/nbproject/project.xml @@ -89,6 +89,14 @@ 1 1.9 + + + + org.netbeans.modules.classfile + + + + 1 diff --git a/java.project/src/org/netbeans/modules/java/project/ExtraProjectJavadocForBinaryQueryImpl.java b/java.project/src/org/netbeans/modules/java/project/ExtraProjectJavadocForBinaryQueryImpl.java --- a/java.project/src/org/netbeans/modules/java/project/ExtraProjectJavadocForBinaryQueryImpl.java +++ b/java.project/src/org/netbeans/modules/java/project/ExtraProjectJavadocForBinaryQueryImpl.java @@ -57,9 +57,12 @@ import javax.swing.event.ChangeListener; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; +import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; import org.netbeans.spi.java.queries.JavadocForBinaryQueryImplementation; import org.netbeans.spi.project.ui.ProjectOpenedHook; +import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; +import org.openide.filesystems.URLMapper; import org.openide.util.ChangeSupport; import org.openide.util.Exceptions; @@ -224,6 +227,16 @@ if (FileUtil.isArchiveFile(url)) { url = FileUtil.getArchiveRoot(url); } + FileObject fo = URLMapper.findFileObject(url); + if (fo != null) { + fo = JavadocAndSourceRootDetection.findJavadocRoot(fo, false); + if (fo != null) { + URL url2 = URLMapper.findURL(fo, URLMapper.EXTERNAL); + if (url2 != null) { + url = url2; + } + } + } return new URL[] { url }; } catch ( MalformedURLException ex ) { diff --git a/java.project/src/org/netbeans/modules/java/project/ExtraProjectSourceForBinaryQueryImpl.java b/java.project/src/org/netbeans/modules/java/project/ExtraProjectSourceForBinaryQueryImpl.java --- a/java.project/src/org/netbeans/modules/java/project/ExtraProjectSourceForBinaryQueryImpl.java +++ b/java.project/src/org/netbeans/modules/java/project/ExtraProjectSourceForBinaryQueryImpl.java @@ -56,6 +56,7 @@ import org.netbeans.api.java.queries.SourceForBinaryQuery; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; +import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2; import org.netbeans.spi.project.support.ant.AntProjectHelper; import org.netbeans.spi.project.support.ant.PropertyEvaluator; @@ -230,6 +231,12 @@ url = FileUtil.getArchiveRoot(url); } FileObject fo = URLMapper.findFileObject(url); + if (fo != null) { + FileObject fo2 = JavadocAndSourceRootDetection.findSourcesRoot(fo, false); + if (fo2 != null) { + fo = fo2; + } + } if ( fo != null ) { return new FileObject[]{fo}; diff --git a/java.project/src/org/netbeans/spi/java/project/support/JavadocAndSourceRootDetection.java b/java.project/src/org/netbeans/spi/java/project/support/JavadocAndSourceRootDetection.java new file mode 100644 --- /dev/null +++ b/java.project/src/org/netbeans/spi/java/project/support/JavadocAndSourceRootDetection.java @@ -0,0 +1,568 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.java.project.support; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.logging.Logger; +import org.netbeans.modules.classfile.ClassFile; +import org.netbeans.modules.classfile.ClassName; +import org.openide.ErrorManager; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.URLMapper; +import org.openide.util.Exceptions; +import org.openide.util.NbPreferences; + +/** + * Miscellaneous helper utils to detect Javadoc root folder, source root folder or + * package of the given java or class file. + * + * @since org.netbeans.modules.java.project/1 1.20 + */ +public class JavadocAndSourceRootDetection { + + private static final int HOW_MANY_DIRS_TO_TRAVERSE_DEEP = 5; + + /** Name of package keyword. */ + private static final String PACKAGE = "package"; //NOI18N + + private static final Logger LOG = Logger.getLogger(JavadocAndSourceRootDetection.class.getName()); + + private JavadocAndSourceRootDetection() { + } + + /** + * Finds Javadoc root inside of given folder. + * + * @param fo base folder to start search in; routine will traverse 5 folders + * deep before giving up; cannot be null; must be folder + * @param ignoreCache any successful found value is cached and will be used + * if possible to avoid potentially slow folder search; set to true to ignore it + * @return found Javadoc root or null if none found + */ + public static FileObject findJavadocRoot(FileObject baseFolder, boolean ignoreCache) { + if (!baseFolder.isFolder()) { + throw new IllegalStateException("baseFolder must be folder - "+baseFolder); // NOI18N + } + String key = null; + try { + key = URLMapper.findURL(baseFolder, URLMapper.EXTERNAL).toURI().toString(); + } catch (URISyntaxException ex) { + Exceptions.printStackTrace(ex); + ignoreCache = true; + } + if (!ignoreCache) { + String value = NbPreferences.forModule(JavadocAndSourceRootDetection.class).get("javadoc."+key, null); // NOI18N + if (value != null) { + FileObject fo1; + try { + fo1 = URLMapper.findFileObject(URI.create(value).toURL()); + if (fo1 != null) { + return fo1; + } + } catch (MalformedURLException ex) { + LOG.info("cached value '"+value+"' cannot be parsed: "+ex.toString()); // NOI18N + } + } + } + FileObject root = findJavadocRoot(baseFolder, 0); + String value = null; + if (root != null) { + try { + value = URLMapper.findURL(root, URLMapper.EXTERNAL).toURI().toString(); + } catch (URISyntaxException ex) { + Exceptions.printStackTrace(ex); + value = null; + } + } + if (value == null) { + NbPreferences.forModule(JavadocAndSourceRootDetection.class).remove("javadoc."+key); // NOI18N + } else { + NbPreferences.forModule(JavadocAndSourceRootDetection.class).put("javadoc."+key, value); // NOI18N + } + return root; + } + + /** + * Finds Java sources root inside of given folder. + * + * @param fo base folder to start search in; routine will traverse subfolders + * to find a Java file to detect package root; cannot be null; must be folder + * @param ignoreCache any successful found value is cached and will be used + * if possible to avoid potentially slow folder search; set to true to ignore it + * @return found package root of first Java file found or null if none found + */ + public static FileObject findSourcesRoot(FileObject fo, boolean ignoreCache) { + if (!fo.isFolder()) { + throw new IllegalStateException("fo must be folder - "+fo); // NOI18N + } + String key = null; + try { + key = URLMapper.findURL(fo, URLMapper.EXTERNAL).toURI().toString(); + } catch (URISyntaxException ex) { + Exceptions.printStackTrace(ex); + ignoreCache = true; + } + if (!ignoreCache) { + String value = NbPreferences.forModule(JavadocAndSourceRootDetection.class).get("sources."+key, null); // NOI18N + if (value != null) { + FileObject fo1; + try { + fo1 = URLMapper.findFileObject(URI.create(value).toURL()); + if (fo1 != null) { + return fo1; + } + } catch (MalformedURLException ex) { + LOG.info("cached value '"+value+"' cannot be parsed: "+ex.toString()); // NOI18N + } + } + } + FileObject root = findJavaSourceFile(fo, 0); + if (root != null) { + root = findPackageRoot(root); + } + String value = null; + if (root != null) { + try { + value = URLMapper.findURL(root, URLMapper.EXTERNAL).toURI().toString(); + } catch (URISyntaxException ex) { + Exceptions.printStackTrace(ex); + value = null; + } + } + if (value == null) { + NbPreferences.forModule(JavadocAndSourceRootDetection.class).remove("sources."+key); // NOI18N + } else { + NbPreferences.forModule(JavadocAndSourceRootDetection.class).put("sources."+key, value); // NOI18N + } + return root; + } + + /** + * Returns package root of the given java or class file. + * + * @param fo either .java or .class file; never null + * @return package root of the given file + */ + public static FileObject findPackageRoot(final FileObject fo) { + String pkg; + if ("java".equals(fo.getExt())) { // NOI18N + pkg = findJavaPackage (fo); + } else if ("class".equals(fo.getExt())) { // NOI18N + pkg = findClassPackage (fo); + } else { + throw new IllegalStateException("only java or class files accepted "+fo); // NOI18N + } + FileObject packageRoot = null; + if (pkg == null) { + packageRoot = fo.getParent(); + } + else { + List elements = new ArrayList (); + for (StringTokenizer tk = new StringTokenizer(pkg,"."); tk.hasMoreTokens();) { // NOI18N + elements.add(tk.nextToken()); + } + FileObject tmp = fo; + for (int i=elements.size()-1; i>=0; i--) { + String name = elements.get(i); + tmp = tmp.getParent(); + if (tmp == null || !tmp.getName().equals(name)) { + tmp = fo; + break; + } + } + packageRoot = tmp.getParent(); + } + return packageRoot; + } + + + private static FileObject findJavadocRoot(FileObject fo, int level) { + FileObject fo1 = fo.getFileObject("package-list", null); // NOI18N + if (fo1 != null) { + return fo; + } + if (level == HOW_MANY_DIRS_TO_TRAVERSE_DEEP) { + return null; + } + for (FileObject fo2 : fo.getChildren()) { + if (!fo2.isFolder()) { + continue; + } + fo2 = findJavadocRoot(fo2, level+1); + if (fo2 != null) { + return fo2; + } + } + return null; + } + + private static FileObject findJavaSourceFile(FileObject fo, int level) { + if (level == 999) { // ignore for now + return null; + } + // go through files first: + for (FileObject fo2 : fo.getChildren()) { + if (fo2.isData() && "java".equals(fo2.getExt())) { // NOI18N + return fo2; + } + } + // now check sunfolders: + for (FileObject fo2 : fo.getChildren()) { + if (fo2.isFolder()) { + fo2 = findJavaSourceFile(fo2, level+1); + if (fo2 != null) { + return fo2; + } + } + } + return null; + } + + /** + * Find java package in side .class file. + * + * @return package or null if not found + */ + private static final String findClassPackage (FileObject file) { + try { + InputStream in = file.getInputStream(); + try { + ClassFile cf = new ClassFile(in,false); + ClassName cn = cf.getName(); + return cn.getPackage(); + } finally { + in.close (); + } + } catch (FileNotFoundException fnf) { + //Ignore it + // The file was removed after checking it for isValid + } catch (IOException e) { + ErrorManager.getDefault().notify(e); + } + return null; + } + + /** + * Find java package in side .java file. + * + * @return package or null if not found + */ + private static String findJavaPackage(FileObject file) { + String pkg = ""; // NOI18N + boolean packageKnown = false; + + // Try to find the package name and then infer a directory to mount. + BufferedReader rd = null; + + try { + int pckgPos; // found package position + + rd = new BufferedReader(new SourceReader(file.getInputStream())); + + // Check for unicode byte watermarks. + rd.mark(2); + char[] cbuf = new char[2]; + rd.read(cbuf, 0, 2); + + if (cbuf[0] == 255 && cbuf[1] == 254) { + rd.close(); + rd = new BufferedReader(new SourceReader(file.getInputStream(), "Unicode")); // NOI18N + } else { + rd.reset(); + } + + while (!packageKnown) { + String line = rd.readLine(); + if (line == null) { + packageKnown = true; // i.e. valid termination of search, default pkg + //break; + return pkg; + } + + pckgPos = line.indexOf(PACKAGE); + if (pckgPos == -1) { + continue; + } + StringTokenizer tok = new StringTokenizer(line, " \t;"); // NOI18N + boolean gotPackage = false; + while (tok.hasMoreTokens()) { + String theTok = tok.nextToken (); + if (gotPackage) { + // Hopefully the package name, but first a sanity check... + StringTokenizer ptok = new StringTokenizer(theTok, "."); // NOI18N + boolean ok = ptok.hasMoreTokens(); + while (ptok.hasMoreTokens()) { + String component = ptok.nextToken(); + if (component.length() == 0) { + ok = false; + break; + } + if (!Character.isJavaIdentifierStart(component.charAt(0))) { + ok = false; + break; + } + for (int pos = 1; pos < component.length(); pos++) { + if (!Character.isJavaIdentifierPart(component.charAt(pos))) { + ok = false; + break; + } + } + } + if (ok) { + pkg = theTok; + packageKnown = true; + //break; + return pkg; + } else { + // Keep on looking for valid package statement. + gotPackage = false; + continue; + } + } else if (theTok.equals (PACKAGE)) { + gotPackage = true; + } else if (theTok.equals ("{")) { // NOI18N + // Most likely we can stop if hit opening brace of class def. + // Usually people leave spaces around it. + packageKnown = true; // valid end of search, default pkg + // break; + return pkg; + } + } + } + } catch (FileNotFoundException fnf) { + //Ignore it + //The file was probably removed after it was checked for isValid + } + catch (IOException e1) { + ErrorManager.getDefault().notify(e1); + } finally { + try { + if (rd != null) { + rd.close(); + } + } catch (IOException e2) { + ErrorManager.getDefault().notify(e2); + } + } + + return null; + } + + /** + * Filtered reader for Java sources - it simply excludes + * comments and some useless whitespaces from the original stream. + */ + public static class SourceReader extends InputStreamReader { + private int preRead = -1; + private boolean inString = false; + private boolean backslashLast = false; + private boolean separatorLast = false; + static private final char separators[] = {'.'}; // dot is enough here... + static private final char whitespaces[] = {' ', '\t', '\r', '\n'}; + + public SourceReader(InputStream in) { + super(in); + } + + public SourceReader(InputStream in, String encoding) throws UnsupportedEncodingException { + super(in, encoding); + } + + /** Reads chars from input reader and filters them. */ + public int read(char[] data, int pos, int len) throws IOException { + int numRead = 0; + int c; + char[] onechar = new char[1]; + + while (numRead < len) { + if (preRead != -1) { + c = preRead; + preRead = -1; + } else { + c = super.read(onechar, 0, 1); + if (c == -1) { // end of stream reached + return (numRead > 0) ? numRead : -1; + } + c = onechar[0]; + } + + if (c == '/' && !inString) { // a comment could start here + preRead = super.read(onechar, 0, 1); + if (preRead == 1) { + preRead = onechar[0]; + } + if (preRead != '*' && preRead != '/') { // it's not a comment + data[pos++] = (char) c; + numRead++; + if (preRead == -1) { // end of stream reached + return numRead; + } + } else { // we have run into the comment - skip it + if (preRead == '*') { // comment started with /* + preRead = -1; + do { + c = moveToChar('*'); + if (c == 0) { + c = super.read(onechar, 0, 1); + if (c == 1) { + c = onechar[0]; + } + if (c == '*') { + preRead = c; + } + } + } while (c != '/' && c != -1); + } else { // comment started with // + preRead = -1; + c = moveToChar('\n'); + if (c == 0) { + preRead = '\n'; + } + } + if (c == -1) { // end of stream reached + return -1; + } + } + } else { // normal valid character + if (!inString) { // not inside a string " ... " + if (isWhitespace(c)) { // reduce some whitespaces + while (true) { + preRead = super.read(onechar, 0, 1); + if (preRead == -1) { // end of stream reached + return (numRead > 0) ? numRead : -1; + } + preRead = onechar[0]; + + if (isSeparator(preRead)) { + c = preRead; + preRead = -1; + break; + } else if (!isWhitespace(preRead)) { + if (separatorLast) { + c = preRead; + preRead = -1; + } + break; + } + } + } + + if (c == '\"' || c == '\'') { + inString = true; + separatorLast = false; + } else { + separatorLast = isSeparator(c); + } + } else { // we are just in a string + if (c == '\"' || c == '\'') { + if (!backslashLast) { + inString = false; + } else { + backslashLast = false; + } + } else { + backslashLast = (c == '\\'); + } + } + + data[pos++] = (char) c; + numRead++; + } + } + return numRead; + } + + private int moveToChar(int c) throws IOException { + int cc; + char[] onechar = new char[1]; + + if (preRead != -1) { + cc = preRead; + preRead = -1; + } else { + cc = super.read(onechar, 0, 1); + if (cc == 1) { + cc = onechar[0]; + } + } + + while (cc != -1 && cc != c) { + cc = super.read(onechar, 0, 1); + if (cc == 1) { + cc = onechar[0]; + } + } + + return (cc == -1) ? -1 : 0; + } + + static private boolean isSeparator(int c) { + for (int i=0; i < separators.length; i++) { + if (c == separators[i]) { + return true; + } + } + return false; + } + + static private boolean isWhitespace(int c) { + for (int i=0; i < whitespaces.length; i++) { + if (c == whitespaces[i]) { + return true; + } + } + return false; + } + } // End of class SourceReader. + + +} diff --git a/java.project/test/unit/data/javadoc-and-sources-detection/build.xml b/java.project/test/unit/data/javadoc-and-sources-detection/build.xml new file mode 100644 --- /dev/null +++ b/java.project/test/unit/data/javadoc-and-sources-detection/build.xml @@ -0,0 +1,69 @@ + + + + + + Builds, tests, and runs the project JavaApplication22. + + + diff --git a/java.project/test/unit/data/javadoc-and-sources-detection/manifest.mf b/java.project/test/unit/data/javadoc-and-sources-detection/manifest.mf new file mode 100644 --- /dev/null +++ b/java.project/test/unit/data/javadoc-and-sources-detection/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/build-impl.xml b/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/build-impl.xml new file mode 100644 --- /dev/null +++ b/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/build-impl.xml @@ -0,0 +1,661 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + diff --git a/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/genfiles.properties b/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/genfiles.properties new file mode 100644 --- /dev/null +++ b/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=53c593e8 +build.xml.script.CRC32=d9a08ab5 +build.xml.stylesheet.CRC32=be360661 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=53c593e8 +nbproject/build-impl.xml.script.CRC32=7b015764 +nbproject/build-impl.xml.stylesheet.CRC32=61b4e419 diff --git a/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/project.properties b/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/project.properties new file mode 100644 --- /dev/null +++ b/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/project.properties @@ -0,0 +1,64 @@ +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/JavaApplication22.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit.classpath}:\ + ${libs.junit_4.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=javaapplication22.Main +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +quick.run=true +quick.run.single=true +quick.test.single=true +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/project.xml b/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/project.xml new file mode 100644 --- /dev/null +++ b/java.project/test/unit/data/javadoc-and-sources-detection/nbproject/project.xml @@ -0,0 +1,19 @@ + + + org.netbeans.modules.java.j2seproject + + + JavaApplication22 + 1.6.5 + + + + + + + + + ./lib/nblibraries.properties + + + diff --git a/java.project/test/unit/data/javadoc-and-sources-detection/src/org/netbeans/testmodule/Main.java b/java.project/test/unit/data/javadoc-and-sources-detection/src/org/netbeans/testmodule/Main.java new file mode 100644 --- /dev/null +++ b/java.project/test/unit/data/javadoc-and-sources-detection/src/org/netbeans/testmodule/Main.java @@ -0,0 +1,24 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.netbeans.testmodule; + +/** + * Main class. + * + * @author David Konecny + */ +public class Main { + + /** + * Start Application. + * + * @param args the command line arguments + */ + public static void main(String[] args) { + // TODO code application logic here + } + +} diff --git a/java.project/test/unit/src/org/netbeans/spi/java/project/support/JavadocAndSourceRootDetectionTest.java b/java.project/test/unit/src/org/netbeans/spi/java/project/support/JavadocAndSourceRootDetectionTest.java new file mode 100644 --- /dev/null +++ b/java.project/test/unit/src/org/netbeans/spi/java/project/support/JavadocAndSourceRootDetectionTest.java @@ -0,0 +1,114 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.java.project.support; + +import java.io.File; +import java.io.IOException; +import org.netbeans.junit.NbTestCase; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; + +/** + * + */ +public class JavadocAndSourceRootDetectionTest extends NbTestCase { + + public JavadocAndSourceRootDetectionTest(String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + clearWorkDir(); + } + + public static FileObject copyFolderRecursively(FileObject sourceFolder, FileObject destination) throws IOException { + assert sourceFolder.isFolder() : sourceFolder; + assert destination.isFolder() : destination; + FileObject destinationSubFolder = destination.getFileObject(sourceFolder.getName()); + if (destinationSubFolder == null) { + destinationSubFolder = destination.createFolder(sourceFolder.getName()); + } + for (FileObject fo : sourceFolder.getChildren()) { + if (fo.isFolder()) { + copyFolderRecursively(fo, destinationSubFolder); + } else { + FileObject foExists = destinationSubFolder.getFileObject(fo.getName(), fo.getExt()); + if (foExists != null) { + foExists.delete(); + } + FileObject newFO = FileUtil.copyFile(fo, destinationSubFolder, fo.getName(), fo.getExt()); + } + } + return destinationSubFolder; + } + + public void testFindJavadocRoot() throws Exception { + FileObject root = copyFolderRecursively(FileUtil.toFileObject(new File(getDataDir(), "javadoc-and-sources-detection")), FileUtil.toFileObject(getWorkDir())); + FileObject javadocRoot = JavadocAndSourceRootDetection.findJavadocRoot(root, true); + assertNotNull(javadocRoot); + assertEquals(new File(getWorkDir(), "javadoc-and-sources-detection/dist/javadoc").getPath(), FileUtil.toFile(javadocRoot).getPath()); + + FileObject sourcesRoot = JavadocAndSourceRootDetection.findSourcesRoot(root, true); + assertNotNull(sourcesRoot); + assertEquals(new File(getWorkDir(), "javadoc-and-sources-detection/src").getPath(), FileUtil.toFile(sourcesRoot).getPath()); + + // removing these files should fail detection unless data are read from cache: + javadocRoot.getFileObject("package-list", null).delete(); + sourcesRoot.getFileObject("org", null).delete(); + + javadocRoot = JavadocAndSourceRootDetection.findJavadocRoot(root, false); + assertNotNull(javadocRoot); + assertEquals(new File(getWorkDir(), "javadoc-and-sources-detection/dist/javadoc").getPath(), FileUtil.toFile(javadocRoot).getPath()); + + sourcesRoot = JavadocAndSourceRootDetection.findSourcesRoot(root, false); + assertNotNull(sourcesRoot); + assertEquals(new File(getWorkDir(), "javadoc-and-sources-detection/src").getPath(), FileUtil.toFile(sourcesRoot).getPath()); + + // force to ignore cache: + javadocRoot = JavadocAndSourceRootDetection.findJavadocRoot(root, true); + assertNull(javadocRoot); + + sourcesRoot = JavadocAndSourceRootDetection.findSourcesRoot(root, true); + assertNull(sourcesRoot); + } + +} \ No newline at end of file