org.tolweb.content.preparers.PageCoPreparer.java Source code

Java tutorial

Introduction

Here is the source code for org.tolweb.content.preparers.PageCoPreparer.java

Source

package org.tolweb.content.preparers;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import nu.xom.Attribute;
import nu.xom.Element;
import nu.xom.Text;

import org.apache.commons.lang.StringEscapeUtils;
import org.tolweb.content.helpers.DaoBundle;
import org.tolweb.content.helpers.MediaContentAttributes;
import org.tolweb.content.helpers.PageContentAttributes;
import org.tolweb.content.helpers.PageContentElements;
import org.tolweb.hibernate.MappedNode;
import org.tolweb.hibernate.MappedOtherName;
import org.tolweb.hibernate.MappedPage;
import org.tolweb.hibernate.MappedTextSection;
import org.tolweb.misc.ContributorLicenseInfo;
import org.tolweb.misc.TextPreparer;
import org.tolweb.treegrow.main.StringUtils;
import org.tolweb.treegrow.page.PageContributor;
import org.tolweb.treegrow.tree.Node;

/* PageCoPreparer
 *   GroupCoPreparer
 *   NameCoPreparer
 *   SubgroupCoPreparer
 *   SectionCoPreparer */

public class PageCoPreparer extends AbstractCoPreparer {
    private static final String IMAGE_REPLACEMENT = "<!-- ToL Image #START# --> "
            + "<a href=\"javascript: w = window.open('http://tolweb.org/media/%1$s'"
            + ", '%1$s', 'resizable,height=600,width=800,scrollbars=yes'); w.focus();\">"
            + "<img src=\"%2$s\"/></a><!-- ToL Image #END# -->";
    private Pattern tolImgRegex;
    private HashMap<Integer, String> embeddedMedia;

    public PageCoPreparer() {
        tolImgRegex = Pattern.compile("<\\s*ToLimg\\s*([^>]*)\\s*id=\"?(\\d+)\"?\\s*([^>]*)>",
                Pattern.CASE_INSENSITIVE);
        embeddedMedia = new HashMap<Integer, String>();
    }

    public void setContentSource(Object mpage, DaoBundle daos, Element doc) {
        setMappedPage((MappedPage) mpage);
        setDaoBundle(daos);
        setParentElement(doc);
        setPreparedElement(doc);
    }

