Source Code Cross Referenced for Menu.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.lang.reflect.Constructor;
0028:        import java.lang.reflect.InvocationHandler;
0029:        import java.lang.reflect.InvocationTargetException;
0030:        import java.lang.reflect.Method;
0031:        import java.lang.reflect.Proxy;
0032:        import java.net.URL;
0033:        import java.sql.ResultSet;
0034:        import java.sql.SQLException;
0035:        import java.util.ArrayList;
0036:        import java.util.Collection;
0037:        import java.util.HashMap;
0038:        import java.util.HashSet;
0039:        import java.util.Iterator;
0040:        import java.util.List;
0041:        import java.util.Map;
0042:        import java.util.Properties;
0043:        import java.util.Set;
0044:        import java.util.TreeSet;
0045:
0046:        import javax.servlet.http.HttpServletRequest;
0047:        import javax.servlet.http.HttpServletResponse;
0048:        import javax.xml.parsers.ParserConfigurationException;
0049:
0050:        import org.apache.log4j.Logger;
0051:        import org.apache.xpath.CachedXPathAPI;
0052:        import org.w3c.dom.Document;
0053:        import org.w3c.dom.Element;
0054:        import org.w3c.dom.Node;
0055:        import org.w3c.dom.NodeList;
0056:        import org.xml.sax.SAXException;
0057:
0058:        import biz.hammurapi.authorization.AuthorizationProvider;
0059:        import biz.hammurapi.cache.Cache;
0060:        import biz.hammurapi.codegen.GenerationException;
0061:        import biz.hammurapi.codegen.InjectingClassLoader;
0062:        import biz.hammurapi.codegen.Interface;
0063:        import biz.hammurapi.codegen.InterfacePool;
0064:        import biz.hammurapi.codegen.InterfacePool.InterfaceDescriptor;
0065:        import biz.hammurapi.config.ChainedContext;
0066:        import biz.hammurapi.config.Component;
0067:        import biz.hammurapi.config.ConfigurationException;
0068:        import biz.hammurapi.config.Context;
0069:        import biz.hammurapi.config.DomConfigurable;
0070:        import biz.hammurapi.config.MapContext;
0071:        import biz.hammurapi.config.PropertyParser;
0072:        import biz.hammurapi.config.Wrapper;
0073:        import biz.hammurapi.convert.CompositeConverter;
0074:        import biz.hammurapi.sql.DataAccessObject;
0075:        import biz.hammurapi.sql.SQLProcessor;
0076:        import biz.hammurapi.sql.metadata.DefaultGenerationPolicy;
0077:        import biz.hammurapi.sql.metadata.GenerationPolicy;
0078:        import biz.hammurapi.web.HammurapiWebException;
0079:        import biz.hammurapi.web.RequestContext;
0080:        import biz.hammurapi.web.eval.EvaluationResult;
0081:        import biz.hammurapi.web.eval.EvaluatorFactory;
0082:        import biz.hammurapi.web.interaction.sql.Interaction;
0083:        import biz.hammurapi.web.interaction.sql.InteractionEngine;
0084:        import biz.hammurapi.web.menu.matchers.ExactUriMatcher;
0085:        import biz.hammurapi.web.menu.matchers.MatchResult;
0086:        import biz.hammurapi.web.menu.matchers.OrRequestMatcher;
0087:        import biz.hammurapi.web.menu.matchers.RequestMatcher;
0088:        import biz.hammurapi.web.menu.matchers.UriMatcher;
0089:        import biz.hammurapi.web.menu.sql.Adornment;
0090:        import biz.hammurapi.web.menu.sql.ItemReference;
0091:        import biz.hammurapi.web.menu.sql.MenuEngine;
0092:        import biz.hammurapi.web.menu.sql.MenuHelpTopics;
0093:        import biz.hammurapi.web.menu.sql.MenuHelpTopicsImpl;
0094:        import biz.hammurapi.web.menu.sql.MenuNavigatorTemplate;
0095:        import biz.hammurapi.web.menu.sql.MenuParameter;
0096:        import biz.hammurapi.web.menu.sql.Permission;
0097:        import biz.hammurapi.web.menu.sql.ResourcePattern;
0098:        import biz.hammurapi.web.menu.sql.XmenuImpl;
0099:        import biz.hammurapi.web.security.UserAuthorizationProvider;
0100:        import biz.hammurapi.web.util.Escaper;
0101:        import biz.hammurapi.wrap.WrapperHandler;
0102:        import biz.hammurapi.xml.dom.AbstractDomObject;
0103:        import biz.hammurapi.xml.dom.DOMUtils;
0104:
0105:        public class Menu extends XmenuImpl implements  DataAccessObject,
0106:                RequestMatcher, ChainedContext {
0107:            private static final String CONTEXT_PREFIX = "context:";
0108:            private static final String TEMPLATE_PREFIX = "template:";
0109:            private static final String TOPIC_CONTENT_URL_PART = "/topicContent?id=T";
0110:            private static final String MENU_HELP_URL_PART = "/menuHelp/help.html?id=";
0111:            public static final String MT_ROOT = "root";
0112:            public static final String MT_FORM_HANDLER = "formHandler";
0113:            public static final String MT_RESOURCE = "resource";
0114:
0115:            private static final Logger logger = Logger.getLogger(Menu.class);
0116:            private static final String MENU_HELP_ACTIONS_GLOBAL_PATH = "global:db/MenuHelpActionsPath";
0117:
0118:            private static final String INTERACTION_CONTROLLER_URI = "/system/interaction.InterActions/start?interactionId=";
0119:
0120:            public Menu() {
0121:                super ();
0122:            }
0123:
0124:            public Menu(boolean force) {
0125:                super (force);
0126:            }
0127:
0128:            public Menu(Element holder, boolean force)
0129:                    throws ConfigurationException {
0130:                super (holder, force);
0131:            }
0132:
0133:            public Menu(Element holder, Properties nameMap,
0134:                    CachedXPathAPI cxpa, boolean force)
0135:                    throws ConfigurationException {
0136:                super (holder, nameMap, cxpa, force);
0137:            }
0138:
0139:            public Menu(ResultSet rs) throws SQLException {
0140:                super (rs);
0141:            }
0142:
0143:            private Collection children;
0144:            private Map itemMap = new HashMap();
0145:            private Map actionMap = new HashMap();
0146:            private Map idMap;
0147:            private Map xidMap;
0148:            private Collection functions;
0149:            private Map navigatorTemplates = new HashMap();
0150:            private Map helpTopics = new HashMap();
0151:            private Help help = new Help(this );
0152:
0153:            private void loadHelpMountPoints(Context context) {
0154:                synchronized (helpMountPoints) {
0155:                    if (!helpMountPoints.isEmpty()) {
0156:                        PropertyParser pp = new PropertyParser(context, false);
0157:                        Iterator it = helpMountPoints.iterator();
0158:                        while (it.hasNext()) {
0159:                            MenuHelpTopics mht = (MenuHelpTopics) it.next();
0160:                            try {
0161:                                String mountUrlStr = pp
0162:                                        .parse(mht.getTopicUrl());
0163:                                Document doc;
0164:                                if (mountUrlStr.startsWith(CONTEXT_PREFIX)) {
0165:                                    Object xml = context
0166:                                            .get(mountUrlStr
0167:                                                    .substring(CONTEXT_PREFIX
0168:                                                            .length()));
0169:                                    if (xml == null) {
0170:                                        logger.error("Invalid mount URL: "
0171:                                                + mountUrlStr);
0172:                                        continue;
0173:                                    }
0174:                                    doc = DOMUtils.parse(new StringReader(xml
0175:                                            .toString()));
0176:                                } else {
0177:                                    URL mountUrl = new URL(mountUrlStr);
0178:                                    doc = DOMUtils.parse(mountUrl.openStream());
0179:                                }
0180:                                doc.getDocumentElement().setAttribute("name",
0181:                                        mht.getName());
0182:                                mount(doc.getDocumentElement(), null, mht
0183:                                        .getName().indexOf("#") != -1,
0184:                                        mountUrlStr);
0185:                            } catch (Exception e) {
0186:                                logger.error("Could not load mount point from "
0187:                                        + mht.getTopicUrl() + " : " + e, e);
0188:                            }
0189:                            it.remove();
0190:                        }
0191:                    }
0192:                }
0193:            }
0194:
0195:            /**
0196:             * @return Root help descriptor for this item.
0197:             */
0198:            public Help getHelp(Context context) {
0199:                loadHelpMountPoints(context);
0200:                return help;
0201:            }
0202:
0203:            public MenuHelpTopics getHelpTopic(String name, Context context) {
0204:                loadHelpMountPoints(context);
0205:                return (MenuHelpTopics) helpTopics.get(name);
0206:            }
0207:
0208:            /**
0209:             * Loads dependent objects.
0210:             */
0211:            public void setSQLProcessor(SQLProcessor processor)
0212:                    throws SQLException {
0213:                final MenuEngine engine = new MenuEngine(processor);
0214:                if (getParent() == null) {
0215:                    interactionOffset = engine.getMaxMenu() + 1;
0216:                    logger.info("Interaction offset: " + interactionOffset);
0217:                    nextVirtualId = interactionOffset
0218:                            + engine.getMaxInteraction();
0219:                }
0220:                children = engine.getXmenuByParent(new Integer(getId()),
0221:                        new ArrayList(), Menu.class);
0222:                Iterator it = children.iterator();
0223:                while (it.hasNext()) {
0224:                    ((Menu) it.next()).setParent(new Integer(getId()));
0225:                }
0226:                it = engine.getItemReferenceByItem(getId()).iterator();
0227:                while (it.hasNext()) {
0228:                    ItemReference ir = (ItemReference) it.next();
0229:                    Menu referenced = (Menu) engine.getXmenu(ir.getRefId(),
0230:                            Menu.class);
0231:                    if (!isBlank(ir.getName())) {
0232:                        referenced.setName(ir.getName());
0233:                    }
0234:                    referenced.setQueryTemplate(ir.getQueryTemplate());
0235:                    referenced.setScope(ir.getScope());
0236:                    if (!isBlank(ir.getTitle())) {
0237:                        referenced.setTitle(ir.getTitle());
0238:                    }
0239:                    referenced.setItemPosition(ir.getRefPosition());
0240:                    //			Integer offset = new Integer((getMaxMenuId()+1)*(ir.getId()+1));
0241:                    //			referenced.refOffset = offset;
0242:                    //			referenced.setId(referenced.getRefOffset()+referenced.getId());
0243:                    children.add(referenced);
0244:                }
0245:
0246:                InteractionEngine iEngine = new InteractionEngine(processor);
0247:                it = iEngine.getInteractionByOwner(getId()).iterator();
0248:                while (it.hasNext()) {
0249:                    Interaction interaction = (Interaction) it.next();
0250:                    Menu iMenu = new Menu();
0251:                    iMenu.setParent(new Integer(getId()));
0252:                    iMenu
0253:                            .setUri(INTERACTION_CONTROLLER_URI
0254:                                    + interaction.getId()/*+"&refOffset="+getRefOffset()*/);
0255:                    iMenu.setName(interaction.getName());
0256:                    iMenu.setScope(interaction.getScope());
0257:                    iMenu.setGuid(interaction.getGuid());
0258:                    iMenu.setId(/*getRefOffset()+*/getInteractionOffset()
0259:                            + interaction.getId());
0260:                    interaction.setLastModified(interaction.getLastModified());
0261:                    iMenu.setSQLProcessor(processor);
0262:                    iMenu.setType("item");
0263:                    children.add(iMenu);
0264:                }
0265:
0266:                adornments = engine
0267:                        .getAdornmentByItem(getId(), new ArrayList());
0268:                resourcePatterns = engine.getResourcePatternByItem(getId(),
0269:                        new ArrayList());
0270:                colors = engine.getMenuColorByMenu(getId(), new ArrayList());
0271:                permissions = engine.getPermission(getId(), new ArrayList());
0272:                parameters = engine.getMenuParameterByMenu(getId(),
0273:                        new ArrayList());
0274:                it = parameters.iterator();
0275:                while (it.hasNext()) {
0276:                    MenuParameter mp = (MenuParameter) it.next();
0277:                    setAttribute(mp.getName(), mp.getParameterValue());
0278:                }
0279:
0280:                functions = engine.getMenuFunctionByMenu(getId(),
0281:                        Function.class);
0282:
0283:                it = engine.getMenuNavigatorTemplateByMenu(getId()).iterator();
0284:                while (it.hasNext()) {
0285:                    MenuNavigatorTemplate mnt = (MenuNavigatorTemplate) it
0286:                            .next();
0287:                    navigatorTemplates.put(mnt.getName(), mnt);
0288:                }
0289:
0290:                it = engine.getMenuHelpTopics(getId()).iterator();
0291:                while (it.hasNext()) {
0292:                    MenuHelpTopics mht = (MenuHelpTopics) it.next();
0293:                    if ("Mount point".equals(mht.getType())) {
0294:                        if (isBlank(mht.getTopicUrl())) {
0295:                            logger
0296:                                    .error("Could not load mount point, URL is blank.");
0297:                        } else {
0298:                            helpMountPoints.add(mht);
0299:                        }
0300:                    } else {
0301:                        helpTopics.put(mht.getName(), mht);
0302:                        help.add("main".equals(mht.getName()) ? null : mht
0303:                                .getName(), mht);
0304:                    }
0305:                }
0306:            }
0307:
0308:            /**
0309:             * Walks up the hierarchy until finds the needed attribute.
0310:             */
0311:            public Object getAttribute(Object key) {
0312:                Object ret = super .getAttribute(key);
0313:                if (ret != null) {
0314:                    return ret;
0315:                }
0316:                return parent == null ? parent.getAttribute(key) : null;
0317:            }
0318:
0319:            private Collection adornments;
0320:            private Collection resourcePatterns;
0321:            private Collection colors;
0322:            private Collection permissions;
0323:            private Collection parameters;
0324:            private Menu[] path;
0325:
0326:            private OrRequestMatcher resourcePatternMatcher;
0327:            private UriMatcher rootMatcher;
0328:            private UriMatcher formHandlerMatcher;
0329:
0330:            private Menu parent;
0331:
0332:            private boolean started;
0333:            private boolean startResult;
0334:            private boolean blankUri;
0335:            private Object engine;
0336:            private Object runtimeEngine;
0337:
0338:            public Object getEngine() {
0339:                return engine;
0340:            }
0341:
0342:            /**
0343:             * @return Generated engine instance, which combines
0344:             * methods from engine class and functions.
0345:             */
0346:            public Object getRuntimeEngine() {
0347:                if (runtimeEngine == null) {
0348:                    return parent == null ? null : parent.getRuntimeEngine();
0349:                }
0350:                return runtimeEngine;
0351:            }
0352:
0353:            private Map functionMap;
0354:
0355:            private class FunctionKey extends ArrayList {
0356:                public FunctionKey(String functionName, int parameterCount) {
0357:                    super ();
0358:                    add(functionName);
0359:                    add(new Integer(parameterCount));
0360:                }
0361:            }
0362:
0363:            /**
0364:             * @param request
0365:             * @param response
0366:             * @return Runtime engine, which is aware of its invocation context.
0367:             */
0368:            public Object getRuntimeEngine(final HttpServletRequest request,
0369:                    final HttpServletResponse response) {
0370:                final Object parentRuntimeEngine = parent == null ? null
0371:                        : parent.getRuntimeEngine(request, response);
0372:
0373:                if (functions.isEmpty()) {
0374:                    return parentRuntimeEngine;
0375:                }
0376:
0377:                // Generate own engine
0378:                InvocationHandler ih = new InvocationHandler() {
0379:
0380:                    public Object invoke(Object proxy, Method method,
0381:                            Object[] args) throws Throwable {
0382:                        if (Object.class.getName().equals(
0383:                                method.getDeclaringClass().getName())) {
0384:                            return method.invoke(functionMap, args); // Delegate Object's methods to function map.
0385:                        }
0386:                        Object key = new FunctionKey(method.getName(), method
0387:                                .getParameterTypes().length);
0388:                        Function function = (Function) functionMap.get(key);
0389:                        if (function != null) {
0390:                            return function.invoke(args, request, response);
0391:                        }
0392:
0393:                        if (parentRuntimeEngine == null) {
0394:                            throw new HammurapiWebException("Function "
0395:                                    + method + " not found in runtime engine");
0396:                        }
0397:
0398:                        return method.invoke(parentRuntimeEngine, args); // Delegate to parent
0399:                    }
0400:
0401:                };
0402:
0403:                return Proxy.newProxyInstance(getInjectingClassLoader(),
0404:                        runtimeEngineInterfaces, ih);
0405:            }
0406:
0407:            /**
0408:             * Starts root menu.
0409:             */
0410:            public boolean start(AuthorizationProvider authorizationProvider,
0411:                    Context context) throws HammurapiWebException {
0412:                return start(null, new HashSet(), authorizationProvider,
0413:                        context);
0414:            }
0415:
0416:            /**
0417:             * Starts menu item.
0418:             * @param parent Parent item.
0419:             * @param authorizationProvider Authorization provider
0420:             * @param contextPath Context path to prepend to uri's
0421:             * @return false if authorization provider doesn't have permissions to access this item.
0422:             * @throws HammurapiWebException
0423:             */
0424:            private boolean start(Menu parent, Set idSet,
0425:                    AuthorizationProvider authorizationProvider, Context context)
0426:                    throws HammurapiWebException {
0427:                if (!started) {
0428:                    startResult = _start(parent, idSet, authorizationProvider,
0429:                            context);
0430:                }
0431:
0432:                return startResult;
0433:            }
0434:
0435:            /**
0436:             * Interfaces implemented by runtime engine
0437:             */
0438:            private Class[] runtimeEngineInterfaces;
0439:
0440:            private boolean _start(final Menu parent, Set idSet,
0441:                    AuthorizationProvider authorizationProvider, Context context)
0442:                    throws HammurapiWebException {
0443:                if (getIsDisabled()) {
0444:                    return false;
0445:                }
0446:
0447:                Integer originalId = new Integer(getId());
0448:                if (!idSet.add(originalId)) {
0449:                    logger.warn("Circular reference, menu " + getId()
0450:                            + " is a child of self");
0451:                    return false;
0452:                }
0453:
0454:                if (authorizationProvider != null) {
0455:                    boolean accessGranted = false;
0456:
0457:                    // Check direct assignment of permissions
0458:                    if (!accessGranted
0459:                            && authorizationProvider instanceof  UserAuthorizationProvider) {
0460:                        Boolean hasAccess = ((UserAuthorizationProvider) authorizationProvider)
0461:                                .hasAccess(getId());
0462:                        if (Boolean.TRUE.equals(hasAccess)) {
0463:                            accessGranted = true;
0464:                        }
0465:
0466:                        if (Boolean.FALSE.equals(hasAccess)) {
0467:                            return false;
0468:                        }
0469:                    }
0470:
0471:                    // If user is not in ACL and is not directly assigned menu id, then check class permissions.
0472:                    if (!accessGranted) {
0473:                        Iterator it = permissions.iterator();
0474:                        while (it.hasNext()) {
0475:                            Permission p = (Permission) it.next();
0476:                            if (!authorizationProvider.hasClassPermission(p
0477:                                    .getClassName(), p.getActionName())) {
0478:                                return false;
0479:                            }
0480:                        }
0481:                    }
0482:
0483:                    boolean strictSecurity = "strict".equals(context
0484:                            .get("db/menu-security"));
0485:
0486:                    // Protect access to the first level menus if permissions haven't been granted explicitly.
0487:                    if (strictSecurity && !accessGranted && parent != null
0488:                            && parent.parent == null) {
0489:                        return false;
0490:                    }
0491:                }
0492:
0493:                this .parent = parent;
0494:                if (parent == null) {
0495:                    path = new Menu[] { this  };
0496:                    matchCache = new HashMap();
0497:                    injectingClassLoader = new InjectingClassLoader(this 
0498:                            .getClass().getClassLoader());
0499:                    interfacePool = new InterfacePool();
0500:                    cache = (Cache) context.get("db/cache");
0501:                    generationPolicy = new DefaultGenerationPolicy();
0502:                    guidMap = new HashMap();
0503:                    idMap = new HashMap();
0504:                    xidMap = new HashMap();
0505:                } else {
0506:                    path = new Menu[parent.getPath().length + 1];
0507:                    System.arraycopy(parent.getPath(), 0, path, 0,
0508:                            path.length - 1);
0509:                    path[path.length - 1] = this ;
0510:                    if (!isBlank(parent.getKeywords())) {
0511:                        setKeywords(parent.getKeywords() + ", " + getKeywords());
0512:                    }
0513:
0514:                    Collection parentAdornmentsToAdd = new ArrayList();
0515:                    Iterator it = parent.adornments.iterator();
0516:                    Z: while (it.hasNext()) {
0517:                        Adornment pa = (Adornment) it.next();
0518:                        Iterator sit = adornments.iterator();
0519:                        while (sit.hasNext()) {
0520:                            Adornment a = (Adornment) sit.next();
0521:                            if (pa.getName().equals(a.getName())
0522:                                    && a.getSuppress()) {
0523:                                continue Z;
0524:                            }
0525:                        }
0526:                        parentAdornmentsToAdd.add(pa);
0527:                    }
0528:                    adornments.addAll(parentAdornmentsToAdd);
0529:                }
0530:
0531:                mapItem(this );
0532:
0533:                if (!isBlank(getGuid())) {
0534:                    putToGuidMap(getGuid(), this );
0535:                }
0536:
0537:                String parentBaseUri = null;
0538:                if (parent != null) {
0539:                    if (parent.getUri().endsWith("/")) {
0540:                        parentBaseUri = parent.getUri();
0541:                    } else {
0542:                        int idx = parent.getUri().lastIndexOf('/');
0543:                        if (idx != -1) {
0544:                            parentBaseUri = parent.getUri().substring(0,
0545:                                    idx + 1);
0546:                        }
0547:                    }
0548:                }
0549:
0550:                PropertyParser selfContextPropertyParser = new PropertyParser(
0551:                        this , false);
0552:
0553:                if (isBlank(getUri())) {
0554:                    setUri("xMenu" + getId() + ".html");
0555:                }
0556:
0557:                if (isBlank(getFormHandlerUri())) {
0558:                    setFormHandlerUri("formHandler" + getId() + ".html");
0559:                }
0560:
0561:                // Parse XID to expand entries like ${parent:XID}.viewSomthing
0562:                setXid(selfContextPropertyParser.parse(getXid()));
0563:
0564:                if (isBlank(getUri()) || "#".equals(getUri().trim())) {
0565:                    blankUri = true;
0566:                    setUri(parent.getUri()); // so children uri's are calculated relative to parent's uri.
0567:                } else {
0568:                    String parsedUri = selfContextPropertyParser
0569:                            .parse(getUri());
0570:                    rootMatcher = new ExactUriMatcher(parsedUri, parentBaseUri,
0571:                            getMatchQueryString(), getWeight());
0572:                    setUri(rootMatcher.getAbsolutePattern()); // Override relative uri with absolute value.
0573:                }
0574:
0575:                String baseUri = null;
0576:                if (getUri().endsWith("/")) {
0577:                    baseUri = getUri();
0578:                } else {
0579:                    int idx = getUri().lastIndexOf('/');
0580:                    if (idx != -1) {
0581:                        baseUri = getUri().substring(0, idx + 1);
0582:                    }
0583:                }
0584:
0585:                if (!resourcePatterns.isEmpty()) {
0586:                    resourcePatternMatcher = new OrRequestMatcher();
0587:                    Iterator it = resourcePatterns.iterator();
0588:                    while (it.hasNext()) {
0589:                        ResourcePattern rp = (ResourcePattern) it.next();
0590:                        resourcePatternMatcher.addMatcher(UriMatcher
0591:                                .newMatcher(rp.getPatternLanguage(), rp
0592:                                        .getPattern(), baseUri, rp
0593:                                        .getMatchQueryString(), getWeight()));
0594:                    }
0595:                }
0596:
0597:                if (!isBlank(getFormHandlerUri())) {
0598:                    String parsedFormHandlerUri = selfContextPropertyParser
0599:                            .parse(getFormHandlerUri());
0600:                    formHandlerMatcher = new ExactUriMatcher(
0601:                            parsedFormHandlerUri, baseUri, false, 0);
0602:                    setFormHandlerUri(formHandlerMatcher.getAbsolutePattern()); // Override relative uri with absolute value.			
0603:                }
0604:
0605:                if (!isBlank(getEngineClass())) {
0606:                    try {
0607:                        Class clazz = Class.forName(getEngineClass());
0608:                        if (isBlank(getEngineConfig())) {
0609:                            engine = clazz.newInstance();
0610:                        } else {
0611:                            // Attempt to construct class from value
0612:                            Constructor[] constructors = clazz
0613:                                    .getConstructors();
0614:                            for (int i = 0; i < constructors.length; i++) {
0615:                                if (constructors[i].getParameterTypes().length == 1
0616:                                        && constructors[i].getParameterTypes()[0]
0617:                                                .equals(String.class)) {
0618:                                    engine = constructors[i]
0619:                                            .newInstance(new Object[] { getEngineConfig() });
0620:                                    break;
0621:                                }
0622:                            }
0623:
0624:                            if (engine == null) {
0625:                                engine = clazz.newInstance();
0626:
0627:                                if (DomConfigurable.class
0628:                                        .isAssignableFrom(clazz)) {
0629:                                    ((DomConfigurable) engine)
0630:                                            .configure(DOMUtils.parse(
0631:                                                    new StringReader(
0632:                                                            getEngineConfig()))
0633:                                                    .getDocumentElement(), this );
0634:                                } else {
0635:                                    engine = CompositeConverter
0636:                                            .getDefaultConverter().convert(
0637:                                                    getEngineConfig(), clazz,
0638:                                                    false);
0639:                                }
0640:                            }
0641:                        }
0642:
0643:                        if (engine instanceof  Wrapper) {
0644:                            engine = ((Wrapper) engine).getMaster();
0645:                        }
0646:                    } catch (InstantiationException e) {
0647:                        throw new HammurapiWebException(
0648:                                "Cannot instantiate engine '"
0649:                                        + getEngineClass() + " with config "
0650:                                        + getEngineConfig() + ": " + e, e);
0651:                    } catch (IllegalAccessException e) {
0652:                        throw new HammurapiWebException(
0653:                                "Cannot instantiate engine '"
0654:                                        + getEngineClass() + " with config "
0655:                                        + getEngineConfig() + ": " + e, e);
0656:                    } catch (ClassNotFoundException e) {
0657:                        throw new HammurapiWebException(
0658:                                "Cannot instantiate engine '"
0659:                                        + getEngineClass() + " with config "
0660:                                        + getEngineConfig() + ": " + e, e);
0661:                    } catch (SecurityException e) {
0662:                        throw new HammurapiWebException(
0663:                                "Cannot instantiate engine '"
0664:                                        + getEngineClass() + " with config "
0665:                                        + getEngineConfig() + ": " + e, e);
0666:                    } catch (InvocationTargetException e) {
0667:                        throw new HammurapiWebException(
0668:                                "Cannot instantiate engine '"
0669:                                        + getEngineClass() + " with config "
0670:                                        + getEngineConfig() + ": " + e, e);
0671:                    } catch (ConfigurationException e) {
0672:                        throw new HammurapiWebException(
0673:                                "Cannot instantiate engine '"
0674:                                        + getEngineClass() + " with config "
0675:                                        + getEngineConfig() + ": " + e, e);
0676:                    } catch (SAXException e) {
0677:                        throw new HammurapiWebException(
0678:                                "Cannot instantiate engine '"
0679:                                        + getEngineClass() + " with config "
0680:                                        + getEngineConfig() + ": " + e, e);
0681:                    } catch (IOException e) {
0682:                        throw new HammurapiWebException(
0683:                                "Cannot instantiate engine '"
0684:                                        + getEngineClass() + " with config "
0685:                                        + getEngineConfig() + ": " + e, e);
0686:                    } catch (ParserConfigurationException e) {
0687:                        throw new HammurapiWebException(
0688:                                "Cannot instantiate engine '"
0689:                                        + getEngineClass() + " with config "
0690:                                        + getEngineConfig() + ": " + e, e);
0691:                    }
0692:                }
0693:
0694:                if (!functions.isEmpty()) {
0695:                    functionMap = new HashMap();
0696:
0697:                    // Create runtime engine here.
0698:                    InterfaceDescriptor ed = getInterfacePool().addInterface(
0699:                            this .getClass().getName() + "$RuntimeEngine"
0700:                                    + getId(), null);
0701:                    Iterator it = functions.iterator();
0702:                    while (it.hasNext()) {
0703:                        Function function = (Function) it.next();
0704:                        function.start(context, this );
0705:                        Object key = new FunctionKey(function.getName(),
0706:                                function.getParameterCount());
0707:                        if (functionMap.containsKey(key)) {
0708:                            throw new HammurapiWebException(
0709:                                    "Duplicate function " + function.getName()
0710:                                            + " with "
0711:                                            + function.getParameterCount()
0712:                                            + " parameters");
0713:                        }
0714:                        functionMap.put(key, function);
0715:                        StringBuffer funcDef = new StringBuffer(
0716:                                "public java.lang.Object ");
0717:                        funcDef.append(function.getName());
0718:                        funcDef.append("(");
0719:                        for (int i = 0; i < function.getParameterCount(); ++i) {
0720:                            if (i > 0) {
0721:                                funcDef.append(",");
0722:                            }
0723:                            funcDef.append("java.lang.Object");
0724:                        }
0725:                        funcDef.append(") throws ");
0726:                        funcDef.append(HammurapiWebException.class.getName());
0727:                        ed.addMethod(funcDef.toString());
0728:                    }
0729:
0730:                    try {
0731:                        if (ed.isMaster()) {
0732:                            // There is no master - need to generate 
0733:                            Collection super Interfaces = ed
0734:                                    .getSuperInterfaces(null);
0735:                            StringBuffer iName = new StringBuffer(
0736:                                    "public interface ");
0737:                            iName.append(ed.getName());
0738:                            if (!super Interfaces.isEmpty()) {
0739:                                iName.append(" extends ");
0740:                                Iterator eit = super Interfaces.iterator();
0741:                                while (eit.hasNext()) {
0742:                                    iName.append(eit.next());
0743:                                    if (eit.hasNext()) {
0744:                                        iName.append(", ");
0745:                                    }
0746:                                }
0747:                            }
0748:                            Interface rsInterface = new Interface(iName
0749:                                    .toString(), "Runtime engine interface",
0750:                                    null);
0751:                            it = ed.getOwnMethods().iterator();
0752:                            while (it.hasNext()) {
0753:                                rsInterface.addMethod((String) it.next(), null,
0754:                                        "Runtime function", null);
0755:                            }
0756:
0757:                            getInjectingClassLoader().consume(rsInterface);
0758:
0759:                        }
0760:
0761:                        final Class runtimeEngineInterface = getInjectingClassLoader()
0762:                                .loadClass(ed.getMaster().getName());
0763:                        final Object parentRuntimeEngine = parent == null ? null
0764:                                : parent.getRuntimeEngine();
0765:
0766:                        if (parentRuntimeEngine == null) {
0767:                            runtimeEngineInterfaces = new Class[] { runtimeEngineInterface };
0768:                        } else {
0769:                            if (runtimeEngineInterface
0770:                                    .isInstance(parentRuntimeEngine)) {
0771:                                runtimeEngineInterfaces = WrapperHandler
0772:                                        .getClassInterfaces(parentRuntimeEngine
0773:                                                .getClass());
0774:                            } else {
0775:                                Class[] parentInterfaces = WrapperHandler
0776:                                        .getClassInterfaces(parentRuntimeEngine
0777:                                                .getClass());
0778:                                runtimeEngineInterfaces = new Class[parentInterfaces.length + 1];
0779:                                runtimeEngineInterfaces[0] = runtimeEngineInterface;
0780:                                System.arraycopy(parentInterfaces, 0,
0781:                                        runtimeEngineInterfaces, 1,
0782:                                        parentInterfaces.length);
0783:                            }
0784:                        }
0785:
0786:                        // Generate own engine
0787:                        InvocationHandler ih = new InvocationHandler() {
0788:
0789:                            public Object invoke(Object proxy, Method method,
0790:                                    Object[] args) throws Throwable {
0791:                                if (Object.class.getName().equals(
0792:                                        method.getDeclaringClass().getName())) {
0793:                                    return method.invoke(functionMap, args); // Delegate Object's methods to function map.
0794:                                }
0795:                                Object key = new FunctionKey(method.getName(),
0796:                                        method.getParameterTypes().length);
0797:                                Function function = (Function) functionMap
0798:                                        .get(key);
0799:                                if (function != null) {
0800:                                    return function.invoke(args);
0801:                                }
0802:
0803:                                if (parentRuntimeEngine == null) {
0804:                                    throw new HammurapiWebException("Function "
0805:                                            + method
0806:                                            + " not found in runtime engine "
0807:                                            + runtimeEngineInterface.getName());
0808:                                }
0809:                                return method.invoke(parentRuntimeEngine, args); // Delegate to parent
0810:                            }
0811:
0812:                        };
0813:
0814:                        runtimeEngine = Proxy.newProxyInstance(
0815:                                getInjectingClassLoader(),
0816:                                runtimeEngineInterfaces, ih);
0817:                    } catch (GenerationException e) {
0818:                        throw new HammurapiWebException(
0819:                                "Could not generate runtime engine: " + e, e);
0820:                    } catch (ClassNotFoundException e) {
0821:                        throw new HammurapiWebException(
0822:                                "Could not generate runtime engine: " + e, e);
0823:                    }
0824:                }
0825:
0826:                // Start children. Remove unaccessible children.
0827:                Iterator it = children.iterator();
0828:                while (it.hasNext()) {
0829:                    Menu child = (Menu) it.next();
0830:                    if (child
0831:                            .start(this , idSet, authorizationProvider, context)) {
0832:                        if ("action".equals(child.getType())) {
0833:                            if (isBlank(child.getXid())) {
0834:                                logger.warn("Action without XID: "
0835:                                        + child.getId());
0836:                            } else {
0837:                                actionMap.put(child.getXid(), child);
0838:                            }
0839:                        } else {
0840:                            if ("menu".equals(child.getType())) {
0841:                                child.setType("item"); // To simplify stylesheets.
0842:                            }
0843:
0844:                            itemMap.put(child.getName(), child);
0845:                        }
0846:                    } else {
0847:                        it.remove();
0848:                    }
0849:                }
0850:
0851:                // Overwrite matchQueryString with OR from patterns and children
0852:                if (!getMatchQueryString()) {
0853:                    setMatchQueryString((rootMatcher != null && rootMatcher
0854:                            .isMatchQueryString())
0855:                            || (resourcePatternMatcher != null && resourcePatternMatcher
0856:                                    .isMatchQueryString())
0857:                            || (formHandlerMatcher != null && formHandlerMatcher
0858:                                    .isMatchQueryString()));
0859:                }
0860:
0861:                it = children.iterator();
0862:                while (!getMatchQueryString() && it.hasNext()) {
0863:                    setMatchQueryString(((Menu) it.next()).isMatchQueryString());
0864:                }
0865:
0866:                idSet.remove(originalId);
0867:                return true;
0868:            }
0869:
0870:            private static int mountPointsCounter = Integer.MAX_VALUE;
0871:            private Collection helpMountPoints = new ArrayList();
0872:
0873:            private void mount(Element helpElement, String parentPath,
0874:                    boolean isSection, String baseURL) {
0875:                if (!isBlank(helpElement.getAttribute("name"))
0876:                        && helpElement.hasAttribute("href")) { // Skip blank topics, go straight to children
0877:                    MenuHelpTopicsImpl mhti = new MenuHelpTopicsImpl();
0878:                    mhti.setType("URL");
0879:                    mhti.setName(parentPath == null ? helpElement
0880:                            .getAttribute("name") : parentPath
0881:                            + (isSection ? "#" : "/")
0882:                            + helpElement.getAttribute("name"));
0883:                    synchronized (this ) {
0884:                        mhti.setId(mountPointsCounter--);
0885:                    }
0886:                    mhti.setTopicUrl(isSection ? baseURL + "#"
0887:                            + helpElement.getAttribute("href") : helpElement
0888:                            .getAttribute("href"));
0889:                    if (helpElement.hasAttribute("title")) {
0890:                        mhti.setTitle(helpElement.getAttribute("title"));
0891:                    }
0892:                    String originalName = mhti.getName();
0893:                    for (int i = 2; helpTopics.containsKey(mhti.getName()); ++i) {
0894:                        mhti.setName(originalName + " (" + i + ")");
0895:                    }
0896:                    helpTopics.put(mhti.getName(), mhti);
0897:                    help.add("main".equals(mhti.getName()) ? null : mhti
0898:                            .getName(), mhti);
0899:                    parentPath = mhti.getName();
0900:                    if (!isSection) {
0901:                        baseURL = mhti.getTopicUrl();
0902:                    }
0903:                } else {
0904:                    logger
0905:                            .warn("Help mount point is missing either name or href attribute");
0906:                }
0907:
0908:                NodeList nl = helpElement.getChildNodes();
0909:                for (int i = 0, l = nl.getLength(); i < l; ++i) {
0910:                    Node n = nl.item(i);
0911:                    if (n instanceof  Element && "topic".equals(n.getNodeName())) {
0912:                        mount((Element) n, parentPath, false, baseURL);
0913:                    }
0914:                }
0915:                nl = helpElement.getChildNodes();
0916:                for (int i = 0, l = nl.getLength(); i < l; ++i) {
0917:                    Node n = nl.item(i);
0918:                    if (n instanceof  Element
0919:                            && "section".equals(n.getNodeName())) {
0920:                        mount((Element) n, parentPath, true, baseURL);
0921:                    }
0922:                }
0923:            }
0924:
0925:            private void mapItem(Menu menu) {
0926:                if (parent == null) {
0927:                    if (menu.getXid() != null) {
0928:                        xidMap.put(menu.getXid(), menu);
0929:                    }
0930:                    Integer mid = new Integer(menu.getId());
0931:                    if (idMap.containsKey(mid)) {
0932:                        menu.setId(nextVirtualId());
0933:                        logger.info("Duplicate item id, changing " + mid
0934:                                + " to " + menu.getId());
0935:                        mid = new Integer(menu.getId());
0936:                    }
0937:                    idMap.put(mid, menu);
0938:                } else {
0939:                    parent.mapItem(menu);
0940:                }
0941:            }
0942:
0943:            public void stop() throws ConfigurationException {
0944:
0945:                Iterator it = children.iterator();
0946:                while (it.hasNext()) {
0947:                    ((Component) it.next()).stop();
0948:                }
0949:
0950:            }
0951:
0952:            /**
0953:             * Renders menu to DOM
0954:             * @param request
0955:             * @param holder
0956:             */
0957:            public void toDom(Element holder, HttpServletRequest request) {
0958:                if (enabled()) {
0959:                    super .toDom(holder);
0960:                    String href = (String) get("href", new RequestContext(
0961:                            request));
0962:                    if (href != null) {
0963:                        holder.setAttribute("href", href);
0964:                    }
0965:                    if (!adornments.isEmpty()) {
0966:                        DOMUtils.toDom(adornments, "adornments", holder);
0967:                    }
0968:                    if (!colors.isEmpty()) {
0969:                        DOMUtils.toDom(colors, "colors", holder);
0970:                    }
0971:                    if (!parameters.isEmpty()) {
0972:                        DOMUtils.toDom(parameters, "parameters", holder);
0973:                    }
0974:                    Iterator it = children.iterator();
0975:                    while (it.hasNext()) {
0976:                        Menu child = (Menu) it.next();
0977:                        Element childHolder = AbstractDomObject.addElement(
0978:                                holder, child.getType());
0979:                        child.toDom(childHolder, request);
0980:                    }
0981:                }
0982:            }
0983:
0984:            public Menu findItemById(String id) {
0985:                if (id.equals(getXid())) {
0986:                    return enabled() ? this  : null;
0987:                }
0988:
0989:                Iterator it = children.iterator();
0990:                while (it.hasNext()) {
0991:                    Menu ret = ((Menu) it.next()).findItemById(id);
0992:                    if (ret != null) {
0993:                        return ret.enabled() ? ret : null;
0994:                    }
0995:                }
0996:
0997:                return null;
0998:            }
0999:
1000:            private Map matchCache;
1001:
1002:            private List _match(HttpServletRequest request) {
1003:                List ret = new ArrayList();
1004:                if (enabled()) {
1005:                    if (rootMatcher != null
1006:                            && !rootMatcher.match(request).isEmpty()) {
1007:                        MatchResult matchResult = new MatchResult(this ,
1008:                                rootMatcher.isMatchQueryString(), getWeight());
1009:                        matchResult.setAttribute("type", MT_ROOT);
1010:                        ret.add(matchResult);
1011:                    } else if (formHandlerMatcher != null
1012:                            && !formHandlerMatcher.match(request).isEmpty()) {
1013:                        MatchResult matchResult = new MatchResult(this ,
1014:                                formHandlerMatcher.isMatchQueryString(),
1015:                                getWeight());
1016:                        matchResult.setAttribute("type", MT_FORM_HANDLER);
1017:                        ret.add(matchResult);
1018:                    } else if (resourcePatternMatcher != null
1019:                            && !resourcePatternMatcher.match(request).isEmpty()) {
1020:                        MatchResult matchResult = new MatchResult(this ,
1021:                                resourcePatternMatcher.isMatchQueryString(),
1022:                                getWeight());
1023:                        matchResult.setAttribute("type", MT_RESOURCE);
1024:                        ret.add(matchResult);
1025:                    }
1026:
1027:                    Iterator it = children.iterator();
1028:                    while (it.hasNext()) {
1029:                        ret.addAll(((Menu) it.next()).match(request));
1030:                    }
1031:                }
1032:                return ret;
1033:            }
1034:
1035:            private int lastMatch;
1036:            private int matchCounter;
1037:
1038:            public List match(HttpServletRequest request) {
1039:                List ret = null;
1040:
1041:                // Root item caches matches
1042:                if (matchCache == null) {
1043:                    ret = _match(request);
1044:                } else {
1045:                    String key = request.getRequestURI();
1046:
1047:                    if (isMatchQueryString()) {
1048:                        String queryString = request.getQueryString();
1049:                        if (queryString != null) {
1050:                            key += "?" + queryString;
1051:                        }
1052:                    }
1053:
1054:                    ret = (List) matchCache.get(key);
1055:                    if (ret == null) {
1056:                        ret = _match(request);
1057:                        if (!ret.isEmpty()) {
1058:                            matchCache.put(key, ret);
1059:                        }
1060:                    }
1061:
1062:                    ++matchCounter;
1063:                    Map parameterMap = request.getParameterMap();
1064:
1065:                    Iterator it = ret.iterator();
1066:                    while (it.hasNext()) {
1067:                        Menu matchedMenu = ((Menu) ((MatchResult) it.next())
1068:                                .getMatcher());
1069:                        if ("GET".equalsIgnoreCase(request.getMethod())) {
1070:                            matchedMenu.matchParameters.putAll(parameterMap);
1071:                        }
1072:                        matchedMenu.setLastMatch(matchCounter);
1073:                    }
1074:                }
1075:
1076:                return ret;
1077:            }
1078:
1079:            private Map matchParameters = new HashMap();
1080:
1081:            /**
1082:             * 
1083:             * @param name
1084:             * @return First value of given parameter at the time when item was matched. Parent matched
1085:             * parameters are inherited.
1086:             */
1087:            public String getMatchParameter(String name) {
1088:                String[] ret = (String[]) matchParameters.get(name);
1089:                if (ret != null && ret.length > 0) {
1090:                    return ret[0];
1091:                }
1092:
1093:                return parent == null ? null : parent.getMatchParameter(name);
1094:            }
1095:
1096:            /**
1097:             * 
1098:             * @param name
1099:             * @return Values of given parameter at the time when item was matched. Parent matched
1100:             * parameters are inherited.
1101:             */
1102:            public String[] getMatchParameters(String name) {
1103:                String[] ret = (String[]) matchParameters.get(name);
1104:                if (ret != null) {
1105:                    return ret;
1106:                }
1107:
1108:                return parent == null ? null : parent.getMatchParameters(name);
1109:            }
1110:
1111:            /**
1112:             * Sets match number in self and parents.
1113:             * @param match
1114:             */
1115:            protected void setLastMatch(int match) {
1116:                lastMatch = match;
1117:                if (parent != null) {
1118:                    parent.setLastMatch(match);
1119:                }
1120:            }
1121:
1122:            /**
1123:             * @return max of last match of this item and parent item(s)
1124:             */
1125:            public int getLastMatch() {
1126:                return parent == null ? lastMatch : Math.max(lastMatch, parent
1127:                        .getLastMatch());
1128:            }
1129:
1130:            public boolean isMatchQueryString() {
1131:                return getMatchQueryString();
1132:            }
1133:
1134:            /**
1135:             * @return path to this item.
1136:             */
1137:            public Menu[] getPath() {
1138:                return path;
1139:            }
1140:
1141:            public Menu getParentMenu() {
1142:                return parent;
1143:            }
1144:
1145:            /**
1146:             * @return Root menu
1147:             */
1148:            public Menu getRoot() {
1149:                return parent == null ? this  : parent.getRoot();
1150:            }
1151:
1152:            public Menu getAction(String name) {
1153:                return (Menu) actionMap.get(name);
1154:            }
1155:
1156:            public Menu getChild(String name) {
1157:                return (Menu) itemMap.get(name);
1158:            }
1159:
1160:            public Menu findByXid(String xid) {
1161:                if (xid.equals(getXid())) {
1162:                    return enabled() ? this  : null;
1163:                }
1164:
1165:                if (parent == null) {
1166:                    Menu ret = (Menu) xidMap.get(xid);
1167:                    return ret != null && ret.enabled() ? ret : null;
1168:                }
1169:                return parent.findByXid(xid);
1170:            }
1171:
1172:            public Menu findById(int id) {
1173:                if (getId() == id) {
1174:                    return enabled() ? this  : null;
1175:                }
1176:
1177:                if (parent == null) {
1178:                    Menu ret = (Menu) idMap.get(new Integer(id));
1179:                    return ret != null && ret.enabled() ? ret : null;
1180:                }
1181:                return parent.findById(id);
1182:            }
1183:
1184:            public static boolean isBlank(String str) {
1185:                return str == null || str.trim().length() == 0;
1186:            }
1187:
1188:            public static String escapeHtml(String txt) {
1189:                if (txt == null) {
1190:                    return null;
1191:                }
1192:
1193:                StringBuffer ret = new StringBuffer();
1194:                char[] chars = txt.toCharArray();
1195:                for (int i = 0; i < chars.length; ++i) {
1196:                    switch (chars[i]) {
1197:                    case '<':
1198:                        ret.append("&lt;");
1199:                        break;
1200:                    case '>':
1201:                        ret.append("&gt;");
1202:                        break;
1203:                    case '&':
1204:                        if (i < chars.length - 1 && '#' == chars[i + 1]) { // Do not double-escape (&#...;)
1205:                            ret.append(chars[i]);
1206:                        } else {
1207:                            ret.append("&amp;");
1208:                        }
1209:                        break;
1210:                    case '\'':
1211:                        ret.append("&#039;");
1212:                        break;
1213:                    case '\\':
1214:                        ret.append("&#092;");
1215:                        break;
1216:                    case '\"':
1217:                        ret.append("&quot;");
1218:                        break;
1219:                    default:
1220:                        ret.append("&#" + ((int) chars[i]) + ";");
1221:                    }
1222:                }
1223:                return ret.toString();
1224:            }
1225:
1226:            private InjectingClassLoader injectingClassLoader;
1227:
1228:            protected InjectingClassLoader getInjectingClassLoader() {
1229:                return parent == null ? injectingClassLoader : parent
1230:                        .getInjectingClassLoader();
1231:            }
1232:
1233:            private InterfacePool interfacePool;
1234:
1235:            protected InterfacePool getInterfacePool() {
1236:                return parent == null ? interfacePool : parent
1237:                        .getInterfacePool();
1238:            }
1239:
1240:            private Cache cache;
1241:
1242:            public Cache getCache() {
1243:                return parent == null ? cache : parent.getCache();
1244:            }
1245:
1246:            private GenerationPolicy generationPolicy;
1247:
1248:            public GenerationPolicy getGenerationPolicy() {
1249:                return parent == null ? generationPolicy : parent
1250:                        .getGenerationPolicy();
1251:            }
1252:
1253:            private Map guidMap;
1254:
1255:            public Menu findByGuid(String id) {
1256:                Menu ret = (Menu) (parent == null ? guidMap.get(id) : parent
1257:                        .findByGuid(id));
1258:                return ret != null && ret.enabled() ? ret : null;
1259:            }
1260:
1261:            private void putToGuidMap(String guid, Menu menu) {
1262:                if (parent == null) {
1263:                    guidMap.put(guid, menu);
1264:                } else {
1265:                    parent.putToGuidMap(guid, menu);
1266:                }
1267:            }
1268:
1269:            /**
1270:             * This context traces whether there have been null
1271:             * returned values.
1272:             * @author Pavel
1273:             *
1274:             */
1275:            private static class MissContext implements  Context {
1276:
1277:                private Context[] masters;
1278:                private boolean hadMisses;
1279:
1280:                public MissContext(Context[] masters) {
1281:                    this .masters = masters;
1282:                }
1283:
1284:                public Object get(String key) {
1285:                    for (int i = 0; i < masters.length; ++i) {
1286:                        Object ret = masters[i].get(key);
1287:                        if (ret != null) {
1288:                            return ret;
1289:                        }
1290:                    }
1291:
1292:                    hadMisses = true;
1293:                    return null;
1294:                }
1295:
1296:                public boolean hadMisses() {
1297:                    return hadMisses;
1298:                }
1299:            }
1300:
1301:            private MenuNavigatorTemplate getTemplate(String templateName) {
1302:                MenuNavigatorTemplate ret = (MenuNavigatorTemplate) navigatorTemplates
1303:                        .get(templateName);
1304:                if (ret == null && parent != null) {
1305:                    return parent.getTemplate(templateName);
1306:                }
1307:                return ret;
1308:            }
1309:
1310:            public Collection getTemplateNames() {
1311:                TreeSet ret = new TreeSet();
1312:                ret.addAll(navigatorTemplates.keySet());
1313:                if (parent != null) {
1314:                    ret.addAll(parent.getTemplateNames());
1315:                }
1316:                return ret;
1317:            }
1318:
1319:            public Object get(String key) {
1320:                if (isBlank(key)) {
1321:                    return null;
1322:                }
1323:
1324:                int idx = key.indexOf(":");
1325:
1326:                if (idx != -1) {
1327:                    if (idx == key.length() - 1) {
1328:                        return null;
1329:                    }
1330:
1331:                    String nameSpace = key.substring(0, idx);
1332:                    String name = key.substring(idx + 1);
1333:                    if ("attribute".equals(nameSpace)) {
1334:                        return getAttribute(name);
1335:                    }
1336:
1337:                    if ("match-parameter".equals(nameSpace)) {
1338:                        return getMatchParameter(name);
1339:                    }
1340:
1341:                    if ("parent".equals(nameSpace)) {
1342:                        return parent == null ? null : parent.get(name);
1343:                    }
1344:                }
1345:
1346:                return super .get(key);
1347:            }
1348:
1349:            /**
1350:             * @return true if there are help topics associated with the menu item.
1351:             */
1352:            public boolean hasHelp() {
1353:                return !helpTopics.isEmpty();
1354:            }
1355:
1356:            /**
1357:             * @return true if this item has sub-items
1358:             */
1359:            public Collection getChildren() {
1360:                return children;
1361:            }
1362:
1363:            /**
1364:             * Chained get
1365:             */
1366:            public Object get(String key, final Context chain) {
1367:
1368:                if (isBlank(key)) {
1369:                    return null;
1370:                }
1371:
1372:                MissContext mc = new MissContext(new Context[] { new Context() {
1373:
1374:                    public Object get(String key) {
1375:                        return Menu.this .get(key, chain);
1376:                    }
1377:                }, chain });
1378:                PropertyParser parser = new PropertyParser(mc, false);
1379:
1380:                String contextPath = (String) chain.get("context-path");
1381:
1382:                if ("ajax-link".equals(key) || "ajax-label".equals(key)) {
1383:                    Object divId = chain.get("0");
1384:                    if (divId == null) {
1385:                        return "";
1386:                    }
1387:
1388:                    String newEmbellishments = "onclick=\"ajax_loadContent('"
1389:                            + divId + "', this.href); return false;\"";
1390:                    String embellishments = (String) chain.get("3");
1391:                    if (embellishments != null) {
1392:                        newEmbellishments += " " + embellishments;
1393:                    }
1394:
1395:                    final String fne = newEmbellishments;
1396:
1397:                    Context shiftingContex = new Context() {
1398:
1399:                        public Object get(String key) {
1400:                            if ("0".equals(key)) {
1401:                                return chain.get("1");
1402:                            }
1403:                            if ("1".equals(key)) {
1404:                                return chain.get("2");
1405:                            }
1406:                            if ("2".equals(key)) {
1407:                                return fne;
1408:                            }
1409:                            return chain.get(key);
1410:                        }
1411:
1412:                    };
1413:
1414:                    return get(key.substring("ajax-".length()), shiftingContex);
1415:                }
1416:
1417:                if ("link".equals(key)) {
1418:                    StringBuffer sb = new StringBuffer("<a href=\"");
1419:                    sb.append(contextPath);
1420:                    sb.append(getUri());
1421:                    String queryString = (String) chain.get("1");
1422:
1423:                    if (!isBlank(queryString)) {
1424:                        sb.append(sb.indexOf("?") == -1 ? "?" : "&");
1425:                        sb.append(queryString);
1426:                    } else if (!isBlank(getQueryTemplate())) {
1427:                        sb.append(sb.indexOf("?") == -1 ? "?" : "&");
1428:                        sb.append(parser.parse(getQueryTemplate()));
1429:                        if (mc.hadMisses()) {
1430:                            return "";
1431:                        }
1432:                    }
1433:
1434:                    sb.append("\"");
1435:                    if (!isBlank(getTitle())) {
1436:                        sb.append(" title=\"");
1437:                        sb.append(getTitle());
1438:                        sb.append("\"");
1439:                    }
1440:
1441:                    if (!isBlank(getTarget())) {
1442:                        sb.append(" target=\"");
1443:                        sb.append(getTarget());
1444:                        sb.append("\"");
1445:                    }
1446:
1447:                    String embellishments = (String) chain.get("2");
1448:
1449:                    if (!isBlank(embellishments)) {
1450:                        sb.append(" ");
1451:                        sb.append(embellishments);
1452:                    }
1453:
1454:                    sb.append(">");
1455:                    String linkText = (String) chain.get("0");
1456:                    sb.append(escapeHtml(isBlank(linkText) ? getName()
1457:                            : linkText));
1458:                    sb.append("</a>");
1459:
1460:                    return sb.toString();
1461:                }
1462:
1463:                if ("tooltip-link".equals(key)) {
1464:                    StringBuffer hrefBuf = new StringBuffer(contextPath);
1465:                    hrefBuf.append(getUri());
1466:                    String queryString = (String) chain.get("1");
1467:
1468:                    if (!isBlank(queryString)) {
1469:                        hrefBuf.append(hrefBuf.indexOf("?") == -1 ? "?" : "&");
1470:                        hrefBuf.append(queryString);
1471:                    } else if (!isBlank(getQueryTemplate())) {
1472:                        hrefBuf.append(hrefBuf.indexOf("?") == -1 ? "?" : "&");
1473:                        hrefBuf.append(parser.parse(getQueryTemplate()));
1474:                        if (mc.hadMisses()) {
1475:                            return "";
1476:                        }
1477:                    }
1478:
1479:                    StringBuffer sb = new StringBuffer(
1480:                            "\n<a style=\"display:none\" id=\"xMenuTooltip");
1481:                    sb.append(getId());
1482:                    sb.append("\" href=\"");
1483:                    sb.append(hrefBuf);
1484:                    if (hrefBuf.indexOf("?") == -1) {
1485:                        sb.append("?");
1486:                    } else {
1487:                        sb.append("&");
1488:                    }
1489:                    sb.append("skin=tooltip\"></a>");
1490:
1491:                    sb.append("<a href=\"");
1492:                    sb.append(hrefBuf);
1493:                    sb
1494:                            .append("\" onmouseover=\"helpTooltip.showTooltip(event,document.getElementById('xMenuTooltip");
1495:                    sb.append(getId());
1496:                    sb
1497:                            .append("').href);return false;\" onmouseout=\"helpTooltip.hideTooltip()\" style=\"border-bottom: 1px dashed gray; text-decoration: none;\" ");
1498:
1499:                    if (!isBlank(getTarget())) {
1500:                        sb.append(" target=\"");
1501:                        sb.append(getTarget());
1502:                        sb.append("\"");
1503:                    }
1504:
1505:                    String embellishments = (String) chain.get("2");
1506:                    if (!isBlank(embellishments)) {
1507:                        sb.append(" ");
1508:                        sb.append(embellishments);
1509:                    }
1510:
1511:                    sb.append(">");
1512:                    String linkText = (String) chain.get("0");
1513:                    sb.append(escapeHtml(isBlank(linkText) ? getName()
1514:                            : linkText));
1515:                    sb.append("</a>");
1516:
1517:                    return sb.toString();
1518:                }
1519:
1520:                if ("ajax".equals(key)) {
1521:                    String divId = (String) chain.get("1");
1522:                    if (divId == null) {
1523:                        divId = "xMenuAjaxDiv" + getId();
1524:                    }
1525:                    StringBuffer sb = new StringBuffer("<DIV id=\"");
1526:                    sb.append(divId);
1527:                    sb.append("\"> </DIV>\n");
1528:
1529:                    sb.append("<a style=\"display:none\" id=\"");
1530:                    sb.append(divId);
1531:                    sb.append("_Anchor\" href=\"");
1532:
1533:                    sb.append(contextPath);
1534:                    sb.append(getUri());
1535:                    String queryString = (String) chain.get("0");
1536:
1537:                    if (!isBlank(queryString)) {
1538:                        sb.append(sb.indexOf("?") == -1 ? "?" : "&");
1539:                        sb.append(queryString);
1540:                    } else if (!isBlank(getQueryTemplate())) {
1541:                        sb.append(sb.indexOf("?") == -1 ? "?" : "&");
1542:                        sb.append(parser.parse(getQueryTemplate()));
1543:                        if (mc.hadMisses()) {
1544:                            return "";
1545:                        }
1546:                    }
1547:
1548:                    sb.append("\"> </a>\n");
1549:
1550:                    sb.append("<script language=\"JavaScript\">\n");
1551:                    sb.append("ajax_loadContent('");
1552:                    sb.append(divId);
1553:                    sb.append("', document.getElementById('");
1554:                    sb.append(divId);
1555:                    sb.append("_Anchor').href);\n</script>");
1556:                    return sb.toString();
1557:                }
1558:
1559:                if ("label".equals(key)) {
1560:                    StringBuffer sb = new StringBuffer("<a href=\"");
1561:                    sb.append(contextPath);
1562:                    sb.append(getUri());
1563:                    String queryString = (String) chain.get("1");
1564:                    String labelText = (String) chain.get("0");
1565:                    if (!isBlank(queryString)) {
1566:                        sb.append(sb.indexOf("?") == -1 ? "?" : "&");
1567:                        sb.append(queryString);
1568:                    } else if (!isBlank(getQueryTemplate())) {
1569:                        sb.append(sb.indexOf("?") == -1 ? "?" : "&");
1570:                        sb.append(parser.parse(getQueryTemplate()));
1571:                        if (mc.hadMisses()) {
1572:                            return labelText;
1573:                        }
1574:                    }
1575:
1576:                    sb.append("\"");
1577:                    if (!isBlank(getTitle())) {
1578:                        sb.append(" title=\"");
1579:                        sb.append(getTitle());
1580:                        sb.append("\"");
1581:                    }
1582:
1583:                    if (!isBlank(getTarget())) {
1584:                        sb.append(" target=\"");
1585:                        sb.append(getTarget());
1586:                        sb.append("\"");
1587:                    }
1588:
1589:                    String embellishments = (String) chain.get("2");
1590:
1591:                    if (!isBlank(embellishments)) {
1592:                        sb.append(" ");
1593:                        sb.append(embellishments);
1594:                    }
1595:
1596:                    sb.append(">");
1597:                    sb.append(escapeHtml(isBlank(labelText) ? getName()
1598:                            : labelText));
1599:                    sb.append("</a>");
1600:
1601:                    return sb.toString();
1602:                }
1603:
1604:                if ("tooltip-label".equals(key)) {
1605:                    StringBuffer hrefBuf = new StringBuffer(contextPath);
1606:                    hrefBuf.append(getUri());
1607:                    String queryString = (String) chain.get("1");
1608:                    String labelText = (String) chain.get("0");
1609:
1610:                    if (!isBlank(queryString)) {
1611:                        hrefBuf.append(hrefBuf.indexOf("?") == -1 ? "?" : "&");
1612:                        hrefBuf.append(queryString);
1613:                    } else if (!isBlank(getQueryTemplate())) {
1614:                        hrefBuf.append(hrefBuf.indexOf("?") == -1 ? "?" : "&");
1615:                        hrefBuf.append(parser.parse(getQueryTemplate()));
1616:                        if (mc.hadMisses()) {
1617:                            return labelText;
1618:                        }
1619:                    }
1620:
1621:                    StringBuffer sb = new StringBuffer(
1622:                            "\n<a style=\"display:none\" id=\"xMenuTooltip");
1623:                    sb.append(getId());
1624:                    sb.append("\" href=\"");
1625:                    sb.append(hrefBuf);
1626:                    if (hrefBuf.indexOf("?") == -1) {
1627:                        sb.append("?");
1628:                    } else {
1629:                        sb.append("&");
1630:                    }
1631:                    sb.append("skin=tooltip\"></a>");
1632:
1633:                    sb.append("<a href=\"");
1634:                    sb.append(hrefBuf);
1635:                    sb
1636:                            .append("\" onmouseover=\"helpTooltip.showTooltip(event,document.getElementById('xMenuTooltip");
1637:                    sb.append(getId());
1638:                    sb
1639:                            .append("').href);return false;\" onmouseout=\"helpTooltip.hideTooltip()\" style=\"border-bottom: 1px dashed gray; text-decoration: none;\" ");
1640:
1641:                    if (!isBlank(getTarget())) {
1642:                        sb.append(" target=\"");
1643:                        sb.append(getTarget());
1644:                        sb.append("\"");
1645:                    }
1646:
1647:                    String embellishments = (String) chain.get("2");
1648:                    if (!isBlank(embellishments)) {
1649:                        sb.append(" ");
1650:                        sb.append(embellishments);
1651:                    }
1652:
1653:                    sb.append(">");
1654:                    sb.append(escapeHtml(isBlank(labelText) ? getName()
1655:                            : labelText));
1656:                    sb.append("</a>");
1657:
1658:                    return sb.toString();
1659:                }
1660:
1661:                if ("href".equals(key)) {
1662:                    if (blankUri) {
1663:                        return "#";
1664:                    }
1665:
1666:                    if (isBlank(getQueryTemplate())) {
1667:                        return contextPath + getUri();
1668:                    }
1669:
1670:                    String ret = contextPath + getUri();
1671:                    ret += (ret.indexOf("?") == -1 ? "?" : "&")
1672:                            + parser.parse(getQueryTemplate());
1673:                    return mc.hadMisses() ? null : ret;
1674:                }
1675:
1676:                if ("uri".equals(key)) {
1677:                    return contextPath + getUri();
1678:                }
1679:
1680:                if ("formHandler".equals(key)) {
1681:                    String fhu = getFormHandlerUri();
1682:                    if (fhu == null) {
1683:                        return null;
1684:                    }
1685:
1686:                    return contextPath + fhu;
1687:
1688:                }
1689:
1690:                if (key.startsWith(TEMPLATE_PREFIX)) {
1691:                    String templateName = key.substring(TEMPLATE_PREFIX
1692:                            .length());
1693:                    Map context = new HashMap();
1694:                    context.put("menuContext", mc);
1695:                    context.put("menu", this );
1696:                    context.put("escaper", new Escaper());
1697:                    context.put("context-path", chain.get("context-path"));
1698:                    Object ret = instantiateTemplate(templateName, context);
1699:                    return mc.hadMisses() ? null : ret;
1700:                }
1701:
1702:                String menuActionsPath = (String) chain
1703:                        .get(MENU_HELP_ACTIONS_GLOBAL_PATH);
1704:
1705:                if (menuActionsPath != null) {
1706:                    menuActionsPath = contextPath + menuActionsPath;
1707:                }
1708:
1709:                String menuHelpId = getHelp(chain).getId();
1710:                if ("phelp".equals(key)) { // Help which takes formatting values from parameters
1711:                    // First parameter - topic path. phelp returns URL of menu item article if this parameter is missing or blank
1712:                    // Second parameter - topic "attribute". phelp return URL of topic content if this parameter is missing or blank.
1713:                    // second parameter is ignored if the first one is blank.
1714:                    if (menuActionsPath == null) {
1715:                        return null;
1716:                    }
1717:
1718:                    String path = (String) chain.get("0");
1719:                    if (isBlank(path)) {
1720:                        return menuActionsPath + MENU_HELP_URL_PART
1721:                                + menuHelpId;
1722:                    }
1723:
1724:                    MenuHelpTopicsImpl mht = (MenuHelpTopicsImpl) helpTopics
1725:                            .get(path);
1726:                    if (mht == null) {
1727:                        return null;
1728:                    }
1729:
1730:                    String attribute = (String) chain.get("1");
1731:                    if (isBlank(attribute)) {
1732:                        return menuActionsPath + TOPIC_CONTENT_URL_PART
1733:                                + mht.getId();
1734:                    }
1735:
1736:                    return mht.get(attribute);
1737:                }
1738:
1739:                if ("help".equals(key)) { // Templated topic help links
1740:                    // First parameter - topic path. 
1741:                    // Second parameter - template name. If template name is null then help topic's template name is used
1742:                    if (menuActionsPath == null) {
1743:                        return null;
1744:                    }
1745:
1746:                    String path = (String) chain.get("0");
1747:                    if (isBlank(path)) {
1748:                        return null;
1749:                    }
1750:
1751:                    MenuHelpTopicsImpl mht = (MenuHelpTopicsImpl) helpTopics
1752:                            .get(path);
1753:                    if (mht == null) {
1754:                        return null;
1755:                    }
1756:
1757:                    String templateName = (String) chain.get("1");
1758:                    if (isBlank(templateName)) {
1759:                        templateName = mht.getRenderTemplate();
1760:                    }
1761:                    if (isBlank(templateName)) {
1762:                        return null;
1763:                    }
1764:
1765:                    Map context = new HashMap();
1766:                    context.put("menuContext", mc);
1767:                    context.put("menu", this );
1768:                    context.put("escaper", new Escaper());
1769:                    context.put("topicId", new Integer(mht.getId()));
1770:                    context.put("context-path", chain.get("context-path"));
1771:                    context.put("helpURL", menuActionsPath + MENU_HELP_URL_PART
1772:                            + "T" + mht.getId());
1773:                    context.put("topicURL", menuActionsPath
1774:                            + TOPIC_CONTENT_URL_PART + mht.getId());
1775:                    Object ret = instantiateTemplate(templateName, context);
1776:                    return mc.hadMisses() ? null : ret;
1777:                }
1778:
1779:                if ("menuhelp".equals(key)) { // Templated menu help links
1780:                    // Parameter - template name
1781:                    if (menuActionsPath == null) {
1782:                        return null;
1783:                    }
1784:
1785:                    String templateName = (String) chain.get("0");
1786:                    if (isBlank(templateName)) {
1787:                        return null;
1788:                    }
1789:
1790:                    Map context = new HashMap();
1791:                    context.put("menuContext", mc);
1792:                    context.put("menu", this );
1793:                    context.put("escaper", new Escaper());
1794:                    context.put("context-path", chain.get("context-path"));
1795:                    context.put("helpURL", menuActionsPath + MENU_HELP_URL_PART
1796:                            + menuHelpId);
1797:                    Object ret = instantiateTemplate(templateName, context);
1798:                    return mc.hadMisses() ? null : ret;
1799:                }
1800:
1801:                if (key.startsWith("parent:")) {
1802:                    return parent == null ? null : parent.get(key
1803:                            .substring("parent:".length()), chain);
1804:                }
1805:
1806:                //		if ("help".equals(key)) {
1807:                //				String menuActionsPath = (String) rctx.get(MENU_HELP_ACTIONS_GLOBAL_PATH);
1808:                //				if (menuActionsPath == null) {
1809:                //					return null;
1810:                //				}
1811:                //				
1812:                //				// URL to action which renders help window with combined topics for menu item.
1813:                //				return contextPath+menuActionsPath+MENU_HELP_URL_PART+getId();
1814:                //			} else if (key.startsWith(HELP_PREFIX)) {
1815:                //				String menuActionsPath = (String) rctx.get(MENU_HELP_ACTIONS_GLOBAL_PATH);
1816:                //				if (menuActionsPath == null) {
1817:                //					return null;
1818:                //				}
1819:                //				
1820:                //				menuActionsPath = contextPath + menuActionsPath;
1821:                //				
1822:                //				String rest = key.substring(0, HELP_PREFIX.length());
1823:                //				if (isBlank(rest)) {
1824:                //					return null;
1825:                //				}
1826:                //				int idx = rest.lastIndexOf(":");
1827:                //				if (idx==-1) { // URL to action which returns topic content.
1828:                //					MenuHelpTopics mht = (MenuHelpTopics) helpTopics.get(rest);
1829:                //					return mht==null ? null : menuActionsPath+"topicContent?id="+mht.getId();						
1830:                //				} else { // One of values of MenuHelpTopics
1831:                //					MenuHelpTopicsImpl mht = (MenuHelpTopicsImpl) helpTopics.get(rest.substring(0, idx));
1832:                //					String topicKey = idx<rest.length()-1 ? rest.substring(idx+1) : null;
1833:                //					return mht.get(topicKey);
1834:                //				}
1835:                //			} else if (key.startsWith(MENU_ATTRIBUTE)) {
1836:                //				return getAttribute(key.substring(MENU_ATTRIBUTE.length()+1));
1837:                //			} else if (key.startsWith(MATCH_PARAMETER)) {
1838:                //				return getMatchParameter(key.substring(MATCH_PARAMETER.length()+1));
1839:                //			}
1840:                //			
1841:                //			// TODO in the future: interaction things.
1842:                //
1843:                //		
1844:                //		ChainedContext cc = new ChainedContext(context);
1845:                //		PropertyParser pp = new PropertyParser(cc, false);
1846:                //		String ret = pp.parse(mnt.getContent());
1847:                //		return cc.hadMisses ? null : ret;
1848:
1849:                Object ret = get(key);
1850:                return ret == null ? chain.get(key) : ret;
1851:            }
1852:
1853:            /**
1854:             * Instantiates template with given context.
1855:             * The context must contain "menuContext" entry.
1856:             * @param templateName
1857:             * @param context
1858:             * @return
1859:             */
1860:            public Object instantiateTemplate(String templateName, Map context) {
1861:                MenuNavigatorTemplate mnt = getTemplate(templateName);
1862:                if (mnt == null) {
1863:                    return null;
1864:                }
1865:
1866:                if (MenuFilter.CT_HTML.equals(mnt.getContentType())) {
1867:                    PropertyParser pp = new PropertyParser(new MapContext(
1868:                            context), false);
1869:                    return pp.parse(mnt.getContent());
1870:                }
1871:
1872:                Context menuContext = (Context) context.get("menuContext");
1873:                EvaluatorFactory eFactory = (EvaluatorFactory) menuContext
1874:                        .get("global:db/EvaluatorFactory");
1875:                if (eFactory == null) {
1876:                    return null;
1877:                }
1878:
1879:                try {
1880:                    EvaluationResult er = eFactory.evaluate(mnt
1881:                            .getContentType(), mnt.getContent(), "Menu "
1882:                            + getId() + " template " + mnt.getName(), context,
1883:                            getInjectingClassLoader());
1884:                    return er.getOutput();
1885:                } catch (HammurapiWebException e) {
1886:                    logger.error("Template evaluation failed " + mnt.getName()
1887:                            + ": " + e, e);
1888:                    return null;
1889:                }
1890:            }
1891:
1892:            /**
1893:             * Get with parameters for MenuNavigator to expand ${...|...|...|...} templates.
1894:             * @param key Context key
1895:             * @param parameters Parameters , addressed by number, e.g. parameter 0 is addressed as ${0}
1896:             * @param chain Chain context
1897:             * @return key value
1898:             */
1899:            public Object get(String key, final String[] parameters,
1900:                    final Context chain) {
1901:                final Map parameterMap = new HashMap();
1902:                for (int i = 0; parameters != null && i < parameters.length; ++i) {
1903:                    if (parameters[i] != null) {
1904:                        parameterMap.put(String.valueOf(i), parameters[i]);
1905:                    }
1906:                }
1907:
1908:                return get(key, new Context() {
1909:
1910:                    public Object get(String key) {
1911:                        Object ret = parameterMap.get(key);
1912:                        return ret == null ? chain.get(key) : ret;
1913:                    }
1914:
1915:                });
1916:            }
1917:
1918:            private Help findHelp(String id, Set idSet, Context context) {
1919:                Integer iid = new Integer(getId());
1920:                if (idSet.add(iid)) { // To avoid infinite loops.
1921:                    Help ret = getHelp(context).findHelp(id);
1922:                    if (ret != null) {
1923:                        return ret;
1924:                    }
1925:
1926:                    Iterator it = children.iterator();
1927:                    while (it.hasNext()) {
1928:                        Menu child = (Menu) it.next();
1929:                        ret = child.findHelp(id, idSet, context);
1930:                        if (ret != null) {
1931:                            return ret;
1932:                        }
1933:                    }
1934:
1935:                    if (parent != null) {
1936:                        return parent.findHelp(id, idSet, context);
1937:                    }
1938:
1939:                }
1940:                return null;
1941:            }
1942:
1943:            public Help findHelp(String id, Context context) {
1944:                if (id.startsWith("M")) {
1945:                    return findById(Integer.parseInt(id.substring(1))).getHelp(
1946:                            context);
1947:                }
1948:                return findHelp(id, new HashSet(), context);
1949:            }
1950:
1951:            /**
1952:             * Invoked by Help to navigate menu tree.
1953:             * @param term
1954:             * @param idSet
1955:             * @return
1956:             */
1957:            Help findTerm(String term, Set idSet, Context context) {
1958:                Integer iid = new Integer(getId());
1959:                if (idSet.add(iid)) { // To avoid infinite loops.
1960:                    Help ret = getHelp(context).findTerm(term, idSet, context);
1961:                    if (ret != null) {
1962:                        return ret;
1963:                    }
1964:
1965:                    Iterator it = children.iterator();
1966:                    while (it.hasNext()) {
1967:                        Menu child = (Menu) it.next();
1968:                        ret = child.findTerm(term, idSet, context);
1969:                        if (ret != null) {
1970:                            return ret;
1971:                        }
1972:                    }
1973:
1974:                    if (parent != null) {
1975:                        return parent.findTerm(term, idSet, context);
1976:                    }
1977:
1978:                }
1979:                return null;
1980:            }
1981:
1982:            private Menu findByPath(String path) {
1983:                if (path == null) {
1984:                    return null;
1985:                }
1986:
1987:                int idx = path.indexOf('/');
1988:                String pathElement = idx == -1 ? path : path.substring(0, idx);
1989:                if ("..".equals(pathElement)) {
1990:                    return getParentMenu();
1991:                }
1992:
1993:                if (".".equals(pathElement)) {
1994:                    return this ;
1995:                }
1996:
1997:                Menu si = getChild(pathElement);
1998:
1999:                if (si == null) {
2000:                    return null;
2001:                }
2002:
2003:                return idx == -1 ? si : si.findByPath(path.substring(idx + 1));
2004:            }
2005:
2006:            /**
2007:             * Finds menu item by path, XID or GUID.
2008:             * @param path
2009:             * @return
2010:             */
2011:            public Menu findItem(String path) {
2012:                if ("matched".equals(path)) { // Current item
2013:                    return this ;
2014:                } else if (path.startsWith("path:/")) {
2015:                    return getRoot().findByPath(
2016:                            path.substring("path:/".length()));
2017:                } else if (path.startsWith("path:")) {
2018:                    return findByPath(path.substring("path:".length()));
2019:                }
2020:                if (path.startsWith("id:")) {
2021:                    return findByXid(path.substring("id:".length()));
2022:                } else if (path.startsWith("guid:")) {
2023:                    return findByGuid(path.substring("guid:".length()));
2024:                }
2025:
2026:                return null;
2027:            }
2028:
2029:            private int interactionOffset;
2030:
2031:            /**
2032:             * Id's for menu items for interactions shall be formed as interaction id + interaction offset + ref offset. 
2033:             * @return Interaction offset
2034:             */
2035:            public int getInteractionOffset() {
2036:                return Integer.MAX_VALUE / 2; // parent==null ? interactionOffset : parent.getInteractionOffset();
2037:            }
2038:
2039:            private int nextVirtualId;
2040:
2041:            /**
2042:             * 
2043:             * @return Next virtual id number for menu.
2044:             */
2045:            public int nextVirtualId() {
2046:                return parent == null ? nextVirtualId++ : parent
2047:                        .nextVirtualId();
2048:            }
2049:
2050:            /**
2051:             * evalGuard() sets this thread local variable. If this variable is false then the menu item is disabled for a given request.
2052:             * Injector filter takes care of invoking guard evaluation.
2053:             */
2054:            private ThreadLocal guardTL = new ThreadLocal();
2055:
2056:            //    private ThreadLocal guardInterpreterTL = new ThreadLocal();
2057:
2058:            /**
2059:             * @return true if there is no guard or if the guard evaluated to not false for the given thread.
2060:             */
2061:            public boolean enabled() {
2062:                return !Boolean.FALSE.equals(guardTL.get());
2063:            }
2064:
2065:            public void evalGuard(HttpServletRequest request) {
2066:                Object ret = null; // TODO Actually evaluate
2067:                if (Boolean.FALSE.equals(ret)) {
2068:                    guardTL.set(Boolean.FALSE);
2069:                } else {
2070:                    guardTL.set(null);
2071:                    Iterator it = children.iterator();
2072:                    while (it.hasNext()) {
2073:                        Menu child = (Menu) it.next();
2074:                        child.evalGuard(request);
2075:                    }
2076:                }
2077:            }
2078:
2079:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.