Source Code Cross Referenced for Help.java in  » Web-Framework » argun » biz » hammurapi » web » menu » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Framework » argun » biz.hammurapi.web.menu 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * argun 1.0
0003:         * Web 2.0 delivery framework 
0004:         * Copyright (C) 2007  Hammurapi Group
0005:         *
0006:         * This program is free software; you can redistribute it and/or
0007:         * modify it under the terms of the GNU Lesser General Public
0008:         * License as published by the Free Software Foundation; either
0009:         * version 2 of the License, or (at your option) any later version.
0010:         *
0011:         * This program is distributed in the hope that it will be useful,
0012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014:         * Lesser General Public License for more details.
0015:         *
0016:         * You should have received a copy of the GNU Lesser General Public
0017:         * License along with this library; if not, write to the Free Software
0018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0019:         *
0020:         * URL: http://www.hammurapi.biz
0021:         * e-Mail: support@hammurapi.biz 
0022:         */
0023:        package biz.hammurapi.web.menu;
0024:
0025:        import java.io.IOException;
0026:        import java.io.StringReader;
0027:        import java.io.Writer;
0028:        import java.lang.ref.Reference;
0029:        import java.lang.ref.SoftReference;
0030:        import java.sql.SQLException;
0031:        import java.util.ArrayList;
0032:        import java.util.Collection;
0033:        import java.util.HashMap;
0034:        import java.util.HashSet;
0035:        import java.util.Iterator;
0036:        import java.util.List;
0037:        import java.util.Map;
0038:        import java.util.Set;
0039:        import java.util.StringTokenizer;
0040:        import java.util.TreeMap;
0041:
0042:        import org.apache.log4j.Logger;
0043:        import org.w3c.dom.Element;
0044:
0045:        import antlr.Token;
0046:        import antlr.TokenStreamException;
0047:        import biz.hammurapi.config.Context;
0048:        import biz.hammurapi.config.PropertyParser;
0049:        import biz.hammurapi.util.Attributable;
0050:        import biz.hammurapi.web.menu.sql.HelpTopic;
0051:        import biz.hammurapi.web.menu.sql.MenuEngine;
0052:        import biz.hammurapi.web.menu.sql.MenuHelpTopics;
0053:        import biz.hammurapi.web.util.HTMLLexer;
0054:        import biz.hammurapi.web.util.HTMLTokenTypes;
0055:        import biz.hammurapi.xml.dom.AbstractDomObject;
0056:        import biz.hammurapi.xml.dom.DomSerializable;
0057:
0058:        /**
0059:         * Helper class to form help topic tree.
0060:         * @author Pavel Vlasov
0061:         *
0062:         */
0063:        public class Help {
0064:            private static final String TERM_URL_PREFIX = "term:";
0065:
0066:            private static final String TOPIC_URL_PREFIX = "topic:";
0067:
0068:            private static final String CT_URL = "URL";
0069:
0070:            private static final String CT_ALIAS = "Alias";
0071:
0072:            private static final String CT_CONTENT = "Content";
0073:
0074:            private static final int MIN_TOOLTIP_LENGTH = 100;
0075:
0076:            private static final String HELP_ATTRIBUTE = "help";
0077:
0078:            private static final Logger logger = Logger.getLogger(Help.class);
0079:
0080:            private static final String MENU_ENGINE_PATH = "global:db/MenuEngine";
0081:
0082:            private static final String TOPIC_TRANSCLUSION_CLOSE = "}}}";
0083:
0084:            private static final String TOPIC_TRANSCLUSION_OPEN = "{{{";
0085:
0086:            private static final String TERM_TRANSCLUSION_CLOSE = "}}";
0087:
0088:            private static final String TERM_TRANSCLUSION_OPEN = "{{";
0089:
0090:            private static final String TOPIC_CLOSE = "]]]";
0091:
0092:            private static final String TOPIC_OPEN = "[[[";
0093:
0094:            private static final String TERM_CLOSE = "]]";
0095:
0096:            private static final String TERM_OPEN = "[[";
0097:
0098:            private static final String HELP_TERM = "HelpTerm";
0099:
0100:            private static final String SAME_PAGE_HELP_TERM = "SamePageHelpTerm";
0101:
0102:            private static final String CONTEXT_TERM_PREFIX = "context:";
0103:
0104:            private static int counter;
0105:
0106:            public static final int DEFAULT_MAX_TOOLTIP_LENGTH = 1000;
0107:            public static final String DEFAULT_TAIL = "...";
0108:            private static final String TOOLTIP_END_MARKER = "tooltip-end";
0109:            static final String ELLIPSIS = " ...";
0110:
0111:            private String name;
0112:            private Map children = new TreeMap();
0113:            private Menu owner;
0114:            private Help parent;
0115:            private String id;
0116:            private MenuHelpTopics menuHelpTopics;
0117:            private Reference words; // Words map for search.
0118:            private Map content = new HashMap(); // page content.
0119:            private Reference tooltip; // content without header truncated if needed.
0120:
0121:            /**
0122:             * URL loaded from mount point.
0123:             */
0124:            private String url;
0125:
0126:            Help(String name, Help parent) {
0127:                this .name = name;
0128:                this .parent = parent;
0129:                id = "V" + (++counter);
0130:                this .owner = parent.owner;
0131:            }
0132:
0133:            public Help(Menu owner) {
0134:                this .owner = owner;
0135:                id = "M" + owner.getId();
0136:                this .name = owner.getName();
0137:            }
0138:
0139:            public String getId() {
0140:                return id;
0141:            }
0142:
0143:            public String getName() {
0144:                return isSection() ? name.substring(1) : name;
0145:            }
0146:
0147:            public String getTitle() {
0148:                if (menuHelpTopics != null) {
0149:                    return menuHelpTopics.getTitle();
0150:                }
0151:
0152:                if (parent == null) {
0153:                    return owner.getTitle();
0154:                }
0155:
0156:                return null;
0157:            }
0158:
0159:            public boolean isSection() {
0160:                if (parent != null && parent.isSection()) {
0161:                    return true;
0162:                }
0163:
0164:                return name != null && name.startsWith("#");
0165:            }
0166:
0167:            /**
0168:             * @param name - Name "tail"
0169:             * @param mht
0170:             * @param isSection True if name separated from parent by #, which means section.
0171:             */
0172:            public void add(String name, MenuHelpTopics mht) {
0173:                if (name == null) {
0174:                    if (menuHelpTopics == null) {
0175:                        menuHelpTopics = mht;
0176:                        ((Attributable) mht).setAttribute(HELP_ATTRIBUTE, this );
0177:                        id = "T" + mht.getId();
0178:                    } else {
0179:                        throw new IllegalStateException(
0180:                                "Duplicate topic for the same help tree node: "
0181:                                        + mht.getName());
0182:                    }
0183:                } else {
0184:                    //Hash cannot be before slash.
0185:                    int slashIdx = name.indexOf("/");
0186:                    while (slashIdx != -1 && name.indexOf("//") == slashIdx) {
0187:                        slashIdx = name.indexOf("/", slashIdx + 2);
0188:                    }
0189:                    if (slashIdx == -1) {
0190:                        int hashIdx = name.indexOf("#");
0191:                        while (hashIdx != -1 && name.indexOf("##") == hashIdx) {
0192:                            hashIdx = name.indexOf("#", hashIdx + 2);
0193:                        }
0194:                        if (hashIdx == 0) {
0195:                            hashIdx = name.indexOf("#", 1);
0196:                            while (hashIdx != -1
0197:                                    && name.indexOf("##") == hashIdx) {
0198:                                hashIdx = name.indexOf("#", hashIdx + 2);
0199:                            }
0200:                        }
0201:                        if (hashIdx == -1) {
0202:                            Help child = getChild(name);
0203:                            child.add(null, mht);
0204:                        } else {
0205:                            Help child = getChild(unescape(name.substring(0,
0206:                                    hashIdx)));
0207:                            child.add(hashIdx == name.length() - 1 ? null
0208:                                    : name.substring(hashIdx), mht);
0209:                        }
0210:                    } else {
0211:                        String nameTail = slashIdx == name.length() - 1 ? null
0212:                                : name.substring(slashIdx + 1);
0213:                        Help child = getChild(unescape(name.substring(0,
0214:                                slashIdx)));
0215:                        child.add(nameTail, mht);
0216:                    }
0217:                }
0218:            }
0219:
0220:            /**
0221:             * Replaces ## with # and // with /
0222:             * @param str
0223:             * @return
0224:             */
0225:            private static String unescape(String str) {
0226:                StringBuffer ret = new StringBuffer();
0227:                int idx;
0228:                do {
0229:                    idx = str.indexOf("##");
0230:                    idx = idx == -1 ? str.indexOf("//") : Math.min(idx, str
0231:                            .indexOf("//"));
0232:                    if (idx != -1) {
0233:                        ret.append(str.substring(0, idx + 1));
0234:                        str = str.substring(idx + 2);
0235:                    }
0236:                } while (idx != -1);
0237:
0238:                ret.append(str);
0239:                return ret.toString();
0240:            }
0241:
0242:            private Help getChild(String name) {
0243:                Help child = (Help) children.get(name);
0244:                if (child == null) {
0245:                    child = new Help(name, this );
0246:                    children.put(name, child);
0247:                }
0248:                return child;
0249:            }
0250:
0251:            /**
0252:             * Helper method to construct <Hx> elements.
0253:             * @param level
0254:             * @return
0255:             */
0256:            private static int headLevel(int level) {
0257:                return Math.min(level, 6);
0258:            }
0259:
0260:            /**
0261:             * 
0262:             * @param level Nesting level. Shall be 1 for the page root and increase by one for eash subsection nesting.
0263:             * @param engine
0264:             * @return
0265:             * @throws SQLException 
0266:             */
0267:            public synchronized String getContent(int level, Context context,
0268:                    boolean withHeader, boolean withChildren, boolean isTooltip)
0269:                    throws SQLException {
0270:                Collection key = new ArrayList();
0271:                key.add(new Integer(level));
0272:                key.add(withHeader ? Boolean.TRUE : Boolean.FALSE);
0273:                key.add(withChildren ? Boolean.TRUE : Boolean.FALSE);
0274:                key.add(isTooltip ? Boolean.TRUE : Boolean.FALSE);
0275:                Reference ref = (Reference) content.get(key);
0276:                String ret = (String) (ref == null ? null : ref.get());
0277:                if (ret != null) {
0278:                    return ret;
0279:                }
0280:
0281:                Set transclusionSet = new HashSet();
0282:                HeadNode head = getParsedContent(level, context, withHeader,
0283:                        withChildren, isTooltip, transclusionSet);
0284:                String parsed = head.getText(context, transclusionSet,
0285:                        isTooltip);
0286:                ref = new SoftReference(parsed);
0287:                content.put(key, ref);
0288:                return parsed;
0289:            }
0290:
0291:            private synchronized HeadNode getParsedContent(int level,
0292:                    Context context, boolean withHeader, boolean withChildren,
0293:                    boolean isTooltip, Set transclusionSet) throws SQLException {
0294:                HeadNode head = new HeadNode();
0295:                if (transclusionSet.add(getId())) {
0296:                    StringBuffer buf = new StringBuffer();
0297:                    // Cases: Menu root (main), with subsections, without.
0298:                    if (menuHelpTopics != null) {
0299:                        MenuEngine engine = (MenuEngine) context
0300:                                .get(MENU_ENGINE_PATH);
0301:                        if (engine == null) {
0302:                            throw new SQLException("Menu engine not found");
0303:                        }
0304:                        if (withHeader) {
0305:                            if (getName() != null) {
0306:                                //						System.out.println(getName());
0307:                                buf.append("<a name=\"T"
0308:                                        + menuHelpTopics.getId() + "\"><H"
0309:                                        + headLevel(level) + ">" + getName()
0310:                                        + "</H" + headLevel(level) + "></a>\n");
0311:                            } else if (parent == null) {
0312:                                if (owner.getName() != null) {
0313:                                    buf.append("<H" + headLevel(level) + ">"
0314:                                            + owner.getName() + "</H"
0315:                                            + headLevel(level) + ">\n");
0316:                                }
0317:                                if (owner.getDescription() != null) {
0318:                                    buf.append("<I>" + owner.getDescription()
0319:                                            + "</I><P/>");
0320:                                }
0321:                            }
0322:                        }
0323:                        if (CT_CONTENT.equals(menuHelpTopics.getType())) {
0324:                            HelpTopic topic = engine
0325:                                    .getHelpTopic(menuHelpTopics.getId());
0326:                            buf.append(topic.getContent());
0327:                        } else if (CT_ALIAS.equals(menuHelpTopics.getType())) {
0328:                            buf
0329:                                    .append("<SPAN style=\"float:right; padding:2px\">Aliased from "
0330:                                            + getName() + "</SPAN>");
0331:                            if (menuHelpTopics.getTopicUrl().startsWith(
0332:                                    TOPIC_URL_PREFIX)) {
0333:                                buf.append("{{{");
0334:                                buf.append(menuHelpTopics.getTopicUrl()
0335:                                        .substring(TOPIC_URL_PREFIX.length()));
0336:                                buf.append("}}}");
0337:                            } else if (menuHelpTopics.getTopicUrl().startsWith(
0338:                                    TERM_URL_PREFIX)) {
0339:                                buf.append("{{");
0340:                                buf.append(menuHelpTopics.getTopicUrl()
0341:                                        .substring(TERM_URL_PREFIX.length()));
0342:                                buf.append("}}");
0343:                            } else {
0344:                                buf
0345:                                        .append("<I>Invalid alias: "
0346:                                                + menuHelpTopics.getTopicUrl()
0347:                                                + "</I>");
0348:                            }
0349:                        } else if (CT_URL.equals(menuHelpTopics.getType())) {
0350:                            url = menuHelpTopics.getTopicUrl();
0351:                            urlLink(context, buf);
0352:                        } else {
0353:                            urlLink(context, buf);
0354:                        }
0355:                    } else if (parent == null) {
0356:                        if (withHeader) {
0357:                            if (owner.getName() != null) {
0358:                                buf.append("<H" + headLevel(level) + ">"
0359:                                        + owner.getName() + "</H"
0360:                                        + headLevel(level) + ">\n");
0361:                            }
0362:                            if (owner.getDescription() != null) {
0363:                                buf.append("<I>" + owner.getDescription()
0364:                                        + "</I><P/>");
0365:                            }
0366:                        }
0367:                        toc(buf, context);
0368:                    } else if (getName() != null) {
0369:                        buf.append("<a name=\"" + getId() + "\"><H"
0370:                                + headLevel(level) + ">" + getName() + "</H"
0371:                                + headLevel(level) + "></a>\n");
0372:                        urlLink(context, buf);
0373:                        toc(buf, context);
0374:                    }
0375:
0376:                    // Transclusion and references.
0377:                    // Break string into nodes - text, {{{, {{, [[[, [[
0378:                    parse(buf.toString(), head, level);
0379:
0380:                    if (withChildren) {
0381:                        Iterator it = children.values().iterator();
0382:                        while (it.hasNext()) {
0383:                            Help child = (Help) it.next();
0384:                            if (child.isSection()) {
0385:                                head.append(child.getParsedContent(level + 1,
0386:                                        context, true, true, isTooltip,
0387:                                        transclusionSet));
0388:                            }
0389:                        }
0390:                    }
0391:                } else {
0392:                    head
0393:                            .setNext(new TextNode(
0394:                                    "<I>{{{Transclusion error: circular reference}}}</I>"));
0395:                }
0396:
0397:                transclusionSet.remove(getId()); // Allow to transclude the same content sequentially, but not hierarchically
0398:                return head;
0399:            }
0400:
0401:            private void urlLink(Context context, StringBuffer buf) {
0402:                PropertyParser pp = new PropertyParser(context, false);
0403:                if (url != null) {
0404:                    String realUrl = pp.parse(url);
0405:                    buf.append("See <a href=\"");
0406:                    buf.append(realUrl);
0407:                    buf.append("\">");
0408:                    buf.append(realUrl);
0409:                    buf.append("</a><P/>");
0410:                }
0411:            }
0412:
0413:            /**
0414:             * Table of content for help nodes without own content.
0415:             * @param buf
0416:             * @param context 
0417:             */
0418:            private void toc(StringBuffer buf, Context context) {
0419:                StringBuffer tbuf = new StringBuffer();
0420:                Iterator it = children.values().iterator();
0421:                while (it.hasNext()) {
0422:                    Help child = (Help) it.next();
0423:                    if (!child.isSection()) {
0424:                        tbuf.append("<LI> <a href=\"helpPage.html?id=");
0425:                        tbuf.append(child.getId());
0426:                        tbuf.append("\">");
0427:                        tbuf.append(Menu.escapeHtml(child.getName()));
0428:                        tbuf.append("</a>");
0429:                        String childTitle = child.getTitle();
0430:                        if (childTitle != null && child.getTitle().length() > 0) {
0431:                            tbuf.append(" - ");
0432:                            tbuf.append(Menu.escapeHtml(childTitle));
0433:                        }
0434:                        tbuf.append("</LI>");
0435:                    }
0436:                }
0437:
0438:                if (tbuf.length() > 0) {
0439:                    buf.append("<B>Topics</B><P/><UL>");
0440:                    buf.append(tbuf);
0441:                    buf.append("</UL><P/>");
0442:                }
0443:
0444:                if (parent == null) {
0445:                    tbuf = new StringBuffer();
0446:                    it = owner.getChildren().iterator();
0447:                    while (it.hasNext()) {
0448:                        Menu mc = (Menu) it.next();
0449:                        if (mc.hasHelp() || !mc.getChildren().isEmpty()) {
0450:                            Help child = mc.getHelp(context);
0451:                            tbuf.append("<LI> <a href=\"helpPage.html?id=");
0452:                            tbuf.append(child.getId());
0453:                            tbuf.append("\">");
0454:                            String childName = child.getName();
0455:                            tbuf.append(Menu.escapeHtml(childName));
0456:                            tbuf.append("</a>");
0457:                            String childTitle = child.getTitle();
0458:                            if (childTitle != null && childTitle.length() > 0) {
0459:                                tbuf.append(" - ");
0460:                                tbuf.append(Menu.escapeHtml(childTitle));
0461:                            }
0462:                            tbuf.append("</LI>");
0463:                        }
0464:                    }
0465:
0466:                    if (tbuf.length() > 0) {
0467:                        buf.append("<B>Subitems</B><P/><UL>");
0468:                        buf.append(tbuf);
0469:                        buf.append("</UL>");
0470:                    }
0471:
0472:                }
0473:            }
0474:
0475:            /**
0476:             * Writes content of self, subtopics and menu children to writer.
0477:             * @param context
0478:             * @param writer
0479:             * @throws IOException
0480:             * @throws SQLException 
0481:             */
0482:            public void writeSinglePageContent(Context context, Writer writer)
0483:                    throws IOException, SQLException {
0484:                writer.write(getContent(1, context, true, true, false));
0485:                Iterator it = children.values().iterator();
0486:                while (it.hasNext()) {
0487:                    Help child = (Help) it.next();
0488:                    if (!child.isSection()) {
0489:                        child.writeSinglePageContent(context, writer);
0490:                    }
0491:                }
0492:
0493:                if (parent == null) {
0494:                    writer
0495:                            .write("<div style=\"PAGE-BREAK-AFTER: always\"><span style=\"DISPLAY: none\">&nbsp;</span></div>");
0496:                    it = owner.getChildren().iterator();
0497:                    while (it.hasNext()) {
0498:                        Menu child = (Menu) it.next();
0499:                        if (child.hasHelp() || !child.getChildren().isEmpty()) {
0500:                            child.getHelp(context).writeSinglePageContent(
0501:                                    context, writer);
0502:                        }
0503:                    }
0504:                }
0505:            }
0506:
0507:            private void parse(String input, HelpNode head, int level) {
0508:                // 1. Break into {{{...|...}}} 
0509:                HelpNode lastNode = head;
0510:                int idx = input.indexOf(TOPIC_TRANSCLUSION_OPEN);
0511:                while (idx != -1) {
0512:                    int cidx = input.indexOf(TOPIC_TRANSCLUSION_CLOSE, idx);
0513:                    if (cidx == -1) { // Wrong syntax
0514:                        break;
0515:                    } else {
0516:                        int pidx = input.indexOf("|");
0517:                        if (pidx == -1 || pidx > cidx) { // Wrong syntax - output {{{...}}} as is.
0518:                            TextNode tn = new TextNode(input.substring(idx,
0519:                                    cidx + 3));
0520:                            lastNode.setNext(tn);
0521:                            lastNode = tn;
0522:                            input = input.substring(cidx + 3);
0523:                            idx = input.indexOf(TOPIC_TRANSCLUSION_OPEN);
0524:                        } else { // Correct syntax
0525:                            if (idx != 0) {
0526:                                TextNode tn = new TextNode(input.substring(0,
0527:                                        idx));
0528:                                lastNode.setNext(tn);
0529:                                lastNode = tn;
0530:                            }
0531:                            TopicTransclusionNode ttn = new TopicTransclusionNode(
0532:                                    input.substring(idx + 3, pidx), input
0533:                                            .substring(pidx + 1, cidx), level);
0534:                            lastNode.setNext(ttn);
0535:                            lastNode = ttn;
0536:                            input = input.substring(cidx + 3);
0537:                            idx = input.indexOf(TOPIC_TRANSCLUSION_OPEN);
0538:                        }
0539:                    }
0540:                }
0541:                TextNode tn = new TextNode(input);
0542:                lastNode.setNext(tn);
0543:                lastNode = tn;
0544:
0545:                // 2. Go through text nodes and break them at {{...}}
0546:                List textNodes = new ArrayList();
0547:                for (HelpNode node = head; node != null; node = node.getNext()) {
0548:                    if (node instanceof  TextNode) {
0549:                        textNodes.add(node);
0550:                    }
0551:                }
0552:
0553:                Iterator it = textNodes.iterator();
0554:                while (it.hasNext()) {
0555:                    TextNode textNode = (TextNode) it.next();
0556:                    HelpNode before = textNode.getPrev();
0557:                    HelpNode after = textNode.getNext();
0558:                    String txt = textNode.getText(null, null, false);
0559:                    int tidx = txt.indexOf(TERM_TRANSCLUSION_OPEN);
0560:                    while (tidx != -1) {
0561:                        int cidx = txt.indexOf(TERM_TRANSCLUSION_CLOSE, tidx);
0562:                        if (cidx == -1) {
0563:                            break;
0564:                        }
0565:                        if (tidx > 0) {
0566:                            TextNode ttn = new TextNode(txt.substring(0, tidx));
0567:                            before.setNext(ttn);
0568:                            before = ttn;
0569:                        }
0570:                        TermTransclusionNode ttn = new TermTransclusionNode(txt
0571:                                .substring(tidx + 2, cidx), level);
0572:                        before.setNext(ttn);
0573:                        before = ttn;
0574:                        txt = txt.substring(cidx + 2);
0575:                        tidx = txt.indexOf(TERM_TRANSCLUSION_OPEN);
0576:                    }
0577:                    TextNode ttn = new TextNode(txt);
0578:                    before.setNext(ttn);
0579:                    ttn.setNext(after);
0580:                }
0581:
0582:                // 3. Go through text nodes and break them at [[[...|...]]
0583:                textNodes = new ArrayList();
0584:                for (HelpNode node = head; node != null; node = node.getNext()) {
0585:                    if (node instanceof  TextNode) {
0586:                        textNodes.add(node);
0587:                    }
0588:                }
0589:
0590:                it = textNodes.iterator();
0591:                while (it.hasNext()) {
0592:                    TextNode textNode = (TextNode) it.next();
0593:                    HelpNode before = textNode.getPrev();
0594:                    HelpNode after = textNode.getNext();
0595:                    String txt = textNode.getText(null, null, false);
0596:                    int tidx = txt.indexOf(TOPIC_OPEN);
0597:                    while (tidx != -1) {
0598:                        int cidx = txt.indexOf(TOPIC_CLOSE, tidx);
0599:                        if (cidx == -1) {
0600:                            break;
0601:                        }
0602:                        int pidx = txt.indexOf("|", tidx);
0603:                        if (pidx == -1 || pidx > cidx) {// Wrong syntax - output [[[...]]] as is.
0604:                            TextNode ttn = new TextNode(txt.substring(tidx,
0605:                                    cidx + 3));
0606:                            before.setNext(ttn);
0607:                            before = ttn;
0608:                            txt = txt.substring(cidx + 3);
0609:                            idx = txt.indexOf(TOPIC_OPEN);
0610:                        } else {
0611:                            if (tidx > 0) {
0612:                                TextNode ttn = new TextNode(txt.substring(0,
0613:                                        tidx));
0614:                                before.setNext(ttn);
0615:                                before = ttn;
0616:                            }
0617:                            String menuPath = txt.substring(tidx + 3, pidx);
0618:                            String topic = txt.substring(pidx + 1, cidx);
0619:                            int tpidx = topic.indexOf("|");
0620:                            TopicNode ttn = new TopicNode(menuPath,
0621:                                    tpidx == -1 ? topic : topic.substring(0,
0622:                                            tpidx), tpidx == -1 ? null : topic
0623:                                            .substring(tpidx + 1));
0624:                            before.setNext(ttn);
0625:                            before = ttn;
0626:                            txt = txt.substring(cidx + 3);
0627:                            tidx = txt.indexOf(TOPIC_OPEN);
0628:                        }
0629:                    }
0630:                    TextNode ttn = new TextNode(txt);
0631:                    before.setNext(ttn);
0632:                    ttn.setNext(after);
0633:                }
0634:
0635:                // 4. Go through text nodes and break them at [[...]]
0636:                textNodes = new ArrayList();
0637:                for (HelpNode node = head; node != null; node = node.getNext()) {
0638:                    if (node instanceof  TextNode) {
0639:                        textNodes.add(node);
0640:                    }
0641:                }
0642:
0643:                it = textNodes.iterator();
0644:                while (it.hasNext()) {
0645:                    TextNode textNode = (TextNode) it.next();
0646:                    HelpNode before = textNode.getPrev();
0647:                    HelpNode after = textNode.getNext();
0648:                    String txt = textNode.getText(null, null, false);
0649:                    int tidx = txt.indexOf(TERM_OPEN);
0650:                    while (tidx != -1) {
0651:                        int cidx = txt.indexOf(TERM_CLOSE, tidx);
0652:                        if (cidx == -1) {
0653:                            break;
0654:                        }
0655:                        if (tidx > 0) {
0656:                            TextNode ttn = new TextNode(txt.substring(0, tidx));
0657:                            before.setNext(ttn);
0658:                            before = ttn;
0659:                        }
0660:                        String term = txt.substring(tidx + 2, cidx);
0661:                        int tpidx = term.indexOf("|");
0662:                        TermNode ttn = new TermNode(tpidx == -1 ? term : term
0663:                                .substring(0, tpidx), tpidx == -1 ? null : term
0664:                                .substring(tpidx + 1));
0665:                        before.setNext(ttn);
0666:                        before = ttn;
0667:                        txt = txt.substring(cidx + 2);
0668:                        tidx = txt.indexOf(TERM_OPEN);
0669:                    }
0670:                    TextNode ttn = new TextNode(txt);
0671:                    before.setNext(ttn);
0672:                    ttn.setNext(after);
0673:                }
0674:            }
0675:
0676:            private abstract static class HelpNode {
0677:                private HelpNode next;
0678:                private HelpNode prev;
0679:
0680:                public void setNext(HelpNode next) {
0681:                    if (this .next != next) {
0682:                        HelpNode oldNext = this .next;
0683:                        this .next = next;
0684:                        if (next != null && next.getPrev() != this ) {
0685:                            next._setPrev(this );
0686:                        }
0687:                        if (oldNext != null) {
0688:                            oldNext._setPrev(null);
0689:                        }
0690:                    }
0691:                }
0692:
0693:                private void _setNext(HelpNode next) {
0694:                    this .next = next;
0695:                }
0696:
0697:                public void setPrev(HelpNode prev) {
0698:                    if (this .prev != prev) {
0699:                        HelpNode oldPrev = this .prev;
0700:                        this .prev = prev;
0701:                        if (prev != null && prev.getNext() != this ) {
0702:                            prev._setNext(this );
0703:                        }
0704:                        if (oldPrev != null) {
0705:                            oldPrev._setNext(null);
0706:                        }
0707:                    }
0708:                }
0709:
0710:                private void _setPrev(HelpNode prev) {
0711:                    this .prev = prev;
0712:                }
0713:
0714:                public HelpNode getNext() {
0715:                    return next;
0716:                }
0717:
0718:                public HelpNode getPrev() {
0719:                    return prev;
0720:                }
0721:
0722:                public boolean isTooltipEnd() {
0723:                    return false;
0724:                }
0725:
0726:                public abstract String getText(Context context,
0727:                        Set transclusionSet, boolean isTooltip)
0728:                        throws SQLException;
0729:            }
0730:
0731:            /**
0732:             * Head node, collects text from other nodes.
0733:             * @author Pavel
0734:             */
0735:            private static class HeadNode extends HelpNode {
0736:
0737:                public String getText(Context context, Set transclusionSet,
0738:                        boolean isTooltip) throws SQLException {
0739:                    StringBuffer ret = new StringBuffer();
0740:                    for (HelpNode next = getNext(); next != null; next = next
0741:                            .getNext()) {
0742:                        ret.append(next.getText(context, transclusionSet,
0743:                                isTooltip));
0744:                        if (isTooltip && next.isTooltipEnd()) {
0745:                            ret.append(TERM_TRANSCLUSION_OPEN
0746:                                    + TOOLTIP_END_MARKER
0747:                                    + TERM_TRANSCLUSION_CLOSE);
0748:                            break;
0749:                        }
0750:                    }
0751:                    return ret.toString();
0752:                }
0753:
0754:                public String toString() {
0755:                    StringBuffer ret = new StringBuffer();
0756:                    for (HelpNode next = getNext(); next != null; next = next
0757:                            .getNext()) {
0758:                        ret.append("\n");
0759:                        ret.append(next);
0760:                    }
0761:                    return ret.toString();
0762:                }
0763:
0764:                public void append(HeadNode otherNode) {
0765:                    if (otherNode.getNext() != null) {
0766:                        HelpNode lastNode = this ;
0767:                        while (lastNode.getNext() != null) {
0768:                            lastNode = lastNode.getNext();
0769:                        }
0770:                        lastNode.setNext(otherNode.getNext());
0771:                    }
0772:                }
0773:            }
0774:
0775:            private static class TextNode extends HelpNode {
0776:                private String text;
0777:
0778:                public TextNode(String text) {
0779:                    this .text = text;
0780:                }
0781:
0782:                public String getText(Context context, Set transclusionSet,
0783:                        boolean isTooltip) {
0784:                    return text;
0785:                }
0786:
0787:                public String toString() {
0788:                    return "[Text] " + text;
0789:                }
0790:            }
0791:
0792:            /**
0793:             * Represents [[...]] constructs
0794:             * @author Pavel
0795:             *
0796:             */
0797:            private class TermNode extends HelpNode {
0798:                private String term;
0799:                private String label;
0800:
0801:                public TermNode(String term, String label) {
0802:                    this .term = term;
0803:                    this .label = label;
0804:                }
0805:
0806:                public String getText(final Context context,
0807:                        Set transclusionSet, boolean isTooltip) {
0808:                    final Help trm = findTerm(this .term, new HashSet(), context);
0809:                    if (trm == null) {
0810:                        logger.info("Help term not found: " + this .term);
0811:                        return this .term;
0812:                    }
0813:
0814:                    Map ctx = new HashMap();
0815:                    ctx.put("id", trm.getId());
0816:                    if (trm.menuHelpTopics != null) {
0817:                        ctx.put("topicId", new Integer(trm.menuHelpTopics
0818:                                .getId()));
0819:                    }
0820:                    ctx.put("menuContext", context);
0821:                    ctx.put("help", trm);
0822:                    String lbl = label == null ? trm.getName() : label;
0823:                    ctx.put("label", lbl);
0824:                    ctx.put("context-path", context.get("context-path"));
0825:                    ctx.put("pageId", trm.getPageId());
0826:                    Object ret = owner.instantiateTemplate(getPageId().equals(
0827:                            trm.getPageId()) ? SAME_PAGE_HELP_TERM : HELP_TERM,
0828:                            ctx);
0829:                    return ret == null ? lbl : ret.toString();
0830:                }
0831:
0832:                public String toString() {
0833:                    return "[Term] " + term;
0834:                }
0835:            }
0836:
0837:            /**
0838:             * Represents [[[...|...]]] constructs
0839:             * @author Pavel
0840:             */
0841:            private class TopicNode extends HelpNode {
0842:                private String menuPath;
0843:                private String topic;
0844:                private String label;
0845:
0846:                public TopicNode(String menuPath, String topic, String label) {
0847:                    this .menuPath = menuPath;
0848:                    this .topic = topic;
0849:                    this .label = label;
0850:                }
0851:
0852:                public String getText(final Context context,
0853:                        Set transclusionSet, boolean isTooltip) {
0854:                    int idx = topic.lastIndexOf("/");
0855:                    idx = idx == -1 ? topic.lastIndexOf("#") : topic
0856:                            .lastIndexOf("#", idx);
0857:                    String shortName = idx == -1 ? topic : topic
0858:                            .substring(idx + 1);
0859:                    Menu menu = owner.findItem(menuPath);
0860:                    if (menu == null) {
0861:                        logger.info("Menu not found: " + menuPath);
0862:                        return label == null ? shortName : label;
0863:                    }
0864:
0865:                    MenuHelpTopics mht = menu.getHelpTopic(topic, context);
0866:                    if (mht == null) {
0867:                        logger.info("Help topic not found: " + topic
0868:                                + " in menu " + menuPath);
0869:                        return label == null ? shortName : label; // Unexpanded.				
0870:                    }
0871:
0872:                    final Help help = (Help) ((Attributable) mht)
0873:                            .getAttribute(HELP_ATTRIBUTE);
0874:                    if (help == null) {
0875:                        throw new IllegalStateException("Menu help topic "
0876:                                + mht.getId() + " without " + HELP_ATTRIBUTE
0877:                                + " attribute set");
0878:                    }
0879:
0880:                    Map ctx = new HashMap();
0881:                    ctx.put("id", help.getId());
0882:                    ctx.put("topicId", new Integer(mht.getId()));
0883:                    ctx.put("menuContext", context);
0884:                    ctx.put("context-path", context.get("context-path"));
0885:                    ctx.put("help", help);
0886:                    String lbl = label == null ? help.getName() : label;
0887:                    ctx.put("label", lbl);
0888:                    ctx.put("pageId", help.getPageId());
0889:                    Object ret = owner
0890:                            .instantiateTemplate(getPageId().equals(
0891:                                    help.getPageId()) ? SAME_PAGE_HELP_TERM
0892:                                    : HELP_TERM, ctx);
0893:                    return ret == null ? lbl : ret.toString();
0894:                }
0895:
0896:                public String toString() {
0897:                    return "[Topic] " + menuPath + ", " + topic;
0898:                }
0899:            }
0900:
0901:            /**
0902:             * Represents {{...}} constructs
0903:             * @author Pavel
0904:             *
0905:             */
0906:            private class TermTransclusionNode extends HelpNode {
0907:                private String term;
0908:                private int level;
0909:
0910:                public TermTransclusionNode(String term, int level) {
0911:                    this .term = term;
0912:                    this .level = level;
0913:                }
0914:
0915:                public boolean isTooltipEnd() {
0916:                    return TOOLTIP_END_MARKER.equals(term);
0917:                }
0918:
0919:                public String getText(final Context context,
0920:                        Set transclusionSet, boolean isTooltip)
0921:                        throws SQLException {
0922:                    if (isTooltipEnd()) {
0923:                        return "";
0924:                    }
0925:
0926:                    // escape sequences
0927:                    if ("dlc".equals(term)) {
0928:                        return "{{";
0929:                    } else if ("drc".equals(term)) {
0930:                        return "}}";
0931:                    } else if ("dlb".equals(term)) {
0932:                        return "[[";
0933:                    } else if ("drb".equals(term)) {
0934:                        return "]]";
0935:                    } else if ("tlc".equals(term)) {
0936:                        return "{{{";
0937:                    } else if ("trc".equals(term)) {
0938:                        return "}}}";
0939:                    } else if ("tlb".equals(term)) {
0940:                        return "[[[";
0941:                    } else if ("trb".equals(term)) {
0942:                        return "]]]";
0943:                    } else if ("system.name".equals(term)) {
0944:                        return "Hammurapi Group Web Delivery Framework";
0945:                    }
0946:
0947:                    if ("context-path".equals(term)) {
0948:                        Object ret = context.get("context-path");
0949:                        return ret == null ? "" : ret.toString();
0950:                    }
0951:
0952:                    for (int i = 1; i <= 6; ++i) {
0953:                        if (("H" + i).equals(term)) {
0954:                            return "<H" + headLevel(level + i - 1) + ">";
0955:                        } else if (("/H" + i).equals(term)) {
0956:                            return "</H" + headLevel(level + i - 1) + ">";
0957:                        }
0958:                    }
0959:
0960:                    if (term.startsWith(CONTEXT_TERM_PREFIX)) {
0961:                        Object cte = context.get(term
0962:                                .substring(CONTEXT_TERM_PREFIX.length()));
0963:                        if (cte == null) {
0964:                            return "";
0965:                        }
0966:                        return cte.toString();
0967:                    }
0968:
0969:                    // normal term
0970:                    final Help trm = findTerm(this .term, new HashSet(), context);
0971:                    if (trm == null) {
0972:                        logger.info("Help term not found: " + this .term);
0973:                        return "{{" + this .term + "}}";
0974:                    }
0975:
0976:                    HeadNode termHead = trm.getParsedContent(level, context,
0977:                            false, true, false, transclusionSet);
0978:                    return termHead
0979:                            .getText(context, transclusionSet, isTooltip);
0980:                }
0981:
0982:                public String toString() {
0983:                    return "[Transclusion term] " + term;
0984:                }
0985:            }
0986:
0987:            /**
0988:             * Represents {{{...|...}}} constructs
0989:             * @author Pavel
0990:             *
0991:             */
0992:            private class TopicTransclusionNode extends HelpNode {
0993:                private String menuPath;
0994:                private String topic;
0995:                private int level;
0996:
0997:                public TopicTransclusionNode(String menuPath, String topic,
0998:                        int level) {
0999:                    this .menuPath = menuPath;
1000:                    this .topic = topic;
1001:                    this .level = level;
1002:                }
1003:
1004:                public String getText(Context context, Set transclusionSet,
1005:                        boolean isTooltip) throws SQLException {
1006:                    Menu menu = owner.findItem(menuPath);
1007:                    if (menu == null) {
1008:                        logger.info("Menu not found: " + menuPath);
1009:                        return "{{{" + menuPath + "|" + topic + "}}}"; // Unexpanded.
1010:                    }
1011:
1012:                    MenuHelpTopics mht = menu.getHelpTopic(topic, context);
1013:                    if (mht == null) {
1014:                        logger.info("Help topic not found: " + topic
1015:                                + " in menu " + menuPath);
1016:                        return "{{{" + menuPath + "|" + topic + "}}}"; // Unexpanded.				
1017:                    }
1018:
1019:                    final Help help = (Help) ((Attributable) mht)
1020:                            .getAttribute(HELP_ATTRIBUTE);
1021:                    if (help == null) {
1022:                        throw new IllegalStateException("Menu help topic "
1023:                                + mht.getId() + " without " + HELP_ATTRIBUTE
1024:                                + " attribute set");
1025:                    }
1026:
1027:                    HeadNode helpHead = help.getParsedContent(level, context,
1028:                            false, true, isTooltip, transclusionSet);
1029:                    return helpHead
1030:                            .getText(context, transclusionSet, isTooltip);
1031:                }
1032:
1033:                public String toString() {
1034:                    return "[Transclusion topic] " + menuPath + ", " + topic;
1035:                }
1036:            }
1037:
1038:            public String getTooltip(Context context) throws SQLException {
1039:                String ret = (String) (tooltip == null ? null : tooltip.get());
1040:                if (ret != null) {
1041:                    return ret;
1042:                }
1043:
1044:                ret = getContent(1, context, false, false, true);
1045:                if (Menu.isBlank(ret)) {
1046:                    ret = "<I>No content</I>";
1047:                    tooltip = new SoftReference(ret);
1048:                    return ret;
1049:                }
1050:
1051:                //Number globalMaxTooltipLength = (Number) getGlobal(request, "db/max-tooltip-length");
1052:                int maxTooltipLength = DEFAULT_MAX_TOOLTIP_LENGTH; //globalMaxTooltipLength==null ? DEFAULT_MAX_TOOLTIP_LENGTH : globalMaxTooltipLength.intValue();
1053:
1054:                String ttem = TERM_TRANSCLUSION_OPEN + TOOLTIP_END_MARKER
1055:                        + TERM_TRANSCLUSION_CLOSE;
1056:                if (ret.endsWith(ttem)) {
1057:                    ret = ret.substring(0, ret.length() - ttem.length())
1058:                            + ELLIPSIS;
1059:                    tooltip = new SoftReference(ret);
1060:                    return ret;
1061:                }
1062:
1063:                //		int ltIdx = ret.lastIndexOf("<");
1064:                //		int gtIdx = ret.lastIndexOf(">");
1065:                //		if (ltIdx!=-1 && gtIdx<ltIdx) {
1066:                //			ret+=">";
1067:                //		}
1068:
1069:                // Paragraph detection.
1070:                Token lastPARA = null;
1071:                List tokenChain = new ArrayList();
1072:                HTMLLexer lexer = new HTMLLexer(new StringReader(ret));
1073:                int textcounter = 0; // To protect against infinite loops.
1074:                try {
1075:                    for (Token t = lexer.nextToken(); t != null
1076:                            && t.getType() != HTMLTokenTypes.CHTML
1077:                            && t.getType() != HTMLTokenTypes.EOF; t = lexer
1078:                            .nextToken()) {
1079:                        tokenChain.add(t);
1080:                        if (t.getText() != null
1081:                                && ((t.getType() == HTMLTokenTypes.UNDEFINED_TOKEN && t
1082:                                        .getText().length() == 1) || t
1083:                                        .getType() == HTMLTokenTypes.PCDATA)) {
1084:                            textcounter += t.getText().length();
1085:                            if (textcounter >= maxTooltipLength) {
1086:                                tokenChain.add(new Token(
1087:                                        HTMLTokenTypes.UNDEFINED_TOKEN,
1088:                                        ELLIPSIS));
1089:                                break;
1090:                            }
1091:                        }
1092:
1093:                        switch (t.getType()) {
1094:                        case HTMLTokenTypes.OPARA:
1095:                        case HTMLTokenTypes.CPARA:
1096:                        case HTMLTokenTypes.SAPARA:
1097:                            lastPARA = t;
1098:                            break;
1099:                        }
1100:                    }
1101:                } catch (TokenStreamException e) {
1102:                    if (ret.length() > maxTooltipLength) {
1103:                        ret = ret.substring(0, maxTooltipLength) + ELLIPSIS;
1104:                    }
1105:
1106:                    tooltip = new SoftReference(ret);
1107:                    return ret;
1108:                }
1109:
1110:                if (lastPARA != null) {
1111:                    StringBuffer rsb = new StringBuffer();
1112:                    Iterator it = tokenChain.iterator();
1113:                    while (it.hasNext()) {
1114:                        Token t = (Token) it.next();
1115:                        if (t == lastPARA) {
1116:                            if (rsb.toString().trim().length() < MIN_TOOLTIP_LENGTH) {
1117:                                break;
1118:                            }
1119:                            rsb.append(ELLIPSIS);
1120:                            ret = rsb.toString();
1121:                            tooltip = new SoftReference(ret);
1122:                            return ret;
1123:                        }
1124:                        rsb.append(t.getText());
1125:                    }
1126:                }
1127:
1128:                StringBuffer rsb = new StringBuffer();
1129:                Iterator it = tokenChain.iterator();
1130:                while (it.hasNext()) {
1131:                    Token t = (Token) it.next();
1132:                    rsb.append(t.getText());
1133:                }
1134:                ret = rsb.toString();
1135:                tooltip = new SoftReference(ret);
1136:                return ret;
1137:            }
1138:
1139:            /**
1140:             * For testing.
1141:             * @param args
1142:             */
1143:            public static void main(String[] args) throws Exception {
1144:                HeadNode head = new HeadNode();
1145:                String str = "Hello {{{a|b}}} {{{db}}} my friend {{good}} and bad {{ [[[d|e]]], [[evil]] [[[alla]]] [[[]";
1146:                System.out.println(str);
1147:                new Help(null).parse(str, head, 1);
1148:                System.out.println(head.getText(null, new HashSet(), false));
1149:            }
1150:
1151:            Help findHelp(String id) {
1152:                if (id.equals(getId())) {
1153:                    return this ;
1154:                }
1155:
1156:                Iterator it = children.values().iterator();
1157:                while (it.hasNext()) {
1158:                    Help child = (Help) it.next();
1159:                    Help ret = child.findHelp(id);
1160:                    if (ret != null) {
1161:                        return ret;
1162:                    }
1163:                }
1164:                return null;
1165:            }
1166:
1167:            Help findTerm(String term, Set idSet, Context context) {
1168:                if (idSet.add(getId())) {
1169:                    if (term.equalsIgnoreCase(getName())) {
1170:                        return this ;
1171:                    }
1172:
1173:                    Iterator it = children.values().iterator();
1174:                    while (it.hasNext()) {
1175:                        Help child = (Help) it.next();
1176:                        Help ret = child.findTerm(term, idSet, context);
1177:                        if (ret != null) {
1178:                            return ret;
1179:                        }
1180:                    }
1181:
1182:                    if (parent == null) {
1183:                        return owner.findTerm(term, idSet, context);
1184:                    }
1185:
1186:                    return parent.findTerm(term, idSet, context);
1187:                }
1188:
1189:                return null;
1190:            }
1191:
1192:            /**
1193:             * For sections returns page ID
1194:             * @return
1195:             */
1196:            String getPageId() {
1197:                return isSection() && parent != null ? parent.getPageId()
1198:                        : getId();
1199:            }
1200:
1201:            /**
1202:             * Recursively outputs children.
1203:             */
1204:            public void toDom(Context context, Element holder) {
1205:                toDomShallow(context, holder);
1206:
1207:                Iterator it = children.values().iterator();
1208:                while (it.hasNext()) {
1209:                    Help child = (Help) it.next();
1210:                    if (child.menuHelpTopics == null
1211:                            || !CT_ALIAS.equals(child.menuHelpTopics.getType())) {
1212:                        child.toDom(context, AbstractDomObject.addElement(
1213:                                holder, "help"));
1214:                    }
1215:                }
1216:
1217:                if (parent == null) {
1218:                    it = owner.getChildren().iterator();
1219:                    while (it.hasNext()) {
1220:                        Menu child = (Menu) it.next();
1221:                        if (child.hasHelp() || !child.getChildren().isEmpty()) {
1222:                            Element childElement = AbstractDomObject
1223:                                    .addElement(holder, "menu");
1224:                            childElement.setAttribute("id", String
1225:                                    .valueOf(child.getId()));
1226:                            childElement.setAttribute("name", child.getName());
1227:                            childElement.setAttribute("menu-type", child
1228:                                    .getType());
1229:                        }
1230:                    }
1231:                }
1232:            }
1233:
1234:            private void toDomShallow(Context context, Element holder) {
1235:                if (parent == null) {
1236:                    holder.setAttribute("help-type", "menu");
1237:                } else if (isSection()) {
1238:                    holder.setAttribute("help-type", "section");
1239:                } else {
1240:                    holder.setAttribute("help-type", "page");
1241:                }
1242:                holder.setAttribute("name", getName());
1243:                if (getId().startsWith("V")) {
1244:                    holder.setAttribute("virtual", "yes");
1245:                }
1246:                holder.setAttribute("id", getId());
1247:                holder.setAttribute("page-id", getPageId());
1248:
1249:                PropertyParser pp = new PropertyParser(context, false);
1250:                if (url != null) {
1251:                    holder.setAttribute("href", pp.parse(url));
1252:                } else if (menuHelpTopics != null
1253:                        && CT_URL.equals(menuHelpTopics.getType())) {
1254:                    holder.setAttribute("href", pp.parse(menuHelpTopics
1255:                            .getTopicUrl()));
1256:                }
1257:            }
1258:
1259:            public Collection getPath(Context context) {
1260:                Collection ret = new ArrayList();
1261:                if (parent == null) {
1262:                    Menu[] menuPath = owner.getPath();
1263:                    for (int i = 0; i < menuPath.length; ++i) {
1264:                        ret.add(menuPath[i].getHelp(context));
1265:                    }
1266:                } else {
1267:                    ret.addAll(parent.getPath(context));
1268:                    ret.add(this );
1269:                }
1270:                return ret;
1271:            }
1272:
1273:            private class SearchEntry implements  Comparable, DomSerializable {
1274:                private int relevance;
1275:                private Context context;
1276:
1277:                public int compareTo(Object o) {
1278:                    if (o == null) {
1279:                        return -1;
1280:                    }
1281:                    if (o == this ) {
1282:                        return 0;
1283:                    }
1284:                    if (o instanceof  SearchEntry) {
1285:                        if (((SearchEntry) o).relevance != relevance) {
1286:                            return ((SearchEntry) o).relevance - relevance;
1287:                        }
1288:
1289:                        return getName().compareTo(((SearchEntry) o).getName());
1290:                    }
1291:
1292:                    return hashCode() - o.hashCode();
1293:                }
1294:
1295:                String getName() {
1296:                    String ret = Help.this .getName();
1297:                    return ret == null ? "" : ret;
1298:                }
1299:
1300:                public void toDom(Element holder) {
1301:                    toDomShallow(context, holder);
1302:                    holder.setAttribute("relevance", String.valueOf(relevance));
1303:                }
1304:
1305:                public SearchEntry(int relevance, Context context) {
1306:                    super ();
1307:                    this .relevance = relevance;
1308:                    this .context = context;
1309:                }
1310:
1311:            }
1312:
1313:            public void search(Collection terms, Context context,
1314:                    Collection findings) {
1315:                synchronized (this ) {
1316:                    Map wordCounter = (Map) (words == null ? null : words.get());
1317:                    if (wordCounter == null) {
1318:                        wordCounter = new HashMap();
1319:                        words = new SoftReference(wordCounter);
1320:
1321:                        if (getName() != null) {
1322:                            StringTokenizer st = new StringTokenizer(getName());
1323:                            while (st.hasMoreElements()) {
1324:                                incCount(wordCounter, st.nextToken(), 10);
1325:                            }
1326:                        }
1327:
1328:                        if (getTitle() != null) {
1329:                            StringTokenizer st = new StringTokenizer(getTitle());
1330:                            while (st.hasMoreElements()) {
1331:                                incCount(wordCounter, st.nextToken(), 5);
1332:                            }
1333:                        }
1334:
1335:                        if (menuHelpTopics != null
1336:                                && CT_CONTENT.equals(menuHelpTopics.getType())
1337:                                && !isSection()) {
1338:                            try {
1339:                                HTMLLexer lexer = new HTMLLexer(
1340:                                        new StringReader(getContent(1, context,
1341:                                                false, true, false)));
1342:                                StringBuffer wordBuffer = new StringBuffer();
1343:                                for (Token t = lexer.nextToken(); t != null
1344:                                        && t.getType() != HTMLTokenTypes.CHTML
1345:                                        && t.getType() != HTMLTokenTypes.EOF; t = lexer
1346:                                        .nextToken()) {
1347:                                    if (t.getText() != null
1348:                                            && ((t.getType() == HTMLTokenTypes.UNDEFINED_TOKEN && t
1349:                                                    .getText().length() == 1) || t
1350:                                                    .getType() == HTMLTokenTypes.PCDATA)) {
1351:                                        if (t.getText().length() == 1
1352:                                                && Character.isWhitespace(t
1353:                                                        .getText().charAt(0))) {
1354:                                            String word = wordBuffer.toString()
1355:                                                    .toLowerCase().trim();
1356:                                            wordBuffer = new StringBuffer();
1357:                                            incCount(wordCounter, word, 1);
1358:                                        } else {
1359:                                            wordBuffer.append(t.getText());
1360:                                        }
1361:                                    } else {
1362:                                        String word = wordBuffer.toString()
1363:                                                .toLowerCase();
1364:                                        wordBuffer = new StringBuffer();
1365:                                        incCount(wordCounter, word, 1);
1366:                                    }
1367:                                }
1368:                            } catch (Exception e) {
1369:                                logger.warn("Exception during search: " + e, e);
1370:                            }
1371:                        }
1372:                    }
1373:
1374:                    int relevance = 1;
1375:                    Iterator it = terms.iterator();
1376:                    while (it.hasNext()) {
1377:                        String term = (String) it.next();
1378:
1379:                        if (term.startsWith("+") && term.length() > 1) {
1380:                            int[] cnt = (int[]) wordCounter.get(term
1381:                                    .substring(1));
1382:                            if (cnt == null) {
1383:                                relevance = 1;
1384:                                break;
1385:                            } else {
1386:                                relevance *= (cnt[0] + 2);
1387:                            }
1388:                        } else if (term.startsWith("-") && term.length() > 1) {
1389:                            int[] cnt = (int[]) wordCounter.get(term
1390:                                    .substring(1));
1391:                            if (cnt != null) {
1392:                                relevance = 1;
1393:                                break;
1394:                            }
1395:                        } else {
1396:                            int[] cnt = (int[]) wordCounter.get(term);
1397:                            if (cnt != null) {
1398:                                relevance *= (cnt[0] + 1);
1399:                            }
1400:                        }
1401:                    }
1402:                    if (relevance > 1) {
1403:                        findings.add(new SearchEntry(relevance, context));
1404:                    }
1405:                }
1406:
1407:                Iterator it = children.values().iterator();
1408:                while (it.hasNext()) {
1409:                    Help child = (Help) it.next();
1410:                    if (!child.isSection()) {
1411:                        child.search(terms, context, findings);
1412:                    }
1413:                }
1414:
1415:                if (parent == null) {
1416:                    it = owner.getChildren().iterator();
1417:                    while (it.hasNext()) {
1418:                        Menu child = (Menu) it.next();
1419:                        child.getHelp(context).search(terms, context, findings);
1420:                    }
1421:                }
1422:
1423:            }
1424:
1425:            private static void incCount(Map wordCounter, String word,
1426:                    int increment) {
1427:                if (word.length() > 0) {
1428:                    int[] count = (int[]) wordCounter.get(word);
1429:                    if (count == null) {
1430:                        count = new int[] { 0 };
1431:                        wordCounter.put(word, count);
1432:                    }
1433:                    count[0] += increment;
1434:                }
1435:            }
1436:
1437:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.