Example usage for java.util ListIterator add

List of usage examples for java.util ListIterator add

Introduction

In this page you can find the example usage for java.util ListIterator add.

Prototype

void add(E e);

Source Link

Document

Inserts the specified element into the list (optional operation).

Usage

From source file:com.apptentive.android.sdk.module.engagement.interaction.fragment.MessageCenterFragment.java

private void prepareMessages(final List<MessageCenterListItem> originalItems) {
    listItems.clear();/*from  www.  j a v  a2 s  .  c o m*/
    unsentMessagesCount = 0;
    // Loop through each message item retrieved from database
    for (MessageCenterListItem item : originalItems) {
        if (item instanceof ApptentiveMessage) {
            ApptentiveMessage apptentiveMessage = (ApptentiveMessage) item;
            Double createdAt = apptentiveMessage.getCreatedAt();
            if (apptentiveMessage.isOutgoingMessage() && createdAt == null) {
                unsentMessagesCount++;
            }

            /*
             * Find proper location to insert into the listItems list of the listview.
             */
            ListIterator<MessageCenterListItem> listIterator = listItems.listIterator();
            ApptentiveMessage next = null;
            while (listIterator.hasNext()) {
                next = (ApptentiveMessage) listIterator.next();
                Double nextCreatedAt = next.getCreatedAt();
                // For unsent and dropped message, move the iterator to the end, and append there
                if (createdAt == null || createdAt <= Double.MIN_VALUE) {
                    continue;
                }
                // next message has not received by server or received, but has a later created_at time
                if (nextCreatedAt == null || nextCreatedAt > createdAt) {
                    break;
                }
            }

            if (next == null || next.getCreatedAt() == null || createdAt == null
                    || next.getCreatedAt() <= createdAt || createdAt <= Double.MIN_VALUE) {
                listIterator.add(item);
            } else {
                // Add in front of the message that has later created_at time
                listIterator.set(item);
                listIterator.add(next);
            }
        }
    }
    messagingActionHandler.sendEmptyMessage(MSG_ADD_GREETING);
}

From source file:org.trnltk.experiment.morphology.ambiguity.DataDiffUtil.java

/**
 * Reduce the number of edits by eliminating semantically trivial equalities.
 *
 * @param diffs LinkedList of Diff objects.
 *//*from   ww w  . j ava 2 s.  com*/
public void diff_cleanupSemantic(LinkedList<Diff<T>> diffs) {
    if (diffs.isEmpty()) {
        return;
    }
    boolean changes = false;
    Stack<Diff<T>> equalities = new Stack<Diff<T>>(); // Stack of qualities.
    List<T> lastequality = null; // Always equal to equalities.lastElement().text
    ListIterator<Diff<T>> pointer = diffs.listIterator();
    // Number of characters that changed prior to the equality.
    int length_insertions1 = 0;
    int length_deletions1 = 0;
    // Number of characters that changed after the equality.
    int length_insertions2 = 0;
    int length_deletions2 = 0;
    Diff<T> thisDiff = pointer.next();
    while (thisDiff != null) {
        if (thisDiff.operation == Operation.EQUAL) {
            // Equality found.
            equalities.push(thisDiff);
            length_insertions1 = length_insertions2;
            length_deletions1 = length_deletions2;
            length_insertions2 = 0;
            length_deletions2 = 0;
            lastequality = thisDiff.text;
        } else {
            // An insertion or deletion.
            if (thisDiff.operation == Operation.INSERT) {
                length_insertions2 += thisDiff.text.size();
            } else {
                length_deletions2 += thisDiff.text.size();
            }
            // Eliminate an equality that is smaller or equal to the edits on both
            // sides of it.
            if (lastequality != null && (lastequality.size() <= Math.max(length_insertions1, length_deletions1))
                    && (lastequality.size() <= Math.max(length_insertions2, length_deletions2))) {
                //System.out.println("Splitting: '" + lastequality + "'");
                // Walk back to offending equality.
                while (thisDiff != equalities.lastElement()) {
                    thisDiff = pointer.previous();
                }
                pointer.next();

                // Replace equality with a delete.
                pointer.set(new Diff(Operation.DELETE, lastequality));
                // Insert a corresponding an insert.
                pointer.add(new Diff(Operation.INSERT, lastequality));

                equalities.pop(); // Throw away the equality we just deleted.
                if (!equalities.empty()) {
                    // Throw away the previous equality (it needs to be reevaluated).
                    equalities.pop();
                }
                if (equalities.empty()) {
                    // There are no previous equalities, walk back to the start.
                    while (pointer.hasPrevious()) {
                        pointer.previous();
                    }
                } else {
                    // There is a safe equality we can fall back to.
                    thisDiff = equalities.lastElement();
                    while (thisDiff != pointer.previous()) {
                        // Intentionally empty loop.
                    }
                }

                length_insertions1 = 0; // Reset the counters.
                length_insertions2 = 0;
                length_deletions1 = 0;
                length_deletions2 = 0;
                lastequality = null;
                changes = true;
            }
        }
        thisDiff = pointer.hasNext() ? pointer.next() : null;
    }

    // Normalize the diff.
    if (changes) {
        diff_cleanupMerge(diffs);
    }
    diff_cleanupSemanticLossless(diffs);

    // Find any overlaps between deletions and insertions.
    // e.g: <del>abcxxx</del><ins>xxxdef</ins>
    //   -> <del>abc</del>xxx<ins>def</ins>
    // e.g: <del>xxxabc</del><ins>defxxx</ins>
    //   -> <ins>def</ins>xxx<del>abc</del>
    // Only extract an overlap if it is as big as the edit ahead or behind it.
    pointer = diffs.listIterator();
    Diff<T> prevDiff = null;
    thisDiff = null;
    if (pointer.hasNext()) {
        prevDiff = pointer.next();
        if (pointer.hasNext()) {
            thisDiff = pointer.next();
        }
    }
    while (thisDiff != null) {
        if (prevDiff.operation == Operation.DELETE && thisDiff.operation == Operation.INSERT) {
            List<T> deletion = prevDiff.text;
            List<T> insertion = thisDiff.text;
            int overlap_length1 = this.diff_commonOverlap(deletion, insertion);
            int overlap_length2 = this.diff_commonOverlap(insertion, deletion);
            if (overlap_length1 >= overlap_length2) {
                if (overlap_length1 >= deletion.size() / 2.0 || overlap_length1 >= insertion.size() / 2.0) {
                    // Overlap found. Insert an equality and trim the surrounding edits.
                    pointer.previous();
                    pointer.add(new Diff<T>(Operation.EQUAL, insertion.subList(0, overlap_length1)));
                    prevDiff.text = deletion.subList(0, deletion.size() - overlap_length1);
                    thisDiff.text = insertion.subList(overlap_length1, insertion.size());
                    // pointer.add inserts the element before the cursor, so there is
                    // no need to step past the new element.
                }
            } else {
                if (overlap_length2 >= deletion.size() / 2.0 || overlap_length2 >= insertion.size() / 2.0) {
                    // Reverse overlap found.
                    // Insert an equality and swap and trim the surrounding edits.
                    pointer.previous();
                    pointer.add(new Diff<T>(Operation.EQUAL, deletion.subList(0, overlap_length2)));
                    prevDiff.operation = Operation.INSERT;
                    prevDiff.text = insertion.subList(0, insertion.size() - overlap_length2);
                    thisDiff.operation = Operation.DELETE;
                    thisDiff.text = deletion.subList(overlap_length2, deletion.size());
                    // pointer.add inserts the element before the cursor, so there is
                    // no need to step past the new element.
                }
            }
            thisDiff = pointer.hasNext() ? pointer.next() : null;
        }
        prevDiff = thisDiff;
        thisDiff = pointer.hasNext() ? pointer.next() : null;
    }
}

