blob: 99e40a1e3bdffb492fd94c4ab107f455f3d81bc3 [file] [log] [blame]
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2013 Oracle and/or its affiliates. All rights reserved.
*
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
* Other names may be trademarks of their respective owners.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*
* Contributor(s):
*
* Portions Copyrighted 2013 Sun Microsystems, Inc.
*/
package org.netbeans.modules.jackpot30.remoting.api;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.lang.model.element.ElementKind;
import javax.swing.text.Document;
import org.netbeans.api.java.source.ElementHandle;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.openide.filesystems.FileObject;
/**
*
* @author lahvac
*/
public class Utilities {
private static final Logger LOG = Logger.getLogger(Utilities.class.getName());
private Utilities() {}
public static final class RemoteSourceDescription {
public final RemoteIndex idx;
public final String relative;
public RemoteSourceDescription(RemoteIndex idx, String relative) {
this.idx = idx;
this.relative = relative;
}
}
public static RemoteSourceDescription remoteSource(Document doc) {
FileObject file = NbEditorUtilities.getFileObject(doc);
if (file == null) return null;
return remoteSource(file);
}
public static RemoteSourceDescription remoteSource(FileObject file) {
Object remoteIndexObj = file.getAttribute("remoteIndex");
RemoteIndex idx = remoteIndexObj instanceof RemoteIndex ? (RemoteIndex) remoteIndexObj : null;
Object relativeObj = file.getAttribute("relative");
String relative = relativeObj instanceof String ? (String) relativeObj : null;
if (idx != null && relative != null) {
return new RemoteSourceDescription(idx, relative);
} else {
return null;
}
}
public static String decodeMethodParameterTypes(String signature) {
StringBuilder name = new StringBuilder();
methodParameterTypes(signature, new int[] {0}, name);
return name.toString();
}
private static char getChar (final String buffer, final int pos) {
if (pos>=buffer.length()) {
throw new IllegalStateException ();
}
return buffer.charAt(pos);
}
private static String typeArgument (final String jvmTypeId, final int[] pos) {
char c = getChar (jvmTypeId, pos[0]);
switch (c) {
case '*':
pos[0]++;
return ""; //XXX?
case '+':
pos[0]++;
return "? extends " + typeSignatureType(jvmTypeId, pos);
case '-':
pos[0]++;
return "? super " + typeSignatureType(jvmTypeId, pos);
default:
return typeSignatureType (jvmTypeId, pos);
}
}
private static void typeArgumentsList (final String jvmTypeId, final int[] pos, StringBuilder result) {
char c = getChar (jvmTypeId, pos[0]++);
if (c != '<') {
throw new IllegalStateException (jvmTypeId);
}
c = getChar (jvmTypeId, pos[0]);
boolean first = true;
while (c !='>') {
if (!first) result.append(", ");
first = false;
result.append(typeArgument (jvmTypeId, pos));
c = getChar (jvmTypeId, pos[0]);
}
pos[0]++;
}
static boolean generateSimpleNames = true;
private static String typeSignatureType (final String jvmTypeId, final int[] pos) {
char c = getChar(jvmTypeId, pos[0]++);
switch (c) {
case 'B': return "byte";
case 'C': return "char";
case 'D': return "double";
case 'F': return "float";
case 'I': return "int";
case 'J': return "long";
case 'S': return "short";
case 'V': return "void";
case 'Z': return "boolean";
case 'L': {
StringBuilder builder = new StringBuilder ();
c = getChar(jvmTypeId, pos[0]++);
while (c != ';') {
if (c == '/' || c == '$') {
if (generateSimpleNames) builder.delete(0, builder.length());
else builder.append('.');
} else {
builder.append(c);
}
if (c=='<') {
pos[0]--;
typeArgumentsList (jvmTypeId, pos, builder);
builder.append(">");
}
c = getChar(jvmTypeId, pos[0]++);
}
return builder.toString();
}
case 'T': {
StringBuilder builder = new StringBuilder ();
c = getChar(jvmTypeId, pos[0]++);
while (c != ';') {
builder.append(c);
c = getChar(jvmTypeId, pos[0]++);
}
return builder.toString();
}
case '[':
return typeSignatureType (jvmTypeId, pos) + "[]";
default:
return "<unknown-type>";
}
}
private static void methodParameterTypes(final String jvmTypeId, final int[] pos, StringBuilder result) {
char c = getChar (jvmTypeId, pos[0]);
if (c == '<') {
do {
c = getChar (jvmTypeId, pos[0]++);
} while (c != '>');
c = getChar (jvmTypeId, pos[0]);
}
if (c!='(') {
throw new IllegalStateException (jvmTypeId);
}
pos[0]++;
c = getChar (jvmTypeId, pos[0]);
result.append("(");
boolean first = true;
while (c != ')') {
if (!first) result.append(", ");
first = false;
result.append(typeSignatureType (jvmTypeId, pos));
c = getChar (jvmTypeId, pos[0]);
}
result.append(")");
}
public static ElementHandle<?> createElementHandle(ElementKind kind, String clazz, String simpleName, String signature) {
LOG.setLevel(Level.ALL);
try {
Class<?> elementHandleAccessor = Class.forName("org.netbeans.modules.java.source.ElementHandleAccessor", false, ElementHandle.class.getClassLoader());
Field instance = elementHandleAccessor.getDeclaredField("INSTANCE");
instance.setAccessible(true);
Method m = elementHandleAccessor.getDeclaredMethod("create", ElementKind.class, String[].class);
String[] signatures;
switch (kind) {
case PACKAGE:
case CLASS:
case INTERFACE:
case ENUM:
case ANNOTATION_TYPE:
case OTHER:
signatures = new String[] {clazz};
break;
case METHOD:
case CONSTRUCTOR:
case FIELD:
case ENUM_CONSTANT:
signatures = new String[] {clazz, simpleName, signature};
break;
case INSTANCE_INIT:
case STATIC_INIT:
signatures = new String[] {clazz, simpleName};
break;
default:
kind = ElementKind.OTHER;
signatures = new String[] {clazz};
break;
}
return (ElementHandle<?>) m.invoke(instance.get(null), kind, signatures);
} catch (IllegalAccessException ex) {
LOG.log(Level.INFO, null, ex);
} catch (IllegalArgumentException ex) {
LOG.log(Level.INFO, null, ex);
} catch (InvocationTargetException ex) {
LOG.log(Level.INFO, null, ex);
} catch (NoSuchMethodException ex) {
LOG.log(Level.INFO, null, ex);
} catch (NoSuchFieldException ex) {
LOG.log(Level.INFO, null, ex);
} catch (SecurityException ex) {
LOG.log(Level.INFO, null, ex);
} catch (ClassNotFoundException ex) {
LOG.log(Level.INFO, null, ex);
}
return ElementHandle.createTypeElementHandle(ElementKind.CLASS, clazz);
}
}