Support for Go to Symbol
authorJan Lahoda <jlahoda@netbeans.org>
Mon, 04 Jul 2011 12:48:44 +0200
changeset 6216181870b7ba7
parent 620 49f2dba8cb19
child 622 726459d70a59
Support for Go to Symbol
remoting/ide/jumpto/nbproject/genfiles.properties
remoting/ide/jumpto/nbproject/project.xml
remoting/ide/jumpto/src/org/netbeans/modules/jackpot30/jumpto/RemoteGoToSymbol.java
remoting/ide/jumpto/test/unit/src/org/netbeans/modules/jackpot30/jumpto/RemoteGoToSymbolTest.java
remoting/server/indexer/usages/nbproject/genfiles.properties
remoting/server/indexer/usages/nbproject/project.xml
remoting/server/indexer/usages/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImpl.java
remoting/server/indexer/usages/test/unit/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImplTest.java
remoting/server/tests/testcases/symbol/symbol-lookup1.tc/request
remoting/server/tests/testcases/symbol/symbol-lookup1.tc/response
remoting/server/web/type.web.api/src/org/netbeans/modules/jackpot30/backend/type/api/API.java
remoting/server/web/type.web.api/src/org/netbeans/modules/jackpot30/backend/type/api/Base.java
remoting/server/web/type.web.api/src/org/netbeans/modules/jackpot30/backend/type/api/Symbol.java
remoting/server/web/type.web.api/src/org/netbeans/modules/jackpot30/backend/type/api/Type.java
     1.1 --- a/remoting/ide/jumpto/nbproject/genfiles.properties	Sun Jul 03 11:51:25 2011 +0200
     1.2 +++ b/remoting/ide/jumpto/nbproject/genfiles.properties	Mon Jul 04 12:48:44 2011 +0200
     1.3 @@ -3,6 +3,6 @@
     1.4  build.xml.stylesheet.CRC32=a56c6a5b@1.45
     1.5  # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
     1.6  # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
     1.7 -nbproject/build-impl.xml.data.CRC32=60391694
     1.8 +nbproject/build-impl.xml.data.CRC32=a2186361
     1.9  nbproject/build-impl.xml.script.CRC32=3404573f
    1.10  nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.47
     2.1 --- a/remoting/ide/jumpto/nbproject/project.xml	Sun Jul 03 11:51:25 2011 +0200
     2.2 +++ b/remoting/ide/jumpto/nbproject/project.xml	Mon Jul 04 12:48:44 2011 +0200
     2.3 @@ -91,6 +91,20 @@
     2.4                      </run-dependency>
     2.5                  </dependency>
     2.6              </module-dependencies>
     2.7 +            <test-dependencies>
     2.8 +                <test-type>
     2.9 +                    <name>unit</name>
    2.10 +                    <test-dependency>
    2.11 +                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
    2.12 +                        <compile-dependency/>
    2.13 +                    </test-dependency>
    2.14 +                    <test-dependency>
    2.15 +                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
    2.16 +                        <recursive/>
    2.17 +                        <compile-dependency/>
    2.18 +                    </test-dependency>
    2.19 +                </test-type>
    2.20 +            </test-dependencies>
    2.21              <public-packages/>
    2.22          </data>
    2.23      </configuration>
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/remoting/ide/jumpto/src/org/netbeans/modules/jackpot30/jumpto/RemoteGoToSymbol.java	Mon Jul 04 12:48:44 2011 +0200
     3.3 @@ -0,0 +1,361 @@
     3.4 +/*
     3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 + *
     3.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
     3.8 + *
     3.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    3.10 + * Other names may be trademarks of their respective owners.
    3.11 + *
    3.12 + * The contents of this file are subject to the terms of either the GNU
    3.13 + * General Public License Version 2 only ("GPL") or the Common
    3.14 + * Development and Distribution License("CDDL") (collectively, the
    3.15 + * "License"). You may not use this file except in compliance with the
    3.16 + * License. You can obtain a copy of the License at
    3.17 + * http://www.netbeans.org/cddl-gplv2.html
    3.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    3.19 + * specific language governing permissions and limitations under the
    3.20 + * License.  When distributing the software, include this License Header
    3.21 + * Notice in each file and include the License file at
    3.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    3.23 + * particular file as subject to the "Classpath" exception as provided
    3.24 + * by Oracle in the GPL Version 2 section of the License file that
    3.25 + * accompanied this code. If applicable, add the following below the
    3.26 + * License Header, with the fields enclosed by brackets [] replaced by
    3.27 + * your own identifying information:
    3.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    3.29 + *
    3.30 + * If you wish your version of this file to be governed by only the CDDL
    3.31 + * or only the GPL Version 2, indicate your decision by adding
    3.32 + * "[Contributor] elects to include this software in this distribution
    3.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    3.34 + * single choice of license, a recipient has the option to distribute
    3.35 + * your version of this file under either the CDDL, the GPL Version 2 or
    3.36 + * to extend the choice of license to its licensees as provided above.
    3.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    3.38 + * Version 2 license, then the option applies only if the new code is
    3.39 + * made subject to such option by the copyright holder.
    3.40 + *
    3.41 + * Contributor(s):
    3.42 + *
    3.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
    3.44 + */
    3.45 +package org.netbeans.modules.jackpot30.jumpto;
    3.46 +
    3.47 +import java.io.File;
    3.48 +import java.net.URI;
    3.49 +import java.net.URISyntaxException;
    3.50 +import java.util.Arrays;
    3.51 +import java.util.Collection;
    3.52 +import java.util.EnumSet;
    3.53 +import java.util.HashSet;
    3.54 +import java.util.LinkedHashMap;
    3.55 +import java.util.List;
    3.56 +import java.util.Map;
    3.57 +import java.util.Map.Entry;
    3.58 +import java.util.Set;
    3.59 +import java.util.concurrent.atomic.AtomicReference;
    3.60 +import javax.lang.model.element.ElementKind;
    3.61 +import javax.lang.model.element.Modifier;
    3.62 +import javax.swing.Icon;
    3.63 +import org.codeviation.pojson.Pojson;
    3.64 +import org.netbeans.api.java.source.ClasspathInfo;
    3.65 +import org.netbeans.api.java.source.ElementHandle;
    3.66 +import org.netbeans.api.java.source.ui.ElementIcons;
    3.67 +import org.netbeans.api.java.source.ui.ElementOpen;
    3.68 +import org.netbeans.api.project.FileOwnerQuery;
    3.69 +import org.netbeans.api.project.Project;
    3.70 +import org.netbeans.api.project.ProjectUtils;
    3.71 +import org.netbeans.modules.jackpot30.remoting.api.RemoteIndex;
    3.72 +import org.netbeans.modules.jackpot30.remoting.api.WebUtilities;
    3.73 +import org.netbeans.modules.java.source.ElementHandleAccessor;
    3.74 +import org.netbeans.modules.java.source.usages.ClassFileUtil;
    3.75 +import org.netbeans.spi.jumpto.symbol.SymbolDescriptor;
    3.76 +import org.netbeans.spi.jumpto.symbol.SymbolProvider;
    3.77 +import org.netbeans.spi.jumpto.type.TypeDescriptor;
    3.78 +import org.netbeans.spi.jumpto.type.TypeProvider;
    3.79 +import org.openide.filesystems.FileObject;
    3.80 +import org.openide.filesystems.FileUtil;
    3.81 +import org.openide.util.Exceptions;
    3.82 +import org.openide.util.lookup.ServiceProvider;
    3.83 +
    3.84 +/**
    3.85 + *
    3.86 + * @author lahvac
    3.87 + */
    3.88 +@ServiceProvider(service=SymbolProvider.class)
    3.89 +public class RemoteGoToSymbol implements SymbolProvider {
    3.90 +
    3.91 +    @Override
    3.92 +    public String name() {
    3.93 +        return "Jackpot 3.0 Remote Index Symbol Provider";
    3.94 +    }
    3.95 +
    3.96 +    @Override
    3.97 +    public String getDisplayName() {
    3.98 +        return "Jackpot 3.0 Remote Index Symbol Provider";
    3.99 +    }
   3.100 +
   3.101 +    @Override
   3.102 +    public void computeSymbolNames(Context context, Result result) {
   3.103 +        for (RemoteIndex ri : RemoteIndex.loadIndices()) {
   3.104 +            try {
   3.105 +                URI resolved = new URI(ri.remote.toExternalForm() + "/symbol/search?path=" + WebUtilities.escapeForQuery(ri.remoteSegment) + "&prefix=" + WebUtilities.escapeForQuery(context.getText()) + "&querykind=" + WebUtilities.escapeForQuery(context.getSearchType().name()));
   3.106 +                String response = WebUtilities.requestStringResponse(resolved);
   3.107 +
   3.108 +                if (response == null) continue;
   3.109 +                
   3.110 +                @SuppressWarnings("unchecked") //XXX: should not trust something got from the network!
   3.111 +                Map<String, Iterable<Map<String, Object>>> types = Pojson.load(LinkedHashMap.class, response);
   3.112 +
   3.113 +                for (Entry<String, Iterable<Map<String, Object>>> e : types.entrySet()) {
   3.114 +                    for (Map<String, Object> properties : e.getValue()) {
   3.115 +                        result.addResult(new RemoteSymbolDescriptor(ri, properties));
   3.116 +                    }
   3.117 +                }
   3.118 +            } catch (URISyntaxException ex) {
   3.119 +                Exceptions.printStackTrace(ex);
   3.120 +            }
   3.121 +        }
   3.122 +    }
   3.123 +
   3.124 +    @Override
   3.125 +    public void cancel() {
   3.126 +    }
   3.127 +
   3.128 +    @Override
   3.129 +    public void cleanup() {
   3.130 +    }
   3.131 +
   3.132 +    static final class RemoteSymbolDescriptor extends SymbolDescriptor {
   3.133 +
   3.134 +        private final RemoteIndex origin;
   3.135 +        private final Map<String, Object> properties;
   3.136 +        private final AtomicReference<FileObject> file = new AtomicReference<FileObject>();
   3.137 +
   3.138 +        public RemoteSymbolDescriptor(RemoteIndex origin, Map<String, Object> properties) {
   3.139 +            this.origin = origin;
   3.140 +            this.properties = properties;
   3.141 +        }
   3.142 +
   3.143 +        @Override
   3.144 +        public Icon getIcon() {
   3.145 +            ElementKind kind = resolveKind();
   3.146 +            Set<Modifier> modifiers = EnumSet.noneOf(Modifier.class);
   3.147 +            Set<String> modNames = new HashSet<String>((Collection<String>) properties.get("modifiers"));
   3.148 +
   3.149 +            for (Modifier mod : Modifier.values()) {
   3.150 +                if (modNames.contains(mod.name())) {
   3.151 +                    modifiers.add(mod);
   3.152 +                }
   3.153 +            }
   3.154 +
   3.155 +            return ElementIcons.getElementIcon(kind, modifiers);
   3.156 +        }
   3.157 +
   3.158 +        private ElementKind resolveKind() {
   3.159 +            String kindName = (String) properties.get("kind"); //XXX: cast
   3.160 +            ElementKind kind = ElementKind.OTHER;
   3.161 +
   3.162 +            for (ElementKind k : ElementKind.values()) {
   3.163 +                if (k.name().equals(kindName)) {
   3.164 +                    kind = k;
   3.165 +                    break;
   3.166 +                }
   3.167 +            }
   3.168 +
   3.169 +            return kind;
   3.170 +        }
   3.171 +
   3.172 +        @Override
   3.173 +        public String getProjectName() {
   3.174 +            FileObject file = getFileObject();
   3.175 +
   3.176 +            if (file == null) return null;
   3.177 +
   3.178 +            Project prj = FileOwnerQuery.getOwner(file);
   3.179 +
   3.180 +            if (prj == null) return null;
   3.181 +
   3.182 +            return ProjectUtils.getInformation(prj).getDisplayName();
   3.183 +        }
   3.184 +
   3.185 +        @Override
   3.186 +        public Icon getProjectIcon() {
   3.187 +            FileObject file = getFileObject();
   3.188 +
   3.189 +            if (file == null) return null;
   3.190 +
   3.191 +            Project prj = FileOwnerQuery.getOwner(file);
   3.192 +
   3.193 +            if (prj == null) return null;
   3.194 +
   3.195 +            return ProjectUtils.getInformation(prj).getIcon();
   3.196 +        }
   3.197 +
   3.198 +        @Override
   3.199 +        public FileObject getFileObject() {
   3.200 +            FileObject f = this.file.get();
   3.201 +
   3.202 +            if (f == null) {
   3.203 +                String relativePath = (String) properties.get("file");
   3.204 +                FileObject originFolder = FileUtil.toFileObject(FileUtil.normalizeFile(new File(origin.folder)));
   3.205 +
   3.206 +                if (originFolder != null) f = originFolder.getFileObject(relativePath);
   3.207 +                if (f != null) this.file.set(f);
   3.208 +            }
   3.209 +
   3.210 +            return f;
   3.211 +        }
   3.212 +
   3.213 +        @Override
   3.214 +        public int getOffset() {
   3.215 +            return 0;
   3.216 +        }
   3.217 +
   3.218 +        @Override
   3.219 +        public void open() {
   3.220 +            FileObject file = getFileObject();
   3.221 +
   3.222 +            if (file == null) return ; //XXX tell to the user
   3.223 +
   3.224 +            ClasspathInfo cpInfo = ClasspathInfo.create(file);
   3.225 +            ElementHandle<?> handle = ElementHandleAccessor.INSTANCE.create(resolveKind(), (String) properties.get("enclosingFQN"), (String) properties.get("simpleName"), (String) properties.get("vmsignature"));
   3.226 +
   3.227 +            ElementOpen.open(cpInfo, handle);
   3.228 +        }
   3.229 +
   3.230 +        @Override
   3.231 +        public String getSymbolName() {
   3.232 +            StringBuilder name = new StringBuilder();
   3.233 +
   3.234 +            name.append(properties.get("simpleName"));
   3.235 +
   3.236 +            if (properties.containsKey("signature") && (resolveKind() == ElementKind.METHOD || resolveKind() == ElementKind.CONSTRUCTOR)) {
   3.237 +                methodParameterTypes((String) properties.get("signature"), new int[] {0}, name);
   3.238 +            }
   3.239 +
   3.240 +            return name.toString();
   3.241 +        }
   3.242 +
   3.243 +        @Override
   3.244 +        public String getOwnerName() {
   3.245 +            return (String) properties.get("enclosingFQN");
   3.246 +        }
   3.247 +
   3.248 +    }
   3.249 +
   3.250 +    private static char getChar (final String buffer, final int pos) {
   3.251 +        if (pos>=buffer.length()) {
   3.252 +            throw new IllegalStateException ();
   3.253 +        }
   3.254 +        return buffer.charAt(pos);
   3.255 +    }
   3.256 +
   3.257 +    private static String typeArgument (final String jvmTypeId, final int[] pos) {
   3.258 +        char c = getChar (jvmTypeId, pos[0]);
   3.259 +        switch (c) {
   3.260 +            case '*': 
   3.261 +                pos[0]++;
   3.262 +                return ""; //XXX?
   3.263 +            case '+':
   3.264 +                pos[0]++;
   3.265 +                return "? extends " + typeSignatureType(jvmTypeId, pos);
   3.266 +            case '-':
   3.267 +                pos[0]++;
   3.268 +                return "? super " + typeSignatureType(jvmTypeId, pos);
   3.269 +            default:
   3.270 +                return typeSignatureType (jvmTypeId, pos);
   3.271 +        }
   3.272 +    }
   3.273 +
   3.274 +
   3.275 +    private static void typeArgumentsList (final String jvmTypeId, final int[] pos, StringBuilder result) {
   3.276 +        char c = getChar (jvmTypeId, pos[0]++);
   3.277 +        if (c != '<') {
   3.278 +            throw new IllegalStateException (jvmTypeId);
   3.279 +        }
   3.280 +        c = getChar (jvmTypeId, pos[0]);
   3.281 +        boolean first = true;
   3.282 +        while (c !='>') {
   3.283 +            if (!first) result.append(", ");
   3.284 +            first = false;
   3.285 +            result.append(typeArgument (jvmTypeId, pos));
   3.286 +            c = getChar (jvmTypeId, pos[0]);
   3.287 +        }
   3.288 +        pos[0]++;
   3.289 +    }
   3.290 +
   3.291 +    static boolean generateSimpleNames = true;
   3.292 +
   3.293 +    private static String typeSignatureType (final String jvmTypeId, final int[] pos) {
   3.294 +        char c = getChar(jvmTypeId, pos[0]++);
   3.295 +        switch (c) {
   3.296 +            case 'B': return "byte";
   3.297 +            case 'C': return "char";
   3.298 +            case 'D': return "double";
   3.299 +            case 'F': return "float";
   3.300 +            case 'I': return "int";
   3.301 +            case 'J': return "long";
   3.302 +            case 'S': return "short";
   3.303 +            case 'V': return "void";
   3.304 +            case 'Z': return "boolean";
   3.305 +            case 'L': {
   3.306 +                StringBuilder builder = new StringBuilder ();
   3.307 +                c = getChar(jvmTypeId, pos[0]++);
   3.308 +                while (c != ';') {
   3.309 +                    if (c == '/' || c == '$') {
   3.310 +                        if (generateSimpleNames) builder.delete(0, builder.length());
   3.311 +                        else builder.append('.');
   3.312 +                    } else {
   3.313 +                        builder.append(c);
   3.314 +                    }
   3.315 +
   3.316 +                    if (c=='<') {
   3.317 +                        pos[0]--;
   3.318 +                        typeArgumentsList (jvmTypeId, pos, builder);
   3.319 +                        builder.append(">");
   3.320 +                    }
   3.321 +                    c = getChar(jvmTypeId, pos[0]++);
   3.322 +                }
   3.323 +                return builder.toString();
   3.324 +            }
   3.325 +            case 'T': {
   3.326 +                StringBuilder builder = new StringBuilder ();
   3.327 +                c = getChar(jvmTypeId, pos[0]++);
   3.328 +                while (c != ';') {
   3.329 +                    builder.append(c);
   3.330 +                    c = getChar(jvmTypeId, pos[0]++);
   3.331 +                }
   3.332 +                return builder.toString();
   3.333 +            }
   3.334 +            case '[':
   3.335 +                return typeSignatureType (jvmTypeId, pos) + "[]";
   3.336 +            default:
   3.337 +                return "<unknown-type>";
   3.338 +        }
   3.339 +    }
   3.340 +
   3.341 +    private static void methodParameterTypes(final String jvmTypeId, final int[] pos, StringBuilder result) {
   3.342 +        char c = getChar (jvmTypeId, pos[0]);
   3.343 +        if (c == '<') {
   3.344 +            do {
   3.345 +                c = getChar (jvmTypeId, pos[0]++);
   3.346 +            } while (c != '>');
   3.347 +            c = getChar (jvmTypeId, pos[0]);
   3.348 +        }
   3.349 +        if (c!='(') {
   3.350 +            throw new IllegalStateException (jvmTypeId);
   3.351 +        }
   3.352 +        pos[0]++;
   3.353 +        c = getChar (jvmTypeId, pos[0]);
   3.354 +        result.append("(");
   3.355 +        boolean first = true;
   3.356 +        while (c != ')') {
   3.357 +            if (!first) result.append(", ");
   3.358 +            first = false;
   3.359 +            result.append(typeSignatureType (jvmTypeId, pos));
   3.360 +            c = getChar (jvmTypeId, pos[0]);
   3.361 +        }
   3.362 +        result.append(")");
   3.363 +    }
   3.364 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/remoting/ide/jumpto/test/unit/src/org/netbeans/modules/jackpot30/jumpto/RemoteGoToSymbolTest.java	Mon Jul 04 12:48:44 2011 +0200
     4.3 @@ -0,0 +1,76 @@
     4.4 +/*
     4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 + *
     4.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
     4.8 + *
     4.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    4.10 + * Other names may be trademarks of their respective owners.
    4.11 + *
    4.12 + * The contents of this file are subject to the terms of either the GNU
    4.13 + * General Public License Version 2 only ("GPL") or the Common
    4.14 + * Development and Distribution License("CDDL") (collectively, the
    4.15 + * "License"). You may not use this file except in compliance with the
    4.16 + * License. You can obtain a copy of the License at
    4.17 + * http://www.netbeans.org/cddl-gplv2.html
    4.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    4.19 + * specific language governing permissions and limitations under the
    4.20 + * License.  When distributing the software, include this License Header
    4.21 + * Notice in each file and include the License file at
    4.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    4.23 + * particular file as subject to the "Classpath" exception as provided
    4.24 + * by Oracle in the GPL Version 2 section of the License file that
    4.25 + * accompanied this code. If applicable, add the following below the
    4.26 + * License Header, with the fields enclosed by brackets [] replaced by
    4.27 + * your own identifying information:
    4.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    4.29 + *
    4.30 + * If you wish your version of this file to be governed by only the CDDL
    4.31 + * or only the GPL Version 2, indicate your decision by adding
    4.32 + * "[Contributor] elects to include this software in this distribution
    4.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    4.34 + * single choice of license, a recipient has the option to distribute
    4.35 + * your version of this file under either the CDDL, the GPL Version 2 or
    4.36 + * to extend the choice of license to its licensees as provided above.
    4.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    4.38 + * Version 2 license, then the option applies only if the new code is
    4.39 + * made subject to such option by the copyright holder.
    4.40 + *
    4.41 + * Contributor(s):
    4.42 + *
    4.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
    4.44 + */
    4.45 +package org.netbeans.modules.jackpot30.jumpto;
    4.46 +
    4.47 +import java.util.HashMap;
    4.48 +import java.util.Map;
    4.49 +import org.netbeans.junit.NbTestCase;
    4.50 +import org.netbeans.modules.jackpot30.jumpto.RemoteGoToSymbol.RemoteSymbolDescriptor;
    4.51 +
    4.52 +/**
    4.53 + *
    4.54 + * @author lahvac
    4.55 + */
    4.56 +public class RemoteGoToSymbolTest extends NbTestCase {
    4.57 +
    4.58 +    public RemoteGoToSymbolTest(String testName) {
    4.59 +        super(testName);
    4.60 +    }
    4.61 +
    4.62 +    public void testSymbolName() {
    4.63 +        doTestSymbolName("test", "()V;", "test()");
    4.64 +        RemoteGoToSymbol.generateSimpleNames = false;
    4.65 +        doTestSymbolName("test", "<T:Ljava/lang/String;>(Ljava/util/Map<Ljava/util/List<Ljava/lang/String;>;TT;>;Z)V;", "test(java.util.Map<java.util.List<java.lang.String>, T>, boolean)");
    4.66 +        RemoteGoToSymbol.generateSimpleNames = true;
    4.67 +        doTestSymbolName("test", "<T:Ljava/lang/String;>(Ljava/util/Map<Ljava/util/List<Ljava/lang/String;>;TT;>;Z)V;", "test(Map<List<String>, T>, boolean)");
    4.68 +        RemoteGoToSymbol.generateSimpleNames = false;
    4.69 +        doTestSymbolName("test", "(Ljava/util/List<+Ljava/lang/String;>;)V;", "test(java.util.List<? extends java.lang.String>)");
    4.70 +    }
    4.71 +
    4.72 +    private void doTestSymbolName(String name, String signature, String golden) {
    4.73 +        Map<String, Object> props = new HashMap<String, Object>();
    4.74 +
    4.75 +        props.put("simpleName", name);
    4.76 +        props.put("signature", signature);
    4.77 +        assertEquals(golden, new RemoteSymbolDescriptor(null, props).getSymbolName());
    4.78 +    }
    4.79 +}
     5.1 --- a/remoting/server/indexer/usages/nbproject/genfiles.properties	Sun Jul 03 11:51:25 2011 +0200
     5.2 +++ b/remoting/server/indexer/usages/nbproject/genfiles.properties	Mon Jul 04 12:48:44 2011 +0200
     5.3 @@ -1,8 +1,8 @@
     5.4 -build.xml.data.CRC32=5ee97dea
     5.5 +build.xml.data.CRC32=615c50ac
     5.6  build.xml.script.CRC32=4ae79e41
     5.7  build.xml.stylesheet.CRC32=a56c6a5b@1.47
     5.8  # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
     5.9  # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
    5.10 -nbproject/build-impl.xml.data.CRC32=5ee97dea
    5.11 +nbproject/build-impl.xml.data.CRC32=615c50ac
    5.12  nbproject/build-impl.xml.script.CRC32=16d3b827
    5.13  nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.47
     6.1 --- a/remoting/server/indexer/usages/nbproject/project.xml	Sun Jul 03 11:51:25 2011 +0200
     6.2 +++ b/remoting/server/indexer/usages/nbproject/project.xml	Mon Jul 04 12:48:44 2011 +0200
     6.3 @@ -54,7 +54,7 @@
     6.4                      <build-prerequisite/>
     6.5                      <compile-dependency/>
     6.6                      <run-dependency>
     6.7 -                        <specification-version>0.81.0.17.15.6</specification-version>
     6.8 +                        <implementation-version/>
     6.9                      </run-dependency>
    6.10                  </dependency>
    6.11                  <dependency>
    6.12 @@ -100,6 +100,24 @@
    6.13                      </run-dependency>
    6.14                  </dependency>
    6.15              </module-dependencies>
    6.16 +            <test-dependencies>
    6.17 +                <test-type>
    6.18 +                    <name>unit</name>
    6.19 +                    <test-dependency>
    6.20 +                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
    6.21 +                        <compile-dependency/>
    6.22 +                    </test-dependency>
    6.23 +                    <test-dependency>
    6.24 +                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
    6.25 +                        <recursive/>
    6.26 +                        <compile-dependency/>
    6.27 +                    </test-dependency>
    6.28 +                    <test-dependency>
    6.29 +                        <code-name-base>org.netbeans.modules.projectui</code-name-base>
    6.30 +                        <compile-dependency/>
    6.31 +                    </test-dependency>
    6.32 +                </test-type>
    6.33 +            </test-dependencies>
    6.34              <public-packages/>
    6.35          </data>
    6.36      </configuration>
     7.1 --- a/remoting/server/indexer/usages/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImpl.java	Sun Jul 03 11:51:25 2011 +0200
     7.2 +++ b/remoting/server/indexer/usages/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImpl.java	Mon Jul 04 12:48:44 2011 +0200
     7.3 @@ -56,7 +56,17 @@
     7.4  import javax.lang.model.element.Element;
     7.5  import javax.lang.model.element.ElementKind;
     7.6  import javax.lang.model.element.ExecutableElement;
     7.7 +import javax.lang.model.element.Modifier;
     7.8  import javax.lang.model.element.TypeElement;
     7.9 +import javax.lang.model.element.TypeParameterElement;
    7.10 +import javax.lang.model.element.VariableElement;
    7.11 +import javax.lang.model.type.ArrayType;
    7.12 +import javax.lang.model.type.DeclaredType;
    7.13 +import javax.lang.model.type.ErrorType;
    7.14 +import javax.lang.model.type.TypeKind;
    7.15 +import javax.lang.model.type.TypeMirror;
    7.16 +import javax.lang.model.type.TypeVariable;
    7.17 +import javax.lang.model.type.WildcardType;
    7.18  import org.apache.lucene.document.Document;
    7.19  import org.apache.lucene.document.Field;
    7.20  import org.apache.lucene.document.Field.Index;
    7.21 @@ -65,11 +75,13 @@
    7.22  import org.netbeans.api.editor.mimelookup.MimeRegistration;
    7.23  import org.netbeans.api.java.source.ClasspathInfo;
    7.24  import org.netbeans.api.java.source.CompilationController;
    7.25 +import org.netbeans.api.java.source.CompilationInfo;
    7.26  import org.netbeans.api.java.source.ElementHandle;
    7.27  import org.netbeans.api.java.source.JavaSource;
    7.28  import org.netbeans.api.java.source.JavaSource.Phase;
    7.29  import org.netbeans.api.java.source.Task;
    7.30  import org.netbeans.modules.jackpot30.backend.impl.spi.IndexAccessor;
    7.31 +import org.netbeans.modules.java.source.usages.ClassFileUtil;
    7.32  import org.netbeans.modules.parsing.spi.indexing.Context;
    7.33  import org.netbeans.modules.parsing.spi.indexing.CustomIndexer;
    7.34  import org.netbeans.modules.parsing.spi.indexing.CustomIndexerFactory;
    7.35 @@ -209,7 +221,8 @@
    7.36                              }
    7.37  
    7.38                              @Override public Void visitVariable(VariableTree node, Void p) {
    7.39 -                                handleFeature();
    7.40 +                                if (!inMethod)
    7.41 +                                    handleFeature();
    7.42                                  return super.visitVariable(node, p);
    7.43                              }
    7.44  
    7.45 @@ -224,8 +237,18 @@
    7.46                                          currentFeatureDocument.add(new Field("featureSimpleName", el.getSimpleName().toString(), Store.YES, Index.NOT_ANALYZED));
    7.47                                          currentFeatureDocument.add(new Field("featureSimpleNameLower", el.getSimpleName().toString().toLowerCase(), Store.YES, Index.NOT_ANALYZED));
    7.48                                          currentFeatureDocument.add(new Field("featureKind", el.getKind().name(), Store.YES, Index.NO));
    7.49 +                                        for (Modifier m : el.getModifiers()) {
    7.50 +                                            currentFeatureDocument.add(new Field("featureModifiers", m.name(), Store.YES, Index.NO));
    7.51 +                                        }
    7.52                                          currentFeatureDocument.add(new Field("file", file, Store.YES, Index.NO));
    7.53  
    7.54 +                                        if (el.getKind() == ElementKind.METHOD || el.getKind() == ElementKind.CONSTRUCTOR) {
    7.55 +                                            String featureSignature = methodTypeSignature(cc, (ExecutableElement) el);
    7.56 +                                            
    7.57 +                                            currentFeatureDocument.add(new Field("featureSignature", featureSignature, Store.YES, Index.NO));
    7.58 +                                            currentFeatureDocument.add(new Field("featureVMSignature", ClassFileUtil.createExecutableDescriptor((ExecutableElement) el)[2], Store.YES, Index.NO));
    7.59 +                                        }
    7.60 +
    7.61                                          IndexAccessor.getCurrent().getIndexWriter().addDocument(currentFeatureDocument);
    7.62                                      } catch (CorruptIndexException ex) {
    7.63                                          Exceptions.printStackTrace(ex);
    7.64 @@ -245,6 +268,133 @@
    7.65          }
    7.66      }
    7.67  
    7.68 +    private static void encodeTypeParameters(CompilationInfo info, Collection<? extends TypeParameterElement> params, StringBuilder result) {
    7.69 +        if (params.isEmpty()) return;
    7.70 +        result.append("<");
    7.71 +        for (TypeParameterElement tpe : params) {
    7.72 +            result.append(tpe.getSimpleName());
    7.73 +            boolean wasClass = false;
    7.74 +            
    7.75 +            for (TypeMirror tm : tpe.getBounds()) {
    7.76 +                assert tm.getKind() == TypeKind.DECLARED;
    7.77 +                
    7.78 +                if (!((DeclaredType) tm).asElement().getKind().isClass() && !wasClass) {
    7.79 +                    result.append(":Ljava/lang/Object;");
    7.80 +                }
    7.81 +                
    7.82 +                wasClass = true;
    7.83 +                result.append(':');
    7.84 +                encodeType(info, tm, result);
    7.85 +            }
    7.86 +        }
    7.87 +        result.append(">");
    7.88 +    }
    7.89 +    
    7.90 +    static String methodTypeSignature(CompilationInfo info, ExecutableElement ee) {
    7.91 +        StringBuilder sb = new StringBuilder ();
    7.92 +        encodeTypeParameters(info, ee.getTypeParameters(), sb);
    7.93 +        sb.append('(');             // NOI18N
    7.94 +        for (VariableElement pd : ee.getParameters()) {
    7.95 +            encodeType(info, pd.asType(),sb);
    7.96 +        }
    7.97 +        sb.append(')');             // NOI18N
    7.98 +        encodeType(info, ee.getReturnType(), sb);
    7.99 +        for (TypeMirror tm : ee.getThrownTypes()) {
   7.100 +            sb.append('^');
   7.101 +            encodeType(info, tm, sb);
   7.102 +        }
   7.103 +        sb.append(';'); //TODO: unsure about this, but classfile signatures seem to have it
   7.104 +        return sb.toString();
   7.105 +    }
   7.106 +
   7.107 +    private static void encodeType (CompilationInfo info, final TypeMirror type, final StringBuilder sb) {
   7.108 +	switch (type.getKind()) {
   7.109 +	    case VOID:
   7.110 +		sb.append('V');	    // NOI18N
   7.111 +		break;
   7.112 +	    case BOOLEAN:
   7.113 +		sb.append('Z');	    // NOI18N
   7.114 +		break;
   7.115 +	    case BYTE:
   7.116 +		sb.append('B');	    // NOI18N
   7.117 +		break;
   7.118 +	    case SHORT:
   7.119 +		sb.append('S');	    // NOI18N
   7.120 +		break;
   7.121 +	    case INT:
   7.122 +		sb.append('I');	    // NOI18N
   7.123 +		break;
   7.124 +	    case LONG:
   7.125 +		sb.append('J');	    // NOI18N
   7.126 +		break;
   7.127 +	    case CHAR:
   7.128 +		sb.append('C');	    // NOI18N
   7.129 +		break;
   7.130 +	    case FLOAT:
   7.131 +		sb.append('F');	    // NOI18N
   7.132 +		break;
   7.133 +	    case DOUBLE:
   7.134 +		sb.append('D');	    // NOI18N
   7.135 +		break;
   7.136 +	    case ARRAY:
   7.137 +		sb.append('[');	    // NOI18N
   7.138 +		assert type instanceof ArrayType;
   7.139 +		encodeType(info, ((ArrayType)type).getComponentType(),sb);
   7.140 +		break;
   7.141 +	    case DECLARED:
   7.142 +            {
   7.143 +		sb.append('L');	    // NOI18N
   7.144 +                DeclaredType dt = (DeclaredType) type;
   7.145 +		TypeElement te = (TypeElement) dt.asElement();
   7.146 +                sb.append(info.getElements().getBinaryName(te).toString().replace('.', '/'));
   7.147 +                if (!dt.getTypeArguments().isEmpty()) {
   7.148 +                    sb.append('<');
   7.149 +                    for (TypeMirror tm : dt.getTypeArguments()) {
   7.150 +                        encodeType(info, tm, sb);
   7.151 +                    }
   7.152 +                    sb.append('>');
   7.153 +                }
   7.154 +		sb.append(';');	    // NOI18N
   7.155 +		break;
   7.156 +            }
   7.157 +	    case TYPEVAR:
   7.158 +            {
   7.159 +		assert type instanceof TypeVariable;
   7.160 +		TypeVariable tr = (TypeVariable) type;
   7.161 +                sb.append('T');
   7.162 +                sb.append(tr.asElement().getSimpleName());
   7.163 +                sb.append(';');
   7.164 +		break;
   7.165 +            }
   7.166 +            case WILDCARD: {
   7.167 +                WildcardType wt = (WildcardType) type;
   7.168 +
   7.169 +                if (wt.getExtendsBound() != null) {
   7.170 +                    sb.append('+');
   7.171 +                    encodeType(info, wt.getExtendsBound(), sb);
   7.172 +                } else if (wt.getSuperBound() != null) {
   7.173 +                    sb.append('-');
   7.174 +                    encodeType(info, wt.getSuperBound(), sb);
   7.175 +                } else {
   7.176 +                    sb.append('*');
   7.177 +                }
   7.178 +                break;
   7.179 +            }
   7.180 +            case ERROR:
   7.181 +            {
   7.182 +                TypeElement te = (TypeElement) ((ErrorType)type).asElement();
   7.183 +                if (te != null) {
   7.184 +                    sb.append('L');
   7.185 +                    sb.append(info.getElements().getBinaryName(te).toString().replace('.', '/'));
   7.186 +                    sb.append(';');	    // NOI18N
   7.187 +                    break;
   7.188 +                }
   7.189 +            }
   7.190 +	    default:
   7.191 +		throw new IllegalArgumentException (type.getKind().name());
   7.192 +	}
   7.193 +    }
   7.194 +
   7.195      @MimeRegistration(mimeType="text/x-java", service=CustomIndexerFactory.class)
   7.196      public static final class FactoryImpl extends CustomIndexerFactory {
   7.197  
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/remoting/server/indexer/usages/test/unit/src/org/netbeans/modules/jackpot30/indexer/usages/IndexerImplTest.java	Mon Jul 04 12:48:44 2011 +0200
     8.3 @@ -0,0 +1,159 @@
     8.4 +/*
     8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     8.6 + *
     8.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
     8.8 + *
     8.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    8.10 + * Other names may be trademarks of their respective owners.
    8.11 + *
    8.12 + * The contents of this file are subject to the terms of either the GNU
    8.13 + * General Public License Version 2 only ("GPL") or the Common
    8.14 + * Development and Distribution License("CDDL") (collectively, the
    8.15 + * "License"). You may not use this file except in compliance with the
    8.16 + * License. You can obtain a copy of the License at
    8.17 + * http://www.netbeans.org/cddl-gplv2.html
    8.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    8.19 + * specific language governing permissions and limitations under the
    8.20 + * License.  When distributing the software, include this License Header
    8.21 + * Notice in each file and include the License file at
    8.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    8.23 + * particular file as subject to the "Classpath" exception as provided
    8.24 + * by Oracle in the GPL Version 2 section of the License file that
    8.25 + * accompanied this code. If applicable, add the following below the
    8.26 + * License Header, with the fields enclosed by brackets [] replaced by
    8.27 + * your own identifying information:
    8.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    8.29 + *
    8.30 + * If you wish your version of this file to be governed by only the CDDL
    8.31 + * or only the GPL Version 2, indicate your decision by adding
    8.32 + * "[Contributor] elects to include this software in this distribution
    8.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    8.34 + * single choice of license, a recipient has the option to distribute
    8.35 + * your version of this file under either the CDDL, the GPL Version 2 or
    8.36 + * to extend the choice of license to its licensees as provided above.
    8.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    8.38 + * Version 2 license, then the option applies only if the new code is
    8.39 + * made subject to such option by the copyright holder.
    8.40 + *
    8.41 + * Contributor(s):
    8.42 + *
    8.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
    8.44 + */
    8.45 +package org.netbeans.modules.jackpot30.indexer.usages;
    8.46 +
    8.47 +import java.io.File;
    8.48 +import java.io.IOException;
    8.49 +import java.io.OutputStream;
    8.50 +import java.util.HashSet;
    8.51 +import javax.lang.model.element.ExecutableElement;
    8.52 +import javax.lang.model.util.ElementFilter;
    8.53 +import org.netbeans.api.editor.mimelookup.MimePath;
    8.54 +import org.netbeans.api.java.source.CompilationController;
    8.55 +import org.netbeans.api.java.source.JavaSource;
    8.56 +import org.netbeans.api.java.source.Task;
    8.57 +import org.netbeans.junit.NbTestCase;
    8.58 +import org.netbeans.modules.java.source.indexing.JavaCustomIndexer;
    8.59 +import org.netbeans.modules.java.source.parsing.JavacParser;
    8.60 +import org.netbeans.modules.java.source.parsing.JavacParserFactory;
    8.61 +import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
    8.62 +import org.netbeans.modules.parsing.impl.indexing.Util;
    8.63 +import org.netbeans.spi.editor.mimelookup.MimeDataProvider;
    8.64 +import org.openide.filesystems.FileObject;
    8.65 +import org.openide.filesystems.FileUtil;
    8.66 +import org.openide.filesystems.MIMEResolver;
    8.67 +import org.openide.util.Lookup;
    8.68 +import org.openide.util.lookup.Lookups;
    8.69 +import org.openide.util.lookup.ServiceProvider;
    8.70 +
    8.71 +/**
    8.72 + *
    8.73 + * @author lahvac
    8.74 + */
    8.75 +public class IndexerImplTest extends NbTestCase {
    8.76 +
    8.77 +    public IndexerImplTest(String testName) {
    8.78 +        super(testName);
    8.79 +    }
    8.80 +
    8.81 +    @Override
    8.82 +    protected void setUp() throws Exception {
    8.83 +        if (Util.allMimeTypes == null) {
    8.84 +            Util.allMimeTypes = new HashSet<String>();
    8.85 +        } else {
    8.86 +            Util.allMimeTypes = new HashSet<String>(Util.allMimeTypes);
    8.87 +        }
    8.88 +
    8.89 +        Util.allMimeTypes.add("text/x-java");
    8.90 +        org.netbeans.api.project.ui.OpenProjects.getDefault().getOpenProjects();
    8.91 +        clearWorkDir();
    8.92 +        CacheFolder.setCacheFolder(FileUtil.toFileObject(getWorkDir()));
    8.93 +        super.setUp();
    8.94 +    }
    8.95 +
    8.96 +    public void testMethodSignatures() throws IOException {
    8.97 +        doMethodSignatureTest("package test; public class Test { public void test() {} }", "()V;");
    8.98 +        doMethodSignatureTest("package test; public class Test { public <T extends String> void test(java.util.Map<java.util.List<String>, T> m, boolean p) {} }", "<T:Ljava/lang/String;>(Ljava/util/Map<Ljava/util/List<Ljava/lang/String;>;TT;>;Z)V;");
    8.99 +        doMethodSignatureTest("package test; public class Test <T extends String> { public void test(java.util.Map<java.util.List<String>, T> m, boolean p) {} }", "(Ljava/util/Map<Ljava/util/List<Ljava/lang/String;>;TT;>;Z)V;");
   8.100 +        doMethodSignatureTest("package test; public class Test { public void test() throws java.io.IOException {} }", "()V^Ljava/io/IOException;;");
   8.101 +        doMethodSignatureTest("package test; public class Test { public void test(java.util.List<? extends String> l) {} }", "(Ljava/util/List<+Ljava/lang/String;>;)V;");
   8.102 +    }
   8.103 +    
   8.104 +    protected void doMethodSignatureTest(String code, final String signature) throws IOException {
   8.105 +        FileObject testFile = FileUtil.createData(new File(getWorkDir(), "Test.java"));
   8.106 +        OutputStream out = testFile.getOutputStream();
   8.107 +
   8.108 +        try {
   8.109 +            out.write(code.getBytes());
   8.110 +        } finally {
   8.111 +            out.close();
   8.112 +        }
   8.113 +
   8.114 +        final boolean[] invoked = new boolean[1];
   8.115 +
   8.116 +        JavaSource.forFileObject(testFile).runUserActionTask(new Task<CompilationController>() {
   8.117 +            @Override public void run(CompilationController parameter) throws Exception {
   8.118 +                parameter.toPhase(JavaSource.Phase.RESOLVED);
   8.119 +
   8.120 +                ExecutableElement method = ElementFilter.methodsIn(parameter.getTopLevelElements().get(0).getEnclosedElements()).iterator().next();
   8.121 +
   8.122 +                assertEquals(signature, IndexerImpl.methodTypeSignature(parameter, method));
   8.123 +                invoked[0] = true;
   8.124 +            }
   8.125 +        }, true);
   8.126 +
   8.127 +        assertTrue(invoked[0]);
   8.128 +    }
   8.129 +
   8.130 +    @ServiceProvider(service=MimeDataProvider.class)
   8.131 +    public static final class JavacParserProvider implements MimeDataProvider {
   8.132 +
   8.133 +        private Lookup javaLookup = Lookups.fixed(new JavacParserFactory(), new JavaCustomIndexer.Factory());
   8.134 +
   8.135 +        public Lookup getLookup(MimePath mimePath) {
   8.136 +            if (mimePath.getPath().endsWith(JavacParser.MIME_TYPE)) {
   8.137 +                return javaLookup;
   8.138 +            }
   8.139 +
   8.140 +            return Lookup.EMPTY;
   8.141 +        }
   8.142 +
   8.143 +    }
   8.144 +
   8.145 +    @ServiceProvider(service=MIMEResolver.class)
   8.146 +    public static final class JavaMimeResolver extends MIMEResolver {
   8.147 +
   8.148 +        public JavaMimeResolver() {
   8.149 +            super(JavacParser.MIME_TYPE);
   8.150 +        }
   8.151 +
   8.152 +        @Override
   8.153 +        public String findMIMEType(FileObject fo) {
   8.154 +            if ("java".equals(fo.getExt())) {
   8.155 +                return JavacParser.MIME_TYPE;
   8.156 +            }
   8.157 +
   8.158 +            return null;
   8.159 +        }
   8.160 +
   8.161 +    }
   8.162 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/remoting/server/tests/testcases/symbol/symbol-lookup1.tc/request	Mon Jul 04 12:48:44 2011 +0200
     9.3 @@ -0,0 +1,1 @@
     9.4 +/index/symbol/search?path=group1&prefix=tes
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/remoting/server/tests/testcases/symbol/symbol-lookup1.tc/response	Mon Jul 04 12:48:44 2011 +0200
    10.3 @@ -0,0 +1,15 @@
    10.4 +{
    10.5 + "prj1/src/": [
    10.6 +     {
    10.7 +         "enclosingFQN": "project1.B",
    10.8 +         "simpleName": "test",
    10.9 +         "file": "prj1/src/project1/B.java",
   10.10 +         "vmsignature": "()V",
   10.11 +         "modifiers": [
   10.12 +             "STATIC"
   10.13 +         ],
   10.14 +         "kind": "METHOD",
   10.15 +         "signature": "()V;"
   10.16 +     }
   10.17 + ]
   10.18 +}
    11.1 --- a/remoting/server/web/type.web.api/src/org/netbeans/modules/jackpot30/backend/type/api/API.java	Sun Jul 03 11:51:25 2011 +0200
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,144 +0,0 @@
    11.4 -/*
    11.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    11.6 - *
    11.7 - * Copyright 2009-2011 Sun Microsystems, Inc. All rights reserved.
    11.8 - *
    11.9 - * The contents of this file are subject to the terms of either the GNU
   11.10 - * General Public License Version 2 only ("GPL") or the Common
   11.11 - * Development and Distribution License("CDDL") (collectively, the
   11.12 - * "License"). You may not use this file except in compliance with the
   11.13 - * License. You can obtain a copy of the License at
   11.14 - * http://www.netbeans.org/cddl-gplv2.html
   11.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   11.16 - * specific language governing permissions and limitations under the
   11.17 - * License.  When distributing the software, include this License Header
   11.18 - * Notice in each file and include the License file at
   11.19 - * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   11.20 - * particular file as subject to the "Classpath" exception as provided
   11.21 - * by Sun in the GPL Version 2 section of the License file that
   11.22 - * accompanied this code. If applicable, add the following below the
   11.23 - * License Header, with the fields enclosed by brackets [] replaced by
   11.24 - * your own identifying information:
   11.25 - * "Portions Copyrighted [year] [name of copyright owner]"
   11.26 - *
   11.27 - * If you wish your version of this file to be governed by only the CDDL
   11.28 - * or only the GPL Version 2, indicate your decision by adding
   11.29 - * "[Contributor] elects to include this software in this distribution
   11.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   11.31 - * single choice of license, a recipient has the option to distribute
   11.32 - * your version of this file under either the CDDL, the GPL Version 2 or
   11.33 - * to extend the choice of license to its licensees as provided above.
   11.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   11.35 - * Version 2 license, then the option applies only if the new code is
   11.36 - * made subject to such option by the copyright holder.
   11.37 - *
   11.38 - * Contributor(s):
   11.39 - *
   11.40 - * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   11.41 - */
   11.42 -
   11.43 -package org.netbeans.modules.jackpot30.backend.type.api;
   11.44 -
   11.45 -import java.io.IOException;
   11.46 -import java.util.AbstractMap.SimpleEntry;
   11.47 -import java.util.ArrayList;
   11.48 -import java.util.LinkedHashMap;
   11.49 -import java.util.List;
   11.50 -import java.util.Map;
   11.51 -import java.util.Map.Entry;
   11.52 -import java.util.concurrent.atomic.AtomicBoolean;
   11.53 -import javax.ws.rs.DefaultValue;
   11.54 -import javax.ws.rs.GET;
   11.55 -import javax.ws.rs.Path;
   11.56 -import javax.ws.rs.Produces;
   11.57 -import javax.ws.rs.QueryParam;
   11.58 -import org.apache.lucene.document.Document;
   11.59 -import org.apache.lucene.search.Query;
   11.60 -import org.codeviation.pojson.Pojson;
   11.61 -import org.netbeans.modules.jackpot30.backend.base.CategoryStorage;
   11.62 -import org.netbeans.modules.jumpto.type.GoToTypeAction;
   11.63 -import org.netbeans.modules.parsing.lucene.support.Convertor;
   11.64 -import org.netbeans.modules.parsing.lucene.support.Index;
   11.65 -import org.netbeans.modules.parsing.lucene.support.Queries;
   11.66 -import org.netbeans.modules.parsing.lucene.support.Queries.QueryKind;
   11.67 -
   11.68 -/**
   11.69 - *
   11.70 - * @author lahvac
   11.71 - */
   11.72 -@Path("/index/type")
   11.73 -public class API {
   11.74 -
   11.75 -    @GET
   11.76 -    @Path("/search")
   11.77 -    @Produces("text/plain")
   11.78 -    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, InterruptedException {
   11.79 -        assert !asynchronous;
   11.80 -
   11.81 -        //copied (and converted to NameKind) from jumpto's GoToTypeAction:
   11.82 -        boolean exact = prefix.endsWith(" "); // NOI18N
   11.83 -
   11.84 -        prefix = prefix.trim();
   11.85 -
   11.86 -        if ( prefix.length() == 0) {
   11.87 -            return "";
   11.88 -        }
   11.89 -
   11.90 -        QueryKind queryKind;
   11.91 -        int wildcard = GoToTypeAction.containsWildCard(prefix);
   11.92 -
   11.93 -        if (exact) {
   11.94 -            //nameKind = panel.isCaseSensitive() ? SearchType.EXACT_NAME : SearchType.CASE_INSENSITIVE_EXACT_NAME;
   11.95 -            queryKind = QueryKind.EXACT;
   11.96 -        }
   11.97 -        else if ((GoToTypeAction.isAllUpper(prefix) && prefix.length() > 1) || GoToTypeAction.isCamelCase(prefix)) {
   11.98 -            queryKind = QueryKind.CAMEL_CASE;
   11.99 -        }
  11.100 -        else if (wildcard != -1) {
  11.101 -            queryKind = casesensitive ? QueryKind.REGEXP : QueryKind.CASE_INSENSITIVE_REGEXP;
  11.102 -        }
  11.103 -        else {
  11.104 -            queryKind = casesensitive ? QueryKind.PREFIX : QueryKind.CASE_INSENSITIVE_PREFIX;
  11.105 -        }
  11.106 -
  11.107 -        Map<String, List<String>> result = new LinkedHashMap<String, List<String>>();
  11.108 -        CategoryStorage category = CategoryStorage.forId(segment);
  11.109 -        Index index = category.getIndex();
  11.110 -
  11.111 -        List<Query> queries = new ArrayList<Query>(2);
  11.112 -
  11.113 -        queries.add(Queries.createQuery("classSimpleName", "classSimpleNameLower", prefix, queryKind));
  11.114 -
  11.115 -        if (queryKind == QueryKind.CAMEL_CASE) {
  11.116 -            queries.add(Queries.createQuery("classSimpleName", "classSimpleNameLower", prefix, QueryKind.CASE_INSENSITIVE_PREFIX));
  11.117 -        }
  11.118 -
  11.119 -        List<Entry<String, String>> found = new ArrayList<Entry<String, String>>();
  11.120 -
  11.121 -        //TODO: field selector:
  11.122 -        index.query(found, new ConvertorImpl(), null, new AtomicBoolean(), queries.toArray(new Query[queries.size()]));
  11.123 -
  11.124 -        for (Entry<String, String> e : found) {
  11.125 -            for (String rel : category.getSourceRoots()) {
  11.126 -                if (e.getKey().startsWith(rel)) {
  11.127 -                    List<String> current = result.get(rel);
  11.128 -
  11.129 -                    if (current == null) {
  11.130 -                        result.put(rel, current = new ArrayList<String>());
  11.131 -                    }
  11.132 -
  11.133 -                    current.add(e.getValue());
  11.134 -                }
  11.135 -            }
  11.136 -        }
  11.137 -
  11.138 -        return Pojson.save(result);
  11.139 -    }
  11.140 -
  11.141 -    private static class ConvertorImpl implements Convertor<Document, Entry<String, String>> {
  11.142 -        @Override public Entry<String, String> convert(Document p) {
  11.143 -            return new SimpleEntry<String, String>(p.get("file"), p.get("classFQN"));
  11.144 -        }
  11.145 -    }
  11.146 -
  11.147 -}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/remoting/server/web/type.web.api/src/org/netbeans/modules/jackpot30/backend/type/api/Base.java	Mon Jul 04 12:48:44 2011 +0200
    12.3 @@ -0,0 +1,139 @@
    12.4 +/*
    12.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    12.6 + *
    12.7 + * Copyright 2009-2011 Sun Microsystems, Inc. All rights reserved.
    12.8 + *
    12.9 + * The contents of this file are subject to the terms of either the GNU
   12.10 + * General Public License Version 2 only ("GPL") or the Common
   12.11 + * Development and Distribution License("CDDL") (collectively, the
   12.12 + * "License"). You may not use this file except in compliance with the
   12.13 + * License. You can obtain a copy of the License at
   12.14 + * http://www.netbeans.org/cddl-gplv2.html
   12.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   12.16 + * specific language governing permissions and limitations under the
   12.17 + * License.  When distributing the software, include this License Header
   12.18 + * Notice in each file and include the License file at
   12.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   12.20 + * particular file as subject to the "Classpath" exception as provided
   12.21 + * by Sun in the GPL Version 2 section of the License file that
   12.22 + * accompanied this code. If applicable, add the following below the
   12.23 + * License Header, with the fields enclosed by brackets [] replaced by
   12.24 + * your own identifying information:
   12.25 + * "Portions Copyrighted [year] [name of copyright owner]"
   12.26 + *
   12.27 + * If you wish your version of this file to be governed by only the CDDL
   12.28 + * or only the GPL Version 2, indicate your decision by adding
   12.29 + * "[Contributor] elects to include this software in this distribution
   12.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   12.31 + * single choice of license, a recipient has the option to distribute
   12.32 + * your version of this file under either the CDDL, the GPL Version 2 or
   12.33 + * to extend the choice of license to its licensees as provided above.
   12.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   12.35 + * Version 2 license, then the option applies only if the new code is
   12.36 + * made subject to such option by the copyright holder.
   12.37 + *
   12.38 + * Contributor(s):
   12.39 + *
   12.40 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   12.41 + */
   12.42 +
   12.43 +package org.netbeans.modules.jackpot30.backend.type.api;
   12.44 +
   12.45 +import java.io.IOException;
   12.46 +import java.util.ArrayList;
   12.47 +import java.util.LinkedHashMap;
   12.48 +import java.util.List;
   12.49 +import java.util.Map;
   12.50 +import java.util.Map.Entry;
   12.51 +import java.util.concurrent.atomic.AtomicBoolean;
   12.52 +import org.apache.lucene.document.Document;
   12.53 +import org.apache.lucene.search.Query;
   12.54 +import org.codeviation.pojson.Pojson;
   12.55 +import org.netbeans.modules.jackpot30.backend.base.CategoryStorage;
   12.56 +import org.netbeans.modules.jumpto.type.GoToTypeAction;
   12.57 +import org.netbeans.modules.parsing.lucene.support.Convertor;
   12.58 +import org.netbeans.modules.parsing.lucene.support.Index;
   12.59 +import org.netbeans.modules.parsing.lucene.support.Queries;
   12.60 +import org.netbeans.modules.parsing.lucene.support.Queries.QueryKind;
   12.61 +
   12.62 +/**
   12.63 + *
   12.64 + * @author lahvac
   12.65 + */
   12.66 +public class Base {
   12.67 +
   12.68 +    protected <T> String doFind(String segment, String prefix, boolean casesensitive, String queryKindName, String fieldPrefix, Convertor<Document, Entry<String, T>> conv) throws IOException, InterruptedException {
   12.69 +        //copied (and converted to NameKind) from jumpto's GoToTypeAction:
   12.70 +        boolean exact = prefix.endsWith(" "); // NOI18N
   12.71 +
   12.72 +        prefix = prefix.trim();
   12.73 +
   12.74 +        if ( prefix.length() == 0) {
   12.75 +            return "";
   12.76 +        }
   12.77 +
   12.78 +        QueryKind queryKind = null;
   12.79 +
   12.80 +        if (queryKindName != null) {
   12.81 +            for (QueryKind k : QueryKind.values()) {
   12.82 +                if (queryKindName.equals(k.name())) {
   12.83 +                    queryKind = k;
   12.84 +                }
   12.85 +            }
   12.86 +
   12.87 +            //TODO: what to do? currently autoguess, but might also return an error
   12.88 +        }
   12.89 +
   12.90 +        if (queryKind == null) {
   12.91 +            int wildcard = GoToTypeAction.containsWildCard(prefix);
   12.92 +
   12.93 +            if (exact) {
   12.94 +                //nameKind = panel.isCaseSensitive() ? SearchType.EXACT_NAME : SearchType.CASE_INSENSITIVE_EXACT_NAME;
   12.95 +                queryKind = QueryKind.EXACT;
   12.96 +            }
   12.97 +            else if ((GoToTypeAction.isAllUpper(prefix) && prefix.length() > 1) || GoToTypeAction.isCamelCase(prefix)) {
   12.98 +                queryKind = QueryKind.CAMEL_CASE;
   12.99 +            }
  12.100 +            else if (wildcard != -1) {
  12.101 +                queryKind = casesensitive ? QueryKind.REGEXP : QueryKind.CASE_INSENSITIVE_REGEXP;
  12.102 +            }
  12.103 +            else {
  12.104 +                queryKind = casesensitive ? QueryKind.PREFIX : QueryKind.CASE_INSENSITIVE_PREFIX;
  12.105 +            }
  12.106 +        }
  12.107 +
  12.108 +        Map<String, List<T>> result = new LinkedHashMap<String, List<T>>();
  12.109 +        CategoryStorage category = CategoryStorage.forId(segment);
  12.110 +        Index index = category.getIndex();
  12.111 +
  12.112 +        List<Query> queries = new ArrayList<Query>(2);
  12.113 +
  12.114 +        queries.add(Queries.createQuery(fieldPrefix + "SimpleName", fieldPrefix + "SimpleNameLower", prefix, queryKind));
  12.115 +
  12.116 +        if (queryKind == QueryKind.CAMEL_CASE) {
  12.117 +            queries.add(Queries.createQuery(fieldPrefix + "SimpleName", fieldPrefix + "SimpleNameLower", prefix, QueryKind.CASE_INSENSITIVE_PREFIX));
  12.118 +        }
  12.119 +
  12.120 +        List<Entry<String, T>> found = new ArrayList<Entry<String, T>>();
  12.121 +
  12.122 +        //TODO: field selector:
  12.123 +        index.query(found, conv, null, new AtomicBoolean(), queries.toArray(new Query[queries.size()]));
  12.124 +
  12.125 +        for (Entry<String, T> e : found) {
  12.126 +            for (String rel : category.getSourceRoots()) {
  12.127 +                if (e.getKey().startsWith(rel)) {
  12.128 +                    List<T> current = result.get(rel);
  12.129 +
  12.130 +                    if (current == null) {
  12.131 +                        result.put(rel, current = new ArrayList<T>());
  12.132 +                    }
  12.133 +
  12.134 +                    current.add(e.getValue());
  12.135 +                }
  12.136 +            }
  12.137 +        }
  12.138 +
  12.139 +        return Pojson.save(result);
  12.140 +    }
  12.141 +
  12.142 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/remoting/server/web/type.web.api/src/org/netbeans/modules/jackpot30/backend/type/api/Symbol.java	Mon Jul 04 12:48:44 2011 +0200
    13.3 @@ -0,0 +1,89 @@
    13.4 +/*
    13.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    13.6 + *
    13.7 + * Copyright 2009-2011 Sun Microsystems, Inc. All rights reserved.
    13.8 + *
    13.9 + * The contents of this file are subject to the terms of either the GNU
   13.10 + * General Public License Version 2 only ("GPL") or the Common
   13.11 + * Development and Distribution License("CDDL") (collectively, the
   13.12 + * "License"). You may not use this file except in compliance with the
   13.13 + * License. You can obtain a copy of the License at
   13.14 + * http://www.netbeans.org/cddl-gplv2.html
   13.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   13.16 + * specific language governing permissions and limitations under the
   13.17 + * License.  When distributing the software, include this License Header
   13.18 + * Notice in each file and include the License file at
   13.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   13.20 + * particular file as subject to the "Classpath" exception as provided
   13.21 + * by Sun in the GPL Version 2 section of the License file that
   13.22 + * accompanied this code. If applicable, add the following below the
   13.23 + * License Header, with the fields enclosed by brackets [] replaced by
   13.24 + * your own identifying information:
   13.25 + * "Portions Copyrighted [year] [name of copyright owner]"
   13.26 + *
   13.27 + * If you wish your version of this file to be governed by only the CDDL
   13.28 + * or only the GPL Version 2, indicate your decision by adding
   13.29 + * "[Contributor] elects to include this software in this distribution
   13.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   13.31 + * single choice of license, a recipient has the option to distribute
   13.32 + * your version of this file under either the CDDL, the GPL Version 2 or
   13.33 + * to extend the choice of license to its licensees as provided above.
   13.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   13.35 + * Version 2 license, then the option applies only if the new code is
   13.36 + * made subject to such option by the copyright holder.
   13.37 + *
   13.38 + * Contributor(s):
   13.39 + *
   13.40 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   13.41 + */
   13.42 +
   13.43 +package org.netbeans.modules.jackpot30.backend.type.api;
   13.44 +
   13.45 +import java.io.IOException;
   13.46 +import java.util.AbstractMap.SimpleEntry;
   13.47 +import java.util.HashMap;
   13.48 +import java.util.Map;
   13.49 +import java.util.Map.Entry;
   13.50 +import javax.ws.rs.DefaultValue;
   13.51 +import javax.ws.rs.GET;
   13.52 +import javax.ws.rs.Path;
   13.53 +import javax.ws.rs.Produces;
   13.54 +import javax.ws.rs.QueryParam;
   13.55 +import org.apache.lucene.document.Document;
   13.56 +import org.netbeans.modules.parsing.lucene.support.Convertor;
   13.57 +
   13.58 +/**
   13.59 + *
   13.60 + * @author lahvac
   13.61 + */
   13.62 +@Path("/index/symbol")
   13.63 +public class Symbol extends Base {
   13.64 +
   13.65 +    @GET
   13.66 +    @Path("/search")
   13.67 +    @Produces("text/plain")
   13.68 +    public String findSymbol(@QueryParam("path") String segment, @QueryParam("prefix") String prefix, @QueryParam("casesensitive") @DefaultValue("false") boolean casesensitive, @QueryParam("querykind") String queryKindName) throws IOException, InterruptedException {
   13.69 +        return doFind(segment, prefix, casesensitive, queryKindName, "feature", new SymbolConvertorImpl());
   13.70 +    }
   13.71 +
   13.72 +    private static class SymbolConvertorImpl implements Convertor<Document, Entry<String, Map<String, Object>>> {
   13.73 +        @Override public Entry<String, Map<String, Object>> convert(Document p) {
   13.74 +            Map<String, Object> result = new HashMap<String, Object>();
   13.75 +
   13.76 +            result.put("file", p.get("file"));
   13.77 +            result.put("enclosingFQN", p.get("featureClassFQN"));
   13.78 +            result.put("simpleName", p.get("featureSimpleName"));
   13.79 +            String featureSignature = p.get("featureSignature");
   13.80 +            if (featureSignature != null)
   13.81 +                result.put("signature", featureSignature);
   13.82 +            String featureVMSignature = p.get("featureVMSignature");
   13.83 +            if (featureVMSignature != null)
   13.84 +                result.put("vmsignature", featureVMSignature);
   13.85 +            result.put("kind", p.get("featureKind"));
   13.86 +            result.put("modifiers", p.getValues("featureModifiers")); //XXX
   13.87 +            
   13.88 +            return new SimpleEntry<String, Map<String, Object>>(p.get("file"), result);
   13.89 +        }
   13.90 +    }
   13.91 +
   13.92 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/remoting/server/web/type.web.api/src/org/netbeans/modules/jackpot30/backend/type/api/Type.java	Mon Jul 04 12:48:44 2011 +0200
    14.3 @@ -0,0 +1,73 @@
    14.4 +/*
    14.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    14.6 + *
    14.7 + * Copyright 2009-2011 Sun Microsystems, Inc. All rights reserved.
    14.8 + *
    14.9 + * The contents of this file are subject to the terms of either the GNU
   14.10 + * General Public License Version 2 only ("GPL") or the Common
   14.11 + * Development and Distribution License("CDDL") (collectively, the
   14.12 + * "License"). You may not use this file except in compliance with the
   14.13 + * License. You can obtain a copy of the License at
   14.14 + * http://www.netbeans.org/cddl-gplv2.html
   14.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   14.16 + * specific language governing permissions and limitations under the
   14.17 + * License.  When distributing the software, include this License Header
   14.18 + * Notice in each file and include the License file at
   14.19 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
   14.20 + * particular file as subject to the "Classpath" exception as provided
   14.21 + * by Sun in the GPL Version 2 section of the License file that
   14.22 + * accompanied this code. If applicable, add the following below the
   14.23 + * License Header, with the fields enclosed by brackets [] replaced by
   14.24 + * your own identifying information:
   14.25 + * "Portions Copyrighted [year] [name of copyright owner]"
   14.26 + *
   14.27 + * If you wish your version of this file to be governed by only the CDDL
   14.28 + * or only the GPL Version 2, indicate your decision by adding
   14.29 + * "[Contributor] elects to include this software in this distribution
   14.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   14.31 + * single choice of license, a recipient has the option to distribute
   14.32 + * your version of this file under either the CDDL, the GPL Version 2 or
   14.33 + * to extend the choice of license to its licensees as provided above.
   14.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   14.35 + * Version 2 license, then the option applies only if the new code is
   14.36 + * made subject to such option by the copyright holder.
   14.37 + *
   14.38 + * Contributor(s):
   14.39 + *
   14.40 + * Portions Copyrighted 2009-2011 Sun Microsystems, Inc.
   14.41 + */
   14.42 +
   14.43 +package org.netbeans.modules.jackpot30.backend.type.api;
   14.44 +
   14.45 +import java.io.IOException;
   14.46 +import java.util.AbstractMap.SimpleEntry;
   14.47 +import java.util.Map.Entry;
   14.48 +import javax.ws.rs.DefaultValue;
   14.49 +import javax.ws.rs.GET;
   14.50 +import javax.ws.rs.Path;
   14.51 +import javax.ws.rs.Produces;
   14.52 +import javax.ws.rs.QueryParam;
   14.53 +import org.apache.lucene.document.Document;
   14.54 +import org.netbeans.modules.parsing.lucene.support.Convertor;
   14.55 +
   14.56 +/**
   14.57 + *
   14.58 + * @author lahvac
   14.59 + */
   14.60 +@Path("/index/type")
   14.61 +public class Type extends Base {
   14.62 +
   14.63 +    @GET
   14.64 +    @Path("/search")
   14.65 +    @Produces("text/plain")
   14.66 +    public String findType(@QueryParam("path") String segment, @QueryParam("prefix") String prefix, @QueryParam("casesensitive") @DefaultValue("false") boolean casesensitive, @QueryParam("querykind") String queryKindName) throws IOException, InterruptedException {
   14.67 +        return doFind(segment, prefix, casesensitive, queryKindName, "class", new TypeConvertorImpl());
   14.68 +    }
   14.69 +
   14.70 +    private static class TypeConvertorImpl implements Convertor<Document, Entry<String, String>> {
   14.71 +        @Override public Entry<String, String> convert(Document p) {
   14.72 +            return new SimpleEntry<String, String>(p.get("file"), p.get("classFQN"));
   14.73 +        }
   14.74 +    }
   14.75 +
   14.76 +}