From source file:org.kuali.kfs.module.bc.document.service.impl.BudgetDocumentServiceImpl.java

/**
 * Reloads benefits target accounting lines. Usually called right after an annual benefits calculation and the display needs
 * updated with a fresh copy from the database. All old row versions are removed and database row versions are inserted in the
 * list in the correct order./*from   w  ww . ja v a2  s.com*/
 * 
 * @param bcDoc
 */
@Transactional
protected void reloadBenefitsLines(BudgetConstructionDocument bcDoc) {

    // get list of potential fringe objects to use as an in query param
    Map<String, Object> fieldValues = new HashMap<String, Object>();
    fieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, bcDoc.getUniversityFiscalYear());
    fieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, bcDoc.getChartOfAccountsCode());

    List<LaborLedgerBenefitsCalculation> benefitsCalculation = kualiModuleService
            .getResponsibleModuleService(LaborLedgerBenefitsCalculation.class)
            .getExternalizableBusinessObjectsList(LaborLedgerBenefitsCalculation.class, fieldValues);

    List<String> fringeObjects = new ArrayList<String>();
    for (LaborLedgerBenefitsCalculation element : benefitsCalculation) {
        fringeObjects.add(element.getPositionFringeBenefitObjectCode());
    }

    List<PendingBudgetConstructionGeneralLedger> dbPBGLFringeLines = budgetConstructionDao
            .getDocumentPBGLFringeLines(bcDoc.getDocumentNumber(), fringeObjects);
    List<PendingBudgetConstructionGeneralLedger> docPBGLExpLines = bcDoc
            .getPendingBudgetConstructionGeneralLedgerExpenditureLines();

    // holds the request sums of removed, added records and used to adjust the document expenditure request total
    KualiInteger docRequestTotals = KualiInteger.ZERO;
    KualiInteger dbRequestTotals = KualiInteger.ZERO;

    // remove the current set of fringe lines
    ListIterator docLines = docPBGLExpLines.listIterator();
    while (docLines.hasNext()) {
        PendingBudgetConstructionGeneralLedger docLine = (PendingBudgetConstructionGeneralLedger) docLines
                .next();
        if (fringeObjects.contains(docLine.getFinancialObjectCode())) {
            docRequestTotals = docRequestTotals.add(docLine.getAccountLineAnnualBalanceAmount());
            docLines.remove();
        }
    }

    // add the dbset of fringe lines, if any
    if (dbPBGLFringeLines != null && !dbPBGLFringeLines.isEmpty()) {

        if (docPBGLExpLines == null || docPBGLExpLines.isEmpty()) {
            docPBGLExpLines.addAll(dbPBGLFringeLines);
        } else {
            ListIterator dbLines = dbPBGLFringeLines.listIterator();
            docLines = docPBGLExpLines.listIterator();
            PendingBudgetConstructionGeneralLedger dbLine = (PendingBudgetConstructionGeneralLedger) dbLines
                    .next();
            PendingBudgetConstructionGeneralLedger docLine = (PendingBudgetConstructionGeneralLedger) docLines
                    .next();
            boolean dbDone = false;
            boolean docDone = false;
            while (!dbDone) {
                if (docDone || docLine.getFinancialObjectCode()
                        .compareToIgnoreCase(dbLine.getFinancialObjectCode()) > 0) {
                    if (!docDone) {
                        docLine = (PendingBudgetConstructionGeneralLedger) docLines.previous();
                    }
                    dbRequestTotals = dbRequestTotals.add(dbLine.getAccountLineAnnualBalanceAmount());
                    dbLine.setPersistedAccountLineAnnualBalanceAmount(
                            dbLine.getAccountLineAnnualBalanceAmount());
                    this.populatePBGLLine(dbLine);
                    docLines.add(dbLine);
                    if (!docDone) {
                        docLine = (PendingBudgetConstructionGeneralLedger) docLines.next();
                    }
                    if (dbLines.hasNext()) {
                        dbLine = (PendingBudgetConstructionGeneralLedger) dbLines.next();
                    } else {
                        dbDone = true;
                    }
                } else {
                    if (docLines.hasNext()) {
                        docLine = (PendingBudgetConstructionGeneralLedger) docLines.next();
                    } else {
                        docDone = true;
                    }
                }
            }
        }
    }

    // adjust the request total for the removed and added recs
    bcDoc.setExpenditureAccountLineAnnualBalanceAmountTotal(
            bcDoc.getExpenditureAccountLineAnnualBalanceAmountTotal()
                    .add(dbRequestTotals.subtract(docRequestTotals)));

}

From source file:org.trnltk.experiment.morphology.ambiguity.DataDiffUtil.java

/**
 * Reorder and merge like edit sections.  Merge equalities.
 * Any edit section can move as long as it doesn't cross an equality.
 *
 * @param diffs LinkedList of Diff objects.
 *///from   w  w w  .  ja  va2  s.  c om
