A crude sketch of find-type over net.
authorJan Lahoda <jlahoda@netbeans.org>
Tue, 15 Feb 2011 20:16:07 +0100
changeset 549c0ac67a767d4
parent 548 4a3f0ba0ebcd
child 550 1b17e3ff36e6
child 551 4e37e4d972ba
A crude sketch of find-type over net.
server/backend/impl/nbproject/genfiles.properties
server/backend/impl/nbproject/project.xml
server/backend/impl/src/org/netbeans/modules/jackpot30/backend/impl/api/API.java
server/backend/impl/src/org/netbeans/modules/jackpot30/backend/impl/ui/UI.java
server/backend/impl/src/org/netbeans/modules/jackpot30/backend/impl/ui/ui-findType.html
     1.1 --- a/server/backend/impl/nbproject/genfiles.properties	Tue Feb 15 20:14:52 2011 +0100
     1.2 +++ b/server/backend/impl/nbproject/genfiles.properties	Tue Feb 15 20:16:07 2011 +0100
     1.3 @@ -1,8 +1,8 @@
     1.4 -build.xml.data.CRC32=a49bef13
     1.5 +build.xml.data.CRC32=f3f7e858
     1.6  build.xml.script.CRC32=c32e03a8
     1.7  build.xml.stylesheet.CRC32=a56c6a5b@1.44
     1.8  # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
     1.9  # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    1.10 -nbproject/build-impl.xml.data.CRC32=a49bef13
    1.11 +nbproject/build-impl.xml.data.CRC32=f3f7e858
    1.12  nbproject/build-impl.xml.script.CRC32=87e6e497
    1.13  nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.44
     2.1 --- a/server/backend/impl/nbproject/project.xml	Tue Feb 15 20:14:52 2011 +0100
     2.2 +++ b/server/backend/impl/nbproject/project.xml	Tue Feb 15 20:16:07 2011 +0100
     2.3 @@ -72,7 +72,7 @@
     2.4                      <build-prerequisite/>
     2.5                      <compile-dependency/>
     2.6                      <run-dependency>
     2.7 -                        <specification-version>0.75.0.17.12.6</specification-version>
     2.8 +                        <implementation-version/>
     2.9                      </run-dependency>
    2.10                  </dependency>
    2.11                  <dependency>
    2.12 @@ -84,6 +84,15 @@
    2.13                      </run-dependency>
    2.14                  </dependency>
    2.15                  <dependency>
    2.16 +                    <code-name-base>org.netbeans.modules.jumpto</code-name-base>
    2.17 +                    <build-prerequisite/>
    2.18 +                    <compile-dependency/>
    2.19 +                    <run-dependency>
    2.20 +                        <release-version>1</release-version>
    2.21 +                        <implementation-version/>
    2.22 +                    </run-dependency>
    2.23 +                </dependency>
    2.24 +                <dependency>
    2.25                      <code-name-base>org.netbeans.modules.project.ant</code-name-base>
    2.26                      <build-prerequisite/>
    2.27                      <compile-dependency/>
    2.28 @@ -187,6 +196,24 @@
    2.29                      </run-dependency>
    2.30                  </dependency>
    2.31              </module-dependencies>
    2.32 +            <test-dependencies>
    2.33 +                <test-type>
    2.34 +                    <name>unit</name>
    2.35 +                    <test-dependency>
    2.36 +                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
    2.37 +                        <compile-dependency/>
    2.38 +                    </test-dependency>
    2.39 +                    <test-dependency>
    2.40 +                        <code-name-base>org.netbeans.modules.junitlib</code-name-base>
    2.41 +                        <compile-dependency/>
    2.42 +                    </test-dependency>
    2.43 +                    <test-dependency>
    2.44 +                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
    2.45 +                        <recursive/>
    2.46 +                        <compile-dependency/>
    2.47 +                    </test-dependency>
    2.48 +                </test-type>
    2.49 +            </test-dependencies>
    2.50              <public-packages/>
    2.51          </data>
    2.52      </configuration>
     3.1 --- a/server/backend/impl/src/org/netbeans/modules/jackpot30/backend/impl/api/API.java	Tue Feb 15 20:14:52 2011 +0100
     3.2 +++ b/server/backend/impl/src/org/netbeans/modules/jackpot30/backend/impl/api/API.java	Tue Feb 15 20:16:07 2011 +0100
     3.3 @@ -52,7 +52,10 @@
     3.4  import java.util.Arrays;
     3.5  import java.util.Collection;
     3.6  import java.util.Collections;
     3.7 +import java.util.EnumSet;
     3.8  import java.util.HashMap;
     3.9 +import java.util.HashSet;
    3.10 +import java.util.LinkedHashMap;
    3.11  import java.util.LinkedList;
    3.12  import java.util.List;
    3.13  import java.util.Map;
    3.14 @@ -60,6 +63,7 @@
    3.15  import java.util.Set;
    3.16  import java.util.concurrent.atomic.AtomicBoolean;
    3.17  import java.util.concurrent.atomic.AtomicLong;
    3.18 +import javax.lang.model.element.TypeElement;
    3.19  import javax.tools.Diagnostic;
    3.20  import javax.tools.JavaFileObject;
    3.21  import javax.ws.rs.DefaultValue;
    3.22 @@ -71,7 +75,11 @@
    3.23  import javax.ws.rs.core.StreamingOutput;
    3.24  import org.codeviation.pojson.Pojson;
    3.25  import org.netbeans.api.java.classpath.ClassPath;
    3.26 +import org.netbeans.api.java.source.ClassIndex.NameKind;
    3.27 +import org.netbeans.api.java.source.ClassIndex.SearchScope;
    3.28 +import org.netbeans.api.java.source.ClasspathInfo;
    3.29  import org.netbeans.api.java.source.CompilationController;
    3.30 +import org.netbeans.api.java.source.ElementHandle;
    3.31  import org.netbeans.api.java.source.ModificationResult;
    3.32  import org.netbeans.modules.jackpot30.backend.impl.CategoryStorage;
    3.33  import org.netbeans.modules.jackpot30.impl.MessageImpl;
    3.34 @@ -89,6 +97,8 @@
    3.35  import org.netbeans.modules.jackpot30.impl.indexing.Index;
    3.36  import org.netbeans.modules.jackpot30.spi.HintDescription;
    3.37  import org.netbeans.modules.jackpot30.spi.PatternConvertor;
    3.38 +import org.netbeans.modules.java.source.usages.ClassIndexManager;
    3.39 +import org.netbeans.modules.jumpto.type.GoToTypeAction;
    3.40  import org.netbeans.spi.editor.hints.ErrorDescription;
    3.41  import org.netbeans.spi.java.classpath.support.ClassPathSupport;
    3.42  import org.openide.filesystems.FileObject;
    3.43 @@ -399,6 +409,65 @@
    3.44          return Pojson.save(result);
    3.45      }
    3.46  
    3.47 +    @GET
    3.48 +    @Path("/findType")
    3.49 +    @Produces("text/plain")
    3.50 +    public String findType(@QueryParam("path") String segment, @QueryParam("prefix") String prefix, @QueryParam("casesensitive") @DefaultValue("false") boolean casesensitive, @QueryParam("asynchronous") @DefaultValue(value="false") boolean asynchronous) throws IOException {
    3.51 +        assert !asynchronous;
    3.52 +
    3.53 +        //copied (and converted to NameKind) from jumpto's GoToTypeAction:
    3.54 +        boolean exact = prefix.endsWith(" "); // NOI18N
    3.55 +
    3.56 +        prefix = prefix.trim();
    3.57 +
    3.58 +        if ( prefix.length() == 0) {
    3.59 +            return "";
    3.60 +        }
    3.61 +
    3.62 +        NameKind nameKind;
    3.63 +        int wildcard = GoToTypeAction.containsWildCard(prefix);
    3.64 +
    3.65 +        if (exact) {
    3.66 +            //nameKind = panel.isCaseSensitive() ? SearchType.EXACT_NAME : SearchType.CASE_INSENSITIVE_EXACT_NAME;
    3.67 +            nameKind = NameKind.SIMPLE_NAME;
    3.68 +        }
    3.69 +        else if ((GoToTypeAction.isAllUpper(prefix) && prefix.length() > 1) || GoToTypeAction.isCamelCase(prefix)) {
    3.70 +            nameKind = NameKind.CAMEL_CASE;
    3.71 +        }
    3.72 +        else if (wildcard != -1) {
    3.73 +            nameKind = casesensitive ? NameKind.REGEXP : NameKind.CASE_INSENSITIVE_REGEXP;
    3.74 +        }
    3.75 +        else {
    3.76 +            nameKind = casesensitive ? NameKind.PREFIX : NameKind.CASE_INSENSITIVE_PREFIX;
    3.77 +        }
    3.78 +
    3.79 +        Map<String, List<String>> result = new LinkedHashMap<String, List<String>>();
    3.80 +        Set<FileObject> srcRoots = CategoryStorage.getCategoryContent(segment);
    3.81 +        FileObject deepestCommonParent = deepestCommonParent(srcRoots);
    3.82 +
    3.83 +        for (FileObject srcRoot : srcRoots) {
    3.84 +            String rootId = FileUtil.getRelativePath(deepestCommonParent, srcRoot);
    3.85 +            List<String> currentResult = new ArrayList<String>();
    3.86 +
    3.87 +            result.put(rootId, currentResult);
    3.88 +
    3.89 +            ClassIndexManager.getDefault().createUsagesQuery(srcRoot.getURL(), true);
    3.90 +            ClasspathInfo cpInfo = ClasspathInfo.create(ClassPath.EMPTY, ClassPath.EMPTY, ClassPathSupport.createClassPath(srcRoot));
    3.91 +            Set<ElementHandle<TypeElement>> names = new HashSet<ElementHandle<TypeElement>>(cpInfo.getClassIndex().getDeclaredTypes(prefix, nameKind, EnumSet.of(SearchScope.SOURCE)));
    3.92 +
    3.93 +            if (nameKind == NameKind.CAMEL_CASE) {
    3.94 +                names.addAll(cpInfo.getClassIndex().getDeclaredTypes(prefix, NameKind.CASE_INSENSITIVE_PREFIX, EnumSet.of(SearchScope.SOURCE)));
    3.95 +            }
    3.96 +
    3.97 +            for (ElementHandle<TypeElement> d : names) {
    3.98 +                currentResult.add(d.getBinaryName());
    3.99 +            }
   3.100 +        }
   3.101 +
   3.102 +        return Pojson.save(result);
   3.103 +    }
   3.104 +
   3.105 +    //XXX: not really correct, a base directory(-ies?) should be set in the category!
   3.106      private static FileObject deepestCommonParent(Set<FileObject> roots) {
   3.107          FileObject result = null;
   3.108  
     4.1 --- a/server/backend/impl/src/org/netbeans/modules/jackpot30/backend/impl/ui/UI.java	Tue Feb 15 20:14:52 2011 +0100
     4.2 +++ b/server/backend/impl/src/org/netbeans/modules/jackpot30/backend/impl/ui/UI.java	Tue Feb 15 20:16:07 2011 +0100
     4.3 @@ -39,6 +39,7 @@
     4.4  
     4.5  package org.netbeans.modules.jackpot30.backend.impl.ui;
     4.6  
     4.7 +import java.util.Comparator;
     4.8  import javax.ws.rs.core.Response;
     4.9  import java.util.LinkedHashMap;
    4.10  import java.util.Map.Entry;
    4.11 @@ -154,18 +155,23 @@
    4.12  
    4.13          URI codeURL = new URI("http://localhost:9998/index/cat?path=" + escapeForQuery(path) + "&relative=" + escapeForQuery(relativePath));
    4.14          String code = WebUtilities.requestStringResponse(codeURL);
    4.15 -        URI spansURL = new URI("http://localhost:9998/index/findSpans?path=" + escapeForQuery(path) + "&relativePath=" + escapeForQuery(relativePath) + "&pattern=" + escapeForQuery(pattern));
    4.16 -        int currentCodePos = 0;
    4.17 -        for (int[] span : parseSpans(WebUtilities.requestStringResponse(spansURL))) { //XXX: sorted!
    4.18 -            Map<String, String> occ = new HashMap<String, String>();
    4.19 -            occ.put("prefix", WebUtilities.escapeForHTMLElement(code.substring(currentCodePos, span[0])));
    4.20 -            occ.put("occurrence", WebUtilities.escapeForHTMLElement(code.substring(span[0], span[1])));
    4.21 -            occurrences.add(occ);
    4.22 -            currentCodePos = span[1];
    4.23 +
    4.24 +        if (pattern != null) {
    4.25 +            URI spansURL = new URI("http://localhost:9998/index/findSpans?path=" + escapeForQuery(path) + "&relativePath=" + escapeForQuery(relativePath) + "&pattern=" + escapeForQuery(pattern));
    4.26 +            int currentCodePos = 0;
    4.27 +            for (int[] span : parseSpans(WebUtilities.requestStringResponse(spansURL))) { //XXX: sorted!
    4.28 +                Map<String, String> occ = new HashMap<String, String>();
    4.29 +                occ.put("prefix", WebUtilities.escapeForHTMLElement(code.substring(currentCodePos, span[0])));
    4.30 +                occ.put("occurrence", WebUtilities.escapeForHTMLElement(code.substring(span[0], span[1])));
    4.31 +                occurrences.add(occ);
    4.32 +                currentCodePos = span[1];
    4.33 +            }
    4.34 +
    4.35 +            configurationData.put("suffix", WebUtilities.escapeForHTMLElement(code.substring(currentCodePos, code.length())));
    4.36 +        } else {
    4.37 +            configurationData.put("suffix", WebUtilities.escapeForHTMLElement(code));
    4.38          }
    4.39  
    4.40 -        configurationData.put("suffix", WebUtilities.escapeForHTMLElement(code.substring(currentCodePos, code.length())));
    4.41 -
    4.42          return processTemplate("ui-cat.html", configurationData);
    4.43      }
    4.44      
    4.45 @@ -238,6 +244,59 @@
    4.46          return Response.ok(processTemplate("ui-apply.html", configurationData), "text/html").build();
    4.47      }
    4.48  
    4.49 +    @GET
    4.50 +    @Path("/searchType")
    4.51 +    @Produces("text/html")
    4.52 +    public String searchType(@QueryParam("path") String path, @QueryParam("prefix") String prefix) throws URISyntaxException, IOException, TemplateException {
    4.53 +        Map<String, Object> configurationData = new HashMap<String, Object>();
    4.54 +
    4.55 +        configurationData.put("paths", list());
    4.56 +        configurationData.put("selectedPath", path);
    4.57 +        configurationData.put("prefix", prefix);
    4.58 +
    4.59 +        if (prefix != null && path != null) {
    4.60 +            URI u = new URI("http://localhost:9998/index/findType?path=" + escapeForQuery(path) + "&prefix=" + escapeForQuery(prefix));
    4.61 +            long queryTime = System.currentTimeMillis();
    4.62 +            @SuppressWarnings("unchecked") //XXX: should not trust something got from the network!
    4.63 +            Map<String, List<String>> types = Pojson.load(LinkedHashMap.class, u);
    4.64 +            List<Map<String, Object>> results = new LinkedList<Map<String, Object>>();
    4.65 +
    4.66 +            queryTime = System.currentTimeMillis() - queryTime;
    4.67 +
    4.68 +            for (Entry<String, List<String>> e : types.entrySet()) {
    4.69 +                for (String fqn : e.getValue()) {
    4.70 +                    Map<String, Object> found = new HashMap<String, Object>(3);
    4.71 +
    4.72 +                    found.put("fqn", fqn);
    4.73 +
    4.74 +                    if (fqn.contains("$")) {
    4.75 +                        fqn = fqn.substring(0, fqn.indexOf("$"));
    4.76 +                    }
    4.77 +
    4.78 +                    found.put("relativePath", e.getKey() + "/" + fqn.replace('.', '/') + ".java");
    4.79 +
    4.80 +                    results.add(found);
    4.81 +                }
    4.82 +            }
    4.83 +
    4.84 +            Collections.sort(results, new Comparator<Map<String, Object>>() {
    4.85 +                @Override public int compare(Map<String, Object> o1, Map<String, Object> o2) {
    4.86 +                    return ((String) o1.get("fqn")).compareTo((String) o2.get("fqn"));
    4.87 +                }
    4.88 +            });
    4.89 +            
    4.90 +            configurationData.put("results", results);
    4.91 +
    4.92 +            Map<String, Object> statistics = new HashMap<String, Object>();
    4.93 +
    4.94 +            statistics.put("queryTime", queryTime);
    4.95 +
    4.96 +            configurationData.put("statistics", statistics);
    4.97 +        }
    4.98 +
    4.99 +        return processTemplate("ui-findType.html", configurationData);
   4.100 +    }
   4.101 +
   4.102      private static final Map<String, String> prefix2SpanName = new LinkedHashMap<String, String>();
   4.103  
   4.104      static {
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/server/backend/impl/src/org/netbeans/modules/jackpot30/backend/impl/ui/ui-findType.html	Tue Feb 15 20:16:07 2011 +0100
     5.3 @@ -0,0 +1,28 @@
     5.4 +<html>
     5.5 +<head>
     5.6 +    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
     5.7 +</head>
     5.8 +<body>
     5.9 +<form method="get">
    5.10 +<label for="path">Project:</label>
    5.11 +<select size="1" name="path">");
    5.12 +    <#list paths as path>
    5.13 +        <option <#if selectedPath?? && path.segment == selectedPath>selected</#if> value="${path.segment}">
    5.14 +            ${path.displayName}
    5.15 +        </option>
    5.16 +    </#list>
    5.17 +</select>
    5.18 +<br>
    5.19 +<label for="prefix">Type Name:</label><input type="text" name="prefix"<#if prefix??>value="${prefix}"</#if>/><br>
    5.20 +<input type="submit" name="Find Candidates"/>
    5.21 +</form>
    5.22 +
    5.23 +<#if results??>
    5.24 +    Found types:<br>
    5.25 +    <#list results as result>
    5.26 +        <a href="/index/ui/show?path=${selectedPath}&relative=${result.relativePath}">${result.fqn}</a><br>
    5.27 +    </#list>
    5.28 +</#if>
    5.29 +
    5.30 +</body>
    5.31 +</html>