/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.ide.ext.java.worker; import org.eclipse.che.ide.collections.Array; import org.eclipse.che.ide.collections.Jso; import org.eclipse.che.ide.collections.js.JsoArray; import org.eclipse.che.ide.ext.java.jdt.internal.codeassist.ISearchRequestor; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.env.INameEnvironment; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.env.NameEnvironmentAnswer; import org.eclipse.che.ide.ext.java.worker.env.BinaryType; import org.eclipse.che.ide.ext.java.worker.env.Util; import org.eclipse.che.ide.ext.java.worker.env.json.BinaryTypeJso; import com.google.gwt.core.client.JavaScriptObject; import java.util.Comparator; import java.util.HashSet; import java.util.Set; /** * Implementation of {@link org.eclipse.che.ide.ext.java.jdt.internal.compiler.env.INameEnvironment} interface, use RestNameEnvironment * for receiving data and * cache Java type data in browser * * @author <a href="mailto:evidolob@exoplatform.com">Evgen Vidolob</a> * @version ${Id}: Jan 13, 2012 3:10:43 PM evgen $ */ public class WorkerNameEnvironment implements INameEnvironment { private static Set<String> packages = new HashSet<>(); protected String restServiceContext; private String projectPath; private Set<String> blackListTypes = new HashSet<>(); private Set<String> blackListPackages = new HashSet<>(); /** * */ public WorkerNameEnvironment(String context, String restContext, String wsName) { restServiceContext = context + "/java-name-environment" + wsName; } public void setProjectPath(String projectPath) { this.projectPath = projectPath; } /** {@inheritDoc} */ @Override public NameEnvironmentAnswer findType(char[][] compoundTypeName) { StringBuilder b = new StringBuilder(); for (char[] c : compoundTypeName) { b.append(c).append('.'); } b.deleteCharAt(b.length() - 1); final String key = validateFqn(b); if(blackListTypes.contains(key)){ return null; } if (WorkerTypeInfoStorage.get().containsKey(key)) { return new NameEnvironmentAnswer(WorkerTypeInfoStorage.get().getType(key), null); } if (projectPath != null) { if (packages.contains(key)) { return null; } StringBuilder builder = new StringBuilder(); for (char[] chars : compoundTypeName) { builder.append(chars).append(','); } if (builder.length() > 1) builder.deleteCharAt(builder.length() - 1); String url = restServiceContext + "/findTypeCompound?compoundTypeName=" + builder.toString() + "&projectpath=" + projectPath; String result = runSyncRequest(url); if (result != null) { Jso jso = Jso.deserialize(result); BinaryType type = new BinaryType(jso.<BinaryTypeJso>cast()); WorkerTypeInfoStorage.get().putType(key, type); return new NameEnvironmentAnswer(type, null); } else { blackListTypes.add(key); return null; } } return null; } private String validateFqn(StringBuilder builder) { if (builder.indexOf("<") != -1) { builder.setLength(builder.indexOf("<")); } return builder.toString(); } /** {@inheritDoc} */ @Override public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) { if ("package-info".equals(new String(typeName))) { return null; } StringBuilder b = new StringBuilder(); for (char[] c : packageName) { b.append(c).append('.'); } b.append(typeName); final String key = validateFqn(b); if(blackListTypes.contains(key)){ return null; } if (WorkerTypeInfoStorage.get().containsKey(key)) { return new NameEnvironmentAnswer(WorkerTypeInfoStorage.get().getType(key), null); } if (projectPath != null) { if (packages.contains(key)) { return null; } StringBuilder builder = new StringBuilder(); for (char[] chars : packageName) { builder.append(chars).append(','); } if (builder.length() > 1) builder.deleteCharAt(builder.length() - 1); String url = restServiceContext + "/findType?packagename=" + builder.toString() + "&typename=" + new String(typeName) + "&projectpath=" + projectPath; String result = runSyncRequest(url); if (result != null) { Jso jso = Jso.deserialize(result); BinaryType type = new BinaryType(jso.<BinaryTypeJso>cast()); WorkerTypeInfoStorage.get().putType(key, type); return new NameEnvironmentAnswer(type, null); } else { blackListTypes.add(key); return null; } } return null; } /** {@inheritDoc} */ @Override public boolean isPackage(char[][] parentPackageName, char[] packageName) { StringBuilder p = new StringBuilder(); try { if (parentPackageName != null) { for (char[] seg : parentPackageName) { p.append(seg).append('.'); } } p.append(packageName); if (packages.contains(p.toString())) { return true; } if (blackListPackages.contains(p.toString())) { return false; } StringBuilder builder = new StringBuilder(); if (parentPackageName != null) { for (char[] chars : parentPackageName) { builder.append(chars).append(','); } if (builder.length() > 1) builder.deleteCharAt(builder.length() - 1); } String url = restServiceContext + "/package" + "?packagename=" + new String(packageName) + "&parent=" + builder.toString() + "&projectpath=" + projectPath; String findPackage = runSyncRequest(url); boolean exist = findPackage != null && Boolean.parseBoolean(findPackage); if (exist) { packages.add(p.toString()); } else { blackListPackages.add(p.toString()); } return exist; } catch (Exception e) { e.printStackTrace(); //TODO log errors return false; } } /** {@inheritDoc} */ @Override public void cleanup() { } /** * Must be used only by CompletionEngine. The progress monitor is used to be able to cancel completion operations * <p/> * Find constructor declarations that are defined in the current environment and whose name starts with the given prefix. The * prefix is a qualified name separated by periods or a simple name (ex. java.util.V or V). * <p/> * The constructors found are passed to one of the following methods: ISearchRequestor.acceptConstructor(...) */ @Override public void findConstructorDeclarations(char[] prefix, boolean camelCaseMatch, final ISearchRequestor requestor) { String url = restServiceContext + "/findConstructor" + "?prefix=" + new String(prefix) + "&camelcase=" + camelCaseMatch + "&projectpath=" + projectPath; String cons = runSyncRequest(url); if (cons != null) { JsoArray<Jso> constructors = Jso.deserialize(cons).cast(); for (Jso jso : constructors.asIterable()) { char[][] parameterTypes = Util.arrayStringToCharArray((Array<String>)jso.getJsObjectField("parameterTypes")); char[][] parameterNames = Util.arrayStringToCharArray((Array<String>)jso.getJsObjectField("parameterNames")); String signature = jso.getStringField("signature"); char[] sig = null; if(signature != null) { sig = signature.toCharArray(); } requestor.acceptConstructor(jso.getIntField("modifiers"), jso.getStringField("simpleTypeName").toCharArray(), jso.getIntField("parameterCount"), sig, parameterTypes, parameterNames, jso.getIntField("typeModifiers"), jso.getStringField("packageName").toCharArray(), jso.getIntField("extraFlags"), "from server", null); } } } /** * Find the packages that start with the given prefix. A valid prefix is a qualified name separated by periods (ex. java.util). * The packages found are passed to: ISearchRequestor.acceptPackage(char[][] packageName) */ @Override public void findPackages(char[] qualifiedName, final ISearchRequestor requestor) { String url = restServiceContext + "/findPackages" + "?packagename=" + new String(qualifiedName) + "&projectpath=" + projectPath; String pak = runSyncRequest(url); if (pak != null) { JsoArray<String> packages = Jso.deserialize(pak).cast(); packages.sort(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }); for (String s : packages.asIterable()) { requestor.acceptPackage(s.toCharArray()); WorkerNameEnvironment.packages.add(s); } } } private String runSyncRequest(String url) { XmlHttpWrapper xmlhttp = nativeRunSyncReques(url); int status = xmlhttp.getStatusCode(); if (status == 200) { return xmlhttp.getResponseText(); } else { // server not find info return null; } } private native XmlHttpWrapper nativeRunSyncReques(String url)/*-{ var xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET", url, false); xmlhttp.send(); return xmlhttp; }-*/; /** * Must be used only by CompletionEngine. The progress monitor is used to be able to cancel completion operations * <p/> * Find the top-level types that are defined in the current environment and whose name starts with the given prefix. The prefix * is a qualified name separated by periods or a simple name (ex. java.util.V or V). * <p/> * The types found are passed to one of the following methods (if additional information is known about the types): * ISearchRequestor.acceptType(char[][] packageName, char[] typeName) ISearchRequestor.acceptClass(char[][] packageName, char[] * typeName, int modifiers) ISearchRequestor.acceptInterface(char[][] packageName, char[] typeName, int modifiers) * <p/> * This method can not be used to find member types... member types are found relative to their enclosing type. */ @Override public void findTypes(char[] qualifiedName, boolean findMembers, boolean camelCaseMatch, int searchFor, final ISearchRequestor requestor) { if (qualifiedName.length == 0) { return; } String url = restServiceContext + "/findTypes" + "?qualifiedname=" + new String(qualifiedName) + "&camelcase=" + camelCaseMatch + "&findmembers=" + findMembers + "&searchfor=" + searchFor + "&projectpath=" + projectPath; String res = runSyncRequest(url); if (res != null) { JsoArray<Jso> types = Jso.deserialize(res).cast(); for (Jso jso : types.asIterable()) { char[][] enclosingTypeNames = Util.arrayStringToCharArray((Array<String>)jso.getJsObjectField("enclosingTypeNames")); requestor.acceptType(jso.getStringField("packageName").toCharArray(), jso.getStringField("typeName").toCharArray(), enclosingTypeNames, jso.getIntField("modifiers"), null); } } } /** * Find the top-level types that are defined * in the current environment and whose simple name matches the given name. * <p/> * The types found are passed to one of the following methods (if additional * information is known about the types): * ISearchRequestor.acceptType(char[][] packageName, char[] typeName) * ISearchRequestor.acceptClass(char[][] packageName, char[] typeName, int modifiers) * ISearchRequestor.acceptInterface(char[][] packageName, char[] typeName, int modifiers) * <p/> * This method can not be used to find member types... member * types are found relative to their enclosing type. */ @Override public void findExactTypes(char[] missingSimpleName, boolean findMembers, int searchFor, final ISearchRequestor storage) { if (missingSimpleName.length == 0) { return; } String url = restServiceContext + "/findExactTypes" + "?missingsimplename=" + new String(missingSimpleName) + "&findmembers=" + findMembers + "&searchfor=" + searchFor + "&projectpath=" + projectPath; String res = runSyncRequest(url); if (res != null) { JsoArray<Jso> types = Jso.deserialize(res).cast(); for (Jso jso : types.asIterable()) { char[][] enclosingTypeNames = Util.arrayStringToCharArray((Array<String>)jso.getJsObjectField("enclosingTypeNames")); storage.acceptType(jso.getStringField("packageName").toCharArray(), jso.getStringField("typeName").toCharArray(), enclosingTypeNames, jso.getIntField("modifiers"), null); } } } public void clearBlackList() { blackListPackages.clear(); blackListTypes.clear(); } private static final class XmlHttpWrapper extends JavaScriptObject { /** * */ protected XmlHttpWrapper() { } public native int getStatusCode()/*-{ return this.status; }-*/; public native String getResponseText()/*-{ return this.responseText; }-*/; } }