public void diff_cleanupMerge(LinkedList<Diff<T>> diffs) {
    diffs.add(new Diff<T>(Operation.EQUAL, new ArrayList<T>())); // Add a dummy entry at the end.
    ListIterator<Diff<T>> pointer = diffs.listIterator();
    int count_delete = 0;
    int count_insert = 0;
    List<T> text_delete = new ArrayList<T>();
    List<T> text_insert = new ArrayList<T>();
    Diff thisDiff = pointer.next();
    Diff prevEqual = null;
    int commonlength;
    while (thisDiff != null) {
        switch (thisDiff.operation) {
        case INSERT:
            count_insert++;
            text_insert = ListUtils.union(text_insert, thisDiff.text);
            prevEqual = null;
            break;
        case DELETE:
            count_delete++;
            text_delete = ListUtils.union(text_delete, thisDiff.text);
            prevEqual = null;
            break;
        case EQUAL:
            if (count_delete + count_insert > 1) {
                boolean both_types = count_delete != 0 && count_insert != 0;
                // Delete the offending records.
                pointer.previous(); // Reverse direction.
                while (count_delete-- > 0) {
                    pointer.previous();
                    pointer.remove();
                }
                while (count_insert-- > 0) {
                    pointer.previous();
                    pointer.remove();
                }
                if (both_types) {
                    // Factor out any common prefixies.
                    commonlength = diff_commonPrefix(text_insert, text_delete);
                    if (commonlength != 0) {
                        if (pointer.hasPrevious()) {
                            thisDiff = pointer.previous();
                            assert thisDiff.operation == Operation.EQUAL : "Previous diff should have been an equality.";
                            thisDiff.text = ListUtils.union(thisDiff.text,
                                    text_insert.subList(0, commonlength));
                            pointer.next();
                        } else {
                            pointer.add(new Diff(Operation.EQUAL, text_insert.subList(0, commonlength)));
                        }
                        text_insert = text_insert.subList(commonlength, text_insert.size());
                        text_delete = text_delete.subList(commonlength, text_delete.size());
                    }
                    // Factor out any common suffixies.
                    commonlength = diff_commonSuffix(text_insert, text_delete);
                    if (commonlength != 0) {
                        thisDiff = pointer.next();
                        thisDiff.text = ListUtils.union(
                                text_insert.subList(text_insert.size() - commonlength, text_insert.size()),
                                thisDiff.text);
                        text_insert = text_insert.subList(0, text_insert.size() - commonlength);
                        text_delete = text_delete.subList(0, text_delete.size() - commonlength);
                        pointer.previous();
                    }
                }
                // Insert the merged records.
                if (text_delete.size() != 0) {
                    pointer.add(new Diff(Operation.DELETE, text_delete));
                }
                if (text_insert.size() != 0) {
                    pointer.add(new Diff(Operation.INSERT, text_insert));
                }
                // Step forward to the equality.
                thisDiff = pointer.hasNext() ? pointer.next() : null;
            } else if (prevEqual != null) {
                // Merge this equality with the previous one.
                prevEqual.text = ListUtils.union(prevEqual.text, thisDiff.text);
                pointer.remove();
                thisDiff = pointer.previous();
                pointer.next(); // Forward direction
            }
            count_insert = 0;
            count_delete = 0;
            text_delete = new ArrayList<T>();
            text_insert = new ArrayList<T>();
            prevEqual = thisDiff;
            break;
        }
        thisDiff = pointer.hasNext() ? pointer.next() : null;
    }
    if (diffs.getLast().text.size() == 0) {
        diffs.removeLast(); // Remove the dummy entry at the end.
    }

    /*
     * Second pass: look for single edits surrounded on both sides by equalities
     * which can be shifted sideways to eliminate an equality.
     * e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
     */
    boolean changes = false;
    // Create a new iterator at the start.
    // (As opposed to walking the current one back.)
    pointer = diffs.listIterator();
    Diff<T> prevDiff = pointer.hasNext() ? pointer.next() : null;
    thisDiff = pointer.hasNext() ? pointer.next() : null;
    Diff nextDiff = pointer.hasNext() ? pointer.next() : null;
    // Intentionally ignore the first and last element (don't need checking).
    while (nextDiff != null) {
        if (prevDiff.operation == Operation.EQUAL && nextDiff.operation == Operation.EQUAL) {
            // This is a single edit surrounded by equalities.
            if (endsWith(thisDiff.text, prevDiff.text)) {
                // Shift the edit over the previous equality.
                thisDiff.text = ListUtils.union(prevDiff.text,
                        thisDiff.text.subList(0, thisDiff.text.size() - prevDiff.text.size()));
                nextDiff.text = ListUtils.union(prevDiff.text, nextDiff.text);
                pointer.previous(); // Walk past nextDiff.
                pointer.previous(); // Walk past thisDiff.
                pointer.previous(); // Walk past prevDiff.
                pointer.remove(); // Delete prevDiff.
                pointer.next(); // Walk past thisDiff.
                thisDiff = pointer.next(); // Walk past nextDiff.
                nextDiff = pointer.hasNext() ? pointer.next() : null;
                changes = true;
            } else if (startsWith(thisDiff.text, nextDiff.text)) {
                // Shift the edit over the next equality.
                prevDiff.text = ListUtils.union(prevDiff.text, nextDiff.text);
                thisDiff.text = ListUtils.union(
                        thisDiff.text.subList(nextDiff.text.size(), thisDiff.text.size()), nextDiff.text);
                pointer.remove(); // Delete nextDiff.
                nextDiff = pointer.hasNext() ? pointer.next() : null;
                changes = true;
            }
        }
        prevDiff = thisDiff;
        thisDiff = nextDiff;
        nextDiff = pointer.hasNext() ? pointer.next() : null;
    }
    // If shifts were made, the diff needs reordering and another shift sweep.
    if (changes) {
        diff_cleanupMerge(diffs);
    }
}

From source file:com.datatorrent.stram.StreamingContainerManager.java

@SuppressWarnings("StatementWithEmptyBody")
void addCheckpoint(PTOperator node, Checkpoint checkpoint) {
    synchronized (node.checkpoints) {
        if (!node.checkpoints.isEmpty()) {
            Checkpoint lastCheckpoint = node.checkpoints.getLast();
            // skip unless checkpoint moves
            if (lastCheckpoint.windowId != checkpoint.windowId) {
                if (lastCheckpoint.windowId > checkpoint.windowId) {
                    // list needs to have max windowId last
                    LOG.warn("Out of sequence checkpoint {} last {} (operator {})", checkpoint, lastCheckpoint,
                            node);/* w  w  w.  ja  v  a2 s.c o  m*/
                    ListIterator<Checkpoint> li = node.checkpoints.listIterator();
                    while (li.hasNext() && li.next().windowId < checkpoint.windowId) {
                        //continue;
                    }
                    if (li.previous().windowId != checkpoint.windowId) {
                        li.add(checkpoint);
                    }
                } else {
                    node.checkpoints.add(checkpoint);
                }
            }
        } else {
            node.checkpoints.add(checkpoint);
        }
    }
}

From source file:org.trnltk.experiment.morphology.ambiguity.DataDiffUtil.java

/**
 * Reduce the number of edits by eliminating operationally trivial equalities.
 *
 * @param diffs LinkedList of Diff objects.
 *//*from   w  w  w.j a  v a2  s.  co  m*/
