generate.tostring.GenerateToStringUtils.java Source code

Java tutorial

Introduction

Here is the source code for generate.tostring.GenerateToStringUtils.java

Source

/*
 * Copyright 2001-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package generate.tostring;

import com.intellij.codeInsight.generation.PsiElementClassMember;
import com.intellij.codeInsight.generation.PsiFieldMember;
import com.intellij.codeInsight.generation.PsiMethodMember;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.*;
import generate.tostring.config.FilterPattern;
import generate.tostring.element.ElementFactory;
import generate.tostring.element.FieldElement;
import generate.tostring.element.MethodElement;
import generate.tostring.exception.GenerateCodeException;
import generate.tostring.exception.PluginException;
import generate.tostring.psi.PsiAdapter;
import generate.tostring.psi.PsiAdapterFactory;
import generate.tostring.util.FileUtil;
import org.apache.log4j.Logger;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

/**
 * Utility methods for GenerationToStringAction and the inspections.
 */
public class GenerateToStringUtils {

    private static Logger log = Logger.getLogger(GenerateToStringUtils.class);

    /**
     * Private constructor.
     */
    private GenerateToStringUtils() {
    }

    /**
     * Filters the list of fields from the class with the given parameters from the {@link generate.tostring.config.Config config} settings.
     *
     * @param project        Project
     * @param psi            PSI adapter
     * @param elementFactory Element Factory
     * @param clazz          the class to filter it's fields
     * @param pattern        the filter pattern to filter out unwanted fields
     * @return fields avaiable for this action after the filter process.
     */
    public static PsiField[] filterAvailableFields(Project project, PsiAdapter psi,
            PsiElementFactory elementFactory, PsiClass clazz, FilterPattern pattern) {
        if (log.isDebugEnabled())
            log.debug("Filtering fields using the pattern: " + pattern);
        List<PsiField> availableFields = new ArrayList<PsiField>();

        // performs til filtering process
        PsiField[] fields = psi.getFields(clazz);
        for (PsiField field : fields) {
            FieldElement fe = ElementFactory.newFieldElement(project, field, elementFactory, psi);
            if (log.isDebugEnabled())
                log.debug("Field being filtered: " + fe);

            // if the field matches the pattern then it shouldn't be in the list of avaialble fields
            if (!fe.applyFilter(pattern)) {
                availableFields.add(field);
            }
        }

        return availableFields.toArray(new PsiField[availableFields.size()]);
    }

    /**
     * Filters the list of methods from the class to be
     * <ul>
     * <li/>a getter method (java bean compliant)
     * <li/>should not be a getter for an existing field
     * <li/>public, non static, non abstract
     * <ul/>
     *
     * @param psi            PSI adapter
     * @param elementFactory Element Factory
     * @param clazz          the class to filter it's fields
     * @param pattern        the filter pattern to filter out unwanted fields
     * @return methods avaiable for this action after the filter process.
     */
    public static PsiMethod[] filterAvailableMethods(PsiAdapter psi, PsiElementFactory elementFactory,
            PsiClass clazz, FilterPattern pattern) {
        if (log.isDebugEnabled())
            log.debug("Filtering methods using the pattern: " + pattern);
        List<PsiMethod> availableMethods = new ArrayList<PsiMethod>();

        PsiMethod[] methods = psi.getMethods(clazz);
        for (PsiMethod method : methods) {

            MethodElement me = ElementFactory.newMethodElement(method, elementFactory, psi);
            if (log.isDebugEnabled())
                log.debug("Method being filtered: " + me);

            // the method should be a getter
            if (!me.isGetter()) {
                continue;
            }

            // must not return void
            if (me.isReturnTypeVoid()) {
                continue;
            }

            // method should be public, non static, non abstract
            if (!me.isModifierPublic() || me.isModifierStatic() || me.isModifierAbstract()) {
                continue;
            }

            // method should not be a getter for an existing field
            if (psi.findFieldByName(clazz, me.getFieldName()) != null) {
                continue;
            }

            // must not be named toString or getClass
            if ("toString".equals(me.getMethodName()) || "getClass".equals(me.getMethodName())) {
                continue;
            }

            // if the method matches the pattern then it shouldn't be in the list of avaialble methods
            if (!me.applyFilter(pattern)) {
                if (log.isDebugEnabled())
                    log.debug("Adding the method " + method.getName() + " as there is not a field for this getter");
                availableMethods.add(method);
            }
        }

        return availableMethods.toArray(new PsiMethod[availableMethods.size()]);
    }

    /**
     * Get's the editor
     *
     * @param project project
     * @return the editor, null if not found
     */
    public static Editor getEditor(final Project project) {
        Editor[] editors = EditorFactory.getInstance().getAllEditors();
        for (Editor ed : editors) {
            if (project == ed.getProject()) {
                return ed;
            }
        }
        return null;
    }

    /**
     * Handles any exception during the executing on this plugin.
     *
     * @param project PSI project
     * @param e       the caused exception.
     * @throws RuntimeException is thrown for severe exceptions
     */
    public static void handleExeption(Project project, Exception e) throws RuntimeException {
        e.printStackTrace(); // must print stacktrace to see caused in IDEA log / console
        log.error(e);

        if (e instanceof GenerateCodeException) {
            // code generation error - display velocity errror in error dialog so user can identify problem quicker
            Messages.showMessageDialog(project,
                    "Velocity error generating code - see IDEA log for more details (stacktrace should be in idea.log):\n"
                            + e.getMessage(),
                    "Warning", Messages.getWarningIcon());
        } else if (e instanceof PluginException) {
            // plugin related error - could be recoverable.
            Messages.showMessageDialog(project,
                    "A PluginException was thrown while performing the action - see IDEA log for details (stacktrace should be in idea.log):\n"
                            + e.getMessage(),
                    "Warning", Messages.getWarningIcon());
        } else if (e instanceof RuntimeException) {
            // unknown error (such as NPE) - not recoverable
            Messages.showMessageDialog(project,
                    "An unrecoverable exception was thrown while performing the action - see IDEA log for details (stacktrace should be in idea.log):\n"
                            + e.getMessage(),
                    "Error", Messages.getErrorIcon());
            throw (RuntimeException) e; // throw to make IDEA alert user
        } else {
            // unknown error (such as NPE) - not recoverable
            Messages.showMessageDialog(project,
                    "An unrecoverable exception was thrown while performing the action - see IDEA log for details (stacktrace should be in idea.log):\n"
                            + e.getMessage(),
                    "Error", Messages.getErrorIcon());
            throw new RuntimeException(e); // rethrow as runtime to make IDEA alert user
        }
    }

    /**
     * Gets the current PsiClass
     *
     * @param editor the editor
     * @return the clazz, <tt>null</tt> if not found
     */
    public static PsiClass getCurrentClass(Editor editor) {
        PsiAdapter psi = PsiAdapterFactory.getPsiAdapter();
        Project project = editor.getProject();
        PsiManager manager = psi.getPsiManager(project);
        PsiJavaFile javaFile = psi.getSelectedJavaFile(project, manager);
        if (javaFile == null) {
            return null; // silently ignore since it's not a javafile.
        }

        PsiClass clazz = psi.getCurrentClass(javaFile, editor);
        if (clazz == null) {
            return null; // silently ignore since current selected class in editor not found.
        } else {
            return clazz;
        }
    }

    /**
     * Combines the two lists into one list of members.
     *
     * @param filteredFields  fields to be included in the dialog
     * @param filteredMethods methods to be included in the dialog
     * @return the combined list
     */
    public static PsiMember[] combineToMemberList(PsiField[] filteredFields, PsiMethod[] filteredMethods) {
        PsiMember[] members = new PsiMember[filteredFields.length + filteredMethods.length];

        // first add fields
        for (int i = 0; i < filteredFields.length; i++) {
            members[i] = filteredFields[i];
        }

        // then add methods
        for (int i = 0; i < filteredMethods.length; i++) {
            members[filteredFields.length + i] = filteredMethods[i];
        }

        return members;
    }

    /**
     * Combines the two lists into one list of members.
     *
     * @param filteredFields  fields to be included in the dialog
     * @param filteredMethods methods to be included in the dialog
     * @return the combined list
     */
    public static PsiElementClassMember[] combineToClassMemberList(PsiField[] filteredFields,
            PsiMethod[] filteredMethods) {
        PsiElementClassMember[] members = new PsiElementClassMember[filteredFields.length + filteredMethods.length];

        // first add fields
        for (int i = 0; i < filteredFields.length; i++) {
            members[i] = new PsiFieldMember(filteredFields[i]);
        }

        // then add methods
        for (int i = 0; i < filteredMethods.length; i++) {
            members[filteredFields.length + i] = new PsiMethodMember(filteredMethods[i]);
        }

        return members;
    }

    /**
     * Converts the list of {@link PsiElementClassMember} to {PsiMember} objects.
     *
     * @param classMemberList  list of {@link PsiElementClassMember}
     * @return a list of {PsiMember} objects. 
     */
    public static List<PsiMember> convertClassMembersToPsiMembers(List<PsiElementClassMember> classMemberList) {
        List<PsiMember> psiMemberList = new ArrayList<PsiMember>();

        for (PsiElementClassMember classMember : classMemberList) {
            psiMemberList.add(classMember.getElement());
        }

        return psiMemberList;
    }

    /**
     * Extracts the documentation from the .jar file as a local file so it's
     * viewable from a browser without accessing a website.
     *
     * @throws java.io.IOException is thrown if any IO errors
     */
    public static void extractDocumentation() throws IOException {
        log.debug("Extracting documentation +++ START +++");

        PsiAdapter psi = PsiAdapterFactory.getPsiAdapter();
        String inf = psi.getPluginFilename();

        if (inf == null) {
            log.warn("Could not find GenerateToString.jar file - documenation disabled");
            return;
        }

        String outf = getDocumentationFilename();

        JarFile jar = null;
        InputStream in = null;
        BufferedInputStream bin = null;
        try {
            if (log.isDebugEnabled())
                log.debug("Reading jar file: " + inf);

            jar = new JarFile(inf);
            ZipEntry entry = jar.getEntry("generate/tostring/package.html");
            if (log.isDebugEnabled())
                log.debug("Got zipentry: " + entry.getName());

            in = jar.getInputStream(entry);
            bin = new BufferedInputStream(in);

            if (log.isDebugEnabled())
                log.debug("Reading content of zipentry");
            String doc = FileUtil.readFileContent(bin);

            if (log.isDebugEnabled())
                log.debug("Saving content to destinationfile: " + outf);
            FileUtil.saveFile(outf, doc);
            if (log.isDebugEnabled())
                log.debug("Save succesfull");

        } catch (IOException e) {
            log.warn("IO error while extracting plugin documentation - documentation disabled. Filename = '" + inf
                    + "'", e);
            return;
        } finally {
            try {
                if (bin != null)
                    bin.close();
                if (in != null)
                    in.close();
                if (jar != null)
                    jar.close();
            } catch (IOException e) {
                log.debug("Ignoring IOException while closing resources", e);
            }
        }

        log.debug("Extracting documentation +++ END +++");
    }

    /**
     * Get's the filename for the local documentation.
     *
     * @return the filename for the local documentation.
     */
    public static String getDocumentationFilename() {
        return PathManager.getPluginsPath() + File.separatorChar + "GenerateToString-doc.html";
    }

}