All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osjava.jardiff.StreamDiffHandler Maven / Gradle / Ivy

/**
 * Copyright 2012-2014 Julien Eluard and contributors
 * This project includes software developed by Julien Eluard: https://github.com/jeluard/
 *
 * 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 org.osjava.jardiff;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import org.objectweb.asm.Type;

/**
 * A specific type of DiffHandler which uses an OutputStream to create an 
 * XML document describing the changes in the diff.
 * This is needed for java 1.2 compatibility for the ant task.
 *
 * @author Antony Riley
 */
public class StreamDiffHandler implements DiffHandler
{
    /**
     * The XML namespace used.
     */
    public static final String XML_URI = "http://www.osjava.org/jardiff/0.1";

    /**
     * The javax.xml.transform.sax.Transformer used to convert
     * the DOM to text.
     */
    private final BufferedWriter out;

    /**
     * Create a new StreamDiffHandler which writes to System.out
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public StreamDiffHandler() throws DiffException {
        try {
            out = new BufferedWriter(
                    new OutputStreamWriter(System.out, "UTF-8")
                    );
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Create a new StreamDiffHandler with the specified OutputStream.
     *
     * @param out Where to write output.
     */
    public StreamDiffHandler(OutputStream out)
        throws DiffException
    {
        try {
            this.out = new BufferedWriter(
                    new OutputStreamWriter(out, "UTF-8")
                    );
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Start the diff.
     * This writes out the start of a <diff> node.
     *
     * @param oldJar name of old jar file.
     * @param newJar name of new jar file.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void startDiff(String oldJar, String newJar) throws DiffException {
        try {
            out.write("");
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }

    /**
     * Start the list of old contents.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void startOldContents() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }

    /**
     * Start the list of old contents.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void startNewContents() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }

    /**
     * Add a contained class.
     *
     * @param info information about a class
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void contains(ClassInfo info) throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }

    /**
     * End the list of old contents.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void endOldContents() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }

    /**
     * End the list of new contents.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void endNewContents() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Start the removed node.
     * This writes out a <removed> node.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void startRemoved() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Write out class info for a removed class.
     * This writes out the nodes describing a class
     *
     * @param info The info to write out.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void classRemoved(ClassInfo info) throws DiffException {
        try {
            writeClassInfo(info);
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * End the removed section.
     * This closes the <removed> tag.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void endRemoved() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Start the added section.
     * This opens the <added> tag.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void startAdded() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Write out the class info for an added class.
     * This writes out the nodes describing an added class.
     *
     * @param info The class info describing the added class.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void classAdded(ClassInfo info) throws DiffException {
        try {
            writeClassInfo(info);
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * End the added section.
     * This closes the <added> tag.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void endAdded() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Start the changed section.
     * This writes out the <changed> node.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void startChanged() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Start a changed section for an individual class.
     * This writes out an <classchanged> node with the real class
     * name as the name attribute.
     *
     * @param internalName the internal name of the class that has changed.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void startClassChanged(String internalName) throws DiffException 
    {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Write out info about a removed field.
     * This just writes out the field info, it will be inside a start/end
     * removed section.
     *
     * @param info Info about the field that's been removed.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void fieldRemoved(FieldInfo info) throws DiffException {
        try {
            writeFieldInfo(info);
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Write out info about a removed method.
     * This just writes out the method info, it will be inside a start/end 
     * removed section.
     *
     * @param info Info about the method that's been removed.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void methodRemoved(MethodInfo info) throws DiffException {
        try {
            writeMethodInfo(info);
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Write out info about an added field.
     * This just writes out the field info, it will be inside a start/end 
     * added section.
     *
     * @param info Info about the added field.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void fieldAdded(FieldInfo info) throws DiffException {
        try {
            writeFieldInfo(info);
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Write out info about a added method.
     * This just writes out the method info, it will be inside a start/end
     * added section.
     *
     * @param info Info about the added method.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void methodAdded(MethodInfo info) throws DiffException {
        try {
            writeMethodInfo(info);
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Write out info aboout a changed class.
     * This writes out a <classchange> node, followed by a 
     * <from> node, with the old information about the class
     * followed by a <to> node with the new information about the
     * class.
     *
     * @param oldInfo Info about the old class.
     * @param newInfo Info about the new class.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void classChanged(ClassInfo oldInfo, ClassInfo newInfo)
        throws DiffException 
    {
        try {
            out.write("");
            writeClassInfo(oldInfo);
            out.write("");
            writeClassInfo(newInfo);
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Invokes {@link #classChanged(ClassInfo, ClassInfo)}.
     */
    public void classDeprecated(ClassInfo oldInfo, ClassInfo newInfo)
	    throws DiffException {
	classChanged(oldInfo, newInfo);
    }

    /**
     * Write out info aboout a changed field.
     * This writes out a <fieldchange> node, followed by a 
     * <from> node, with the old information about the field
     * followed by a <to> node with the new information about the
     * field.
     *
     * @param oldInfo Info about the old field.
     * @param newInfo Info about the new field.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void fieldChanged(FieldInfo oldInfo, FieldInfo newInfo)
        throws DiffException 
    {
        try {
            out.write("");
            writeFieldInfo(oldInfo);
            out.write("");
            writeFieldInfo(newInfo);
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Invokes {@link #fieldChanged(FieldInfo, FieldInfo)}.
     */
    public void fieldDeprecated(FieldInfo oldInfo, FieldInfo newInfo)
	    throws DiffException {
	fieldChanged(oldInfo, newInfo);
    }

    /**
     * Write out info aboout a changed method.
     * This writes out a <methodchange> node, followed by a 
     * <from> node, with the old information about the method
     * followed by a <to> node with the new information about the
     * method.
     *
     * @param oldInfo Info about the old method.
     * @param newInfo Info about the new method.
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void methodChanged(MethodInfo oldInfo, MethodInfo newInfo)
        throws DiffException
    {
        try {
            out.write("");
            writeMethodInfo(oldInfo);
            out.write("");
            writeMethodInfo(newInfo);
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Invokes {@link #methodChanged(MethodInfo, MethodInfo)}.
     */
    public void methodDeprecated(MethodInfo oldInfo, MethodInfo newInfo)
	    throws DiffException {
	methodChanged(oldInfo, newInfo);
    }

    /**
     * End the changed section for an individual class.
     * This closes the <classchanged> node.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void endClassChanged() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * End the changed section.
     * This closes the <changed> node.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void endChanged() throws DiffException {
        try {
            out.write("");
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * End the diff.
     * This closes the <diff> node.
     *
     * @throws DiffException when there is an underlying exception, e.g.
     *                       writing to a file caused an IOException
     */
    public void endDiff() throws DiffException {
        try {
            out.write("");
            out.newLine();
            out.close();
        } catch (IOException ioe) {
            throw new DiffException(ioe);
        }
    }
    
    /**
     * Write out information about a class.
     * This writes out a <class> node, which contains information about
     * what interfaces are implemented each in a <implements> node.
     *
     * @param info Info about the class to write out.
     * @throws IOException when there is an underlying IOException.
     */
    protected void writeClassInfo(ClassInfo info) throws IOException {
        out.write("");
        }
        String[] interfaces = info.getInterfaces();
        for (int i = 0; i < interfaces.length; i++) {
            out.write("");
        }
        out.write("");
    }
    
    /**
     * Write out information about a method.
     * This writes out a <method> node which contains information about
     * the arguments, the return type, and the exceptions thrown by the 
     * method.
     *
     * @param info Info about the method.
     * @throws IOException when there is an underlying IOException.
     */
    protected void writeMethodInfo(MethodInfo info) throws IOException {
        out.write("");
        if (info.getDesc() != null) {
            addMethodNodes(info.getDesc());
        }
        String[] exceptions = info.getExceptions();
        if (exceptions != null) {
            for (int i = 0; i < exceptions.length; i++) {
                out.write("");
            }
        }
        out.write("");
    }
    
    /**
     * Write out information about a field.
     * This writes out a <field> node with attributes describing the
     * field.
     *
     * @param info Info about the field.
     * @throws IOException when there is an underlying IOException.
     */
    protected void writeFieldInfo(FieldInfo info) throws IOException {
        out.write("");
        if (info.getDesc() != null) {
            addTypeNode(info.getDesc());
        }
        out.write("");
    }
    
    /**
     * Add attributes describing some access flags.
     * This adds the attributes to the attr field.
     *
     * @param info Info describing the access flags.
     * @throws IOException when there is an underlying IOException.
     */
    protected void addAccessFlags(AbstractInfo info) throws IOException {
        out.write(" access=\"");
        // Doesn't need escaping.
        out.write(info.getAccessType());
        out.write("\"");
        if (info.isAbstract())
            out.write(" abstract=\"yes\"");
        if (info.isAnnotation())
            out.write(" annotation=\"yes\"");
        if (info.isBridge())
            out.write(" bridge=\"yes\"");
        if (info.isDeprecated())
            out.write(" deprecated=\"yes\"");
        if (info.isEnum())
            out.write(" enum=\"yes\"");
        if (info.isFinal())
            out.write(" final=\"yes\"");
        if (info.isInterface())
            out.write(" interface=\"yes\"");
        if (info.isNative())
            out.write(" native=\"yes\"");
        if (info.isStatic())
            out.write(" static=\"yes\"");
        if (info.isStrict())
            out.write(" strict=\"yes\"");
        if (info.isSuper())
            out.write(" super=\"yes\"");
        if (info.isSynchronized())
            out.write(" synchronized=\"yes\"");
        if (info.isSynthetic())
            out.write(" synthetic=\"yes\"");
        if (info.isTransient())
            out.write(" transient=\"yes\"");
        if (info.isVarargs())
            out.write(" varargs=\"yes\"");
        if (info.isVolatile())
            out.write(" volatile=\"yes\"");
    }
    
    /**
     * Add the method nodes for the method descriptor.
     * This writes out an <arguments> node containing the 
     * argument types for the method, followed by a <return> node
     * containing the return type.
     *
     * @param desc The descriptor for the method to write out.
     * @throws IOException when there is an underlying IOException.
     */
    protected void addMethodNodes(String desc) throws IOException {
        Type[] args = Type.getArgumentTypes(desc);
        Type ret = Type.getReturnType(desc);
        out.write("");
        for (int i = 0; i < args.length; i++)
            addTypeNode(args[i]);
        out.write("");
        out.write("");
        addTypeNode(ret);
        out.write("");
    }
    
    /**
     * Add a type node for the specified descriptor.
     *
     * @param desc A type descriptor.
     * @throws IOException when there is an underlying IOException.
     */
    protected void addTypeNode(String desc) throws IOException {
        addTypeNode(Type.getType(desc));
    }
    
    /**
     * Add a type node for the specified type.
     * This writes out a <type> node with attributes describing
     * the type.
     *
     * @param type The type to describe.
     * @throws IOException when there is an underlying IOException.
     */
    protected void addTypeNode(Type type) throws IOException {
        out.write("");
            break;
        case Type.BYTE:
            out.write(" primitive=\"yes\" name=\"byte\"/>");
            break;
        case Type.CHAR:
            out.write(" primitive=\"yes\" name=\"char\"/>");
            break;
        case Type.DOUBLE:
            out.write(" primitive=\"yes\" name=\"double\"/>");
            break;
        case Type.FLOAT:
            out.write(" primitive=\"yes\" name=\"float\"/>");
            break;
        case Type.INT:
            out.write(" primitive=\"yes\" name=\"int\"/>");
            break;
        case Type.LONG:
            out.write(" primitive=\"yes\" name=\"long\"/>");
            break;
        case Type.OBJECT:
            out.write(" name=\"");
            out.write(xmlEscape(type.getInternalName()));
            out.write("\"/>");
            break;
        case Type.SHORT:
            out.write(" primitive=\"yes\" name=\"short\"/>");
            break;
        case Type.VOID:
            out.write(" primitive=\"yes\" name=\"void\"/>");
            break;
        }
    }

    /**
     * Escape some text into a format suitable for output as xml.
     *
     * @param str the text to format
     * @return the formatted text
     */
    private final String xmlEscape(final String str) {
        StringBuffer ret = new StringBuffer(str.length());
        for(int i=0;i':
                    ret.append(">");
                    break;
                default:
                    ret.append(ch);
            }
        }
        return ret.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy