com.wolvereness.bluebutton.crash.ExceptionMessage.java Source code

Java tutorial

Introduction

Here is the source code for com.wolvereness.bluebutton.crash.ExceptionMessage.java

Source

package com.wolvereness.bluebutton.crash;

import static com.wolvereness.bluebutton.crash.Tokens.CAUSED_START;
import static com.wolvereness.bluebutton.crash.Tokens.DESCRIPTION_START;
import static com.wolvereness.bluebutton.crash.Tokens.DETAILS_START;
import static com.wolvereness.bluebutton.crash.Tokens.STACK_MORE_END;
import static com.wolvereness.bluebutton.crash.Tokens.STACK_MORE_START;
import static com.wolvereness.bluebutton.crash.Tokens.STACK_START;
import static com.wolvereness.bluebutton.crash.Tokens.START;
import static com.wolvereness.bluebutton.crash.Tokens.TIME_START;
import static com.wolvereness.bluebutton.crash.Tokens.WORLD;
import static com.wolvereness.bluebutton.crash.Tokens.WORLD_START;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.time.DateFormatUtils;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.wolvereness.util.bluebutton.Splitter;
import com.wolvereness.util.bluebutton.StringMaker;

class ExceptionMessage implements Serializable, StringMaker.Appendable {
    private static final long serialVersionUID = -8052119166635775588L;
    private static final String[] TYPES = new String[] { "type", "message", "stack" };

    final String exceptionType;
    final String message;
    final List<StackTraceElement> stacks;

    ExceptionMessage(final List<String> description, final List<StackTraceElement> stacks) {
        this.stacks = ImmutableList.copyOf(stacks);
        final Iterator<String> it = description.iterator();
        final String exception = it.next();
        final int colon = exception.indexOf(':');
        if (colon != -1) {
            this.exceptionType = exception.substring(0, colon);
            final StringBuilder message = new StringBuilder(exception.substring(colon + 2));
            while (it.hasNext()) {
                message.append('\n').append(it.next());
            }
            this.message = message.toString();
        } else {
            this.exceptionType = exception;
            this.message = "";
        }
    }

    @Override
    public StringBuilder appendTo(final StringBuilder builder, final int indent) {
        return StringMaker.appendTo(TYPES, new Object[] { exceptionType, message, stacks },
                builder.append(ExceptionMessage.class.getName()), indent);
    }

    List<StackTraceElement> getStackTrace() {
        return stacks;
    }

    @Override
    public String toString() {
        return appendTo(new StringBuilder(), 1).toString();
    }

}

class Node implements Serializable, StringMaker.Appendable {
    private static final long serialVersionUID = -7456417988332538402L;
    private static final String[] TYPES = new String[] { "type" };

    private final Nodes type;

    Node(final Nodes type) {
        this.type = type;
    }

    @Override
    public StringBuilder appendTo(final StringBuilder builder, final int indent) {
        return StringMaker.appendTo(TYPES, new Object[] { type }, builder.append(Node.class.getName()), indent);
    }

    @Override
    public String toString() {
        return appendTo(new StringBuilder(), 1).toString();
    }

}
//return StringMaker.appendTo(\n\t\t\t\t\t\tTYPES,\n\t\t\t\t\t\tnew Object[] {\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\tsuper.appendTo(builder, indent).append('.').append(getClass().getName()),\n\t\t\t\t\t\tindent);