    @SuppressWarnings("unchecked")
    public void processContent() {

        Element page = new Element(PageContentElements.PAGE, ContentPreparer.NS);
        page.addAttribute(new Attribute(PageContentAttributes.ID, "" + getMappedPage().getPageId()));

        String pageNodeNameUrl = getMappedPage().getMappedNode().getName();
        try {
            pageNodeNameUrl = URLEncoder.encode(pageNodeNameUrl, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        String nodeIdString = "" + getMappedPage().getMappedNode().getId();
        pageNodeNameUrl = StringUtils.notEmpty(pageNodeNameUrl) ? pageNodeNameUrl + "/" + nodeIdString
                : nodeIdString;
        String pageUrl = "http://tolweb.org/" + pageNodeNameUrl;
        page.addAttribute(new Attribute(PageContentAttributes.PAGE_URL, pageUrl));
        page.addAttribute(new Attribute(PageContentAttributes.PAGE_STATUS, getMappedPage().getStatus()));
        page.addAttribute(new Attribute(PageContentAttributes.DATE_CREATED,
                getSafeString(getMappedPage().getFirstOnlineString())));
        page.addAttribute(new Attribute(PageContentAttributes.DATE_CHANGED,
                safeToString(getMappedPage().getContentChangedDate())));

        Element group = new Element(PageContentElements.GROUP, ContentPreparer.NS);
        page.appendChild(group);

        group.addAttribute(new Attribute(PageContentAttributes.NODE, "" + getMappedPage().getMappedNode().getId()));
        group.addAttribute(new Attribute(PageContentAttributes.EXTINCT,
                (getMappedPage().getMappedNode().getExtinct() == 2) ? "true" : "false"));
        group.addAttribute(new Attribute(PageContentAttributes.PHYLESIS,
                getPhylesisString(getMappedPage().getMappedNode().getPhylesis())));
        group.addAttribute(new Attribute(PageContentAttributes.LEAF,
                getMappedPage().getMappedNode().getIsLeaf() ? "true" : "false"));

        Element groupDesc = new Element(PageContentElements.GROUP_DESCRIPTION, ContentPreparer.NS);
        String groupDescText = getMappedPage().getMappedNode().getDescription();
        groupDesc.appendChild(new Text(groupDescText));

        if (StringUtils.notEmpty(groupDescText)) {
            group.appendChild(groupDesc);
        }

        Element groupCmt = new Element(PageContentElements.GROUP_COMMENT, ContentPreparer.NS);
        String groupCmtText = getMappedPage().getLeadText();
        groupCmt.appendChild(new Text(groupCmtText));

        if (StringUtils.notEmpty(groupCmtText)) {
            group.appendChild(groupCmt);
        }

        Element names = new Element(PageContentElements.NAMES, ContentPreparer.NS);
        page.appendChild(names);

        Element name = new Element(PageContentElements.NAME, ContentPreparer.NS);
        names.appendChild(name);

        name.appendChild(new Text(getMappedPage().getMappedNode().getName()));
        name.addAttribute(new Attribute(PageContentAttributes.ITALICIZE_NAME,
                Boolean.valueOf(getMappedPage().getMappedNode().getItalicizeName()).toString()));
        name.addAttribute(new Attribute(PageContentAttributes.AUTHORITY,
                getSafeString(getMappedPage().getMappedNode().getNameAuthority())));
        name.addAttribute(new Attribute(PageContentAttributes.AUTH_DATE,
                safeToString(getMappedPage().getMappedNode().getAuthorityDate())));
        name.addAttribute(new Attribute(PageContentAttributes.NAME_COMMENT,
                getSafeString(getMappedPage().getMappedNode().getNameComment())));
        name.addAttribute(new Attribute(PageContentAttributes.NEW_COMBINATION,
                Boolean.valueOf(getMappedPage().getMappedNode().getIsNewCombination()).toString()));
        name.addAttribute(new Attribute(PageContentAttributes.COMBINATION_AUTHOR,
                getSafeString(getMappedPage().getMappedNode().getCombinationAuthor())));
        name.addAttribute(new Attribute(PageContentAttributes.COMBINATION_DATE,
                safeToString(getMappedPage().getMappedNode().getCombinationDate())));

        Element othernames = new Element(PageContentElements.OTHERNAMES, ContentPreparer.NS);

        SortedSet otherNamesSet = getMappedPage().getMappedNode().getSynonyms();

        for (Iterator itr = otherNamesSet.iterator(); itr.hasNext();) {
            MappedOtherName moname = (MappedOtherName) itr.next();
            Element othername = new Element(PageContentElements.OTHERNAME, ContentPreparer.NS);
            othername.addAttribute(new Attribute(PageContentAttributes.ID, "" + moname.getId()));
            othername.addAttribute(new Attribute(PageContentAttributes.ITALICIZE_NAME,
                    Boolean.valueOf(moname.getItalicize()).toString()));
            othername.addAttribute(
                    new Attribute(PageContentAttributes.AUTHORITY, getSafeString(moname.getAuthority())));
            othername.addAttribute(
                    new Attribute(PageContentAttributes.AUTH_DATE, safeToString(moname.getAuthorityYear())));
            othername.addAttribute(
                    new Attribute(PageContentAttributes.NAME_COMMENT, getSafeString(moname.getComment())));
            othername.addAttribute(new Attribute(PageContentAttributes.IS_IMPORTANT,
                    Boolean.valueOf(moname.getIsImportant()).toString()));
            othername.addAttribute(new Attribute(PageContentAttributes.IS_PREFERRED,
                    Boolean.valueOf(moname.getIsPreferred()).toString()));
            othername.addAttribute(new Attribute(PageContentAttributes.SEQUENCE, safeToString(moname.getOrder())));
        }

        if (!otherNamesSet.isEmpty()) {
            names.appendChild(othernames);
        }

        List children = getMappedPage().getMappedNode().getChildren();
        boolean isTerminal = children != null && children.isEmpty();

        // add this if not a leaf or writeaslist is false... or is terminal (e.g. no children)
        if (getMappedPage().getMappedNode().getIsLeaf() && !isTerminal) {
            Element subgroups = new Element(PageContentElements.SUBGROUPS, ContentPreparer.NS);
            page.appendChild(subgroups);

            if (!getMappedPage().getWriteAsList()) {
                Element treeimage = new Element(PageContentElements.TREEIMAGE, ContentPreparer.NS);
                ContributorLicenseInfo currDefault = new ContributorLicenseInfo(
                        ContributorLicenseInfo.TREE_IMAGE_LICENSE);
                treeimage.addAttribute(new Attribute(PageContentAttributes.LICENSE, currDefault.toShortString()));
                String treeImageName = getMappedPage().getGroupName().replaceAll("\\s", "_");
                treeimage
                        .appendChild(new Text("http://www.tolweb.org/Public/treeImages/" + treeImageName + ".png"));
                subgroups.appendChild(treeimage);
            }

            Element newicktree = new Element(PageContentElements.NEWICKTREE, ContentPreparer.NS);
            subgroups.appendChild(newicktree);

            Element taxonlist = new Element(PageContentElements.TAXON_LIST, ContentPreparer.NS);
            taxonlist.appendChild(new Text(StringEscapeUtils.escapeXml(getTaxonListAsHTML())));
            subgroups.appendChild(taxonlist);

            Element treecomment = new Element(PageContentElements.TREE_COMMENT, ContentPreparer.NS);
            subgroups.appendChild(treecomment);
            treecomment.appendChild(new Text(StringEscapeUtils.escapeXml(getMappedPage().getPostTreeText())));
        }

        Element sections = new Element(PageContentElements.SECTIONS, ContentPreparer.NS);
        page.appendChild(sections);

        SortedSet textSections = getMappedPage().getTextSections();
        for (Iterator itr = textSections.iterator(); itr.hasNext();) {
            MappedTextSection mtxt = (MappedTextSection) itr.next();
            Element section = new Element(PageContentElements.SECTION, ContentPreparer.NS);
            section.addAttribute(new Attribute(PageContentAttributes.ID, "" + mtxt.getTextSectionId()));
            section.addAttribute(new Attribute(PageContentAttributes.SECTION_TITLE, mtxt.getHeading()));
            section.addAttribute(new Attribute(PageContentAttributes.PAGE_ORDER, safeToString(mtxt.getOrder())));
            section.addAttribute(
                    new Attribute(PageContentAttributes.COPYRIGHT_DATE, getMappedPage().getCopyrightDate()));
            section.addAttribute(new Attribute(PageContentAttributes.LICENSE,
                    getLicenseShortName(getMappedPage().getUsePermission())));
            section.addAttribute(new Attribute(PageContentAttributes.AUTHORS,
                    getAuthorsIdString(getMappedPage().getContributors())));
            section.addAttribute(new Attribute(PageContentAttributes.CORRESPONDENTS,
                    getCorrespondentsIdString(getMappedPage().getContributors())));
            section.addAttribute(new Attribute(PageContentAttributes.COPYRIGHT_OWNERS,
                    getCopyrightOwnersIdString(getMappedPage().getContributors())));
            section.addAttribute(new Attribute(PageContentAttributes.OTHER_COPYRIGHT,
                    getSafeString(getMappedPage().getCopyrightHolder())));
            section.addAttribute(new Attribute(PageContentAttributes.CONTENT_CHANGED,
                    safeToString(getMappedPage().getContentChangedDate())));

            // add the section-text text element
            Element sectionText = new Element(PageContentElements.SECTION_TEXT, ContentPreparer.NS);
            sectionText.appendChild(new Text(processSectionText(mtxt.getText(), pageUrl)));
            section.appendChild(sectionText);

            Element sectionMedia = new Element(PageContentElements.SECTION_MEDIA, ContentPreparer.NS);
            processSectionMedia(sectionMedia);
            section.appendChild(sectionMedia);

            // add the section-source element
            Element sectionSource = new Element(PageContentElements.SECTION_SOURCE, ContentPreparer.NS);
            // TODO add attribute data to section-source
            section.appendChild(sectionSource);

            String sectionAnchor = mtxt.getHeadingNoSpaces();
            sectionSource.addAttribute(new Attribute(PageContentAttributes.SOURCE_COLLECTION, "0"));
            sectionSource.addAttribute(new Attribute(PageContentAttributes.SOURCE_TITLE, mtxt.getHeading()));
            sectionSource.addAttribute(new Attribute(PageContentAttributes.SOURCE_URL,
                    "http://tolweb.org/" + pageNodeNameUrl + "#" + sectionAnchor));
            sectionSource.addAttribute(new Attribute(PageContentAttributes.MORE_SOURCE, "[future-use]"));

            sections.appendChild(section);
        }

        Element refs = new Element(PageContentElements.REFERENCES, ContentPreparer.NS);
        page.appendChild(refs);
        TextPreparer txtPrep = new TextPreparer();
        List refsList = txtPrep.getNewlineSeparatedList(getMappedPage().getReferences());
        for (Iterator itr = refsList.iterator(); itr.hasNext();) {
            String ref = (String) itr.next();
            // only add the reference element if it's not empty
            if (StringUtils.notEmpty(ref)) {
                Element refEl = new Element(PageContentElements.REFERENCE, ContentPreparer.NS);
                refEl.appendChild(new Text(StringEscapeUtils.escapeXml(ref)));
                refs.appendChild(refEl);
            }
        }

        Element internetInfo = new Element(PageContentElements.INTERNET_INFO, ContentPreparer.NS);
        page.appendChild(internetInfo);
        internetInfo.appendChild(new Text(StringEscapeUtils.escapeXml(getMappedPage().getInternetInfo())));

        getElement().appendChild(page);
    }

    private void processSectionMedia(Element sectionMedia) {
        // for each embedded media found in the text-section, add it to the media section as a media-set
        for (Map.Entry<Integer, String> entry : embeddedMedia.entrySet()) {
            Element sectionMediaSet = new Element(PageContentElements.MEDIA_SET, ContentPreparer.NS);
            sectionMediaSet.addAttribute(new Attribute(PageContentAttributes.ID, "" + entry.getKey()));
            sectionMediaSet.addAttribute(new Attribute(MediaContentAttributes.THUMBNAIL, entry.getValue()));
            sectionMedia.appendChild(sectionMediaSet);
        }
        // hey - we're in a loop, and it's got "text-section" locality, so we need to clear this 
        // hashmap out before the next text-section is processed
        embeddedMedia.clear();
    }

    private String processSectionText(String sectionText, String pageUrl) {

        // handles href="#link", href="/link", and href="../"
        sectionText = processAnchors(sectionText, pageUrl);
        // as method suggests, this is a temporary solution to resolving embedded image tags in section text
        sectionText = tmpProcessToLImageTags(sectionText);
        // strip out class, id, and style attributes from embedded markup
        sectionText = stripOutClassIdStyleAttributes(sectionText);
        return StringEscapeUtils.escapeXml(sectionText);
    }

    private String stripOutClassIdStyleAttributes(String sectionText) {
        sectionText = sectionText
                .replaceAll("<\\s*([^>]*)\\s*([^>]*)\\s*((class|[^_]id|style)=\"?[^>]*\"?)\\s*([^>]*)>", "<$1>");
        return sectionText;
    }

    private String tmpProcessToLImageTags(String sectionText) {
        //javascript: w = window.open('/onlinecontributors/app?service=external/ViewImageData&sp=1539', '1539', 'resizable,height=500,width=670,scrollbars=yes'); w.focus();
        //      sectionText = sectionText.replaceAll("<\\s*ToLimg\\s*([^>]*)\\s*id=\"?(\\d+)\"?\\s*([^>]*)>", 
        //            "<a href=\"javascript: w = window.open('http://tolweb.org/media/$2', '$2', 'resizable,height=600,width=800,scrollbars=yes'); w.focus();\">Tree of Life Image</a>");

        if (sectionText != null) {
            StringBuffer buffer = new StringBuffer();
            Matcher matcher = tolImgRegex.matcher(sectionText);
            while (matcher.find()) {
                String tolMediaId = matcher.group(2);
                Integer id = Integer.valueOf(tolMediaId);
                String thumbnailUrl = getDaoBundle().getImageDAO().getThumbnailUrlForImageWithId(id.intValue());
                if (!thumbnailUrl.startsWith("/tree")) {
                    thumbnailUrl = "http://tolweb.org/tree" + thumbnailUrl;
                } else {
                    thumbnailUrl = "http://tolweb.org" + thumbnailUrl;
                }
                embeddedMedia.put(id, thumbnailUrl);
                String fmt = IMAGE_REPLACEMENT;
                String output = String.format(fmt, id, thumbnailUrl);
                matcher.appendReplacement(buffer, output);
            }
            matcher.appendTail(buffer);
            return buffer.toString();
        } else {
            return "";
        }
    }

    private String processAnchors(String sectionText, String pageUrl) {
        sectionText = sectionText.replaceAll("href=\"#(.*)\"", "href=\"" + pageUrl + "#$1\"");
        sectionText = sectionText.replaceAll("href=\"(\\.\\.)?/([^>]*)\"([^<])*>",
                "href=\"http://tolweb.org/$2\">");
        return sectionText;
    }

    @SuppressWarnings("unchecked")
    private String getAuthorsIdString(Collection contributors) {
        ArrayList names = new ArrayList();
        Iterator it = contributors.iterator();
        while (it.hasNext()) {
            PageContributor contr = (PageContributor) it.next();
            if (contr.getIsAuthor()) {
                names.add(contr.getContributor().getId());
            }
        }
        return StringUtils.returnCommaJoinedString(names);
    }

    @SuppressWarnings("unchecked")
    private String getCorrespondentsIdString(Collection contributors) {
        ArrayList names = new ArrayList();
        Iterator it = contributors.iterator();
        while (it.hasNext()) {
            PageContributor contr = (PageContributor) it.next();
            if (contr.getIsContact()) {
                names.add(contr.getContributor().getId());
            }
        }
        return StringUtils.returnCommaJoinedString(names);
    }

    @SuppressWarnings("unchecked")
    private String getCopyrightOwnersIdString(Collection contributors) {
        ArrayList names = new ArrayList();
        Iterator it = contributors.iterator();
        while (it.hasNext()) {
            PageContributor contr = (PageContributor) it.next();
            if (contr.getIsCopyOwner()) {
                names.add(contr.getContributor().getId());
            }
        }
        return StringUtils.returnCommaJoinedString(names);
    }

    private String getLicenseShortName(byte licenseCode) {
        ContributorLicenseInfo cLicInfo = new ContributorLicenseInfo(licenseCode);
        return cLicInfo.toShortString();
    }

    private String getPhylesisString(int phylesis) {
        if (phylesis == Node.MONOPHYLETIC) {
            return "monophyletic";
        } else if (phylesis == Node.MONOPHYLY_UNCERTAIN) {
            return "monophyletic uncertain";
        } else if (phylesis == Node.NOT_MONOPHYLETIC) {
            return "not monophyletic";
        } else {
            return "";
        }
    }

    @SuppressWarnings("unchecked")
    private String getTaxonListAsHTML() {
        List nodes = getDaoBundle().getPageDAO().getOrderedByParentNodesOnPage(getMappedPage(), true);
        MappedNode rootNode = getMappedPage().getMappedNode();
        nodes.add(rootNode);
        // build a hashtable to set up the tree structure
        Hashtable<Long, MappedNode> idsToNodes = new Hashtable();
        for (Iterator iter = nodes.iterator(); iter.hasNext();) {
            MappedNode nextNode = (MappedNode) iter.next();
            idsToNodes.put(nextNode.getNodeId(), nextNode);
        }
        for (Iterator iter = nodes.iterator(); iter.hasNext();) {
            MappedNode nextNode = (MappedNode) iter.next();
            // get our parent and add ourselves to the children of the parent
            MappedNode parent = idsToNodes.get(nextNode.getParentNodeId());
            if (parent != null) {
                parent.addToChildren(nextNode);
            }
        }
        StringBuffer list = new StringBuffer();
        list.append("<ul>");
        traverseTaxonTree(list, rootNode);
        list.append("</ul>");
        return list.toString();
    }

    @SuppressWarnings("unchecked")
    private void traverseTaxonTree(StringBuffer buff, MappedNode curr) {
        if (curr != null) {
            boolean emptyOrInternal = StringUtils.notEmpty(curr.getName());
            if (emptyOrInternal) {
                buff.append("<li>" + curr.getName());
            }
            List children = curr.getChildren();
            if (!children.isEmpty()) {
                if (emptyOrInternal) {
                    buff.append("<ul>");
                }
                for (Iterator itr = children.iterator(); itr.hasNext();) {
                    MappedNode child = (MappedNode) itr.next();
                    traverseTaxonTree(buff, child);
                }
                if (emptyOrInternal) {
                    buff.append("</ul>");
                }
            }
            if (emptyOrInternal) {
                buff.append("</li>");
            }
        }
    }
    /*
       private void traverseTree(NodeDAO ndao, MappedNode curr) {
          if (curr != null) {
     System.out.println(" " + curr.getName());
     increment();
     curr.setTreeOrder(getCounterValue());
              
     List children = ndao.getChildrenNodes(curr);
                  
     for (Iterator i = children.iterator(); i.hasNext(); ) {
        MappedNode child = (MappedNode)i.next();
        System.out.println("\t child:" + child.getName());
        traverseTree(ndao, child);
     }
         
     ndao.saveNode(curr);
          }
       }
     */

    /*
        private void createListForNode(IMarkupWriter writer, MappedNode node, boolean isRoot, int currentRank, Integer parentRank, Long projectId) {
    Integer classInteger = null;
    boolean openedAdditionalList = false;
    boolean openedLi = false;
    Iterator it;
    if (getNodes() == null) { 
       it = getNodeDAO().getChildrenNodes(node, !isRoot, false).itprocessSectionMedia(sectionMedia);erator();
    } else {
       List childNodes = getNodes().get(node.getNodeId());
       if (childNodes != null) {
          it = childNodes.iterator();
       } else {
          List list = new ArrayList<Object>();
          it = list.iterator();
       }
    }        
    boolean hasChildren = it.hasNext();
    if (!isRoot && StringUtils.notEmpty(node.getName())) {
       PageDAO dao = getPageDAO();
        boolean hasPage = dao.getNodeHasPage(node);
        boolean hadFakeParent = false;
        // If there is no page, then do this fake parent child relationship
        // with the supertitle
        if (!hasPage && node.getPageSupertitle() != null) {
            hadFakeParent = true;
            writer.begin("li");
            if ((classInteger = getRankInteger(parentRank, node, currentRank)) != null) {
                writer.attribute("class", "over" + classInteger);                    
            }
            writer.begin("em");
            String emClass = getEmClass(((MappedOtherName) node.getFirstPreferredOtherName()).getItalicize(), 
                  false);
            String name = node.getActualPageTitle(false, true, true);
            writer.attribute("class", emClass);
            writer.printRaw(name);
            if (node.getShowAuthorityInContainingGroup()) {
                addAuthority(writer, node.getPageAuthority());
            }   
            writer.end("em");
            writer.printRaw("\n");
            // Open an additional unordered list in order to create
            // the appearance of another node in the tree
            writer.begin("ul");
            // we won't make the fake parent collapsable or render the links
            writer.attribute("class", getDefaultUlClass());
            writer.printRaw("\n");
            openedAdditionalList = true;
        }
        openedLi = true;
        writer.begin("li");
        if ((classInteger = getRankInteger(parentRank, node, currentRank)) != null) {
            writer.attribute("class", "over" + classInteger);
            currentRank = node.getNodeRankInteger().intValue();
        }
        String emClass = getEmClass(node.getItalicizeName(), hasChildren);
        writer.begin("em");
        writer.attribute("class", emClass);
        writer.attribute("id", getEmIdForNode(node));
        String titleLinkString = getIsIndex() ? " title=\"go to Taxon Sampling page\"" : " title=\"go to ToL page\"";
         // when we want to write a taxon index link:
        boolean writeTaxonIndexLink = getNodeNameBlock() != null && hasChildren;
            
        String linkString = getPageNameForNode(node);
        if (writeTaxonIndexLink || hasPage) {
            String name = node.getName();
            if (getNodeNameBlock() == null) {
               String branchPageUrl = getURLBuilder().getURLForBranchPage(URLBuilder.NO_HOST_PREFIX, name, node.getNodeId());                   
                writer.printRaw("<a href=\"" + branchPageUrl + "\"" + titleLinkString + " >" + linkString + "</a>");                   
            } else if (writeTaxonIndexLink) {
                String url = "/onlinecontributors/app?service=external&page=TaxaIndex&sp=l" + node.getNodeId() + "&sp=l" + projectId;
                writer.printRaw("<a href=\"" + url + "\" " + titleLinkString + " >" + linkString + "</a>");               
            } else {
                writer.printRaw(name);
            }
        } else {
            String nodeName = node.getName();
            writer.printRaw(nodeName);
        }
        
               
            
        writer.end("em");
        // tack on the authority after the name
        if (node.getShowAuthorityInContainingGroup()) {
            String authString = hadFakeParent ? node.getNodeAuthority() : node.getPageAuthority();
            addAuthority(writer, authString);
        }   
        if (!getIsIndex()) {
           if (node.getExtinct() == Node.EXTINCT) {
               writer.printRaw(" <img src=\"/tree/icons/extinct.gif\" width=\"7\" height=\"9\">");
           }
           if (StringUtils.notEmpty(node.getDescription())) {
               writer.printRaw("  <span class=\"description\">" + node.getDescription() + "</span>");
           }
           if (node.getPhylesis() == Node.MONOPHYLY_UNCERTAIN) {
               writer.printRaw("<span class=\"property\"> (monophyly uncertain) </span>");
           } else if (node.getPhylesis() == Node.NOT_MONOPHYLETIC) {
               writer.printRaw("<span class=\"property\"> (non-monophyletic) </span>");
           }
           if (node.getConfidence() == Node.INCERT_PUTATIVE || node.getConfidence() == Node.INCERT_UNSPECIFIED) {
               writer.printRaw("<span class=\"property\"> (incertae sedis) </span>");
           }
        } 
    }
    boolean openedList = false;
    if (!isRoot && it.hasNext() && StringUtils.notEmpty(node.getName())) {
       String listId = getUlIdForNode(node);           
        writer.begin("ul");
        writer.attribute("id", listId);
        writer.attribute("class", getDefaultUlClass());
        if (getIsIndex()) {
           String expandClosedAttribute = getIndexPage().getExpandMostAttribute(node);
           if (expandClosedAttribute != null) {
              writer.attribute(TaxaIndex.SHOW_MOST, expandClosedAttribute);
           }
        }
        writer.printRaw("\n");
        openedList = true;
        currentRank += 1;
    } 
    while (it.hasNext()) {
        MappedNode nextChild = (MappedNode) it.next();
        createListForNode(writer, nextChild, false, currentRank, classInteger, projectId);
    }
    if (openedList) {
       closeList(writer);
    }
    if (openedLi) {
       closeListElement(writer);
    }
    if (openedAdditionalList) {
       closeList(writer);
        closeListElement(writer);
    }
        }
     */
}