public void diff_cleanupEfficiency(LinkedList<Diff<T>> diffs) {
    if (diffs.isEmpty()) {
        return;
    }
    boolean changes = false;
    Stack<Diff> equalities = new Stack<Diff>(); // Stack of equalities.
    List<T> lastequality = null; // Always equal to equalities.lastElement().text
    ListIterator<Diff<T>> pointer = diffs.listIterator();
    // Is there an insertion operation before the last equality.
    boolean pre_ins = false;
    // Is there a deletion operation before the last equality.
    boolean pre_del = false;
    // Is there an insertion operation after the last equality.
    boolean post_ins = false;
    // Is there a deletion operation after the last equality.
    boolean post_del = false;
    Diff<T> thisDiff = pointer.next();
    Diff<T> safeDiff = thisDiff; // The last Diff that is known to be unsplitable.
    while (thisDiff != null) {
        if (thisDiff.operation == Operation.EQUAL) {
            // Equality found.
            if (thisDiff.text.size() < Diff_EditCost && (post_ins || post_del)) {
                // Candidate found.
                equalities.push(thisDiff);
                pre_ins = post_ins;
                pre_del = post_del;
                lastequality = thisDiff.text;
            } else {
                // Not a candidate, and can never become one.
                equalities.clear();
                lastequality = null;
                safeDiff = thisDiff;
            }
            post_ins = post_del = false;
        } else {
            // An insertion or deletion.
            if (thisDiff.operation == Operation.DELETE) {
                post_del = true;
            } else {
                post_ins = true;
            }
            /*
             * Five types to be split:
             * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
             * <ins>A</ins>X<ins>C</ins><del>D</del>
             * <ins>A</ins><del>B</del>X<ins>C</ins>
             * <ins>A</del>X<ins>C</ins><del>D</del>
             * <ins>A</ins><del>B</del>X<del>C</del>
             */
            if (lastequality != null && ((pre_ins && pre_del && post_ins && post_del)
                    || ((lastequality.size() < Diff_EditCost / 2) && ((pre_ins ? 1 : 0) + (pre_del ? 1 : 0)
                            + (post_ins ? 1 : 0) + (post_del ? 1 : 0)) == 3))) {
                //System.out.println("Splitting: '" + lastequality + "'");
                // Walk back to offending equality.
                while (thisDiff != equalities.lastElement()) {
                    thisDiff = pointer.previous();
                }
                pointer.next();

                // Replace equality with a delete.
                pointer.set(new Diff(Operation.DELETE, lastequality));
                // Insert a corresponding an insert.
                pointer.add(thisDiff = new Diff(Operation.INSERT, lastequality));

                equalities.pop(); // Throw away the equality we just deleted.
                lastequality = null;
                if (pre_ins && pre_del) {
                    // No changes made which could affect previous entry, keep going.
                    post_ins = post_del = true;
                    equalities.clear();
                    safeDiff = thisDiff;
                } else {
                    if (!equalities.empty()) {
                        // Throw away the previous equality (it needs to be reevaluated).
                        equalities.pop();
                    }
                    if (equalities.empty()) {
                        // There are no previous questionable equalities,
                        // walk back to the last known safe diff.
                        thisDiff = safeDiff;
                    } else {
                        // There is an equality we can fall back to.
                        thisDiff = equalities.lastElement();
                    }
                    while (thisDiff != pointer.previous()) {
                        // Intentionally empty loop.
                    }
                    post_ins = post_del = false;
                }

                changes = true;
            }
        }
        thisDiff = pointer.hasNext() ? pointer.next() : null;
    }

    if (changes) {
        diff_cleanupMerge(diffs);
    }
}

From source file:hudson.plugins.project_inheritance.projects.InheritanceProject.java

/**
 * Wrapper for {@link #getAllParentReferences(SELECTOR)}, but will add
 * a reference to this project too, if needed.
 * //w  w  w  .  j av  a 2 s.c om
 * @param sortKey the key specifying the order in which projects are returned.
 * @param addSelf if true, add a self-reference in the correct spot
 * @return a list of all parent references, including a self-reference if
 * addSelf is true.
 */
public List<AbstractProjectReference> getAllParentReferences(ProjectReference.PrioComparator.SELECTOR sortKey,
        boolean addSelf) {
    List<AbstractProjectReference> lst = this.getAllParentReferences(sortKey);

    if (addSelf) {
        boolean hasAddedSelf = false;
        ListIterator<AbstractProjectReference> iter = lst.listIterator();
        while (iter.hasNext()) {
            AbstractProjectReference ref = iter.next();
            int prio;
            if (ref instanceof ProjectReference) {
                prio = PrioComparator.getPriorityFor(ref, sortKey);
            } else {
                //An anonymous ref is always at priority 0
                prio = 0;
            }
            if (!hasAddedSelf && prio > 0) {
                hasAddedSelf = true;
                iter.add(new SimpleProjectReference(this.getFullName()));
            }
        }
        //Check if we were able to add a self-reference at all
        if (!hasAddedSelf) {
            lst.add(new SimpleProjectReference(this.getFullName()));
        }
    }

    return lst;
}

From source file:marytts.modules.phonemiser.AllophoneSet.java

/**
 * Syllabify a string of allophones. If stress markers are provided, they are preserved; otherwise, primary stress will be
 * assigned to the initial syllable./*  ww  w  .j av  a  2 s  . c  o  m*/
 * <p>
 * The syllabification algorithm itself follows the <i>Core Syllabification Principle (CSP)</i> from <blockquote>G.N. Clements
 * (1990) "The role of the sonority cycle in core syllabification." In: J. Kingston &amp; M.E. Beckman (Eds.),
 * <em>Papers in Laboratory Phonology I: Between the Grammar and Physics of Speech</em>, Ch. 17, pp. 283-333, Cambridge
 * University Press.</blockquote>
 *
 * @param phoneString
 *            phoneString
 * @return a syllabified string; individual allophones are separated by spaces, and syllables, by dashes.
 * @throws IllegalArgumentException
 *             if the <b>phoneString</b> is empty or contains a symbol that satisfies none of the following conditions:
 *             <ol>
 *             <li>the symbol corresponds to an Allophone, or</li> <li>the symbol is a stress symbol (cf. {@link Stress}), or
 *             </li> <li>the symbol is a syllable boundary (<code>-</code>)</li>
 *             </ol>
 * 
 */
