| /******************************************************************************* |
| * Copyright (c) 2001, 2004 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jem.internal.adapters.jdom; |
| /* |
| * $RCSfile: JDOMAdaptor.java,v $ |
| * $Revision: 1.5 $ $Date: 2005/02/15 23:09:27 $ |
| */ |
| |
| import java.io.File; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.Notifier; |
| import org.eclipse.emf.ecore.xmi.XMIResource; |
| import org.eclipse.jdt.core.*; |
| import org.eclipse.jem.java.*; |
| import org.eclipse.jem.internal.java.adapters.JavaReflectionAdaptor; |
| import org.eclipse.jem.internal.java.adapters.nls.ResourceHandler; |
| import org.eclipse.jem.java.impl.JavaRefFactoryImpl; |
| /** |
| * Insert the type's description here. |
| * Creation date: (6/6/2000 4:42:50 PM) |
| * @author: Administrator |
| */ |
| public abstract class JDOMAdaptor extends JavaReflectionAdaptor { |
| |
| protected final static JavaRefPackage JAVA_PACK = JavaRefFactoryImpl.getPackage(); |
| protected IJavaProject sourceProject; |
| final public static int INVALID_LINENO = -1; |
| final protected Integer fLINENOLock = new Integer(INVALID_LINENO); |
| // This object is not static, as it is used as synchronization element. |
| private int fResolvedLineNo = INVALID_LINENO; // Line offset in source file |
| private int fResolvedColNo = INVALID_LINENO; // Column offset in source file |
| public JDOMAdaptor(Notifier target, IJavaProject workingProject) { |
| super(target); |
| setSourceProject(workingProject); |
| } |
| protected void clearSource() { |
| // To be overidden if needed. |
| } |
| /** |
| * Scan for CRs and LFs within a character buffer |
| * Creation date: (8/17/2001 2:14:13 PM) |
| * @return int LineNo at charOffset |
| * @param charOffset int |
| * @param buffer org.eclipse.jdt.core.IBuffer |
| */ |
| private void computeLineOffset(int charOffset, IBuffer buffer) { |
| |
| fResolvedColNo = fResolvedLineNo = INVALID_LINENO; |
| |
| if (buffer == null) |
| return; |
| |
| char[] charBuff = buffer.getCharacters(); |
| |
| if (charBuff == null) |
| return; |
| |
| int LineCount = 0; |
| int ColNo = 0; |
| for (int i = 0; i <= charOffset; i++) { |
| ColNo++; |
| if (charBuff[i] == '\r') { |
| LineCount++; |
| ColNo = 0; |
| if (charBuff[i + 1] == '\n') |
| i++; // skip LineFeed followed a CR |
| } else if (charBuff[i] == '\n') { |
| LineCount++; |
| ColNo = 0; |
| } |
| |
| } |
| fResolvedColNo = ColNo; |
| fResolvedLineNo = LineCount; |
| } |
| /** |
| * computeMethodID - generate the unique ID to be used to identify a method. |
| * Similar to a Signature, but hopefully more readable. |
| * The name format will be: |
| * simpleTypeName.methodName(my.package.Parm_Type1,parmType2 |
| * Note: This implementation is tightly coupled with ReflectionAdapter.getTypeNamesFromMethodID(). |
| */ |
| public static String computeMethodID(IMethod jdomMethod) { |
| return computeMethodID(jdomMethod, jdomMethod.getDeclaringType(), null); |
| } |
| /** |
| * computeMethodID - generate the unique ID to be used to identify a method. |
| * Similar to a Signature, but hopefully more readable. |
| * The name format will be: |
| * simpleTypeName.methodName(my.package.Parm_Type1,parmType2 |
| * Note: This implementation is tightly coupled with ReflectionAdapter.getTypeNamesFromMethodID(). |
| */ |
| public static String computeMethodID(IMethod jdomMethod, IType type, Map typeCache) { |
| StringBuffer out = new StringBuffer(); |
| out.append(type.getTypeQualifiedName()); |
| out.append(C_CLASS_MEMBER_DELIMITER); |
| out.append(jdomMethod.getElementName()); |
| out.append(C_METHOD_PARM_DELIMITER); |
| String[] parmTypeNames = jdomMethod.getParameterTypes(); |
| String parmName; |
| for (int i = 0; i < parmTypeNames.length; i++) { |
| parmName = convertJDOMtypeName(parmTypeNames[i]); |
| parmName = JDOMSearchHelper.getResolvedTypeName(parmName, type, typeCache); |
| out.append(parmName); |
| if (i < (parmTypeNames.length - 1)) |
| out.append(C_PARM_PARM_DELIMITER); |
| } |
| try { |
| if (jdomMethod.isConstructor()) |
| out.append(S_CONSTRUCTOR_TOKEN); |
| } catch (JavaModelException e) { |
| } |
| return out.toString(); |
| } |
| /** |
| * computeMethodName - generate the name to be used to identify a method. |
| * For the moment, names are simple, and UUID's are complex. |
| */ |
| public static String computeMethodName(IMethod jdomMethod) { |
| return jdomMethod.getElementName(); |
| } |
| /** |
| * Java content has changed, but no structural changes that require |
| * to reflectValues(); e.g., the body of a method has changed. |
| * Creation date: (8/17/2001 10:47:58 AM) |
| */ |
| public void contentChanged() { |
| synchronized (fLINENOLock) { |
| fResolvedLineNo = INVALID_LINENO; |
| fResolvedColNo = INVALID_LINENO; |
| } |
| } |
| /** |
| * computeMethodID - generate the unique ID to be used to identify a method. |
| * Similar to a Signature, but hopefully more readable. |
| * The name format will be: |
| * methodName_parmType1_parmType2 |
| */ |
| public static String convertJDOMtypeName(String jdomTypeName) { |
| return signatureToString(jdomTypeName); |
| } |
| /** |
| * createJavaField - instantiate a Java Field based on the passed Java Model IField |
| * We are deferring field contents assuming that its adaptor will reflect its details. |
| */ |
| public Field createJavaField(IField jdomField, XMIResource resource) { |
| String name = jdomField.getElementName(); |
| Field newField = getJavaFactory().createField(); |
| newField.setName(name); |
| resource.setID(newField, ((JavaClass) getTarget()).getName() + C_CLASS_MEMBER_DELIMITER + name); |
| return newField; |
| } |
| /** |
| * createJavaMethod - instantiate a Java Method based on the passed Java Model IMethod |
| * We are deferring method contents assuming that its adaptor will reflect its details. |
| * We need to store enough info in the empty Method to find its Java source. |
| * The UUID will eventually hold enough info to identify the source, so we use it. |
| */ |
| public Method createJavaMethod(IMethod jdomMethod, XMIResource resource) { |
| Method newMethod = getJavaFactory().createMethod(); |
| // We use a simple name, but a complex ID |
| newMethod.setName(computeMethodName(jdomMethod)); |
| resource.setID(newMethod, computeMethodID(jdomMethod, getType(), getTypeResolutionCache())); |
| return newMethod; |
| } |
| protected IPath getBinaryPathFromQualifiedName(String qualifiedName) { |
| return new Path(qualifiedName.replace('.', File.separatorChar) + ".class"); //$NON-NLS-1$ |
| } |
| public IType getBinaryType(String qualifiedName) { |
| try { |
| if (getSourceProject() != null) { |
| IJavaElement found = getSourceProject().findElement(getBinaryPathFromQualifiedName(qualifiedName)); |
| if (found != null) |
| return ((IClassFile) found).getType(); |
| } |
| } catch (JavaModelException jme) { |
| System.out.println(ResourceHandler.getString("Error_Looking_Up_Type_ERROR_", (new Object[] { qualifiedName, jme.getMessage()}))); //$NON-NLS-1$ = "Error looking up type: " |
| } |
| return null; |
| } |
| /** |
| * Compute a column number from the ISourceRange offset |
| * Cache the line number thereafter. Source change will |
| * Invoke the contentChanged() method. |
| * Creation date: (8/17/2001 11:16:51 AM) |
| * @return int |
| */ |
| public int getColNo() { |
| |
| synchronized (fLINENOLock) { |
| if (fResolvedColNo == INVALID_LINENO) |
| resolveLineColNo(); |
| } |
| return fResolvedColNo; |
| } |
| /** |
| * Compute a line number from the ISourceRange offset |
| * Cache the line number thereafter. Source change will |
| * Invoke the contentChanged() method. |
| * Creation date: (8/17/2001 11:16:51 AM) |
| * @return int |
| */ |
| public int getLineNo() { |
| |
| synchronized (fLINENOLock) { |
| if (fResolvedLineNo == INVALID_LINENO) |
| resolveLineColNo(); |
| } |
| return fResolvedLineNo; |
| } |
| /** |
| * Insert the method's description here. |
| * Creation date: (8/17/2001 1:18:29 PM) |
| */ |
| public abstract Object getReflectionSource(); |
| /* |
| * Resolve a type name in the context of a Type. |
| * (Borrowed from org.eclipse.jdt.ui.codemanipulation.StubUtility.getResolvedTypeName()) |
| * The input is a simple or qualified name, NOT a signature |
| * The output will be a qualified name, NOT a signature |
| */ |
| public static String getResolvedTypeName(String typeName, IType declaringType) { |
| String name = typeName; |
| try { |
| name = JDOMSearchHelper.resolveSimpleTypeName(declaringType, typeName); |
| } catch (JavaModelException e) { |
| // ignore |
| } |
| return name; |
| } |
| |
| protected IJavaProject getSourceProject() { |
| return sourceProject; |
| } |
| protected abstract IType getType(); |
| protected abstract Map getTypeResolutionCache(); |
| |
| public void releaseSourceType() { |
| flushReflectedValuesIfNecessary(true); // induce clients to get Notified. |
| } |
| |
| public Notification releaseSourceTypeNoNotification() { |
| return flushReflectedValuesIfNecessaryNoNotification(true); // induce clients to get Notified. |
| } |
| /** |
| * Insert the method's description here. |
| * Creation date: (8/21/2001 8:09:34 AM) |
| */ |
| private void resolveLineColNo() { |
| |
| IMember rs = (IMember) getReflectionSource(); |
| if (rs != null) { |
| int offset = INVALID_LINENO; |
| try { |
| ISourceRange sr = rs.getNameRange(); |
| if (sr.getLength() <= 0) |
| return; |
| offset = sr.getOffset(); |
| } catch (JavaModelException je) { |
| return; |
| } |
| ICompilationUnit cu = rs.getCompilationUnit(); |
| if (cu != null) { |
| try { |
| IBuffer buffer = cu.getBuffer(); |
| computeLineOffset(offset, buffer); |
| } catch (JavaModelException je) { |
| } |
| } |
| } |
| } |
| protected void setSourceProject(IJavaProject workingProject) { |
| sourceProject = workingProject; |
| } |
| /** |
| * Converts a type signature to a readable string. |
| * |
| * Uses Signature.toString(), then tries to undo bad replacement for inner classes. |
| * |
| */ |
| public static String signatureToString(String signature) throws IllegalArgumentException { |
| boolean hasDollar = (signature.indexOf(Signature.C_DOLLAR) != -1); |
| String result = Signature.toString(signature); |
| if (hasDollar) { |
| int newPos = result.lastIndexOf("."); //$NON-NLS-1$ |
| if (newPos != -1) { |
| result = result.substring(0, newPos) + "$" + result.substring(newPos + 1); //$NON-NLS-1$ |
| } |
| } |
| return result; |
| } |
| /** |
| * setType - set our type here |
| */ |
| protected String typeNameFromSignature(String sig) { |
| return typeNameFromSignature(sig, getType()); |
| } |
| /** |
| * setType - set our type here |
| */ |
| protected String typeNameFromSignature(String sig, IType parent) { |
| return typeNameFromSignature(sig, parent, getTypeResolutionCache()); |
| } |
| /** |
| * setType - set our type here |
| */ |
| public static String typeNameFromSignature(String sig, IType parent, Map typeCache) { |
| String result; |
| String componentSignature = Signature.getElementType(sig); |
| int arrayDimensions = Signature.getArrayCount(sig); |
| result = JDOMSearchHelper.getResolvedTypeName(signatureToString(componentSignature), parent, typeCache); |
| for (int i = 0; i < arrayDimensions; i++) { |
| result = result + "[]"; //$NON-NLS-1$ |
| } |
| return result; |
| } |
| /** |
| * @deprecated |
| * @see org.eclipse.jem.internal.adapters.jdom.JDOMSearchHelper#findType(String, boolean, IJavaProject, JDOMAdaptor) |
| */ |
| public IType getType(String qualifiedName) { |
| return JDOMSearchHelper.findType(qualifiedName, false, getSourceProject(), this); |
| } |
| } |