package org.eclipse.jdt.internal.core;
import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaModelStatus;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
import org.eclipse.jdt.internal.core.util.Util;
@SuppressWarnings({"rawtypes", "unchecked"})
public abstract class JavaElement extends PlatformObject implements IJavaElement {
private static final byte[] CLOSING_DOUBLE_QUOTE = new byte[] { 34 };
private static final byte[] CHARSET = new byte[] { 99, 104, 97, 114, 115, 101, 116, 61 };
private static final byte[] CHARSET_HTML5 = new byte[] { 99, 104, 97, 114, 115, 101, 116, 61, 34 };
private static final byte[] META_START = new byte[] { 60, 109, 101, 116, 97 };
private static final byte[] META_END = new byte[] { 34, 62 };
public static final char JEM_ESCAPE = '\\';
public static final char JEM_JAVAPROJECT = '=';
public static final char JEM_PACKAGEFRAGMENTROOT = '/';
public static final char JEM_PACKAGEFRAGMENT = '<';
public static final char JEM_FIELD = '^';
public static final char JEM_METHOD = '~';
public static final char JEM_INITIALIZER = '|';
public static final char JEM_COMPILATIONUNIT = '{';
public static final char JEM_CLASSFILE = '(';
public static final char JEM_MODULAR_CLASSFILE = '\'';
public static final char JEM_TYPE = '[';
public static final char JEM_PACKAGEDECLARATION = '%';
public static final char JEM_IMPORTDECLARATION = '#';
public static final char JEM_COUNT = '!';
public static final char JEM_LOCALVARIABLE = '@';
public static final char JEM_TYPE_PARAMETER = ']';
public static final char JEM_ANNOTATION = '}';
public static final char JEM_LAMBDA_EXPRESSION = ')';
public static final char JEM_LAMBDA_METHOD = '&';
public static final char JEM_STRING = '"';
public static final char JEM_MODULE = '`';
public static final char JEM_DELIMITER_ESCAPE = JEM_JAVAPROJECT;
protected JavaElement parent;
protected static final String[] NO_STRINGS = new String[0];
protected static final JavaElement[] NO_ELEMENTS = new JavaElement[0];
protected static final Object NO_INFO = new Object();
private static Set<String> invalidURLs = null;
private static Set<String> validURLs = null;
protected JavaElement(JavaElement parent) throws IllegalArgumentException {
this.parent = parent;
}
public void close() throws JavaModelException {
JavaModelManager.getJavaModelManager().removeInfoAndChildren(this);
}
protected abstract void closing(Object info) throws JavaModelException;
protected abstract Object createElementInfo();
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (this.parent == null) return super.equals(o);
JavaElement other = (JavaElement) o;
return getElementName().equals(other.getElementName()) &&
this.parent.equals(other.parent);
}
protected void appendEscapedDelimiter(StringBuffer buffer, char delimiter) {
buffer.append(JEM_DELIMITER_ESCAPE);
buffer.append(delimiter);
}
protected void escapeMementoName(StringBuffer buffer, String mementoName) {
for (int i = 0, length = mementoName.length(); i < length; i++) {
char character = mementoName.charAt(i);
switch (character) {
case JEM_ESCAPE:
case JEM_COUNT:
case JEM_JAVAPROJECT:
case JEM_PACKAGEFRAGMENTROOT:
case JEM_PACKAGEFRAGMENT:
case JEM_FIELD:
case JEM_METHOD:
case JEM_INITIALIZER:
case JEM_COMPILATIONUNIT:
case JEM_CLASSFILE:
case JEM_MODULAR_CLASSFILE:
case JEM_TYPE:
case JEM_PACKAGEDECLARATION:
case JEM_IMPORTDECLARATION:
case JEM_LOCALVARIABLE:
case JEM_TYPE_PARAMETER:
case JEM_ANNOTATION:
buffer.append(JEM_ESCAPE);
}
buffer.append(character);
}
}
@Override
public boolean exists() {
try {
getElementInfo();
return true;
} catch (JavaModelException e) {
}
return false;
}
public ASTNode findNode(CompilationUnit ast) {
return null;
}
protected abstract void generateInfos(Object info, HashMap newElements, IProgressMonitor pm) throws JavaModelException;
@Override
public IJavaElement getAncestor(int ancestorType) {
IJavaElement element = this;
while (element != null) {
if (element.getElementType() == ancestorType) return element;
element= element.getParent();
}
return null;
}
public IJavaElement[] getChildren() throws JavaModelException {
Object elementInfo = getElementInfo();
if (elementInfo instanceof JavaElementInfo) {
return ((JavaElementInfo)elementInfo).getChildren();
} else {
return NO_ELEMENTS;
}
}
public ArrayList getChildrenOfType(int type) throws JavaModelException {
IJavaElement[] children = getChildren();
int size = children.length;
ArrayList list = new ArrayList(size);
for (int i = 0; i < size; ++i) {
JavaElement elt = (JavaElement)children[i];
if (elt.getElementType() == type) {
list.add(elt);
}
}
return list;
}
public IClassFile getClassFile() {
return null;
}
public ICompilationUnit getCompilationUnit() {
return null;
}
public Object getElementInfo() throws JavaModelException {
return getElementInfo(null);
}
public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
JavaModelManager manager = JavaModelManager.getJavaModelManager();
Object info = manager.getInfo(this);
if (info != null) return info;
return openWhenClosed(createElementInfo(), false, monitor);
}
@Override
public String getElementName() {
return "";
}
public abstract IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner);
public IJavaElement getHandleFromMemento(MementoTokenizer memento, WorkingCopyOwner owner) {
if (!memento.hasMoreTokens()) return this;
String token = memento.nextToken();
return getHandleFromMemento(token, memento, owner);
}
@Override
public String getHandleIdentifier() {
return getHandleMemento();
}
public String getHandleMemento(){
StringBuffer buff = new StringBuffer();
getHandleMemento(buff);
return buff.toString();
}
protected void getHandleMemento(StringBuffer buff) {
((JavaElement)getParent()).getHandleMemento(buff);
buff.append(getHandleMementoDelimiter());
escapeMementoName(buff, getElementName());
}
protected abstract char getHandleMementoDelimiter();
@Override
public IJavaModel getJavaModel() {
IJavaElement current = this;
do {
if (current instanceof IJavaModel) return (IJavaModel) current;
} while ((current = current.getParent()) != null);
return null;
}
@Override
public IJavaProject getJavaProject() {
IJavaElement current = this;
do {
if (current instanceof IJavaProject) return (IJavaProject) current;
} while ((current = current.getParent()) != null);
return null;
}
@Override
public IOpenable getOpenable() {
return getOpenableParent();
}
public IOpenable getOpenableParent() {
return (IOpenable)this.parent;
}
@Override
public IJavaElement getParent() {
return this.parent;
}
@Override
public IJavaElement getPrimaryElement() {
return getPrimaryElement(true);
}
public IJavaElement getPrimaryElement(boolean checkOwner) {
return this;
}
@Override
public IResource getResource() {
return resource();
}
public abstract IResource resource();
protected IJavaElement getSourceElementAt(int position) throws JavaModelException {
if (this instanceof ISourceReference) {
IJavaElement[] children = getChildren();
for (int i = children.length-1; i >= 0; i--) {
IJavaElement aChild = children[i];
if (aChild instanceof SourceRefElement) {
SourceRefElement child = (SourceRefElement) children[i];
ISourceRange range = child.getSourceRange();
int start = range.getOffset();
int end = start + range.getLength();
if (start <= position && position <= end) {
if (child instanceof IField) {
int declarationStart = start;
SourceRefElement candidate = null;
do {
range = ((IField)child).getNameRange();
if (position <= range.getOffset() + range.getLength()) {
candidate = child;
} else {
return candidate == null ? child.getSourceElementAt(position) : candidate.getSourceElementAt(position);
}
child = --i>=0 ? (SourceRefElement) children[i] : null;
} while (child != null && child.getSourceRange().getOffset() == declarationStart);
return candidate.getSourceElementAt(position);
} else if (child instanceof IParent) {
return child.getSourceElementAt(position);
} else {
return child;
}
}
}
}
} else {
Assert.isTrue(false);
}
return this;
}
public SourceMapper getSourceMapper() {
return ((JavaElement)getParent()).getSourceMapper();
}
@Override
public ISchedulingRule getSchedulingRule() {
IResource resource = resource();
if (resource == null) {
class NoResourceSchedulingRule implements ISchedulingRule {
public IPath path;
public NoResourceSchedulingRule(IPath path) {
this.path = path;
}
@Override
public boolean contains(ISchedulingRule rule) {
if (rule instanceof NoResourceSchedulingRule) {
return this.path.isPrefixOf(((NoResourceSchedulingRule)rule).path);
} else {
return false;
}
}
@Override
public boolean isConflicting(ISchedulingRule rule) {
if (rule instanceof NoResourceSchedulingRule) {
IPath otherPath = ((NoResourceSchedulingRule)rule).path;
return this.path.isPrefixOf(otherPath) || otherPath.isPrefixOf(this.path);
} else {
return false;
}
}
}
return new NoResourceSchedulingRule(getPath());
} else {
return resource;
}
}
public boolean hasChildren() throws JavaModelException {
Object elementInfo = JavaModelManager.getJavaModelManager().getInfo(this);
if (elementInfo instanceof JavaElementInfo) {
return ((JavaElementInfo)elementInfo).getChildren().length > 0;
} else {
return true;
}
}
@Override
public int hashCode() {
if (this.parent == null) return super.hashCode();
return Util.combineHashCodes(getElementName().hashCode(), this.parent.hashCode());
}
public boolean isAncestorOf(IJavaElement e) {
IJavaElement parentElement= e.getParent();
while (parentElement != null && !parentElement.equals(this)) {
parentElement= parentElement.getParent();
}
return parentElement != null;
}
@Override
public boolean isReadOnly() {
return false;
}
public JavaModelException newNotPresentException() {
return new JavaModelException(newDoesNotExistStatus());
}
protected JavaModelStatus newDoesNotExistStatus() {
return new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this);
}
public JavaModelException newJavaModelException(IStatus status) {
if (status instanceof IJavaModelStatus)
return new JavaModelException((IJavaModelStatus) status);
else
return new JavaModelException(new JavaModelStatus(status.getSeverity(), status.getCode(), status.getMessage()));
}
protected Object openWhenClosed(Object info, boolean forceAdd, IProgressMonitor monitor) throws JavaModelException {
JavaModelManager manager = JavaModelManager.getJavaModelManager();
boolean hadTemporaryCache = manager.hasTemporaryCache();
try {
HashMap<IJavaElement, Object> newElements = manager.getTemporaryCache();
generateInfos(info, newElements, monitor);
if (info == null) {
info = newElements.get(this);
}
if (info == null) {
info = manager.getInfo(this);
if (info != null) {
return info;
}
}
if (info == null) {
Openable openable = (Openable) getOpenable();
if (newElements.containsKey(openable)) {
openable.closeBuffer();
}
throw newNotPresentException();
}
if (!hadTemporaryCache) {
info = manager.putInfos(this, info, forceAdd, newElements);
}
} finally {
if (!hadTemporaryCache) {
manager.resetTemporaryCache();
}
}
return info;
}
public String readableName() {
return getElementName();
}
public JavaElement resolved(Binding binding) {
return this;
}
public JavaElement unresolved() {
return this;
}
protected String tabString(int tab) {
StringBuffer buffer = new StringBuffer();
for (int i = tab; i > 0; i--)
buffer.append(" ");
return buffer.toString();
}
public String toDebugString() {
StringBuffer buffer = new StringBuffer();
this.toStringInfo(0, buffer, NO_INFO, true);
return buffer.toString();
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
toString(0, buffer);
return buffer.toString();
}
protected void toString(int tab, StringBuffer buffer) {
Object info = this.toStringInfo(tab, buffer);
if (tab == 0) {
toStringAncestors(buffer);
}
toStringChildren(tab, buffer, info);
}
public String toStringWithAncestors() {
return toStringWithAncestors(true);
}
public String toStringWithAncestors(boolean showResolvedInfo) {
StringBuffer buffer = new StringBuffer();
this.toStringInfo(0, buffer, NO_INFO, showResolvedInfo);
toStringAncestors(buffer);
return buffer.toString();
}
protected void toStringAncestors(StringBuffer buffer) {
JavaElement parentElement = (JavaElement)getParent();
if (parentElement != null && parentElement.getParent() != null) {
buffer.append(" [in ");
parentElement.toStringInfo(0, buffer, NO_INFO, false);
parentElement.toStringAncestors(buffer);
buffer.append("]");
}
}
protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
if (info == null || !(info instanceof JavaElementInfo)) return;
IJavaElement[] children = ((JavaElementInfo)info).getChildren();
for (int i = 0; i < children.length; i++) {
buffer.append("\n");
((JavaElement)children[i]).toString(tab + 1, buffer);
}
}
public Object toStringInfo(int tab, StringBuffer buffer) {
Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
this.toStringInfo(tab, buffer, info, true);
return info;
}
protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
buffer.append(tabString(tab));
toStringName(buffer);
if (info == null) {
buffer.append(" (not open)");
}
}
protected void toStringName(StringBuffer buffer) {
buffer.append(getElementName());
}
protected URL getJavadocBaseLocation() throws JavaModelException {
IPackageFragmentRoot root= (IPackageFragmentRoot) getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
if (root == null) {
return null;
}
if (root.getKind() == IPackageFragmentRoot.K_BINARY) {
IClasspathEntry entry= null;
try {
entry= root.getResolvedClasspathEntry();
URL url = getLibraryJavadocLocation(entry);
if (url != null) {
return url;
}
}
catch(JavaModelException jme) {
}
entry= root.getRawClasspathEntry();
switch (entry.getEntryKind()) {
case IClasspathEntry.CPE_LIBRARY:
case IClasspathEntry.CPE_VARIABLE:
return getLibraryJavadocLocation(entry);
default:
return null;
}
}
return null;
}
protected static URL getLibraryJavadocLocation(IClasspathEntry entry) throws JavaModelException {
switch(entry.getEntryKind()) {
case IClasspathEntry.CPE_LIBRARY :
case IClasspathEntry.CPE_VARIABLE :
break;
default :
throw new IllegalArgumentException("Entry must be of kind CPE_LIBRARY or CPE_VARIABLE");
}
IClasspathAttribute[] extraAttributes= entry.getExtraAttributes();
for (int i= 0; i < extraAttributes.length; i++) {
IClasspathAttribute attrib= extraAttributes[i];
if (IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME.equals(attrib.getName())) {
String value = attrib.getValue();
try {
return new URL(value);
} catch (MalformedURLException e) {
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC, value));
}
}
}
return null;
}
@Override
public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
return null;
}
int getIndexOf(byte[] array, byte[] toBeFound, int start, int end) {
if (array == null || toBeFound == null)
return -1;
final int toBeFoundLength = toBeFound.length;
final int arrayLength = (end != -1 && end < array.length) ? end : array.length;
if (arrayLength < toBeFoundLength)
return -1;
loop: for (int i = start, max = arrayLength - toBeFoundLength + 1; i < max; i++) {
if (isSameCharacter(array[i], toBeFound[0])) {
for (int j = 1; j < toBeFoundLength; j++) {
if (!isSameCharacter(array[i + j], toBeFound[j]))
continue loop;
}
return i;
}
}
return -1;
}
boolean isSameCharacter(byte b1, byte b2) {
if (b1 == b2 || Character.toUpperCase((char) b1) == Character.toUpperCase((char) b2)) {
return true;
}
return false;
}
protected void validateAndCache(URL baseLoc, FileNotFoundException e) throws JavaModelException {
String url = baseLoc.toString();
if (validURLs != null && validURLs.contains(url)) return;
if (invalidURLs != null && invalidURLs.contains(url))
throw new JavaModelException(e, IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC);
InputStream input = null;
try {
URLConnection connection = baseLoc.openConnection();
input = connection.getInputStream();
if (validURLs == null) {
validURLs = new HashSet<String>(1);
}
validURLs.add(url);
} catch (Exception e1) {
if (invalidURLs == null) {
invalidURLs = new HashSet<String>(1);
}
invalidURLs.add(url);
throw new JavaModelException(e, IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC);
} finally {
if (input != null) {
try {
input.close();
} catch (Exception e1) {
}
}
}
}
protected String getURLContents(URL baseLoc, String docUrlValue) throws JavaModelException {
InputStream stream = null;
JarURLConnection connection2 = null;
URL docUrl = null;
URLConnection connection = null;
try {
redirect: for (int i= 0; i < 5; i++) {
docUrl = new URL(docUrlValue);
connection = docUrl.openConnection();
int timeoutVal = 10000;
connection.setConnectTimeout(timeoutVal);
connection.setReadTimeout(timeoutVal);
if (connection instanceof HttpURLConnection) {
HttpURLConnection httpCon = (HttpURLConnection) connection;
if (httpCon.getResponseCode() == 301) {
docUrlValue = httpCon.getHeaderField("location");
if (docUrlValue != null) {
continue redirect;
}
}
} else if (connection instanceof JarURLConnection) {
connection2 = (JarURLConnection) connection;
connection.setUseCaches(false);
}
break;
}
stream = new BufferedInputStream(connection.getInputStream());
String encoding = connection.getContentEncoding();
byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, connection.getContentLength());
if (encoding == null) {
int index = getIndexOf(contents, META_START, 0, -1);
if (index != -1) {
int end = getIndexOf(contents, META_END, index, -1);
if (end != -1) {
if ((end + 1) <= contents.length) end++;
int charsetIndex = getIndexOf(contents, CHARSET_HTML5, index, end);
if (charsetIndex == -1) {
charsetIndex = getIndexOf(contents, CHARSET, index, end);
if (charsetIndex != -1)
charsetIndex = charsetIndex + CHARSET.length;
} else {
charsetIndex = charsetIndex + CHARSET_HTML5.length;
}
if (charsetIndex != -1) {
end = getIndexOf(contents, CLOSING_DOUBLE_QUOTE, charsetIndex, end);
encoding = new String(contents, charsetIndex, end - charsetIndex, org.eclipse.jdt.internal.compiler.util.Util.UTF_8);
}
}
}
}
try {
if (encoding == null) {
encoding = getJavaProject().getProject().getDefaultCharset();
}
} catch (CoreException e) {
}
if (contents != null) {
if (encoding != null) {
return new String(contents, encoding);
} else {
return new String(contents);
}
}
} catch (IllegalArgumentException | NullPointerException e) {
return null;
} catch (SocketTimeoutException e) {
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC_TIMEOUT, this));
} catch (MalformedURLException e) {
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC, this));
} catch (FileNotFoundException e) {
validateAndCache(baseLoc, e);
} catch (SocketException | UnknownHostException | ProtocolException e) {
throw new JavaModelException(e, IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC);
} catch (IOException e) {
throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
} catch(Exception e) {
if (e.getCause() instanceof IllegalArgumentException) return null;
throw new JavaModelException(e, IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC);
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
}
}
if (connection2 != null) {
try {
connection2.getJarFile().close();
} catch(IOException | IllegalStateException e) {
}
}
}
return null;
}
}