public String syllabify(String phoneString) throws IllegalArgumentException {
    // Before we process, a sanity check:
    if (phoneString.trim().isEmpty()) {
        throw new IllegalArgumentException("Cannot syllabify empty phone string");
    }

    // First, split phoneString into a List of allophone Strings...
    List<String> allophoneStrings = splitIntoAllophoneList(phoneString, true);
    // ...and create from it a List of generic Objects
    List<Object> phonesAndSyllables = new ArrayList<Object>(allophoneStrings);

    // Create an iterator
    ListIterator<Object> iterator = phonesAndSyllables.listIterator();

    // First iteration (left-to-right):
    // CSP (a): Associate each [+syllabic] segment to a syllable node.
    Syllable currentSyllable = null;
    while (iterator.hasNext()) {
        String phone = (String) iterator.next();
        try {
            // either it's an Allophone
            Allophone allophone = getAllophone(phone);
            if (allophone.isSyllabic()) {
                // if /6/ immediately follows a non-diphthong vowel, it should be appended instead of forming its own syllable
                boolean appendR = false;
                if (allophone.getFeature("ctype").equals("r")) {
                    // it's an /6/
                    if (iterator.previousIndex() > 1) {
                        Object previousPhoneOrSyllable = phonesAndSyllables.get(iterator.previousIndex() - 1);
                        if (previousPhoneOrSyllable == currentSyllable) {
                            // the /6/ immediately follows the current syllable
                            if (!currentSyllable.getLastAllophone().isDiphthong()) {
                                // the vowel immediately preceding the /6/ is not a diphthong
                                appendR = true;
                            }
                        }
                    }
                }
                if (appendR) {
                    iterator.remove();
                    currentSyllable.appendAllophone(allophone);
                } else {
                    currentSyllable = new Syllable(allophone);
                    iterator.set(currentSyllable);
                }
            }
        } catch (IllegalArgumentException e) {
            // or a stress or boundary marker
            if (!getIgnoreChars().contains(phone)) {
                throw e;
            }
        }
    }

    // Second iteration (right-to-left):
    // CSP (b): Given P (an unsyllabified segment) preceding Q (a syllabified segment), adjoin P to the syllable containing Q
    // iff P has lower sonority rank than Q (iterative).
    currentSyllable = null;
    boolean foundPrimaryStress = false;
    iterator = phonesAndSyllables.listIterator(phonesAndSyllables.size());
    while (iterator.hasPrevious()) {
        Object phoneOrSyllable = iterator.previous();
        if (phoneOrSyllable instanceof Syllable) {
            currentSyllable = (Syllable) phoneOrSyllable;
        } else if (currentSyllable == null) {
            // haven't seen a Syllable yet in this iteration
            continue;
        } else {
            String phone = (String) phoneOrSyllable;
            try {
                // it's an Allophone -- prepend to the Syllable
                Allophone allophone = getAllophone(phone);
                if (allophone.sonority() < currentSyllable.getFirstAllophone().sonority()) {
                    iterator.remove();
                    currentSyllable.prependAllophone(allophone);
                }
            } catch (IllegalArgumentException e) {
                // it's a provided stress marker -- assign it to the Syllable
                switch (phone) {
                case Stress.PRIMARY:
                    iterator.remove();
                    currentSyllable.setStress(Stress.PRIMARY);
                    foundPrimaryStress = true;
                    break;
                case Stress.SECONDARY:
                    iterator.remove();
                    currentSyllable.setStress(Stress.SECONDARY);
                    break;
                case "-":
                    iterator.remove();
                    // TODO handle syllable boundaries
                    break;
                default:
                    throw e;
                }
            }
        }
    }

    // Third iteration (left-to-right):
    // CSP (c): Given Q (a syllabified segment) followed by R (an unsyllabified segment), adjoin R to the syllable containing
    // Q iff has a lower sonority rank than Q (iterative).
    Syllable initialSyllable = currentSyllable;
    currentSyllable = null;
    iterator = phonesAndSyllables.listIterator();
    while (iterator.hasNext()) {
        Object phoneOrSyllable = iterator.next();
        if (phoneOrSyllable instanceof Syllable) {
            currentSyllable = (Syllable) phoneOrSyllable;
        } else {
            String phone = (String) phoneOrSyllable;
            try {
                // it's an Allophone -- append to the Syllable
                Allophone allophone;
                try {
                    allophone = getAllophone(phone);
                } catch (IllegalArgumentException e) {
                    // or a stress or boundary marker -- remove
                    if (getIgnoreChars().contains(phone)) {
                        iterator.remove();
                        continue;
                    } else {
                        throw e;
                    }
                }
                if (currentSyllable == null) {
                    // haven't seen a Syllable yet in this iteration
                    iterator.remove();
                    if (initialSyllable == null) {
                        // haven't seen any syllable at all
                        initialSyllable = new Syllable(allophone);
                        iterator.add(initialSyllable);
                    } else {
                        initialSyllable.prependAllophone(allophone);
                    }
                } else {
                    // append it to the last seen Syllable
                    iterator.remove();
                    currentSyllable.appendAllophone(allophone);
                }
            } catch (IllegalArgumentException e) {
                throw e;
            }
        }
    }

    // if primary stress was not provided, assign it to initial syllable
    if (!foundPrimaryStress) {
        initialSyllable.setStress(Stress.PRIMARY);
    }

    // join Syllables with dashes and return the String
    return StringUtils.join(phonesAndSyllables, " - ");
}

From source file:pku.sei.checkedcoverage.tracer.instrumentation.TracingMethodInstrumenter.java

