org.eclipse.jem.internal.adapters.jdom.JDOMAdaptor.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jem.internal.adapters.jdom.JDOMAdaptor.java

Source

/*******************************************************************************
 * Copyright (c) 2001, 2005 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;
/*
    
    
 */

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.EObject;
import org.eclipse.emf.ecore.resource.Resource;
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.internal.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.
    }

    /**
     * Called by subclasses in canReflect(). If the target is not in a resource, or the
     * resource is not loaded, then it can't reflect. Mustn't reflect if the target
     * has been unloaded.
     * 
     * @return
     */
    protected boolean isResourceLoaded() {
        Resource res = ((EObject) getTarget()).eResource();
        return res != null && res.isLoaded();
    }

    /**
     * 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_", //$NON-NLS-1$
                    (new Object[] { qualifiedName, jme.getMessage() }))); //= "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.
     * 
     * Bug: 166226 [https://bugs.eclipse.org/bugs/show_bug.cgi?id=166226]
     * Update to use the erasure type from the signature in order to 
     * tolerate JDK 5 generics.
     *
     */
    public static String signatureToString(String signature) throws IllegalArgumentException {
        boolean hasDollar = (signature.indexOf(Signature.C_DOLLAR) != -1);
        //begin 166226 fix
        String result = Signature.getTypeErasure(signature);
        result = Signature.toString(result);
        //end 166226 fix
        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);
    }
}