Source Code Cross Referenced for Skin.java in  » Web-Framework » helma » helma » framework » core » 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 » helma » helma.framework.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Helma License Notice
0003:         *
0004:         * The contents of this file are subject to the Helma License
0005:         * Version 2.0 (the "License"). You may not use this file except in
0006:         * compliance with the License. A copy of the License is available at
0007:         * http://adele.helma.org/download/helma/license.txt
0008:         *
0009:         * Copyright 1998-2003 Helma Software. All Rights Reserved.
0010:         *
0011:         * $RCSfile$
0012:         * $Author: hannes $
0013:         * $Revision: 8638 $
0014:         * $Date: 2007-11-12 15:43:48 +0100 (Mon, 12 Nov 2007) $
0015:         */
0016:
0017:        package helma.framework.core;
0018:
0019:        import helma.framework.*;
0020:        import helma.framework.repository.Resource;
0021:        import helma.objectmodel.ConcurrencyException;
0022:        import helma.util.*;
0023:        import helma.scripting.ScriptingEngine;
0024:
0025:        import java.util.*;
0026:        import java.io.UnsupportedEncodingException;
0027:        import java.io.Reader;
0028:        import java.io.InputStreamReader;
0029:        import java.io.IOException;
0030:
0031:        /**
0032:         * This represents a Helma skin, i.e. a template created from containing Macro tags
0033:         * that will be dynamically evaluated.. It uses the request path array
0034:         * from the RequestEvaluator object to resolve Macro handlers by type name.
0035:         */
0036:        public final class Skin {
0037:
0038:            private Macro[] macros;
0039:            private Application app;
0040:            private char[] source;
0041:            private int offset, length; // start and end index of skin content
0042:            private HashSet sandbox;
0043:            private HashMap subskins;
0044:            private Skin parentSkin = this ;
0045:
0046:            static private final int PARSE_MACRONAME = 0;
0047:            static private final int PARSE_PARAM = 1;
0048:            static private final int PARSE_DONE = 2;
0049:
0050:            static private final int ENCODE_NONE = 0;
0051:            static private final int ENCODE_HTML = 1;
0052:            static private final int ENCODE_XML = 2;
0053:            static private final int ENCODE_FORM = 3;
0054:            static private final int ENCODE_URL = 4;
0055:            static private final int ENCODE_ALL = 5;
0056:
0057:            static private final int HANDLER_RESPONSE = 0;
0058:            static private final int HANDLER_REQUEST = 1;
0059:            static private final int HANDLER_SESSION = 2;
0060:            static private final int HANDLER_PARAM = 3;
0061:            static private final int HANDLER_GLOBAL = 4;
0062:            static private final int HANDLER_THIS = 5;
0063:            static private final int HANDLER_OTHER = 6;
0064:
0065:            static private final int FAIL_DEFAULT = 0;
0066:            static private final int FAIL_SILENT = 1;
0067:            static private final int FAIL_VERBOSE = 2;
0068:
0069:            /**
0070:             * Create a skin without any restrictions on which macros are allowed to be called from it
0071:             */
0072:            public Skin(String content, Application app) {
0073:                this .app = app;
0074:                this .sandbox = null;
0075:                this .source = content.toCharArray();
0076:                this .offset = 0;
0077:                this .length = source.length;
0078:                parse();
0079:            }
0080:
0081:            /**
0082:             * Create a skin with a sandbox which contains the names of macros allowed to be called
0083:             */
0084:            public Skin(String content, Application app, HashSet sandbox) {
0085:                this .app = app;
0086:                this .sandbox = sandbox;
0087:                this .source = content.toCharArray();
0088:                this .offset = 0;
0089:                length = source.length;
0090:                parse();
0091:            }
0092:
0093:            /**
0094:             *  Create a skin without any restrictions on the macros from a char array.
0095:             */
0096:            public Skin(char[] content, int length, Application app) {
0097:                this .app = app;
0098:                this .sandbox = null;
0099:                this .source = content;
0100:                this .offset = 0;
0101:                this .length = length;
0102:                parse();
0103:            }
0104:
0105:            /**
0106:             *  Subskin constructor.
0107:             */
0108:            private Skin(Skin parentSkin, Macro anchorMacro) {
0109:                this .parentSkin = parentSkin;
0110:                this .app = parentSkin.app;
0111:                this .sandbox = parentSkin.sandbox;
0112:                this .source = parentSkin.source;
0113:                this .offset = anchorMacro.end;
0114:                this .length = parentSkin.length;
0115:                parentSkin.addSubskin(anchorMacro.name, this );
0116:                parse();
0117:            }
0118:
0119:            public static Skin getSkin(Resource res, Application app)
0120:                    throws IOException {
0121:                String encoding = app.getProperty("skinCharset");
0122:                Reader reader;
0123:                if (encoding == null) {
0124:                    reader = new InputStreamReader(res.getInputStream());
0125:                } else {
0126:                    reader = new InputStreamReader(res.getInputStream(),
0127:                            encoding);
0128:                }
0129:
0130:                int length = (int) res.getLength();
0131:                char[] characterBuffer = new char[length];
0132:                int read = 0;
0133:                try {
0134:                    while (read < length) {
0135:                        int r = reader.read(characterBuffer, read, length
0136:                                - read);
0137:                        if (r == -1)
0138:                            break;
0139:                        read += r;
0140:                    }
0141:                } finally {
0142:                    reader.close();
0143:                }
0144:                return new Skin(characterBuffer, read, app);
0145:            }
0146:
0147:            /**
0148:             * Parse a skin object from source text
0149:             */
0150:            private void parse() {
0151:                ArrayList partBuffer = new ArrayList();
0152:
0153:                boolean escape = false;
0154:                for (int i = offset; i < (length - 1); i++) {
0155:                    if (source[i] == '<' && source[i + 1] == '%' && !escape) {
0156:                        // found macro start tag
0157:                        Macro macro = new Macro(i, 2);
0158:                        if (macro.isSubskinMacro) {
0159:                            new Skin(parentSkin, macro);
0160:                            length = i;
0161:                            break;
0162:                        } else {
0163:                            partBuffer.add(macro);
0164:                        }
0165:                        i = macro.end - 1;
0166:                    } else {
0167:                        escape = source[i] == '\\' && !escape;
0168:                    }
0169:                }
0170:
0171:                macros = new Macro[partBuffer.size()];
0172:                partBuffer.toArray(macros);
0173:            }
0174:
0175:            private void addSubskin(String name, Skin subskin) {
0176:                if (subskins == null) {
0177:                    subskins = new HashMap();
0178:                }
0179:                subskins.put(name, subskin);
0180:            }
0181:
0182:            /**
0183:             * Check if this skin has a main skin, as opposed to consisting just of subskins
0184:             * @return true if this skin contains a main skin
0185:             */
0186:            public boolean hasMainskin() {
0187:                return length - offset > 0 || subskins == null;
0188:            }
0189:
0190:            /**
0191:             * Check if this skin contains a subskin with the given name
0192:             * @param name a subskin name
0193:             * @return true if the given subskin exists
0194:             */
0195:            public boolean hasSubskin(String name) {
0196:                return subskins != null && subskins.containsKey(name);
0197:            }
0198:
0199:            /**
0200:             * Get a subskin by name
0201:             * @param name the subskin name
0202:             * @return the subskin
0203:             */
0204:            public Skin getSubskin(String name) {
0205:                return subskins == null ? null : (Skin) subskins.get(name);
0206:            }
0207:
0208:            /**
0209:             * Return an array of subskin names defined in this skin
0210:             * @return a string array containing this skin's substrings
0211:             */
0212:            public String[] getSubskinNames() {
0213:                return subskins == null ? new String[0] : (String[]) subskins
0214:                        .keySet().toArray(new String[0]);
0215:            }
0216:
0217:            /**
0218:             * Get the raw source text this skin was parsed from
0219:             */
0220:            public String getSource() {
0221:                return new String(source, offset, length - offset);
0222:            }
0223:
0224:            /**
0225:             * Render this skin and return it as string
0226:             */
0227:            public String renderAsString(RequestEvaluator reval,
0228:                    Object this Object, Object paramObject)
0229:                    throws RedirectException, UnsupportedEncodingException {
0230:                String result = "";
0231:                ResponseTrans res = reval.getResponse();
0232:                res.pushBuffer(null);
0233:                try {
0234:                    render(reval, this Object, paramObject);
0235:                } finally {
0236:                    result = res.popString();
0237:                }
0238:                return result;
0239:            }
0240:
0241:            /**
0242:             * Render this skin
0243:             */
0244:            public void render(RequestEvaluator reval, Object this Object,
0245:                    Object paramObject) throws RedirectException,
0246:                    UnsupportedEncodingException {
0247:                // check for endless skin recursion
0248:                if (++reval.skinDepth > 50) {
0249:                    throw new RuntimeException(
0250:                            "Recursive skin invocation suspected");
0251:                }
0252:
0253:                ResponseTrans res = reval.getResponse();
0254:
0255:                if (macros == null) {
0256:                    res.write(source, offset, length - offset);
0257:                    reval.skinDepth--;
0258:                    return;
0259:                }
0260:
0261:                // register param object, remember previous one to reset afterwards
0262:                Map handlers = res.getMacroHandlers();
0263:                Object previousParam = handlers.put("param", paramObject);
0264:                Skin previousSkin = res.switchActiveSkin(parentSkin);
0265:
0266:                try {
0267:                    int written = offset;
0268:                    Map handlerCache = null;
0269:
0270:                    if (macros.length > 3) {
0271:                        handlerCache = new HashMap();
0272:                    }
0273:                    RenderContext cx = new RenderContext(reval, this Object,
0274:                            handlerCache);
0275:
0276:                    for (int i = 0; i < macros.length; i++) {
0277:                        if (macros[i].start > written) {
0278:                            res.write(source, written, macros[i].start
0279:                                    - written);
0280:                        }
0281:
0282:                        macros[i].render(cx);
0283:                        written = macros[i].end;
0284:                    }
0285:
0286:                    if (written < length) {
0287:                        res.write(source, written, length - written);
0288:                    }
0289:                } finally {
0290:                    reval.skinDepth--;
0291:                    res.switchActiveSkin(previousSkin);
0292:                    if (previousParam == null) {
0293:                        handlers.remove("param");
0294:                    } else {
0295:                        handlers.put("param", previousParam);
0296:                    }
0297:                }
0298:            }
0299:
0300:            /**
0301:             * Check if a certain macro is present in this skin. The macro name is in handler.name notation
0302:             */
0303:            public boolean containsMacro(String macroname) {
0304:                for (int i = 0; i < macros.length; i++) {
0305:                    if (macros[i] instanceof  Macro) {
0306:                        Macro m = macros[i];
0307:
0308:                        if (macroname.equals(m.name)) {
0309:                            return true;
0310:                        }
0311:                    }
0312:                }
0313:
0314:                return false;
0315:            }
0316:
0317:            /**
0318:             *  Adds a macro to the list of allowed macros. The macro is in handler.name notation.
0319:             */
0320:            public void allowMacro(String macroname) {
0321:                if (sandbox == null) {
0322:                    sandbox = new HashSet();
0323:                }
0324:
0325:                sandbox.add(macroname);
0326:            }
0327:
0328:            private Object processParameter(Object value, RenderContext cx)
0329:                    throws Exception {
0330:                if (value instanceof  Macro) {
0331:                    return ((Macro) value).invokeAsParameter(cx);
0332:                } else {
0333:                    return value;
0334:                }
0335:            }
0336:
0337:            class Macro {
0338:                final int start, end;
0339:                String name;
0340:                String[] path;
0341:                int handlerType = HANDLER_OTHER;
0342:                int encoding = ENCODE_NONE;
0343:                boolean hasNestedMacros = false;
0344:
0345:                // default render parameters - may be overridden if macro changes
0346:                // param.prefix/suffix/default
0347:                StandardParams standardParams = new StandardParams();
0348:                Map namedParams = null;
0349:                List positionalParams = null;
0350:                // filters defined via <% foo | bar %>
0351:                Macro filterChain;
0352:
0353:                // comment macros are silently dropped during rendering
0354:                boolean isCommentMacro = false;
0355:                // subskin macros delimits the beginning of a new subskin
0356:                boolean isSubskinMacro = false;
0357:
0358:                /**
0359:                 * Create and parse a new macro.
0360:                 * @param start the start of the macro within the skin source
0361:                 * @param macroOffset offset of the macro content from the start index
0362:                 */
0363:                Macro(int start, int macroOffset) {
0364:                    this .start = start;
0365:
0366:                    int i = parse(macroOffset, false);
0367:
0368:                    if (isSubskinMacro) {
0369:                        if (i + 1 < length && source[i] == '\r'
0370:                                && source[i + 1] == '\n')
0371:                            end = Math.min(length, i + 2);
0372:                        else if (i < length
0373:                                && (source[i] == '\r' || source[i] == '\n'))
0374:                            end = Math.min(length, i + 1);
0375:                        else
0376:                            end = Math.min(length, i);
0377:                    } else {
0378:                        end = Math.min(length, i);
0379:                    }
0380:
0381:                    path = StringUtils.split(name, ".");
0382:                    if (path.length <= 1) {
0383:                        handlerType = HANDLER_GLOBAL;
0384:                    } else {
0385:                        String handlerName = path[0];
0386:                        if ("this".equalsIgnoreCase(handlerName)) {
0387:                            handlerType = HANDLER_THIS;
0388:                        } else if ("response".equalsIgnoreCase(handlerName)) {
0389:                            handlerType = HANDLER_RESPONSE;
0390:                        } else if ("request".equalsIgnoreCase(handlerName)) {
0391:                            handlerType = HANDLER_REQUEST;
0392:                        } else if ("session".equalsIgnoreCase(handlerName)) {
0393:                            handlerType = HANDLER_SESSION;
0394:                        } else if ("param".equalsIgnoreCase(handlerName)) {
0395:                            handlerType = HANDLER_PARAM;
0396:                        }
0397:                    }
0398:                }
0399:
0400:                private int parse(int macroOffset, boolean lenient) {
0401:                    int state = PARSE_MACRONAME;
0402:                    boolean escape = false;
0403:                    char quotechar = '\u0000';
0404:                    String lastParamName = null;
0405:                    StringBuffer b = new StringBuffer();
0406:                    int i;
0407:
0408:                    loop: for (i = start + macroOffset; i < length - 1; i++) {
0409:
0410:                        switch (source[i]) {
0411:
0412:                        case '<':
0413:
0414:                            if (state == PARSE_PARAM && quotechar == '\u0000'
0415:                                    && b.length() == 0 && source[i + 1] == '%') {
0416:                                Macro macro = new Macro(i, 2);
0417:                                addParameter(lastParamName, macro);
0418:                                lastParamName = null;
0419:                                b.setLength(0);
0420:                                i = macro.end - 1;
0421:                            } else {
0422:                                b.append(source[i]);
0423:                                escape = false;
0424:                            }
0425:                            break;
0426:
0427:                        case '%':
0428:
0429:                            if ((state != PARSE_PARAM || quotechar == '\u0000' || lenient)
0430:                                    && source[i + 1] == '>') {
0431:                                state = PARSE_DONE;
0432:                                break loop;
0433:                            }
0434:                            b.append(source[i]);
0435:                            escape = false;
0436:                            break;
0437:
0438:                        case '/':
0439:
0440:                            b.append(source[i]);
0441:                            escape = false;
0442:
0443:                            if (state == PARSE_MACRONAME
0444:                                    && "//".equals(b.toString())) {
0445:                                isCommentMacro = true;
0446:                                // search macro end tag
0447:                                while (i < length - 1
0448:                                        && (source[i] != '%' || source[i + 1] != '>')) {
0449:                                    i++;
0450:                                }
0451:                                state = PARSE_DONE;
0452:                                break loop;
0453:                            }
0454:                            break;
0455:
0456:                        case '#':
0457:
0458:                            if (state == PARSE_MACRONAME && b.length() == 0) {
0459:                                // this is a subskin/skinlet
0460:                                isSubskinMacro = true;
0461:                                break;
0462:                            }
0463:                            b.append(source[i]);
0464:                            escape = false;
0465:                            break;
0466:
0467:                        case '|':
0468:
0469:                            if (!escape && quotechar == '\u0000') {
0470:                                filterChain = new Macro(i, 1);
0471:                                i = filterChain.end - 2;
0472:                                lastParamName = null;
0473:                                b.setLength(0);
0474:                                state = PARSE_DONE;
0475:                                break loop;
0476:                            }
0477:                            b.append(source[i]);
0478:                            escape = false;
0479:                            break;
0480:
0481:                        case '\\':
0482:
0483:                            if (escape) {
0484:                                b.append(source[i]);
0485:                            }
0486:
0487:                            escape = !escape;
0488:
0489:                            break;
0490:
0491:                        case '"':
0492:                        case '\'':
0493:
0494:                            if (!escape && state == PARSE_PARAM) {
0495:                                if (quotechar == source[i]) {
0496:                                    if (source[i + 1] != '%'
0497:                                            && !Character
0498:                                                    .isWhitespace(source[i + 1])
0499:                                            && !lenient) {
0500:                                        // closing quotes and next character is not space or end tag -
0501:                                        // switch to lenient mode
0502:                                        reset();
0503:                                        return parse(macroOffset, true);
0504:                                    }
0505:                                    // add parameter
0506:                                    addParameter(lastParamName, b.toString());
0507:                                    lastParamName = null;
0508:                                    b.setLength(0);
0509:                                    quotechar = '\u0000';
0510:                                } else if (quotechar == '\u0000') {
0511:                                    quotechar = source[i];
0512:                                    b.setLength(0);
0513:                                } else {
0514:                                    b.append(source[i]);
0515:                                }
0516:                            } else {
0517:                                b.append(source[i]);
0518:                            }
0519:
0520:                            escape = false;
0521:
0522:                            break;
0523:
0524:                        case ' ':
0525:                        case '\t':
0526:                        case '\n':
0527:                        case '\r':
0528:                        case '\f':
0529:
0530:                            if (state == PARSE_MACRONAME && b.length() > 0) {
0531:                                name = b.toString().trim();
0532:                                b.setLength(0);
0533:                                state = PARSE_PARAM;
0534:                            } else if (state == PARSE_PARAM) {
0535:                                if (quotechar == '\u0000') {
0536:                                    if (b.length() > 0) {
0537:                                        // add parameter
0538:                                        addParameter(lastParamName, b
0539:                                                .toString());
0540:                                        lastParamName = null;
0541:                                        b.setLength(0);
0542:                                    }
0543:                                } else {
0544:                                    b.append(source[i]);
0545:                                    escape = false;
0546:                                }
0547:                            }
0548:
0549:                            break;
0550:
0551:                        case '=':
0552:
0553:                            if (!escape && quotechar == '\u0000'
0554:                                    && state == PARSE_PARAM
0555:                                    && lastParamName == null) {
0556:                                lastParamName = b.toString().trim();
0557:                                b.setLength(0);
0558:                            } else {
0559:                                b.append(source[i]);
0560:                                escape = false;
0561:                            }
0562:
0563:                            break;
0564:
0565:                        default:
0566:                            b.append(source[i]);
0567:                            escape = false;
0568:                        }
0569:
0570:                        if (i == length - 2
0571:                                && !lenient
0572:                                && (state != PARSE_DONE || quotechar != '\u0000')) {
0573:                            // macro tag is not properly terminated, switch to lenient mode                    
0574:                            reset();
0575:                            return parse(macroOffset, true);
0576:                        }
0577:                    }
0578:
0579:                    if (b.length() > 0) {
0580:                        if (name == null) {
0581:                            name = b.toString().trim();
0582:                        } else {
0583:                            addParameter(lastParamName, b.toString());
0584:                        }
0585:                    }
0586:
0587:                    if (state != PARSE_DONE) {
0588:                        app.logError("Unterminated Macro Tag: " + this );
0589:                    }
0590:
0591:                    return i + 2;
0592:                }
0593:
0594:                private void reset() {
0595:                    filterChain = null;
0596:                    name = null;
0597:                    standardParams = new StandardParams();
0598:                    namedParams = null;
0599:                    positionalParams = null;
0600:                }
0601:
0602:                private void addParameter(String name, Object value) {
0603:                    if (!(value instanceof  String)) {
0604:                        hasNestedMacros = true;
0605:                    }
0606:                    if (name == null) {
0607:                        // take shortcut for positional parameters
0608:                        if (positionalParams == null) {
0609:                            positionalParams = new ArrayList();
0610:                        }
0611:                        positionalParams.add(value);
0612:                        return;
0613:                    }
0614:                    // check if this is parameter is relevant to us
0615:                    if ("prefix".equals(name)) {
0616:                        standardParams.prefix = value;
0617:                    } else if ("suffix".equals(name)) {
0618:                        standardParams.suffix = value;
0619:                    } else if ("encoding".equals(name)) {
0620:                        if ("html".equals(value)) {
0621:                            encoding = ENCODE_HTML;
0622:                        } else if ("xml".equals(value)) {
0623:                            encoding = ENCODE_XML;
0624:                        } else if ("form".equals(value)) {
0625:                            encoding = ENCODE_FORM;
0626:                        } else if ("url".equals(value)) {
0627:                            encoding = ENCODE_URL;
0628:                        } else if ("all".equals(value)) {
0629:                            encoding = ENCODE_ALL;
0630:                        } else {
0631:                            app
0632:                                    .logEvent("Unrecognized encoding in skin macro: "
0633:                                            + value);
0634:                        }
0635:                    } else if ("default".equals(name)) {
0636:                        standardParams.defaultValue = value;
0637:                    } else if ("failmode".equals(name)) {
0638:                        standardParams.setFailMode(value);
0639:                    }
0640:
0641:                    // Add parameter to parameter map
0642:                    if (namedParams == null) {
0643:                        namedParams = new HashMap();
0644:                    }
0645:                    namedParams.put(name, value);
0646:                }
0647:
0648:                private Object invokeAsMacro(RenderContext cx,
0649:                        StandardParams stdParams, boolean asObject)
0650:                        throws Exception {
0651:
0652:                    // immediately return for comment macros
0653:                    if (isCommentMacro || name == null) {
0654:                        return null;
0655:                    }
0656:
0657:                    if ((sandbox != null) && !sandbox.contains(name)) {
0658:                        throw new RuntimeException("Macro " + name
0659:                                + " not allowed in sandbox");
0660:                    }
0661:
0662:                    Object handler = null;
0663:                    Object value = null;
0664:                    ScriptingEngine engine = cx.reval.scriptingEngine;
0665:
0666:                    if (handlerType != HANDLER_GLOBAL) {
0667:                        handler = cx.resolveHandler(path[0], handlerType);
0668:                        handler = resolvePath(handler, cx.reval);
0669:                    }
0670:
0671:                    if (handlerType == HANDLER_GLOBAL || handler != null) {
0672:                        // check if a function called name_macro is defined.
0673:                        // if so, the macro evaluates to the function. Otherwise,
0674:                        // a property/field with the name is used, if defined.
0675:                        String propName = path[path.length - 1];
0676:                        String funcName = resolveFunctionName(handler, propName
0677:                                + "_macro", engine);
0678:
0679:                        // remember length of response buffer before calling macro
0680:                        StringBuffer buffer = cx.reval.getResponse()
0681:                                .getBuffer();
0682:                        int bufLength = buffer.length();
0683:
0684:                        if (funcName != null) {
0685:
0686:                            Object[] arguments = prepareArguments(0, cx);
0687:                            // get reference to rendered named params for after invocation
0688:                            Map params = (Map) arguments[0];
0689:                            value = cx.reval.invokeDirectFunction(handler,
0690:                                    funcName, arguments);
0691:
0692:                            // update StandardParams to override defaults in case the macro changed anything
0693:                            if (stdParams != null)
0694:                                stdParams.readFrom(params);
0695:
0696:                            // if macro has a filter chain and didn't return anything, use output
0697:                            // as filter argument.
0698:                            if (asObject && value == null
0699:                                    && buffer.length() > bufLength) {
0700:                                value = buffer.substring(bufLength);
0701:                                buffer.setLength(bufLength);
0702:                            }
0703:
0704:                            return filter(value, cx);
0705:                        } else {
0706:                            if (handlerType == HANDLER_RESPONSE) {
0707:                                // some special handling for response handler
0708:                                if ("message".equals(propName))
0709:                                    value = cx.reval.getResponse().getMessage();
0710:                                else if ("error".equals(propName))
0711:                                    value = cx.reval.getResponse().getError();
0712:                                if (value != null)
0713:                                    return filter(value, cx);
0714:                            }
0715:                            // display error message unless onUnhandledMacro is defined or silent failmode is on
0716:                            if (!engine.hasProperty(handler, propName)) {
0717:                                if (engine.hasFunction(handler,
0718:                                        "onUnhandledMacro", false)) {
0719:                                    Object[] arguments = prepareArguments(1, cx);
0720:                                    arguments[0] = propName;
0721:                                    value = cx.reval.invokeDirectFunction(
0722:                                            handler, "onUnhandledMacro",
0723:                                            arguments);
0724:                                    // if macro has a filter chain and didn't return anything, use output
0725:                                    // as filter argument.
0726:                                    if (asObject && value == null
0727:                                            && buffer.length() > bufLength) {
0728:                                        value = buffer.substring(bufLength);
0729:                                        buffer.setLength(bufLength);
0730:                                    }
0731:                                } else if (standardParams.verboseFailmode(
0732:                                        handler, engine)) {
0733:                                    throw new UnhandledMacroException(name);
0734:                                }
0735:                            } else {
0736:                                value = engine.getProperty(handler, propName);
0737:                            }
0738:                            return filter(value, cx);
0739:                        }
0740:                    } else if (standardParams.verboseFailmode(handler, engine)) {
0741:                        throw new UnhandledMacroException(name);
0742:                    }
0743:                    return filter(null, cx);
0744:                }
0745:
0746:                /**
0747:                 * Render this macro as nested macro, only converting to string
0748:                 * if necessary.
0749:                 */
0750:                Object invokeAsParameter(RenderContext cx) throws Exception {
0751:                    StandardParams stdParams = standardParams.render(cx);
0752:                    Object value = invokeAsMacro(cx, stdParams, true);
0753:                    if (stdParams.prefix != null || stdParams.suffix != null) {
0754:                        ResponseTrans res = cx.reval.getResponse();
0755:                        res.pushBuffer(null);
0756:                        writeResponse(value, cx.reval, stdParams, true);
0757:                        return res.popString();
0758:                    } else if (stdParams.defaultValue != null
0759:                            && (value == null || "".equals(value))) {
0760:                        return stdParams.defaultValue;
0761:                    } else {
0762:                        return value;
0763:                    }
0764:                }
0765:
0766:                /**
0767:                 *  Render the macro given a handler object.
0768:                 */
0769:                void render(RenderContext cx) throws RedirectException,
0770:                        UnsupportedEncodingException {
0771:                    StringBuffer buffer = cx.reval.getResponse().getBuffer();
0772:                    // remember length of response buffer before calling macro
0773:                    int bufLength = buffer.length();
0774:                    try {
0775:                        StandardParams stdParams = standardParams.render(cx);
0776:                        boolean asObject = filterChain != null;
0777:                        Object value = invokeAsMacro(cx, stdParams, asObject);
0778:
0779:                        // check if macro wrote out to response buffer
0780:                        if (buffer.length() == bufLength) {
0781:                            // If the macro function didn't write anything to the response itself,
0782:                            // we interpret its return value as macro output.
0783:                            writeResponse(value, cx.reval, stdParams, true);
0784:                        } else {
0785:                            // if an encoding is specified, re-encode the macro's output
0786:                            if (encoding != ENCODE_NONE) {
0787:                                String output = buffer.substring(bufLength);
0788:
0789:                                buffer.setLength(bufLength);
0790:                                writeResponse(output, cx.reval, stdParams,
0791:                                        false);
0792:                            } else {
0793:                                // insert prefix,
0794:                                if (stdParams.prefix != null) {
0795:                                    buffer.insert(bufLength, stdParams.prefix);
0796:                                }
0797:                                // append suffix
0798:                                if (stdParams.suffix != null) {
0799:                                    buffer.append(stdParams.suffix);
0800:                                }
0801:                            }
0802:
0803:                            // Append macro return value even if it wrote something to the response,
0804:                            // but don't render default value in case it returned nothing.
0805:                            // We do this for the sake of consistency.
0806:                            writeResponse(value, cx.reval, stdParams, false);
0807:                        }
0808:
0809:                    } catch (RedirectException redir) {
0810:                        throw redir;
0811:                    } catch (ConcurrencyException concur) {
0812:                        throw concur;
0813:                    } catch (TimeoutException timeout) {
0814:                        throw timeout;
0815:                    } catch (UnhandledMacroException unhandled) {
0816:                        String msg = "Unhandled Macro: "
0817:                                + unhandled.getMessage();
0818:                        cx.reval.getResponse().write(" [" + msg + "] ");
0819:                        app.logError(msg);
0820:                    } catch (Exception x) {
0821:                        String msg = x.getMessage();
0822:                        if ((msg == null) || (msg.length() < 10)) {
0823:                            msg = x.toString();
0824:                        }
0825:                        msg = new StringBuffer("Macro error in ").append(name)
0826:                                .append(": ").append(msg).toString();
0827:                        cx.reval.getResponse().write(" [" + msg + "] ");
0828:                        app.logError(msg, x);
0829:                    }
0830:                }
0831:
0832:                private Object filter(Object returnValue, RenderContext cx)
0833:                        throws Exception {
0834:                    // invoke filter chain if defined
0835:                    if (filterChain != null) {
0836:                        return filterChain.invokeAsFilter(returnValue, cx);
0837:                    } else {
0838:                        return returnValue;
0839:                    }
0840:                }
0841:
0842:                private Object invokeAsFilter(Object returnValue,
0843:                        RenderContext cx) throws Exception {
0844:
0845:                    if (name == null) {
0846:                        throw new RuntimeException("Empty macro filter");
0847:                    } else if (sandbox != null && !sandbox.contains(name)) {
0848:                        throw new RuntimeException("Macro " + name
0849:                                + " not allowed in sandbox");
0850:                    }
0851:                    Object handlerObject = null;
0852:
0853:                    if (handlerType != HANDLER_GLOBAL) {
0854:                        handlerObject = cx.resolveHandler(path[0], handlerType);
0855:                        handlerObject = resolvePath(handlerObject, cx.reval);
0856:                    }
0857:
0858:                    String propName = path[path.length - 1] + "_filter";
0859:                    String funcName = resolveFunctionName(handlerObject,
0860:                            propName, cx.reval.scriptingEngine);
0861:
0862:                    if (funcName != null) {
0863:                        Object[] arguments = prepareArguments(1, cx);
0864:                        arguments[0] = returnValue;
0865:                        Object retval = cx.reval.invokeDirectFunction(
0866:                                handlerObject, funcName, arguments);
0867:
0868:                        return filter(retval, cx);
0869:                    } else {
0870:                        throw new RuntimeException("Undefined Filter " + name);
0871:                    }
0872:                }
0873:
0874:                private Object[] prepareArguments(int offset, RenderContext cx)
0875:                        throws Exception {
0876:                    int nPosArgs = (positionalParams == null) ? 0
0877:                            : positionalParams.size();
0878:                    Object[] arguments = new Object[offset + 1 + nPosArgs];
0879:
0880:                    if (namedParams == null) {
0881:                        arguments[offset] = new SystemMap(4);
0882:                    } else if (hasNestedMacros) {
0883:                        SystemMap map = new SystemMap(
0884:                                (int) (namedParams.size() * 1.5));
0885:                        for (Iterator it = namedParams.entrySet().iterator(); it
0886:                                .hasNext();) {
0887:                            Map.Entry entry = (Map.Entry) it.next();
0888:                            Object value = entry.getValue();
0889:                            if (!(value instanceof  String))
0890:                                value = processParameter(value, cx);
0891:                            map.put(entry.getKey(), value);
0892:                        }
0893:                        arguments[offset] = map;
0894:                    } else {
0895:                        // pass a clone/copy of the parameter map so if the script changes it,
0896:                        arguments[offset] = new CopyOnWriteMap(namedParams);
0897:                    }
0898:                    if (positionalParams != null) {
0899:                        for (int i = 0; i < nPosArgs; i++) {
0900:                            Object value = positionalParams.get(i);
0901:                            if (!(value instanceof  String))
0902:                                value = processParameter(value, cx);
0903:                            arguments[offset + 1 + i] = value;
0904:                        }
0905:                    }
0906:                    return arguments;
0907:                }
0908:
0909:                private Object resolvePath(Object handler,
0910:                        RequestEvaluator reval) throws Exception {
0911:                    for (int i = 1; i < path.length - 1; i++) {
0912:                        Object[] arguments = { path[i] };
0913:                        Object next = reval.invokeDirectFunction(handler,
0914:                                "getMacroHandler", arguments);
0915:                        if (next != null) {
0916:                            handler = next;
0917:                        } else if (!reval.scriptingEngine
0918:                                .isTypedObject(handler)) {
0919:                            handler = reval.scriptingEngine.getProperty(
0920:                                    handler, path[i]);
0921:                            if (handler == null) {
0922:                                return null;
0923:                            }
0924:                        } else {
0925:                            return null;
0926:                        }
0927:                    }
0928:                    return handler;
0929:                }
0930:
0931:                private String resolveFunctionName(Object handler,
0932:                        String functionName, ScriptingEngine engine) {
0933:                    if (handlerType == HANDLER_GLOBAL) {
0934:                        String[] macroPath = app.globalMacroPath;
0935:                        if (macroPath == null || macroPath.length == 0) {
0936:                            if (engine.hasFunction(null, functionName, false))
0937:                                return functionName;
0938:                        } else {
0939:                            for (int i = 0; i < macroPath.length; i++) {
0940:                                String path = macroPath[i];
0941:                                String funcName = path == null
0942:                                        || path.length() == 0 ? functionName
0943:                                        : path + "." + functionName;
0944:                                if (engine.hasFunction(null, funcName, true))
0945:                                    return funcName;
0946:                            }
0947:                        }
0948:                    } else {
0949:                        if (engine.hasFunction(handler, functionName, false))
0950:                            return functionName;
0951:                    }
0952:                    return null;
0953:                }
0954:
0955:                /**
0956:                 * Utility method for writing text out to the response object.
0957:                 */
0958:                void writeResponse(Object value, RequestEvaluator reval,
0959:                        StandardParams stdParams, boolean useDefault)
0960:                        throws Exception {
0961:                    String text;
0962:                    StringBuffer buffer = reval.getResponse().getBuffer();
0963:
0964:                    if (value == null || "".equals(value)) {
0965:                        if (useDefault) {
0966:                            text = (String) stdParams.defaultValue;
0967:                        } else {
0968:                            return;
0969:                        }
0970:                    } else {
0971:                        text = reval.scriptingEngine.toString(value);
0972:                    }
0973:
0974:                    if ((text != null) && (text.length() > 0)) {
0975:                        // only write prefix/suffix if value is not null, if we write the default
0976:                        // value provided by the macro tag, we assume it's already complete
0977:                        if (stdParams.prefix != null && value != null) {
0978:                            buffer.append(stdParams.prefix);
0979:                        }
0980:
0981:                        switch (encoding) {
0982:                        case ENCODE_NONE:
0983:                            buffer.append(text);
0984:
0985:                            break;
0986:
0987:                        case ENCODE_HTML:
0988:                            HtmlEncoder.encode(text, buffer);
0989:
0990:                            break;
0991:
0992:                        case ENCODE_XML:
0993:                            HtmlEncoder.encodeXml(text, buffer);
0994:
0995:                            break;
0996:
0997:                        case ENCODE_FORM:
0998:                            HtmlEncoder.encodeFormValue(text, buffer);
0999:
1000:                            break;
1001:
1002:                        case ENCODE_URL:
1003:                            buffer.append(UrlEncoded.encode(text, app.charset));
1004:
1005:                            break;
1006:
1007:                        case ENCODE_ALL:
1008:                            HtmlEncoder.encodeAll(text, buffer);
1009:
1010:                            break;
1011:                        }
1012:
1013:                        if (stdParams.suffix != null && value != null) {
1014:                            buffer.append(stdParams.suffix);
1015:                        }
1016:                    }
1017:                }
1018:
1019:                public String toString() {
1020:                    return "[Macro: " + name + "]";
1021:                }
1022:
1023:                /**
1024:                 * Return the full name of the macro in handler.name notation
1025:                 * @return the macro name
1026:                 */
1027:                String getName() {
1028:                    return name;
1029:                }
1030:            }
1031:
1032:            class StandardParams {
1033:                Object prefix = null;
1034:                Object suffix = null;
1035:                Object defaultValue = null;
1036:                int failmode = FAIL_DEFAULT;
1037:
1038:                StandardParams() {
1039:                }
1040:
1041:                StandardParams(Map map) {
1042:                    readFrom(map);
1043:                }
1044:
1045:                void readFrom(Map map) {
1046:                    prefix = map.get("prefix");
1047:                    suffix = map.get("suffix");
1048:                    defaultValue = map.get("default");
1049:                }
1050:
1051:                boolean containsMacros() {
1052:                    return !(prefix instanceof  String)
1053:                            || !(suffix instanceof  String)
1054:                            || !(defaultValue instanceof  String);
1055:                }
1056:
1057:                void setFailMode(Object value) {
1058:                    if ("silent".equals(value))
1059:                        failmode = FAIL_SILENT;
1060:                    else if ("verbose".equals(value))
1061:                        failmode = FAIL_VERBOSE;
1062:                    else if (value != null)
1063:                        app.logEvent("unrecognized failmode value: " + value);
1064:                }
1065:
1066:                boolean verboseFailmode(Object handler, ScriptingEngine engine) {
1067:                    return (failmode == FAIL_VERBOSE)
1068:                            || (failmode == FAIL_DEFAULT && (handler == null || engine
1069:                                    .isTypedObject(handler)));
1070:                }
1071:
1072:                StandardParams render(RenderContext cx) throws Exception {
1073:                    if (!containsMacros())
1074:                        return this ;
1075:                    StandardParams stdParams = new StandardParams();
1076:                    stdParams.prefix = renderToString(prefix, cx);
1077:                    stdParams.suffix = renderToString(suffix, cx);
1078:                    stdParams.defaultValue = renderToString(defaultValue, cx);
1079:                    return stdParams;
1080:                }
1081:
1082:                String renderToString(Object obj, RenderContext cx)
1083:                        throws Exception {
1084:                    Object value = processParameter(obj, cx);
1085:                    if (value == null)
1086:                        return null;
1087:                    else if (value instanceof  String)
1088:                        return (String) value;
1089:                    else
1090:                        return cx.reval.scriptingEngine.toString(value);
1091:                }
1092:
1093:            }
1094:
1095:            class RenderContext {
1096:                final RequestEvaluator reval;
1097:                final Object this Object;
1098:                final Map handlerCache;
1099:
1100:                RenderContext(RequestEvaluator reval, Object this Object,
1101:                        Map handlerCache) {
1102:                    this .reval = reval;
1103:                    this .this Object = this Object;
1104:                    this .handlerCache = handlerCache;
1105:                }
1106:
1107:                private Object resolveHandler(String handlerName,
1108:                        int handlerType) {
1109:                    switch (handlerType) {
1110:                    case HANDLER_THIS:
1111:                        return this Object;
1112:                    case HANDLER_RESPONSE:
1113:                        return reval.getResponse().getResponseData();
1114:                    case HANDLER_REQUEST:
1115:                        return reval.getRequest().getRequestData();
1116:                    case HANDLER_SESSION:
1117:                        return reval.getSession().getCacheNode();
1118:                    }
1119:
1120:                    // try to get handler from handlerCache first
1121:                    if (handlerCache != null
1122:                            && handlerCache.containsKey(handlerName)) {
1123:                        return handlerCache.get(handlerName);
1124:                    }
1125:
1126:                    // if handler object wasn't found in cache retrieve it
1127:                    if (this Object != null) {
1128:                        // not a global macro - need to find handler object
1129:                        // was called with this object - check it or its parents for matching prototype
1130:                        if (handlerName.equalsIgnoreCase(app
1131:                                .getPrototypeName(this Object))) {
1132:                            // we already have the right handler object
1133:                            // put the found handler object into the cache so we don't have to look again
1134:                            if (handlerCache != null)
1135:                                handlerCache.put(handlerName, this Object);
1136:                            return this Object;
1137:                        } else {
1138:                            // the handler object is not what we want
1139:                            Object obj = this Object;
1140:
1141:                            // walk down parent chain to find handler object,
1142:                            // limiting to 50 passes to avoid infinite loops
1143:                            int maxloop = 50;
1144:                            while (obj != null && maxloop-- > 0) {
1145:                                Prototype proto = app.getPrototype(obj);
1146:
1147:                                if ((proto != null)
1148:                                        && proto.isInstanceOf(handlerName)) {
1149:                                    if (handlerCache != null)
1150:                                        handlerCache.put(handlerName, obj);
1151:                                    return obj;
1152:                                }
1153:
1154:                                obj = app.getParentElement(obj);
1155:                            }
1156:                        }
1157:                    }
1158:
1159:                    Map macroHandlers = reval.getResponse().getMacroHandlers();
1160:                    Object obj = macroHandlers.get(handlerName);
1161:                    if (handlerCache != null && obj != null) {
1162:                        handlerCache.put(handlerName, obj);
1163:                    }
1164:                    return obj;
1165:                }
1166:            }
1167:
1168:            /**
1169:             * Exception type for unhandled macros
1170:             */
1171:            class UnhandledMacroException extends Exception {
1172:                UnhandledMacroException(String name) {
1173:                    super(name);
1174:                }
1175:            }
1176:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.