@SuppressWarnings("unchecked")
public void transform(final ListIterator<MethodNode> methodIt) {

    // do not modify abstract or native methods
    if ((this.methodNode.access & ACC_ABSTRACT) != 0 || (this.methodNode.access & ACC_NATIVE) != 0)
        return;/*from ww w .ja v  a2 s .  c  o  m*/

    // check out what labels are jump targets (only these have to be traced)
    analyze(this.methodNode);

    this.instructionIterator = new FixedInstructionIterator(this.methodNode.instructions);
    // in the old method, initialize the new local variable for the threadtracer
    this.instructionIterator.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(Tracer.class),
            "getInstance", "()L" + Type.getInternalName(Tracer.class) + ";"));
    this.instructionIterator.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(Tracer.class),
            "getThreadTracer", "()L" + Type.getInternalName(ThreadTracer.class) + ";"));
    this.instructionIterator.add(new InsnNode(DUP));
    this.instructionIterator.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));

    this.instructionIterator.add(
            new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class), "isPaused", "()Z"));
    final LabelNode noTracingLabel = new LabelNode();
    this.instructionIterator.add(new JumpInsnNode(IFNE, noTracingLabel));
    // create a copy of the (uninstrumented) instructions (later, while iterating through the instructions)
    final InsnList oldInstructions = new InsnList();
    final Map<LabelNode, LabelNode> labelCopies = LazyMap.decorate(new HashMap<LabelNode, LabelNode>(),
            new Factory() {
                @Override
                public Object create() {
                    return new LabelNode();
                }
            });
    // copy the try-catch-blocks
    final Object[] oldTryCatchblockNodes = this.methodNode.tryCatchBlocks.toArray();
    for (final Object o : oldTryCatchblockNodes) {
        final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        final TryCatchBlockNode newTcb = new TryCatchBlockNode(labelCopies.get(tcb.start),
                labelCopies.get(tcb.end), labelCopies.get(tcb.handler), tcb.type);
        this.methodNode.tryCatchBlocks.add(newTcb);
    }

    // increment number of local variables by one (for the threadtracer)
    ++this.methodNode.maxLocals;

    // and increment all local variable indexes after the new one by one
    for (final Object o : this.methodNode.localVariables) {
        final LocalVariableNode localVar = (LocalVariableNode) o;
        if (localVar.index >= this.tracerLocalVarIndex)
            ++localVar.index;
    }

    // store information about local variables in the ReadMethod object
    List<LocalVariable> localVariables = new ArrayList<LocalVariable>();
    for (final Object o : this.methodNode.localVariables) {
        final LocalVariableNode localVar = (LocalVariableNode) o;
        while (localVariables.size() <= localVar.index)
            localVariables.add(null);
        localVariables.set(localVar.index, new LocalVariable(localVar.index, localVar.name, localVar.desc));
    }
    this.readMethod.setLocalVariables(localVariables.toArray(new LocalVariable[localVariables.size()]));
    localVariables = null;

    // each method must start with a (dedicated) label:
    assert this.readMethod.getInstructions().isEmpty();
    traceLabel(null, InstructionType.METHODENTRY);
    assert this.readMethod.getInstructions().size() == 1
            && this.readMethod.getInstructions().get(0) instanceof LabelMarker
            && ((LabelMarker) this.readMethod.getInstructions().get(0)).isAdditionalLabel();
    this.readMethod.setMethodEntryLabel((LabelMarker) this.readMethod.getInstructions().get(0));

    // needed later:
    final LabelNode l0 = new LabelNode();
    this.instructionIterator.add(l0);

    // then, visit the instructions that were in the method before
    while (this.instructionIterator.hasNext()) {
        final AbstractInsnNode insnNode = this.instructionIterator.next();
        switch (insnNode.getType()) {
        case AbstractInsnNode.INSN:
            transformInsn((InsnNode) insnNode);
            break;
        case AbstractInsnNode.INT_INSN:
            transformIntInsn((IntInsnNode) insnNode);
            break;
        case AbstractInsnNode.VAR_INSN:
            transformVarInsn((VarInsnNode) insnNode);
            break;
        case AbstractInsnNode.TYPE_INSN:
            transformTypeInsn((TypeInsnNode) insnNode);
            break;
        case AbstractInsnNode.FIELD_INSN:
            transformFieldInsn((FieldInsnNode) insnNode);
            break;
        case AbstractInsnNode.METHOD_INSN:
            transformMethodInsn((MethodInsnNode) insnNode);
            break;
        case AbstractInsnNode.JUMP_INSN:
            transformJumpInsn((JumpInsnNode) insnNode);
            break;
        case AbstractInsnNode.LABEL:
            transformLabel((LabelNode) insnNode);
            break;
        case AbstractInsnNode.LDC_INSN:
            transformLdcInsn((LdcInsnNode) insnNode);
            break;
        case AbstractInsnNode.IINC_INSN:
            transformIincInsn((IincInsnNode) insnNode);
            break;
        case AbstractInsnNode.TABLESWITCH_INSN:
            transformTableSwitchInsn((TableSwitchInsnNode) insnNode);
            break;
        case AbstractInsnNode.LOOKUPSWITCH_INSN:
            transformLookupSwitchInsn((LookupSwitchInsnNode) insnNode);
            break;
        case AbstractInsnNode.MULTIANEWARRAY_INSN:
            transformMultiANewArrayInsn((MultiANewArrayInsnNode) insnNode);
            break;
        case AbstractInsnNode.FRAME:
            // ignore
            break;
        case AbstractInsnNode.LINE:
            // ignore
            break;
        default:
            throw new RuntimeException("Unknown instruction type " + insnNode.getType() + " ("
                    + insnNode.getClass().getSimpleName() + ")");
        }
        oldInstructions.add(insnNode.clone(labelCopies));
    }

    assert this.outstandingInitializations == 0;

    // add the (old) try-catch blocks to the readMethods
    // (can only be done down here since we use the information in the
    // labels map)
    for (final Object o : oldTryCatchblockNodes) {
        final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        this.readMethod.addTryCatchBlock(new TryCatchBlock(this.labels.get(tcb.start), this.labels.get(tcb.end),
                this.labels.get(tcb.handler), tcb.type));
    }

    final LabelNode l1 = new LabelNode();
    this.instructionIterator.add(l1);
    final int newPos = this.readMethod.getInstructions().size();
    traceLabel(null, InstructionType.METHODEXIT);
    assert this.readMethod.getInstructions().size() == newPos + 1;
    final AbstractInstruction abnormalTerminationLabel = this.readMethod.getInstructions().get(newPos);
    assert abnormalTerminationLabel instanceof LabelMarker;
    this.readMethod.setAbnormalTerminationLabel((LabelMarker) abnormalTerminationLabel);
    this.methodNode.instructions.add(new InsnNode(ATHROW));

    // add a try catch block around the method so that we can trace when this method is left
    // a thrown exception
    this.methodNode.tryCatchBlocks.add(new TryCatchBlockNode(l0, l1, l1, null));

    // now add the code that is executed if no tracing should be performed
    this.methodNode.instructions.add(noTracingLabel);
    if (this.firstLine != -1)
        this.methodNode.instructions.add(new LineNumberNode(this.firstLine, noTracingLabel));
    this.methodNode.instructions.add(new InsnNode(ACONST_NULL));
    this.methodNode.instructions.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));
    this.methodNode.instructions.add(oldInstructions);

    // finally: create a copy of the method that gets the ThreadTracer as argument
    // this is only necessary for private methods or "<init>"
    if (this.tracer.wasRedefined(this.readMethod.getReadClass().getName())
            && (this.methodNode.access & ACC_PRIVATE) != 0) {
        final Type[] oldMethodArguments = Type.getArgumentTypes(this.methodNode.desc);
        final Type[] newMethodArguments = Arrays.copyOf(oldMethodArguments, oldMethodArguments.length + 1);
        newMethodArguments[oldMethodArguments.length] = Type.getType(ThreadTracer.class);
        final String newMethodDesc = Type.getMethodDescriptor(Type.getReturnType(this.methodNode.desc),
                newMethodArguments);
        final MethodNode newMethod = new MethodNode(this.methodNode.access, this.methodNode.name, newMethodDesc,
                this.methodNode.signature,
                (String[]) this.methodNode.exceptions.toArray(new String[this.methodNode.exceptions.size()]));
        methodIt.add(newMethod);

        int threadTracerParamPos = ((this.readMethod.getAccess() & Opcodes.ACC_STATIC) == 0 ? 1 : 0);
        for (final Type t : oldMethodArguments)
            threadTracerParamPos += t.getSize();

        final Map<LabelNode, LabelNode> newMethodLabels = LazyMap.decorate(new HashMap<LabelNode, LabelNode>(),
                new Factory() {
                    @Override
                    public Object create() {
                        return new LabelNode();
                    }
                });

        // copy the local variables information to the new method
        for (final Object o : this.methodNode.localVariables) {
            final LocalVariableNode lv = (LocalVariableNode) o;
            newMethod.localVariables.add(new LocalVariableNode(lv.name, lv.desc, lv.signature,
                    newMethodLabels.get(lv.start), newMethodLabels.get(lv.end), lv.index));
        }

        newMethod.maxLocals = this.methodNode.maxLocals;
        newMethod.maxStack = this.methodNode.maxStack;

        // copy the try-catch-blocks
        for (final Object o : this.methodNode.tryCatchBlocks) {
            final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
            newMethod.tryCatchBlocks.add(new TryCatchBlockNode(newMethodLabels.get(tcb.start),
                    newMethodLabels.get(tcb.end), newMethodLabels.get(tcb.handler), tcb.type));
        }

        // skip the first 6 instructions, replace them with these:
        newMethod.instructions.add(new VarInsnNode(ALOAD, threadTracerParamPos));
        newMethod.instructions.add(new InsnNode(DUP));
        newMethod.instructions.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));
        newMethod.instructions.add(new JumpInsnNode(IFNULL, newMethodLabels.get(noTracingLabel)));
        final Iterator<AbstractInsnNode> oldInsnIt = this.methodNode.instructions.iterator(6);
        // and add all the other instructions
        while (oldInsnIt.hasNext()) {
            final AbstractInsnNode insn = oldInsnIt.next();
            newMethod.instructions.add(insn.clone(newMethodLabels));
        }
    }

    ready();
}