enum Nodes implements Serializable {
    _NA {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = 1806744531754775486L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    CRAFTBUKKIT_INFORMATION {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = -1238140494055183276L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    IS_MODDED {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = -2978008995834097857L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    JAVA_VERSION {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = 6469440502730283729L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    JAVA_VM_VERSION {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = -3031947030091611359L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    JVM_FLAGS {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = -7789346901121607201L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    MEMORY {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = -5483966477648362518L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    MINECRAFT_VERSION {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = 6272160377152734479L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    OPERATING_SYSTEM {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = -3913076311178282768L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    PLAYER_COUNT {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = -2655651225284524999L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    PROFILER_POSITION {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = 5133277576735422736L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    TYPE {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = 8823694713117783921L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    },
    WORLD {
        @Override
        public Node makeNode(final String line, final List<String> data) {
            return new Node(this) {
                private static final long serialVersionUID = -2700511998935256883L;
                // TODO Auto-generated method stub
                private final String[] TYPES = new String[] {};

                @Override
                public StringBuilder appendTo(final StringBuilder builder, final int indent) {
                    // TODO Auto-generated method stub
                    return StringMaker.appendTo(TYPES, new Object[] {},
                            super.appendTo(builder, indent).append(getClass().getName()), indent);
                }
            };
        }
    };

    public abstract Node makeNode(String line, List<String> data);
}

/**
 * <pre>
 * This file is part of BlueButton.
 *
 * BlueButton is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * BlueButton is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with BlueButton.  If not, see < http://www.gnu.org/licenses/ >.
 * </pre>
 * @author Wolfe
 */
@SuppressWarnings("javadoc")
public class Report implements Serializable, StringMaker.Appendable {
    private static final long serialVersionUID = 3476171284348297887L;
    private static final Pattern STACK_ELEMENT = Pattern.compile(
            "^(\\tat )(([a-zA-Z_\\$]+\\.)+[A-Za-z_\\$]+)\\.([A-Za-z_\\$<>]+)\\(((.*):(\\d+)|Unknown Source)\\)$");
    private static final String[] TYPES = new String[] { "description", "fun", "nodes", "exceptions", "time", };

    static StackTraceElement toStackTraceElement(final String element) {
        final Matcher matcher = STACK_ELEMENT.matcher(element);
        if (!matcher.matches())
            throw new IllegalArgumentException("Invalid stack trace element: " + element);
        if (matcher.group(6) == null)
            return new StackTraceElement(matcher.group(2), matcher.group(4), null, -2);
        else
            return new StackTraceElement(matcher.group(2), matcher.group(4), matcher.group(6),
                    Integer.parseInt(matcher.group(7)));
    }

    final String description;
    final ImmutableList<ExceptionMessage> exceptions;
    final String fun;
    final ImmutableMap<Nodes, Node> nodes;
    final Date time;

    public Report(final String text) {
        final ArrayList<String> lines;
        { // _LINES_
            int i;
            if ((i = text.indexOf('\r')) != -1) {
                if (text.startsWith("\r\n", i)) { // StartsWith prevents OOB exception
                    lines = Splitter.splitAll(text, "\r\n");
                } else {
                    lines = Splitter.splitAll(text, '\r');
                }
            } else {
                lines = Splitter.splitAll(text, '\n');
            }
        } // _LINES_

        final ImmutableMap.Builder<Nodes, Node> nodes = ImmutableMap.builder();
        final ListIterator<String> it = lines.listIterator(lines.size() - 1);

        { // _DETAILS_
            int count = 0; // Number of lines with no "- " for sub-listing
            while (true) {
                String entry = it.previous();
                if (entry.startsWith(START)) {
                    if (entry.startsWith(WORLD, 2)) {
                        continue; // Process this at end
                    }

                    final int colon = entry.indexOf(':');
                    Nodes type = Nodes.valueOf(entry.substring(2, colon).toUpperCase().replace(' ', '_'));
                    if (type == null) {
                        type = Nodes._NA;
                    }
                    final List<String> subList = lines.subList(it.nextIndex(), it.nextIndex() + count);
                    final Node node = type.makeNode(entry.substring(colon + 1), subList);
                    nodes.put(type, node);

                    count = 0; // Reset count, as it is used for sub-listing
                } else if (entry.equals(DETAILS_START)) {
                    {
                        final ArrayList<String> worlds = new ArrayList<String>();
                        while (it.hasNext()) {
                            entry = it.next();
                            if (entry.startsWith(WORLD_START)) {
                                worlds.add(entry);
                            }
                        }
                        nodes.put(Nodes.WORLD, Nodes.WORLD.makeNode(null, worlds));
                    }

                    while (!it.previous().equals(DETAILS_START)) {
                    }
                    if (!it.previous().equals("")) // NOTE_0- blank line preceding details check, see NOTE_0- below
                        throw new IllegalStateException("Expected blank line in " + lines.toString());
                    while (!it.previous().startsWith(DESCRIPTION_START)) {
                    }
                    it.next(); // Description_start
                    it.next(); // Blank line
                    break; // We're done in the loop
                } else {
                    count++;
                }
            }
        } // _DETAILS_

        { // _STACK_
            final LinkedList<ExceptionMessage> exceptions = new LinkedList<ExceptionMessage>();
            final List<StackTraceElement> stacks = new ArrayList<StackTraceElement>();
            final List<String> description = new ArrayList<String>();
            description.add(it.next()); // Initialize; first line is always first exception
            for (String entry = it.next(); !entry.equals(DETAILS_START); entry = it.next()) {
                // Read in all the exception information.
                // Apocalypse if the formating changes...
                if (entry.startsWith(STACK_START)) {
                    // Normal stack element
                    stacks.add(toStackTraceElement(entry));
                } else if (entry.startsWith(STACK_MORE_START)) {
                    // "... n more" final line
                    final ExceptionMessage previous = exceptions.getLast();
                    final List<StackTraceElement> previousTrace = previous.getStackTrace();
                    entry = entry.substring(STACK_MORE_START.length(), entry.length() - STACK_MORE_END.length());
                    final int stackCount = Integer.valueOf(entry);
                    stacks.addAll(previousTrace.subList(previousTrace.size() - stackCount, previousTrace.size()));
                    exceptions.add(new ExceptionMessage(description, stacks));

                    // Reset our counters
                    description.clear();
                    stacks.clear();
                } else if (entry.startsWith(CAUSED_START)) {
                    // Finish old exception
                    if (description.size() != 0) {
                        exceptions.add(new ExceptionMessage(description, stacks));
                        description.clear();
                        stacks.clear();
                    }

                    // New exception
                    description.add(entry.substring(CAUSED_START.length()));
                } else {
                    // Random description information
                    description.add(entry);
                }
            }
            description.remove(description.size() - 1); // NOTE_0- There will be a blank line here, see NOTE_0- above
            if (description.size() != 0) {
                exceptions.add(new ExceptionMessage(description, stacks));
            }

            this.exceptions = ImmutableList.copyOf(exceptions);
        } // _STACK_

        while (!it.previous().startsWith(DESCRIPTION_START)) {
        } // This puts us on the line before the "description:"
        it.next(); // Push iterator for description_start to hit twice

        this.description = it.previous().substring(DESCRIPTION_START.length());

        { // _TIMESTAMP_
            final String timeStamp = it.previous().substring(TIME_START.length());
            Date time = null;
            try {
                time = (Date) DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.parseObject(timeStamp);
            } catch (final ParseException ex) {
                try {
                    time = new SimpleDateFormat().parse(timeStamp);
                } catch (final ParseException e) {
                }
            }
            this.time = time == null ? new Date(0l) : time;
        } // _TIMESTAMP_

        it.previous(); // Blank line after joke
        this.fun = it.previous();

        this.nodes = nodes.build();
    }

    @Override
    public StringBuilder appendTo(final StringBuilder builder, final int indent) {
        builder.append(Report.class.getName());
        return StringMaker.appendTo(TYPES, new Object[] { description, fun, nodes, exceptions,
                DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(time), }, builder, indent);
    }

    @Override
    public String toString() {
        return appendTo(new StringBuilder(), 1).toString();
    }
}