From source file:de.unisb.cs.st.javaslicer.tracer.instrumentation.TracingMethodInstrumenter.java

@SuppressWarnings("unchecked")
public void transform(final ListIterator<MethodNode> methodIt) {

    // do not modify abstract or native methods
    if ((this.methodNode.access & ACC_ABSTRACT) != 0 || (this.methodNode.access & ACC_NATIVE) != 0)
        return;/*w ww .j  a  v a 2s . c  om*/

    // check out what labels are jump targets (only these have to be traced)
    analyze(this.methodNode);

    this.instructionIterator = new FixedInstructionIterator(this.methodNode.instructions);
    // in the old method, initialize the new local variable for the threadtracer
    this.instructionIterator.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(Tracer.class),
            "getInstance", "()L" + Type.getInternalName(Tracer.class) + ";"));
    this.instructionIterator.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(Tracer.class),
            "getThreadTracer", "()L" + Type.getInternalName(ThreadTracer.class) + ";"));
    this.instructionIterator.add(new InsnNode(DUP));
    this.instructionIterator.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));

    this.instructionIterator.add(
            new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class), "isPaused", "()Z"));
    final LabelNode noTracingLabel = new LabelNode();
    this.instructionIterator.add(new JumpInsnNode(IFNE, noTracingLabel));
    // create a copy of the (uninstrumented) instructions (later, while iterating through the instructions)
    final InsnList oldInstructions = new InsnList();
    final Map<LabelNode, LabelNode> labelCopies = LazyMap.decorate(new HashMap<LabelNode, LabelNode>(),
            new Factory() {
                @Override
                public Object create() {
                    return new LabelNode();
                }
            });
    // copy the try-catch-blocks
    final Object[] oldTryCatchblockNodes = this.methodNode.tryCatchBlocks.toArray();
    for (final Object o : oldTryCatchblockNodes) {
        final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        final TryCatchBlockNode newTcb = new TryCatchBlockNode(labelCopies.get(tcb.start),
                labelCopies.get(tcb.end), labelCopies.get(tcb.handler), tcb.type);
        this.methodNode.tryCatchBlocks.add(newTcb);
    }

    // increment number of local variables by one (for the threadtracer)
    ++this.methodNode.maxLocals;

    // and increment all local variable indexes after the new one by one
    for (final Object o : this.methodNode.localVariables) {
        final LocalVariableNode localVar = (LocalVariableNode) o;
        if (localVar.index >= this.tracerLocalVarIndex)
            ++localVar.index;
    }

    // store information about local variables in the ReadMethod object
    List<LocalVariable> localVariables = new ArrayList<LocalVariable>();
    for (final Object o : this.methodNode.localVariables) {
        final LocalVariableNode localVar = (LocalVariableNode) o;
        while (localVariables.size() <= localVar.index)
            localVariables.add(null);
        localVariables.set(localVar.index, new LocalVariable(localVar.index, localVar.name, localVar.desc));
    }
    this.readMethod.setLocalVariables(localVariables.toArray(new LocalVariable[localVariables.size()]));
    localVariables = null;

    // each method must start with a (dedicated) label:
    assert this.readMethod.getInstructions().isEmpty();
    traceLabel(null, InstructionType.METHODENTRY);
    assert this.readMethod.getInstructions().size() == 1
            && this.readMethod.getInstructions().get(0) instanceof LabelMarker
            && ((LabelMarker) this.readMethod.getInstructions().get(0)).isAdditionalLabel();
    this.readMethod.setMethodEntryLabel((LabelMarker) this.readMethod.getInstructions().get(0));

    // needed later:
    final LabelNode l0 = new LabelNode();
    this.instructionIterator.add(l0);

    // then, visit the instructions that were in the method before
    while (this.instructionIterator.hasNext()) {

        final AbstractInsnNode insnNode = this.instructionIterator.next();
        switch (insnNode.getType()) {
        case AbstractInsnNode.INSN:
            transformInsn((InsnNode) insnNode);
            break;
        case AbstractInsnNode.INT_INSN:
            transformIntInsn((IntInsnNode) insnNode);
            break;
        case AbstractInsnNode.VAR_INSN:
            transformVarInsn((VarInsnNode) insnNode);
            break;
        case AbstractInsnNode.TYPE_INSN:
            transformTypeInsn((TypeInsnNode) insnNode);
            break;
        case AbstractInsnNode.FIELD_INSN:
            transformFieldInsn((FieldInsnNode) insnNode);
            break;
        case AbstractInsnNode.METHOD_INSN:
            transformMethodInsn((MethodInsnNode) insnNode);
            break;
        case AbstractInsnNode.JUMP_INSN:
            transformJumpInsn((JumpInsnNode) insnNode);
            break;
        case AbstractInsnNode.LABEL:
            transformLabel((LabelNode) insnNode);
            break;
        case AbstractInsnNode.LDC_INSN:
            transformLdcInsn((LdcInsnNode) insnNode);
            break;
        case AbstractInsnNode.IINC_INSN:
            transformIincInsn((IincInsnNode) insnNode);
            break;
        case AbstractInsnNode.TABLESWITCH_INSN:
            transformTableSwitchInsn((TableSwitchInsnNode) insnNode);
            break;
        case AbstractInsnNode.LOOKUPSWITCH_INSN:
            transformLookupSwitchInsn((LookupSwitchInsnNode) insnNode);
            break;
        case AbstractInsnNode.MULTIANEWARRAY_INSN:
            transformMultiANewArrayInsn((MultiANewArrayInsnNode) insnNode);
            break;
        case AbstractInsnNode.FRAME:
            // ignore
            break;
        case AbstractInsnNode.LINE:
            // ignore
            break;
        default:
            throw new RuntimeException("Unknown instruction type " + insnNode.getType() + " ("
                    + insnNode.getClass().getSimpleName() + ")");
        }
        oldInstructions.add(insnNode.clone(labelCopies));
    }

    assert this.outstandingInitializations == 0;

    // add exception handlers for array allocations, *before* any other exception handler.
    // the Java VM Spec (paragraph 3.10) specified that they are executed in the order in which they
    // appear in the bytecode
    if (this.newArrayErrorHandlers != null) {
        for (Entry<LabelNode, Integer> handler : this.newArrayErrorHandlers.entrySet()) {
            this.methodNode.instructions.add(handler.getKey());
            this.methodNode.instructions.add(new VarInsnNode(ALOAD, this.tracerLocalVarIndex));
            this.methodNode.instructions.add(new InsnNode(ACONST_NULL));
            this.methodNode.instructions.add(getIntConstInsn(handler.getValue()));
            this.methodNode.instructions.add(new MethodInsnNode(INVOKEINTERFACE,
                    Type.getInternalName(ThreadTracer.class), "traceObject", "(Ljava/lang/Object;I)V"));
            this.methodNode.instructions.add(new InsnNode(ATHROW));
        }
        this.newArrayErrorHandlers = null;
    }

    // add the (old) try-catch blocks to the readMethods
    // (can only be done down here since we use the information in the
    // labels map)
    for (final Object o : oldTryCatchblockNodes) {
        final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        this.readMethod.addTryCatchBlock(new TryCatchBlock(this.labels.get(tcb.start), this.labels.get(tcb.end),
                this.labels.get(tcb.handler), tcb.type));
    }

    final LabelNode l1 = new LabelNode();
    this.instructionIterator.add(l1);
    final int newPos = this.readMethod.getInstructions().size();
    traceLabel(null, InstructionType.METHODEXIT);
    assert this.readMethod.getInstructions().size() == newPos + 1;
    final AbstractInstruction abnormalTerminationLabel = this.readMethod.getInstructions().get(newPos);
    assert abnormalTerminationLabel instanceof LabelMarker;
    this.readMethod.setAbnormalTerminationLabel((LabelMarker) abnormalTerminationLabel);
    this.methodNode.instructions.add(new InsnNode(ATHROW));

    // add a try catch block around the method so that we can trace when this method is left
    // by a thrown exception
    this.methodNode.tryCatchBlocks.add(new TryCatchBlockNode(l0, l1, l1, null));

    // now add the code that is executed if no tracing should be performed
    this.methodNode.instructions.add(noTracingLabel);
    if (this.firstLine != -1)
        this.methodNode.instructions.add(new LineNumberNode(this.firstLine, noTracingLabel));
    this.methodNode.instructions.add(new InsnNode(ACONST_NULL));
    this.methodNode.instructions.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));
    this.methodNode.instructions.add(oldInstructions);

    // finally: create a copy of the method that gets the ThreadTracer as argument
    // this is only necessary for private methods or "<init>"
    if (this.tracer.wasRedefined(this.readMethod.getReadClass().getName())
            && (this.methodNode.access & ACC_PRIVATE) != 0) {
        final Type[] oldMethodArguments = Type.getArgumentTypes(this.methodNode.desc);
        final Type[] newMethodArguments = Arrays.copyOf(oldMethodArguments, oldMethodArguments.length + 1);
        newMethodArguments[oldMethodArguments.length] = Type.getType(ThreadTracer.class);
        final String newMethodDesc = Type.getMethodDescriptor(Type.getReturnType(this.methodNode.desc),
                newMethodArguments);
        final MethodNode newMethod = new MethodNode(this.methodNode.access, this.methodNode.name, newMethodDesc,
                this.methodNode.signature,
                (String[]) this.methodNode.exceptions.toArray(new String[this.methodNode.exceptions.size()]));
        methodIt.add(newMethod);

        int threadTracerParamPos = ((this.readMethod.getAccess() & Opcodes.ACC_STATIC) == 0 ? 1 : 0);
        for (final Type t : oldMethodArguments)
            threadTracerParamPos += t.getSize();

        final Map<LabelNode, LabelNode> newMethodLabels = LazyMap.decorate(new HashMap<LabelNode, LabelNode>(),
                new Factory() {
                    @Override
                    public Object create() {
                        return new LabelNode();
                    }
                });

        // copy the local variables information to the new method
        for (final Object o : this.methodNode.localVariables) {
            final LocalVariableNode lv = (LocalVariableNode) o;
            newMethod.localVariables.add(new LocalVariableNode(lv.name, lv.desc, lv.signature,
                    newMethodLabels.get(lv.start), newMethodLabels.get(lv.end), lv.index));
        }

        newMethod.maxLocals = this.methodNode.maxLocals;
        newMethod.maxStack = this.methodNode.maxStack;

        // copy the try-catch-blocks
        for (final Object o : this.methodNode.tryCatchBlocks) {
            final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
            newMethod.tryCatchBlocks.add(new TryCatchBlockNode(newMethodLabels.get(tcb.start),
                    newMethodLabels.get(tcb.end), newMethodLabels.get(tcb.handler), tcb.type));
        }

        // skip the first 6 instructions, replace them with these:
        newMethod.instructions.add(new VarInsnNode(ALOAD, threadTracerParamPos));
        newMethod.instructions.add(new InsnNode(DUP));
        newMethod.instructions.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));
        newMethod.instructions.add(new JumpInsnNode(IFNULL, newMethodLabels.get(noTracingLabel)));
        final Iterator<AbstractInsnNode> oldInsnIt = this.methodNode.instructions.iterator(6);
        // and add all the other instructions
        while (oldInsnIt.hasNext()) {
            final AbstractInsnNode insn = oldInsnIt.next();
            newMethod.instructions.add(insn.clone(newMethodLabels));
        }
    }

    ready();
}