Source Code Cross Referenced for JXTemplateGenerator.java in  » Web-Framework » cocoon » org » apache » cocoon » generation » 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 » cocoon » org.apache.cocoon.generation 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:        package org.apache.cocoon.generation;
0018:
0019:        import java.beans.PropertyDescriptor;
0020:        import java.io.CharArrayReader;
0021:        import java.io.IOException;
0022:        import java.io.PrintStream;
0023:        import java.io.PrintWriter;
0024:        import java.io.Serializable;
0025:        import java.io.StringReader;
0026:        import java.lang.reflect.Field;
0027:        import java.lang.reflect.InvocationTargetException;
0028:        import java.lang.reflect.Method;
0029:        import java.text.DateFormat;
0030:        import java.text.DecimalFormat;
0031:        import java.text.DecimalFormatSymbols;
0032:        import java.text.NumberFormat;
0033:        import java.text.SimpleDateFormat;
0034:        import java.util.Enumeration;
0035:        import java.util.HashMap;
0036:        import java.util.Iterator;
0037:        import java.util.LinkedList;
0038:        import java.util.List;
0039:        import java.util.Locale;
0040:        import java.util.Map;
0041:        import java.util.Properties;
0042:        import java.util.Stack;
0043:        import java.util.TimeZone;
0044:
0045:        import org.apache.avalon.framework.parameters.Parameters;
0046:        import org.apache.avalon.framework.service.ServiceException;
0047:        import org.apache.avalon.framework.service.ServiceManager;
0048:        import org.apache.cocoon.ProcessingException;
0049:        import org.apache.cocoon.caching.CacheableProcessingComponent;
0050:        import org.apache.cocoon.components.flow.FlowHelper;
0051:        import org.apache.cocoon.components.flow.WebContinuation;
0052:        import org.apache.cocoon.components.flow.javascript.fom.FOM_JavaScriptFlowHelper;
0053:        import org.apache.cocoon.components.source.SourceUtil;
0054:        import org.apache.cocoon.environment.ObjectModelHelper;
0055:        import org.apache.cocoon.environment.Request;
0056:        import org.apache.cocoon.environment.SourceResolver;
0057:        import org.apache.cocoon.transformation.ServiceableTransformer;
0058:        import org.apache.cocoon.util.jxpath.NamespacesTablePointer;
0059:        import org.apache.cocoon.util.location.LocatedRuntimeException;
0060:        import org.apache.cocoon.util.location.Location;
0061:        import org.apache.cocoon.util.location.LocationUtils;
0062:        import org.apache.cocoon.xml.IncludeXMLConsumer;
0063:        import org.apache.cocoon.xml.NamespacesTable;
0064:        import org.apache.cocoon.xml.RedundantNamespacesFilter;
0065:        import org.apache.cocoon.xml.XMLConsumer;
0066:        import org.apache.cocoon.xml.XMLUtils;
0067:        import org.apache.cocoon.xml.dom.DOMBuilder;
0068:        import org.apache.cocoon.xml.dom.DOMStreamer;
0069:        import org.apache.commons.jexl.Expression;
0070:        import org.apache.commons.jexl.ExpressionFactory;
0071:        import org.apache.commons.jexl.JexlContext;
0072:        import org.apache.commons.jexl.util.Introspector;
0073:        import org.apache.commons.jexl.util.introspection.Info;
0074:        import org.apache.commons.jexl.util.introspection.UberspectImpl;
0075:        import org.apache.commons.jexl.util.introspection.VelMethod;
0076:        import org.apache.commons.jexl.util.introspection.VelPropertyGet;
0077:        import org.apache.commons.jexl.util.introspection.VelPropertySet;
0078:        import org.apache.commons.jxpath.*;
0079:        import org.apache.commons.lang.ArrayUtils;
0080:        import org.apache.commons.lang.StringUtils;
0081:        import org.apache.excalibur.source.Source;
0082:        import org.apache.excalibur.source.SourceException;
0083:        import org.apache.excalibur.source.SourceValidity;
0084:        import org.apache.excalibur.xml.sax.XMLizable;
0085:        import org.mozilla.javascript.Context;
0086:        import org.mozilla.javascript.Function;
0087:        import org.mozilla.javascript.JavaScriptException;
0088:        import org.mozilla.javascript.NativeArray;
0089:        import org.mozilla.javascript.NativeJavaClass;
0090:        import org.mozilla.javascript.ScriptRuntime;
0091:        import org.mozilla.javascript.Scriptable;
0092:        import org.mozilla.javascript.ScriptableObject;
0093:        import org.mozilla.javascript.Undefined;
0094:        import org.mozilla.javascript.Wrapper;
0095:        import org.w3c.dom.Node;
0096:        import org.w3c.dom.NodeList;
0097:        import org.xml.sax.Attributes;
0098:        import org.xml.sax.ContentHandler;
0099:        import org.xml.sax.Locator;
0100:        import org.xml.sax.SAXException;
0101:        import org.xml.sax.ext.LexicalHandler;
0102:        import org.xml.sax.helpers.AttributesImpl;
0103:
0104:        /**
0105:         * @cocoon.sitemap.component.documentation
0106:         * Provides a generic page template with embedded JSTL and XPath
0107:         * expression substitution to access data sent by Cocoon Flowscripts.
0108:         *
0109:         * @cocoon.sitemap.component.name   jx
0110:         * @cocoon.sitemap.component.label  content
0111:         * @cocoon.sitemap.component.logger sitemap.generator.jx
0112:         *
0113:         * @cocoon.sitemap.component.pooling.max  16
0114:         *
0115:         * @deprecated Replaced with the template block: {@link org.apache.cocoon.template.JXTemplateGenerator}.
0116:         *
0117:         * @version $Id: JXTemplateGenerator.java 452138 2006-10-02 17:32:00Z joerg $
0118:         */
0119:        public class JXTemplateGenerator extends ServiceableGenerator implements 
0120:                CacheableProcessingComponent {
0121:
0122:            // Quick'n dirty hack to replace all SAXParseException by a located runtime exception
0123:            private static final class JXTException extends
0124:                    LocatedRuntimeException {
0125:                JXTException(String message, Location loc, Throwable thr) {
0126:                    super (message, thr, loc);
0127:                }
0128:            }
0129:
0130:            private static final JXPathContextFactory jxpathContextFactory = JXPathContextFactory
0131:                    .newInstance();
0132:
0133:            private static final Attributes EMPTY_ATTRS = XMLUtils.EMPTY_ATTRIBUTES;
0134:
0135:            private final NamespacesTable namespaces = new NamespacesTable();
0136:
0137:            private static final Iterator EMPTY_ITER = new Iterator() {
0138:                public boolean hasNext() {
0139:                    return false;
0140:                }
0141:
0142:                public Object next() {
0143:                    return null;
0144:                }
0145:
0146:                public void remove() {
0147:                    // EMPTY
0148:                }
0149:            };
0150:
0151:            private static final Iterator NULL_ITER = new Iterator() {
0152:                public boolean hasNext() {
0153:                    return true;
0154:                }
0155:
0156:                public Object next() {
0157:                    return null;
0158:                }
0159:
0160:                public void remove() {
0161:                    // EMPTY
0162:                }
0163:            };
0164:
0165:            private XMLConsumer getConsumer() {
0166:                return this .xmlConsumer;
0167:            }
0168:
0169:            public static class ErrorHolder extends Exception {
0170:
0171:                private Error err;
0172:
0173:                public ErrorHolder(Error err) {
0174:                    super (err.getMessage());
0175:                    this .err = err;
0176:                }
0177:
0178:                public void printStackTrace(PrintStream ps) {
0179:                    err.printStackTrace(ps);
0180:                }
0181:
0182:                public void printStackTrace(PrintWriter pw) {
0183:                    err.printStackTrace(pw);
0184:                }
0185:
0186:                public void printStackTrace() {
0187:                    err.printStackTrace();
0188:                }
0189:
0190:                public Error getError() {
0191:                    return err;
0192:                }
0193:
0194:            }
0195:
0196:            /**
0197:             * Facade to the Location to be set on the consumer prior to
0198:             * sending other events, location member changeable
0199:             */
0200:            public static class LocationFacade implements  Locator {
0201:                private Location locator;
0202:
0203:                public LocationFacade(Location initialLocation) {
0204:                    this .locator = initialLocation;
0205:                }
0206:
0207:                public void setDocumentLocation(Location newLocation) {
0208:                    this .locator = newLocation;
0209:                }
0210:
0211:                public int getColumnNumber() {
0212:                    return this .locator.getColumnNumber();
0213:                }
0214:
0215:                public int getLineNumber() {
0216:                    return this .locator.getLineNumber();
0217:                }
0218:
0219:                public String getPublicId() {
0220:                    return null;
0221:                }
0222:
0223:                public String getSystemId() {
0224:                    return this .locator.getURI();
0225:                }
0226:            }
0227:
0228:            /**
0229:             * Jexl Introspector that supports Rhino JavaScript objects
0230:             * as well as Java Objects
0231:             */
0232:            static class JSIntrospector extends UberspectImpl {
0233:
0234:                static class JSMethod implements  VelMethod {
0235:
0236:                    Scriptable scope;
0237:                    String name;
0238:
0239:                    public JSMethod(Scriptable scope, String name) {
0240:                        this .scope = scope;
0241:                        this .name = name;
0242:                    }
0243:
0244:                    public Object invoke(Object this Arg, Object[] args)
0245:                            throws Exception {
0246:                        Context cx = Context.enter();
0247:                        try {
0248:                            Object result;
0249:                            Scriptable this Obj = !(this Arg instanceof  Scriptable) ? Context
0250:                                    .toObject(this Arg, scope)
0251:                                    : (Scriptable) this Arg;
0252:                            result = ScriptableObject
0253:                                    .getProperty(this Obj, name);
0254:                            Object[] newArgs = null;
0255:                            if (args != null) {
0256:                                newArgs = new Object[args.length];
0257:                                int len = args.length;
0258:                                for (int i = 0; i < len; i++) {
0259:                                    newArgs[i] = args[i];
0260:                                    if (args[i] != null
0261:                                            && !(args[i] instanceof  Number)
0262:                                            && !(args[i] instanceof  Boolean)
0263:                                            && !(args[i] instanceof  String)
0264:                                            && !(args[i] instanceof  Scriptable)) {
0265:                                        newArgs[i] = Context.toObject(args[i],
0266:                                                scope);
0267:                                    }
0268:                                }
0269:                            }
0270:                            result = ScriptRuntime.call(cx, result, this Obj,
0271:                                    newArgs, scope);
0272:                            if (result == Undefined.instance
0273:                                    || result == Scriptable.NOT_FOUND) {
0274:                                result = null;
0275:                            } else if (!(result instanceof  NativeJavaClass)) {
0276:                                while (result instanceof  Wrapper) {
0277:                                    result = ((Wrapper) result).unwrap();
0278:                                }
0279:                            }
0280:                            return result;
0281:                        } catch (JavaScriptException e) {
0282:                            throw new java.lang.reflect.InvocationTargetException(
0283:                                    e);
0284:                        } finally {
0285:                            Context.exit();
0286:                        }
0287:                    }
0288:
0289:                    public boolean isCacheable() {
0290:                        return false;
0291:                    }
0292:
0293:                    public String getMethodName() {
0294:                        return name;
0295:                    }
0296:
0297:                    public Class getReturnType() {
0298:                        return Object.class;
0299:                    }
0300:
0301:                }
0302:
0303:                static class JSPropertyGet implements  VelPropertyGet {
0304:
0305:                    Scriptable scope;
0306:                    String name;
0307:
0308:                    public JSPropertyGet(Scriptable scope, String name) {
0309:                        this .scope = scope;
0310:                        this .name = name;
0311:                    }
0312:
0313:                    public Object invoke(Object this Arg) throws Exception {
0314:                        Context cx = Context.enter();
0315:                        try {
0316:                            Scriptable this Obj = !(this Arg instanceof  Scriptable) ? Context
0317:                                    .toObject(this Arg, scope)
0318:                                    : (Scriptable) this Arg;
0319:                            Object result = ScriptableObject.getProperty(
0320:                                    this Obj, name);
0321:                            if (result == Scriptable.NOT_FOUND) {
0322:                                result = ScriptableObject.getProperty(this Obj,
0323:                                        "get" + StringUtils.capitalize(name));
0324:                                if (result != Scriptable.NOT_FOUND
0325:                                        && result instanceof  Function) {
0326:                                    try {
0327:                                        result = ((Function) result)
0328:                                                .call(
0329:                                                        cx,
0330:                                                        ScriptableObject
0331:                                                                .getTopLevelScope(this Obj),
0332:                                                        this Obj,
0333:                                                        new Object[] {});
0334:                                    } catch (JavaScriptException exc) {
0335:                                        exc.printStackTrace();
0336:                                        result = null;
0337:                                    }
0338:                                }
0339:                            }
0340:                            if (result == Scriptable.NOT_FOUND
0341:                                    || result == Undefined.instance) {
0342:                                result = null;
0343:                            } else if (result instanceof  Wrapper
0344:                                    && !(result instanceof  NativeJavaClass)) {
0345:                                result = ((Wrapper) result).unwrap();
0346:                            }
0347:                            return result;
0348:                        } finally {
0349:                            Context.exit();
0350:                        }
0351:                    }
0352:
0353:                    public boolean isCacheable() {
0354:                        return false;
0355:                    }
0356:
0357:                    public String getMethodName() {
0358:                        return name;
0359:                    }
0360:                }
0361:
0362:                static class JSPropertySet implements  VelPropertySet {
0363:
0364:                    Scriptable scope;
0365:                    String name;
0366:
0367:                    public JSPropertySet(Scriptable scope, String name) {
0368:                        this .scope = scope;
0369:                        this .name = name;
0370:                    }
0371:
0372:                    public Object invoke(Object this Arg, Object rhs)
0373:                            throws Exception {
0374:                        Context.enter();
0375:                        try {
0376:                            Scriptable this Obj;
0377:                            Object arg = rhs;
0378:                            if (!(this Arg instanceof  Scriptable)) {
0379:                                this Obj = Context.toObject(this Arg, scope);
0380:                            } else {
0381:                                this Obj = (Scriptable) this Arg;
0382:                            }
0383:                            if (arg != null && !(arg instanceof  Number)
0384:                                    && !(arg instanceof  Boolean)
0385:                                    && !(arg instanceof  String)
0386:                                    && !(arg instanceof  Scriptable)) {
0387:                                arg = Context.toObject(arg, scope);
0388:                            }
0389:                            ScriptableObject.putProperty(this Obj, name, arg);
0390:                            return rhs;
0391:                        } finally {
0392:                            Context.exit();
0393:                        }
0394:                    }
0395:
0396:                    public boolean isCacheable() {
0397:                        return false;
0398:                    }
0399:
0400:                    public String getMethodName() {
0401:                        return name;
0402:                    }
0403:                }
0404:
0405:                static class NativeArrayIterator implements  Iterator {
0406:
0407:                    NativeArray arr;
0408:                    int index;
0409:
0410:                    public NativeArrayIterator(NativeArray arr) {
0411:                        this .arr = arr;
0412:                        this .index = 0;
0413:                    }
0414:
0415:                    public boolean hasNext() {
0416:                        return index < (int) arr.jsGet_length();
0417:                    }
0418:
0419:                    public Object next() {
0420:                        Context.enter();
0421:                        try {
0422:                            Object result = arr.get(index++, arr);
0423:                            if (result == Undefined.instance
0424:                                    || result == Scriptable.NOT_FOUND) {
0425:                                result = null;
0426:                            } else {
0427:                                if (!(result instanceof  NativeJavaClass)) {
0428:                                    while (result instanceof  Wrapper) {
0429:                                        result = ((Wrapper) result).unwrap();
0430:                                    }
0431:                                }
0432:                            }
0433:                            return result;
0434:                        } finally {
0435:                            Context.exit();
0436:                        }
0437:                    }
0438:
0439:                    public void remove() {
0440:                        arr.delete(index);
0441:                    }
0442:                }
0443:
0444:                static class ScriptableIterator implements  Iterator {
0445:
0446:                    Scriptable scope;
0447:                    Object[] ids;
0448:                    int index;
0449:
0450:                    public ScriptableIterator(Scriptable scope) {
0451:                        this .scope = scope;
0452:                        this .ids = scope.getIds();
0453:                        this .index = 0;
0454:                    }
0455:
0456:                    public boolean hasNext() {
0457:                        return index < ids.length;
0458:                    }
0459:
0460:                    public Object next() {
0461:                        Context.enter();
0462:                        try {
0463:                            Object result = ScriptableObject.getProperty(scope,
0464:                                    ids[index++].toString());
0465:                            if (result == Undefined.instance
0466:                                    || result == Scriptable.NOT_FOUND) {
0467:                                result = null;
0468:                            } else if (!(result instanceof  NativeJavaClass)) {
0469:                                while (result instanceof  Wrapper) {
0470:                                    result = ((Wrapper) result).unwrap();
0471:                                }
0472:                            }
0473:                            return result;
0474:                        } finally {
0475:                            Context.exit();
0476:                        }
0477:                    }
0478:
0479:                    public void remove() {
0480:                        Context.enter();
0481:                        try {
0482:                            scope.delete(ids[index].toString());
0483:                        } finally {
0484:                            Context.exit();
0485:                        }
0486:                    }
0487:                }
0488:
0489:                public Iterator getIterator(Object obj, Info i)
0490:                        throws Exception {
0491:                    if (!(obj instanceof  Scriptable)) {
0492:                        // support Enumeration
0493:                        if (obj instanceof  Enumeration) {
0494:                            final Enumeration e = (Enumeration) obj;
0495:                            return new Iterator() {
0496:
0497:                                public boolean hasNext() {
0498:                                    return e.hasMoreElements();
0499:                                }
0500:
0501:                                public Object next() {
0502:                                    return e.nextElement();
0503:                                }
0504:
0505:                                public void remove() {
0506:                                    // no action
0507:                                }
0508:
0509:                            };
0510:                        }
0511:                        if (obj instanceof  Iterator) {
0512:                            // support Iterator
0513:                            return (Iterator) obj;
0514:                        }
0515:                        return super .getIterator(obj, i);
0516:                    }
0517:                    if (obj instanceof  NativeArray) {
0518:                        return new NativeArrayIterator((NativeArray) obj);
0519:                    }
0520:                    return new ScriptableIterator((Scriptable) obj);
0521:                }
0522:
0523:                public VelMethod getMethod(Object obj, String methodName,
0524:                        Object[] args, Info i) throws Exception {
0525:                    return !(obj instanceof  Scriptable) ? super .getMethod(obj,
0526:                            methodName, args, i) : new JSMethod(
0527:                            (Scriptable) obj, methodName);
0528:                }
0529:
0530:                public VelPropertyGet getPropertyGet(Object obj,
0531:                        String identifier, Info i) throws Exception {
0532:                    return !(obj instanceof  Scriptable) ? super .getPropertyGet(
0533:                            obj, identifier, i) : new JSPropertyGet(
0534:                            (Scriptable) obj, identifier);
0535:                }
0536:
0537:                public VelPropertySet getPropertySet(Object obj,
0538:                        String identifier, Object arg, Info i) throws Exception {
0539:                    return !(obj instanceof  Scriptable) ? super .getPropertySet(
0540:                            obj, identifier, arg, i) : new JSPropertySet(
0541:                            (Scriptable) obj, identifier);
0542:                }
0543:            }
0544:
0545:            static class MyJexlContext extends HashMap implements  JexlContext {
0546:
0547:                private MyJexlContext closure;
0548:
0549:                MyJexlContext() {
0550:                    this (null);
0551:                }
0552:
0553:                MyJexlContext(MyJexlContext closure) {
0554:                    this .closure = closure;
0555:                }
0556:
0557:                public Map getVars() {
0558:                    return this ;
0559:                }
0560:
0561:                public void setVars(Map map) {
0562:                    putAll(map);
0563:                }
0564:
0565:                public boolean containsKey(Object key) {
0566:                    return this .get(key) != null;
0567:                }
0568:
0569:                public Object get(Object key) {
0570:                    if (key.equals("this")) {
0571:                        return this ;
0572:                    }
0573:                    Object result = super .get(key);
0574:                    if (result == null && closure != null) {
0575:                        result = closure.get(key);
0576:                    }
0577:                    return result;
0578:                }
0579:            }
0580:
0581:            static class MyVariables implements  Variables {
0582:
0583:                MyVariables closure;
0584:
0585:                Map localVariables = new HashMap();
0586:
0587:                static final String[] VARIABLES = new String[] { "cocoon",
0588:                        "continuation", "flowContext", "request", "response",
0589:                        "context", "session", "parameters" };
0590:
0591:                Object cocoon;
0592:
0593:                // backward compatibility
0594:                Object bean, kont, request, response, session, context,
0595:                        parameters;
0596:
0597:                MyVariables(Object cocoon, Object bean, WebContinuation kont,
0598:                        Object request, Object session, Object context,
0599:                        Object parameters) {
0600:                    this .cocoon = cocoon;
0601:                    this .bean = bean;
0602:                    this .kont = kont;
0603:                    this .request = request;
0604:                    this .session = session;
0605:                    this .context = context;
0606:                    this .parameters = parameters;
0607:                }
0608:
0609:                public MyVariables(MyVariables parent) {
0610:                    this .closure = parent;
0611:                }
0612:
0613:                public boolean isDeclaredVariable(String varName) {
0614:                    int len = VARIABLES.length;
0615:                    for (int i = 0; i < len; i++) {
0616:                        if (varName.equals(VARIABLES[i])) {
0617:                            return true;
0618:                        }
0619:                    }
0620:                    if (localVariables.containsKey(varName)) {
0621:                        return true;
0622:                    }
0623:                    if (closure != null) {
0624:                        return closure.isDeclaredVariable(varName);
0625:                    }
0626:                    return false;
0627:                }
0628:
0629:                public Object getVariable(String varName) {
0630:                    Object result = localVariables.get(varName);
0631:                    if (result != null) {
0632:                        return result;
0633:                    }
0634:                    if (closure != null) {
0635:                        return closure.getVariable(varName);
0636:                    }
0637:                    if (varName.equals("cocoon")) {
0638:                        return cocoon;
0639:                    }
0640:                    // backward compatibility
0641:                    if (varName.equals("continuation")) {
0642:                        return kont;
0643:                    } else if (varName.equals("flowContext")) {
0644:                        return bean;
0645:                    } else if (varName.equals("request")) {
0646:                        return request;
0647:                    } else if (varName.equals("session")) {
0648:                        return session;
0649:                    } else if (varName.equals("context")) {
0650:                        return context;
0651:                    } else if (varName.equals("parameters")) {
0652:                        return parameters;
0653:                    }
0654:                    return null;
0655:                }
0656:
0657:                public void declareVariable(String varName, Object value) {
0658:                    localVariables.put(varName, value);
0659:                }
0660:
0661:                public void undeclareVariable(String varName) {
0662:                    localVariables.remove(varName);
0663:                }
0664:            }
0665:
0666:            static {
0667:                // Hack: there's no _nice_ way to add my introspector to Jexl right now
0668:                try {
0669:                    Field field = Introspector.class
0670:                            .getDeclaredField("uberSpect");
0671:                    field.setAccessible(true);
0672:                    field.set(null, new JSIntrospector());
0673:                } catch (Exception e) {
0674:                    e.printStackTrace();
0675:                }
0676:            }
0677:
0678:            /** The namespace used by this generator */
0679:            public final static String NS = "http://apache.org/cocoon/templates/jx/1.0";
0680:
0681:            final static String TEMPLATE = "template";
0682:            final static String FOR_EACH = "forEach";
0683:            final static String IF = "if";
0684:            final static String CHOOSE = "choose";
0685:            final static String WHEN = "when";
0686:            final static String OTHERWISE = "otherwise";
0687:            final static String OUT = "out";
0688:            final static String IMPORT = "import";
0689:            final static String SET = "set";
0690:            final static String MACRO = "macro";
0691:            final static String EVALBODY = "evalBody";
0692:            final static String EVAL = "eval";
0693:            final static String PARAMETER = "parameter";
0694:            final static String FORMAT_NUMBER = "formatNumber";
0695:            final static String FORMAT_DATE = "formatDate";
0696:            final static String COMMENT = "comment";
0697:            final static String CACHE_KEY = "cache-key";
0698:            final static String VALIDITY = "cache-validity";
0699:
0700:            /**
0701:             * Compile a single Jexl expr (contained in ${}) or XPath expression
0702:             * (contained in #{})
0703:             */
0704:
0705:            private static JXTExpression compileExpr(String expr,
0706:                    String errorPrefix, Location location) throws JXTException {
0707:                try {
0708:                    return compileExpr(expr);
0709:                } catch (Exception exc) {
0710:                    throw new JXTException(errorPrefix + exc.getMessage(),
0711:                            location, exc);
0712:                }
0713:            }
0714:
0715:            private static JXTExpression compileExpr(String inStr)
0716:                    throws Exception {
0717:                try {
0718:                    if (inStr == null) {
0719:                        return null;
0720:                    }
0721:                    StringReader in = new StringReader(inStr.trim());
0722:                    int ch;
0723:                    boolean xpath = false;
0724:                    boolean inExpr = false;
0725:                    StringBuffer expr = new StringBuffer();
0726:                    while ((ch = in.read()) != -1) {
0727:                        char c = (char) ch;
0728:                        if (inExpr) {
0729:                            if (c == '\\') {
0730:                                ch = in.read();
0731:                                expr.append((ch == -1) ? '\\' : (char) ch);
0732:                            } else if (c == '}') {
0733:                                return compile(expr.toString(), xpath);
0734:                            } else {
0735:                                expr.append(c);
0736:                            }
0737:                        } else {
0738:                            if (c == '$' || c == '#') {
0739:                                ch = in.read();
0740:                                if (ch == '{') {
0741:                                    inExpr = true;
0742:                                    xpath = c == '#';
0743:                                    continue;
0744:                                }
0745:                            }
0746:                            // hack: invalid expression?
0747:                            // just return the original and swallow exception
0748:                            return new JXTExpression(inStr, null);
0749:                        }
0750:                    }
0751:                    if (inExpr) {
0752:                        // unclosed #{} or ${}
0753:                        throw new Exception("Unterminated "
0754:                                + (xpath ? "#" : "$") + "{");
0755:                    }
0756:                } catch (IOException ignored) {
0757:                    ignored.printStackTrace();
0758:                }
0759:                return new JXTExpression(inStr, null);
0760:            }
0761:
0762:            /*
0763:             * Compile an integer expression (returns either a Compiled Expression
0764:             * or an Integer literal)
0765:             */
0766:            private static JXTExpression compileInt(String val, String msg,
0767:                    Location location) throws SAXException {
0768:                JXTExpression res = compileExpr(val, msg, location);
0769:                if (res != null) {
0770:                    if (res.compiledExpression == null) {
0771:                        res.compiledExpression = Integer.valueOf(res.raw);
0772:                    }
0773:                    return res;
0774:                }
0775:                return null;
0776:            }
0777:
0778:            private static JXTExpression compileBoolean(String val, String msg,
0779:                    Location location) throws SAXException {
0780:                JXTExpression res = compileExpr(val, msg, location);
0781:                if (res != null) {
0782:                    if (res.compiledExpression == null) {
0783:                        res.compiledExpression = Boolean.valueOf(res.raw);
0784:                    }
0785:                    return res;
0786:                }
0787:                return null;
0788:            }
0789:
0790:            private static JXTExpression compile(final String variable,
0791:                    boolean xpath) throws Exception {
0792:                Object compiled;
0793:                if (xpath) {
0794:                    compiled = JXPathContext.compile(variable);
0795:                } else {
0796:                    compiled = ExpressionFactory.createExpression(variable);
0797:                }
0798:                return new JXTExpression(variable, compiled);
0799:            }
0800:
0801:            static private Object getValue(JXTExpression expr,
0802:                    JexlContext jexlContext, JXPathContext jxpathContext,
0803:                    Boolean lenient) throws Exception {
0804:                if (expr != null) {
0805:                    Object compiled = expr.compiledExpression;
0806:                    try {
0807:                        if (compiled instanceof  CompiledExpression) {
0808:                            CompiledExpression e = (CompiledExpression) compiled;
0809:                            boolean oldLenient = jxpathContext.isLenient();
0810:                            if (lenient != null) {
0811:                                jxpathContext
0812:                                        .setLenient(lenient.booleanValue());
0813:                            }
0814:                            try {
0815:                                return e.getValue(jxpathContext);
0816:                            } finally {
0817:                                jxpathContext.setLenient(oldLenient);
0818:                            }
0819:                        } else if (compiled instanceof  Expression) {
0820:                            Expression e = (Expression) compiled;
0821:                            return e.evaluate(jexlContext);
0822:                        }
0823:                        return compiled;
0824:                    } catch (InvocationTargetException e) {
0825:                        Throwable t = e.getTargetException();
0826:                        if (t instanceof  Exception) {
0827:                            throw (Exception) t;
0828:                        }
0829:                        throw (Error) t;
0830:                    }
0831:                } else {
0832:                    return null;
0833:                }
0834:            }
0835:
0836:            static private Object getValue(JXTExpression expr,
0837:                    JexlContext jexlContext, JXPathContext jxpathContext)
0838:                    throws Exception {
0839:                return getValue(expr, jexlContext, jxpathContext, null);
0840:            }
0841:
0842:            static private int getIntValue(JXTExpression expr,
0843:                    JexlContext jexlContext, JXPathContext jxpathContext)
0844:                    throws Exception {
0845:                Object res = getValue(expr, jexlContext, jxpathContext);
0846:                return res instanceof  Number ? ((Number) res).intValue() : 0;
0847:            }
0848:
0849:            static private Number getNumberValue(JXTExpression expr,
0850:                    JexlContext jexlContext, JXPathContext jxpathContext)
0851:                    throws Exception {
0852:                Object res = getValue(expr, jexlContext, jxpathContext);
0853:                if (res instanceof  Number) {
0854:                    return (Number) res;
0855:                }
0856:                if (res != null) {
0857:                    return Double.valueOf(res.toString());
0858:                }
0859:                return null;
0860:            }
0861:
0862:            static private String getStringValue(JXTExpression expr,
0863:                    JexlContext jexlContext, JXPathContext jxpathContext)
0864:                    throws Exception {
0865:                Object res = getValue(expr, jexlContext, jxpathContext);
0866:                if (res != null) {
0867:                    return res.toString();
0868:                }
0869:                if (expr != null && expr.compiledExpression == null) {
0870:                    return expr.raw;
0871:                }
0872:                return null;
0873:            }
0874:
0875:            static private Boolean getBooleanValue(JXTExpression expr,
0876:                    JexlContext jexlContext, JXPathContext jxpathContext)
0877:                    throws Exception {
0878:                Object res = getValue(expr, jexlContext, jxpathContext);
0879:                return res instanceof  Boolean ? (Boolean) res : null;
0880:            }
0881:
0882:            private Object getNode(JXTExpression expr, JexlContext jexlContext,
0883:                    JXPathContext jxpathContext) throws Exception {
0884:                return getNode(expr, jexlContext, jxpathContext, null);
0885:            }
0886:
0887:            // Hack: try to prevent JXPath from converting result to a String
0888:            private Object getNode(JXTExpression expr, JexlContext jexlContext,
0889:                    JXPathContext jxpathContext, Boolean lenient)
0890:                    throws Exception {
0891:                try {
0892:                    Object compiled = expr.compiledExpression;
0893:                    if (compiled instanceof  CompiledExpression) {
0894:                        CompiledExpression e = (CompiledExpression) compiled;
0895:                        boolean oldLenient = jxpathContext.isLenient();
0896:                        if (lenient != null)
0897:                            jxpathContext.setLenient(lenient.booleanValue());
0898:                        try {
0899:                            Iterator iter = e.iteratePointers(jxpathContext);
0900:                            if (iter.hasNext()) {
0901:                                Pointer first = (Pointer) iter.next();
0902:                                if (iter.hasNext()) {
0903:                                    List result = new LinkedList();
0904:                                    result.add(first.getNode());
0905:                                    boolean dom = (first.getNode() instanceof  Node);
0906:                                    while (iter.hasNext()) {
0907:                                        Object obj = ((Pointer) iter.next())
0908:                                                .getNode();
0909:                                        dom = dom && (obj instanceof  Node);
0910:                                        result.add(obj);
0911:                                    }
0912:                                    Object[] arr;
0913:                                    if (dom) {
0914:                                        arr = new Node[result.size()];
0915:                                    } else {
0916:                                        arr = new Object[result.size()];
0917:                                    }
0918:                                    result.toArray(arr);
0919:                                    return arr;
0920:                                }
0921:                                return first.getNode();
0922:                            }
0923:                            return null;
0924:                        } finally {
0925:                            jxpathContext.setLenient(oldLenient);
0926:                        }
0927:                    } else if (compiled instanceof  Expression) {
0928:                        Expression e = (Expression) compiled;
0929:                        return e.evaluate(jexlContext);
0930:                    }
0931:                    return expr.raw;
0932:                } catch (InvocationTargetException e) {
0933:                    Throwable t = e.getTargetException();
0934:                    if (t instanceof  Exception) {
0935:                        throw (Exception) t;
0936:                    }
0937:                    throw (Error) t;
0938:                }
0939:            }
0940:
0941:            static class Event {
0942:                final Location location;
0943:                Event next; // in document order
0944:
0945:                Event(Location locator) {
0946:                    this .location = locator != null ? locator
0947:                            : Location.UNKNOWN;
0948:                }
0949:
0950:                public String locationString() {
0951:                    return location.toString();
0952:                }
0953:            }
0954:
0955:            static class TextEvent extends Event {
0956:                TextEvent(Location location, char[] chars, int start, int length)
0957:                        throws SAXException {
0958:                    super (location);
0959:                    StringBuffer buf = new StringBuffer();
0960:                    this .raw = new char[length];
0961:                    System.arraycopy(chars, start, this .raw, 0, length);
0962:                    CharArrayReader in = new CharArrayReader(chars, start,
0963:                            length);
0964:                    int ch;
0965:                    boolean inExpr = false;
0966:                    boolean xpath = false;
0967:                    try {
0968:                        top: while ((ch = in.read()) != -1) {
0969:                            // column++;
0970:                            char c = (char) ch;
0971:                            processChar: while (true) {
0972:                                if (inExpr) {
0973:                                    if (c == '\\') {
0974:                                        ch = in.read();
0975:                                        buf.append(ch == -1 ? '\\' : (char) ch);
0976:                                    } else if (c == '}') {
0977:                                        String str = buf.toString();
0978:                                        Object compiledExpression;
0979:                                        try {
0980:                                            if (xpath) {
0981:                                                compiledExpression = JXPathContext
0982:                                                        .compile(str);
0983:                                            } else {
0984:                                                compiledExpression = ExpressionFactory
0985:                                                        .createExpression(str);
0986:                                            }
0987:                                        } catch (Exception exc) {
0988:                                            throw new JXTException(exc
0989:                                                    .getMessage(),
0990:                                                    this .location, exc);
0991:                                        }
0992:                                        substitutions.add(new JXTExpression(
0993:                                                str, compiledExpression));
0994:                                        buf.setLength(0);
0995:                                        inExpr = false;
0996:                                    } else {
0997:                                        buf.append(c);
0998:                                    }
0999:                                } else if (c == '$' || c == '#') {
1000:                                    ch = in.read();
1001:                                    if (ch == '{') {
1002:                                        xpath = c == '#';
1003:                                        inExpr = true;
1004:                                        if (buf.length() > 0) {
1005:                                            char[] charArray = new char[buf
1006:                                                    .length()];
1007:
1008:                                            buf.getChars(0, buf.length(),
1009:                                                    charArray, 0);
1010:                                            substitutions.add(charArray);
1011:                                            buf.setLength(0);
1012:                                        }
1013:                                        continue top;
1014:                                    }
1015:                                    buf.append(c);
1016:                                    if (ch != -1) {
1017:                                        c = (char) ch;
1018:                                        continue processChar;
1019:                                    }
1020:                                } else {
1021:                                    buf.append(c);
1022:                                }
1023:                                break;
1024:                            }
1025:                        }
1026:                    } catch (IOException ignored) {
1027:                        // won't happen
1028:                        ignored.printStackTrace();
1029:                    }
1030:                    if (inExpr) {
1031:                        // unclosed #{} or ${}
1032:                        buf.insert(0, (xpath ? "#" : "$") + "{");
1033:                    }
1034:                    if (buf.length() > 0) {
1035:                        char[] charArray = new char[buf.length()];
1036:
1037:                        buf.getChars(0, buf.length(), charArray, 0);
1038:                        substitutions.add(charArray);
1039:                    } else if (substitutions.isEmpty()) {
1040:                        substitutions.add(ArrayUtils.EMPTY_CHAR_ARRAY);
1041:                    }
1042:                }
1043:
1044:                final List substitutions = new LinkedList();
1045:                final char[] raw;
1046:            }
1047:
1048:            static class Characters extends TextEvent {
1049:                Characters(Location location, char[] chars, int start,
1050:                        int length) throws SAXException {
1051:                    super (location, chars, start, length);
1052:                }
1053:            }
1054:
1055:            static class StartDocument extends Event {
1056:                StartDocument(Location location) {
1057:                    super (location);
1058:                    templateProperties = new HashMap();
1059:                }
1060:
1061:                SourceValidity compileTime;
1062:                EndDocument endDocument; // null if document fragment
1063:                Map templateProperties;
1064:            }
1065:
1066:            static class EndDocument extends Event {
1067:                EndDocument(Location location) {
1068:                    super (location);
1069:                }
1070:            }
1071:
1072:            static class EndElement extends Event {
1073:                EndElement(Location location, StartElement startElement) {
1074:                    super (location);
1075:                    this .startElement = startElement;
1076:                }
1077:
1078:                final StartElement startElement;
1079:            }
1080:
1081:            static class EndPrefixMapping extends Event {
1082:                EndPrefixMapping(Location location, String prefix) {
1083:                    super (location);
1084:                    this .prefix = prefix;
1085:                }
1086:
1087:                final String prefix;
1088:            }
1089:
1090:            static class IgnorableWhitespace extends TextEvent {
1091:                IgnorableWhitespace(Location location, char[] chars, int start,
1092:                        int length) throws SAXException {
1093:                    super (location, chars, start, length);
1094:                }
1095:            }
1096:
1097:            static class ProcessingInstruction extends Event {
1098:                ProcessingInstruction(Location location, String target,
1099:                        String data) {
1100:                    super (location);
1101:                    this .target = target;
1102:                    this .data = data;
1103:                }
1104:
1105:                final String target;
1106:                final String data;
1107:            }
1108:
1109:            static class SkippedEntity extends Event {
1110:                SkippedEntity(Location location, String name) {
1111:                    super (location);
1112:                    this .name = name;
1113:                }
1114:
1115:                final String name;
1116:            }
1117:
1118:            abstract static class AttributeEvent {
1119:                AttributeEvent(String namespaceURI, String localName,
1120:                        String raw, String type) {
1121:                    this .namespaceURI = namespaceURI;
1122:                    this .localName = localName;
1123:                    this .raw = raw;
1124:                    this .type = type;
1125:                }
1126:
1127:                final String namespaceURI;
1128:                final String localName;
1129:                final String raw;
1130:                final String type;
1131:            }
1132:
1133:            static class CopyAttribute extends AttributeEvent {
1134:                CopyAttribute(String namespaceURI, String localName,
1135:                        String raw, String type, String value) {
1136:                    super (namespaceURI, localName, raw, type);
1137:                    this .value = value;
1138:                }
1139:
1140:                final String value;
1141:            }
1142:
1143:            static class Subst {
1144:                // VOID
1145:            }
1146:
1147:            static class Literal extends Subst {
1148:                Literal(String val) {
1149:                    this .value = val;
1150:                }
1151:
1152:                final String value;
1153:            }
1154:
1155:            static class JXTExpression extends Subst {
1156:                JXTExpression(String raw, Object expr) {
1157:                    this .raw = raw;
1158:                    this .compiledExpression = expr;
1159:                }
1160:
1161:                String raw;
1162:                Object compiledExpression;
1163:            }
1164:
1165:            static class SubstituteAttribute extends AttributeEvent {
1166:                SubstituteAttribute(String namespaceURI, String localName,
1167:                        String raw, String type, List substs) {
1168:                    super (namespaceURI, localName, raw, type);
1169:                    this .substitutions = substs;
1170:                }
1171:
1172:                final List substitutions;
1173:            }
1174:
1175:            static class StartElement extends Event {
1176:                StartElement(Location location, String namespaceURI,
1177:                        String localName, String raw, Attributes attrs)
1178:                        throws SAXException {
1179:                    super (location);
1180:
1181:                    this .namespaceURI = namespaceURI;
1182:                    this .localName = localName;
1183:                    this .raw = raw;
1184:                    this .qname = "{" + namespaceURI + "}" + localName;
1185:
1186:                    StringBuffer buf = new StringBuffer();
1187:                    int len = attrs.getLength();
1188:                    for (int i = 0; i < len; i++) {
1189:                        String uri = attrs.getURI(i);
1190:                        String local = attrs.getLocalName(i);
1191:                        String qname = attrs.getQName(i);
1192:                        String type = attrs.getType(i);
1193:                        String value = attrs.getValue(i);
1194:                        StringReader in = new StringReader(value);
1195:
1196:                        int ch;
1197:                        buf.setLength(0);
1198:                        boolean inExpr = false;
1199:                        List substEvents = new LinkedList();
1200:                        boolean xpath = false;
1201:                        try {
1202:                            top: while ((ch = in.read()) != -1) {
1203:                                char c = (char) ch;
1204:                                processChar: while (true) {
1205:                                    if (inExpr) {
1206:                                        if (c == '\\') {
1207:                                            ch = in.read();
1208:                                            buf.append(ch == -1 ? '\\'
1209:                                                    : (char) ch);
1210:                                        } else if (c == '}') {
1211:                                            String str = buf.toString();
1212:                                            JXTExpression compiledExpression;
1213:                                            try {
1214:                                                compiledExpression = compile(
1215:                                                        str, xpath);
1216:                                            } catch (Exception exc) {
1217:                                                throw new JXTException(exc
1218:                                                        .getMessage(),
1219:                                                        location, exc);
1220:                                            }
1221:                                            substEvents.add(compiledExpression);
1222:                                            buf.setLength(0);
1223:                                            inExpr = false;
1224:                                        } else {
1225:                                            buf.append(c);
1226:                                        }
1227:                                    } else if (c == '$' || c == '#') {
1228:                                        ch = in.read();
1229:                                        if (ch == '{') {
1230:                                            if (buf.length() > 0) {
1231:                                                substEvents.add(new Literal(buf
1232:                                                        .toString()));
1233:                                                buf.setLength(0);
1234:                                            }
1235:                                            inExpr = true;
1236:                                            xpath = c == '#';
1237:                                            continue top;
1238:                                        }
1239:                                        buf.append(c);
1240:                                        if (ch != -1) {
1241:                                            c = (char) ch;
1242:                                            continue processChar;
1243:                                        }
1244:                                    } else {
1245:                                        buf.append(c);
1246:                                    }
1247:                                    break;
1248:                                }
1249:                            }
1250:                        } catch (IOException ignored) {
1251:                            ignored.printStackTrace();
1252:                        }
1253:
1254:                        if (inExpr) {
1255:                            // unclosed #{} or ${}
1256:                            String msg = "Unterminated " + (xpath ? "#" : "$")
1257:                                    + "{";
1258:                            throw new JXTException(msg, location, null);
1259:                        }
1260:
1261:                        if (buf.length() > 0) {
1262:                            if (substEvents.size() == 0) {
1263:                                attributeEvents.add(new CopyAttribute(uri,
1264:                                        local, qname, type, buf.toString()));
1265:                            } else {
1266:                                substEvents.add(new Literal(buf.toString()));
1267:                                attributeEvents.add(new SubstituteAttribute(
1268:                                        uri, local, qname, type, substEvents));
1269:                            }
1270:                        } else {
1271:                            if (substEvents.size() > 0) {
1272:                                attributeEvents.add(new SubstituteAttribute(
1273:                                        uri, local, qname, type, substEvents));
1274:                            } else {
1275:                                attributeEvents.add(new CopyAttribute(uri,
1276:                                        local, qname, type, ""));
1277:                            }
1278:                        }
1279:                    }
1280:                    this .attributes = new AttributesImpl(attrs);
1281:                }
1282:
1283:                final String namespaceURI;
1284:                final String localName;
1285:                final String raw;
1286:                final String qname;
1287:                final List attributeEvents = new LinkedList();
1288:                final Attributes attributes;
1289:                EndElement endElement;
1290:            }
1291:
1292:            static class StartPrefixMapping extends Event {
1293:                StartPrefixMapping(Location location, String prefix, String uri) {
1294:                    super (location);
1295:                    this .prefix = prefix;
1296:                    this .uri = uri;
1297:                }
1298:
1299:                final String prefix;
1300:                final String uri;
1301:            }
1302:
1303:            static class EndCDATA extends Event {
1304:                EndCDATA(Location location) {
1305:                    super (location);
1306:                }
1307:            }
1308:
1309:            static class EndDTD extends Event {
1310:                EndDTD(Location location) {
1311:                    super (location);
1312:                }
1313:            }
1314:
1315:            static class EndEntity extends Event {
1316:                EndEntity(Location location, String name) {
1317:                    super (location);
1318:                    this .name = name;
1319:                }
1320:
1321:                final String name;
1322:            }
1323:
1324:            static class StartCDATA extends Event {
1325:                StartCDATA(Location location) {
1326:                    super (location);
1327:                }
1328:            }
1329:
1330:            static class StartDTD extends Event {
1331:                StartDTD(Location location, String name, String publicId,
1332:                        String systemId) {
1333:                    super (location);
1334:                    this .name = name;
1335:                    this .publicId = publicId;
1336:                    this .systemId = systemId;
1337:                }
1338:
1339:                final String name;
1340:                final String publicId;
1341:                final String systemId;
1342:            }
1343:
1344:            static class StartEntity extends Event {
1345:                public StartEntity(Location location, String name) {
1346:                    super (location);
1347:                    this .name = name;
1348:                }
1349:
1350:                final String name;
1351:            }
1352:
1353:            static class StartInstruction extends Event {
1354:                StartInstruction(StartElement startElement) {
1355:                    super (startElement.location);
1356:                    this .startElement = startElement;
1357:                }
1358:
1359:                final StartElement startElement;
1360:                EndInstruction endInstruction;
1361:            }
1362:
1363:            static class EndInstruction extends Event {
1364:                EndInstruction(Location locator,
1365:                        StartInstruction startInstruction) {
1366:                    super (locator);
1367:                    this .startInstruction = startInstruction;
1368:                    startInstruction.endInstruction = this ;
1369:                }
1370:
1371:                final StartInstruction startInstruction;
1372:            }
1373:
1374:            static class StartForEach extends StartInstruction {
1375:                StartForEach(StartElement raw, JXTExpression items,
1376:                        JXTExpression var, JXTExpression varStatus,
1377:                        JXTExpression begin, JXTExpression end,
1378:                        JXTExpression step, Boolean lenient) {
1379:                    super (raw);
1380:                    this .items = items;
1381:                    this .var = var;
1382:                    this .varStatus = varStatus;
1383:                    this .begin = begin;
1384:                    this .end = end;
1385:                    this .step = step;
1386:                    this .lenient = lenient;
1387:                }
1388:
1389:                final JXTExpression items;
1390:                final JXTExpression var;
1391:                final JXTExpression varStatus;
1392:                final JXTExpression begin;
1393:                final JXTExpression end;
1394:                final JXTExpression step;
1395:                final Boolean lenient;
1396:            }
1397:
1398:            static class StartIf extends StartInstruction {
1399:                StartIf(StartElement raw, JXTExpression test) {
1400:                    super (raw);
1401:                    this .test = test;
1402:                }
1403:
1404:                final JXTExpression test;
1405:            }
1406:
1407:            static class StartChoose extends StartInstruction {
1408:                StartChoose(StartElement raw) {
1409:                    super (raw);
1410:                }
1411:
1412:                StartWhen firstChoice;
1413:                StartOtherwise otherwise;
1414:            }
1415:
1416:            static class StartWhen extends StartInstruction {
1417:                StartWhen(StartElement raw, JXTExpression test) {
1418:                    super (raw);
1419:                    this .test = test;
1420:                }
1421:
1422:                final JXTExpression test;
1423:                StartWhen nextChoice;
1424:            }
1425:
1426:            static class StartOtherwise extends StartInstruction {
1427:                StartOtherwise(StartElement raw) {
1428:                    super (raw);
1429:                }
1430:            }
1431:
1432:            static class StartOut extends StartInstruction {
1433:                StartOut(StartElement raw, JXTExpression expr, Boolean lenient) {
1434:                    super (raw);
1435:                    this .compiledExpression = expr;
1436:                    this .lenient = lenient;
1437:                }
1438:
1439:                final JXTExpression compiledExpression;
1440:                final Boolean lenient;
1441:            }
1442:
1443:            static class StartImport extends StartInstruction {
1444:                StartImport(StartElement raw, AttributeEvent uri,
1445:                        JXTExpression select) {
1446:                    super (raw);
1447:                    this .uri = uri;
1448:                    this .select = select;
1449:                }
1450:
1451:                final AttributeEvent uri;
1452:                final JXTExpression select;
1453:            }
1454:
1455:            static class StartTemplate extends StartInstruction {
1456:                StartTemplate(StartElement raw) {
1457:                    super (raw);
1458:                }
1459:            }
1460:
1461:            static class StartEvalBody extends StartInstruction {
1462:                StartEvalBody(StartElement raw) {
1463:                    super (raw);
1464:                }
1465:            }
1466:
1467:            static class StartEval extends StartInstruction {
1468:                StartEval(StartElement raw, JXTExpression value) {
1469:                    super (raw);
1470:                    this .value = value;
1471:                }
1472:
1473:                final JXTExpression value;
1474:            }
1475:
1476:            static class StartDefine extends StartInstruction {
1477:                StartDefine(StartElement raw, String namespace, String name) {
1478:                    super (raw);
1479:                    this .namespace = namespace;
1480:                    this .name = name;
1481:                    this .qname = "{" + namespace + "}" + name;
1482:                    this .parameters = new HashMap();
1483:                }
1484:
1485:                final String name;
1486:                final String namespace;
1487:                final String qname;
1488:                final Map parameters;
1489:                Event body;
1490:
1491:                void finish() throws SAXException {
1492:                    Event e = next;
1493:                    boolean params = true;
1494:                    while (e != this .endInstruction) {
1495:                        if (e instanceof  StartParameter) {
1496:                            StartParameter startParam = (StartParameter) e;
1497:                            if (!params) {
1498:                                throw new JXTException(
1499:                                        "<parameter> not allowed here: \""
1500:                                                + startParam.name + "\"",
1501:                                        startParam.location, null);
1502:                            }
1503:                            Object prev = parameters.put(startParam.name,
1504:                                    startParam);
1505:                            if (prev != null) {
1506:                                throw new JXTException(
1507:                                        "duplicate parameter: \""
1508:                                                + startParam.name + "\"",
1509:                                        location, null);
1510:                            }
1511:                            e = startParam.endInstruction;
1512:                        } else if (e instanceof  IgnorableWhitespace) {
1513:                            // EMPTY
1514:                        } else if (e instanceof  Characters) {
1515:                            // check for whitespace
1516:                            char[] ch = ((TextEvent) e).raw;
1517:                            int len = ch.length;
1518:                            for (int i = 0; i < len; i++) {
1519:                                if (!Character.isWhitespace(ch[i])) {
1520:                                    if (params) {
1521:                                        params = false;
1522:                                        body = e;
1523:                                    }
1524:                                    break;
1525:                                }
1526:                            }
1527:                        } else {
1528:                            if (params) {
1529:                                params = false;
1530:                                body = e;
1531:                            }
1532:                        }
1533:                        e = e.next;
1534:                    }
1535:                    if (this .body == null) {
1536:                        this .body = this .endInstruction;
1537:                    }
1538:                }
1539:            }
1540:
1541:            static class StartParameter extends StartInstruction {
1542:                StartParameter(StartElement raw, String name, String optional,
1543:                        String default_) {
1544:                    super (raw);
1545:                    this .name = name;
1546:                    this .optional = optional;
1547:                    this .default_ = default_;
1548:                }
1549:
1550:                final String name;
1551:                final String optional;
1552:                final String default_;
1553:            }
1554:
1555:            static class StartSet extends StartInstruction {
1556:                StartSet(StartElement raw, JXTExpression var,
1557:                        JXTExpression value) {
1558:                    super (raw);
1559:                    this .var = var;
1560:                    this .value = value;
1561:                }
1562:
1563:                final JXTExpression var;
1564:                final JXTExpression value;
1565:            }
1566:
1567:            static class StartComment extends StartInstruction {
1568:                StartComment(StartElement raw) {
1569:                    super (raw);
1570:                }
1571:            }
1572:
1573:            // formatNumber tag (borrows from Jakarta taglibs JSTL)
1574:
1575:            private static Locale parseLocale(String locale, String variant) {
1576:                Locale ret = null;
1577:                String language = locale;
1578:                String country = null;
1579:                int index = StringUtils.indexOfAny(locale, "-_");
1580:
1581:                if (index > -1) {
1582:                    language = locale.substring(0, index);
1583:                    country = locale.substring(index + 1);
1584:                }
1585:                if (StringUtils.isEmpty(language)) {
1586:                    throw new IllegalArgumentException("No language in locale");
1587:                }
1588:                if (country == null) {
1589:                    ret = variant != null ? new Locale(language, "", variant)
1590:                            : new Locale(language, "");
1591:                } else if (country.length() > 0) {
1592:                    ret = variant != null ? new Locale(language, country,
1593:                            variant) : new Locale(language, country);
1594:                } else {
1595:                    throw new IllegalArgumentException(
1596:                            "Empty country in locale");
1597:                }
1598:                return ret;
1599:            }
1600:
1601:            private static final String NUMBER = "number";
1602:            private static final String CURRENCY = "currency";
1603:            private static final String PERCENT = "percent";
1604:
1605:            static class LocaleAwareInstruction extends StartInstruction {
1606:                private JXTExpression locale;
1607:
1608:                LocaleAwareInstruction(StartElement startElement,
1609:                        JXTExpression locale) {
1610:                    super (startElement);
1611:                    this .locale = locale;
1612:                }
1613:
1614:                protected Locale getLocale(JexlContext jexl, JXPathContext jxp)
1615:                        throws Exception {
1616:                    Object locVal = getValue(this .locale, jexl, jxp);
1617:                    if (locVal == null)
1618:                        locVal = getStringValue(this .locale, jexl, jxp);
1619:
1620:                    if (locVal != null) {
1621:                        return locVal instanceof  Locale ? (Locale) locVal
1622:                                : parseLocale(locVal.toString(), null);
1623:                    } else {
1624:                        return Locale.getDefault();
1625:                    }
1626:                }
1627:            }
1628:
1629:            static class StartFormatNumber extends LocaleAwareInstruction {
1630:
1631:                JXTExpression value;
1632:                JXTExpression type;
1633:                JXTExpression pattern;
1634:                JXTExpression currencyCode;
1635:                JXTExpression currencySymbol;
1636:                JXTExpression isGroupingUsed;
1637:                JXTExpression maxIntegerDigits;
1638:                JXTExpression minIntegerDigits;
1639:                JXTExpression maxFractionDigits;
1640:                JXTExpression minFractionDigits;
1641:
1642:                JXTExpression var;
1643:
1644:                private static Class currencyClass;
1645:
1646:                static {
1647:                    try {
1648:                        currencyClass = Class.forName("java.util.Currency");
1649:                        // container's runtime is J2SE 1.4 or greater
1650:                    } catch (Exception cnfe) {
1651:                        // EMPTY
1652:                    }
1653:                }
1654:
1655:                public StartFormatNumber(StartElement raw, JXTExpression var,
1656:                        JXTExpression value, JXTExpression type,
1657:                        JXTExpression pattern, JXTExpression currencyCode,
1658:                        JXTExpression currencySymbol,
1659:                        JXTExpression isGroupingUsed,
1660:                        JXTExpression maxIntegerDigits,
1661:                        JXTExpression minIntegerDigits,
1662:                        JXTExpression maxFractionDigits,
1663:                        JXTExpression minFractionDigits, JXTExpression locale) {
1664:                    super (raw, locale);
1665:                    this .var = var;
1666:                    this .value = value;
1667:                    this .type = type;
1668:                    this .pattern = pattern;
1669:                    this .currencyCode = currencyCode;
1670:                    this .currencySymbol = currencySymbol;
1671:                    this .isGroupingUsed = isGroupingUsed;
1672:                    this .maxIntegerDigits = maxIntegerDigits;
1673:                    this .minIntegerDigits = minIntegerDigits;
1674:                    this .maxFractionDigits = maxFractionDigits;
1675:                    this .minFractionDigits = minFractionDigits;
1676:                }
1677:
1678:                String format(JexlContext jexl, JXPathContext jxp)
1679:                        throws Exception {
1680:                    // Determine formatting locale
1681:                    String var = getStringValue(this .var, jexl, jxp);
1682:                    Number input = getNumberValue(this .value, jexl, jxp);
1683:                    String type = getStringValue(this .type, jexl, jxp);
1684:                    String pattern = getStringValue(this .pattern, jexl, jxp);
1685:                    String currencyCode = getStringValue(this .currencyCode,
1686:                            jexl, jxp);
1687:                    String currencySymbol = getStringValue(this .currencySymbol,
1688:                            jexl, jxp);
1689:                    Boolean isGroupingUsed = getBooleanValue(
1690:                            this .isGroupingUsed, jexl, jxp);
1691:                    Number maxIntegerDigits = getNumberValue(
1692:                            this .maxIntegerDigits, jexl, jxp);
1693:                    Number minIntegerDigits = getNumberValue(
1694:                            this .minIntegerDigits, jexl, jxp);
1695:                    Number maxFractionDigits = getNumberValue(
1696:                            this .maxFractionDigits, jexl, jxp);
1697:                    Number minFractionDigits = getNumberValue(
1698:                            this .minFractionDigits, jexl, jxp);
1699:                    Locale loc = getLocale(jexl, jxp);
1700:                    String formatted;
1701:                    if (loc != null) {
1702:                        // Create formatter
1703:                        NumberFormat formatter = null;
1704:                        if (StringUtils.isNotEmpty(pattern)) {
1705:                            // if 'pattern' is specified, 'type' is ignored
1706:                            DecimalFormatSymbols symbols = new DecimalFormatSymbols(
1707:                                    loc);
1708:                            formatter = new DecimalFormat(pattern, symbols);
1709:                        } else {
1710:                            formatter = createFormatter(loc, type);
1711:                        }
1712:                        if (StringUtils.isNotEmpty(pattern)
1713:                                || CURRENCY.equalsIgnoreCase(type)) {
1714:                            setCurrency(formatter, currencyCode, currencySymbol);
1715:                        }
1716:                        configureFormatter(formatter, isGroupingUsed,
1717:                                maxIntegerDigits, minIntegerDigits,
1718:                                maxFractionDigits, minFractionDigits);
1719:                        formatted = formatter.format(input);
1720:                    } else {
1721:                        // no formatting locale available, use toString()
1722:                        formatted = input.toString();
1723:                    }
1724:                    if (var != null) {
1725:                        jexl.getVars().put(var, formatted);
1726:                        jxp.getVariables().declareVariable(var, formatted);
1727:                        return null;
1728:                    }
1729:                    return formatted;
1730:                }
1731:
1732:                private NumberFormat createFormatter(Locale loc, String type)
1733:                        throws Exception {
1734:                    NumberFormat formatter = null;
1735:                    if ((type == null) || NUMBER.equalsIgnoreCase(type)) {
1736:                        formatter = NumberFormat.getNumberInstance(loc);
1737:                    } else if (CURRENCY.equalsIgnoreCase(type)) {
1738:                        formatter = NumberFormat.getCurrencyInstance(loc);
1739:                    } else if (PERCENT.equalsIgnoreCase(type)) {
1740:                        formatter = NumberFormat.getPercentInstance(loc);
1741:                    } else {
1742:                        throw new IllegalArgumentException(
1743:                                "Invalid type: \""
1744:                                        + type
1745:                                        + "\": should be \"number\" or \"currency\" or \"percent\"");
1746:                    }
1747:                    return formatter;
1748:                }
1749:
1750:                /*
1751:                 * Applies the 'groupingUsed', 'maxIntegerDigits', 'minIntegerDigits',
1752:                 * 'maxFractionDigits', and 'minFractionDigits' attributes to the given
1753:                 * formatter.
1754:                 */
1755:                private void configureFormatter(NumberFormat formatter,
1756:                        Boolean isGroupingUsed, Number maxIntegerDigits,
1757:                        Number minIntegerDigits, Number maxFractionDigits,
1758:                        Number minFractionDigits) {
1759:                    if (isGroupingUsed != null)
1760:                        formatter
1761:                                .setGroupingUsed(isGroupingUsed.booleanValue());
1762:                    if (maxIntegerDigits != null)
1763:                        formatter.setMaximumIntegerDigits(maxIntegerDigits
1764:                                .intValue());
1765:                    if (minIntegerDigits != null)
1766:                        formatter.setMinimumIntegerDigits(minIntegerDigits
1767:                                .intValue());
1768:                    if (maxFractionDigits != null)
1769:                        formatter.setMaximumFractionDigits(maxFractionDigits
1770:                                .intValue());
1771:                    if (minFractionDigits != null)
1772:                        formatter.setMinimumFractionDigits(minFractionDigits
1773:                                .intValue());
1774:                }
1775:
1776:                /*
1777:                 * Override the formatting locale's default currency symbol with the
1778:                 * specified currency code (specified via the "currencyCode" attribute) or
1779:                 * currency symbol (specified via the "currencySymbol" attribute).
1780:                 *
1781:                 * If both "currencyCode" and "currencySymbol" are present,
1782:                 * "currencyCode" takes precedence over "currencySymbol" if the
1783:                 * java.util.Currency class is defined in the container's runtime (that
1784:                 * is, if the container's runtime is J2SE 1.4 or greater), and
1785:                 * "currencySymbol" takes precendence over "currencyCode" otherwise.
1786:                 *
1787:                 * If only "currencyCode" is given, it is used as a currency symbol if
1788:                 * java.util.Currency is not defined.
1789:                 *
1790:                 * Example:
1791:                 *
1792:                 * JDK    "currencyCode" "currencySymbol" Currency symbol being displayed
1793:                 * -----------------------------------------------------------------------
1794:                 * all         ---            ---         Locale's default currency symbol
1795:                 *
1796:                 * <1.4        EUR            ---         EUR
1797:                 * >=1.4       EUR            ---         Locale's currency symbol for Euro
1798:                 *
1799:                 * all         ---           \u20AC       \u20AC
1800:                 *
1801:                 * <1.4        EUR           \u20AC       \u20AC
1802:                 * >=1.4       EUR           \u20AC       Locale's currency symbol for Euro
1803:                 */
1804:                private void setCurrency(NumberFormat formatter,
1805:                        String currencyCode, String currencySymbol)
1806:                        throws Exception {
1807:                    String code = null;
1808:                    String symbol = null;
1809:
1810:                    if (currencyCode == null) {
1811:                        if (currencySymbol == null) {
1812:                            return;
1813:                        }
1814:                        symbol = currencySymbol;
1815:                    } else if (currencySymbol != null) {
1816:                        if (currencyClass != null) {
1817:                            code = currencyCode;
1818:                        } else {
1819:                            symbol = currencySymbol;
1820:                        }
1821:                    } else if (currencyClass != null) {
1822:                        code = currencyCode;
1823:                    } else {
1824:                        symbol = currencyCode;
1825:                    }
1826:                    if (code != null) {
1827:                        Object[] methodArgs = new Object[1];
1828:
1829:                        /*
1830:                         * java.util.Currency.getInstance()
1831:                         */
1832:                        Method m = currencyClass.getMethod("getInstance",
1833:                                new Class[] { String.class });
1834:
1835:                        methodArgs[0] = code;
1836:                        Object currency = m.invoke(null, methodArgs);
1837:
1838:                        /*
1839:                         * java.text.NumberFormat.setCurrency()
1840:                         */
1841:                        Class[] paramTypes = new Class[1];
1842:                        paramTypes[0] = currencyClass;
1843:                        Class numberFormatClass = Class
1844:                                .forName("java.text.NumberFormat");
1845:                        m = numberFormatClass.getMethod("setCurrency",
1846:                                paramTypes);
1847:                        methodArgs[0] = currency;
1848:                        m.invoke(formatter, methodArgs);
1849:                    } else {
1850:                        /*
1851:                         * Let potential ClassCastException propagate up (will almost
1852:                         * never happen)
1853:                         */
1854:                        DecimalFormat df = (DecimalFormat) formatter;
1855:                        DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
1856:                        dfs.setCurrencySymbol(symbol);
1857:                        df.setDecimalFormatSymbols(dfs);
1858:                    }
1859:                }
1860:            }
1861:
1862:            // formatDate tag (borrows from Jakarta taglibs JSTL)
1863:
1864:            static class StartFormatDate extends LocaleAwareInstruction {
1865:
1866:                private static final String DATE = "date";
1867:                private static final String TIME = "time";
1868:                private static final String DATETIME = "both";
1869:
1870:                JXTExpression var;
1871:                JXTExpression value;
1872:                JXTExpression type;
1873:                JXTExpression pattern;
1874:                JXTExpression timeZone;
1875:                JXTExpression dateStyle;
1876:                JXTExpression timeStyle;
1877:                JXTExpression locale;
1878:
1879:                StartFormatDate(StartElement raw, JXTExpression var,
1880:                        JXTExpression value, JXTExpression type,
1881:                        JXTExpression pattern, JXTExpression timeZone,
1882:                        JXTExpression dateStyle, JXTExpression timeStyle,
1883:                        JXTExpression locale) {
1884:                    super (raw, locale);
1885:                    this .var = var;
1886:                    this .value = value;
1887:                    this .type = type;
1888:                    this .pattern = pattern;
1889:                    this .timeZone = timeZone;
1890:                    this .dateStyle = dateStyle;
1891:                    this .timeStyle = timeStyle;
1892:                }
1893:
1894:                String format(JexlContext jexl, JXPathContext jxp)
1895:                        throws Exception {
1896:                    String var = getStringValue(this .var, jexl, jxp);
1897:                    Object value = getValue(this .value, jexl, jxp);
1898:                    String pattern = getStringValue(this .pattern, jexl, jxp);
1899:                    Object timeZone = getValue(this .timeZone, jexl, jxp);
1900:
1901:                    String type = getStringValue(this .type, jexl, jxp);
1902:                    String timeStyle = getStringValue(this .timeStyle, jexl, jxp);
1903:                    String dateStyle = getStringValue(this .dateStyle, jexl, jxp);
1904:
1905:                    String formatted = null;
1906:
1907:                    // Create formatter
1908:                    Locale locale = getLocale(jexl, jxp);
1909:                    DateFormat formatter = createFormatter(locale, type,
1910:                            dateStyle, timeStyle);
1911:                    // Apply pattern, if present
1912:                    if (pattern != null) {
1913:                        try {
1914:                            ((SimpleDateFormat) formatter)
1915:                                    .applyPattern(pattern);
1916:                        } catch (ClassCastException cce) {
1917:                            formatter = new SimpleDateFormat(pattern, locale);
1918:                        }
1919:                    }
1920:                    // Set time zone
1921:                    TimeZone tz = null;
1922:                    if ((timeZone instanceof  String) && timeZone.equals("")) {
1923:                        timeZone = null;
1924:                    }
1925:                    if (timeZone != null) {
1926:                        if (timeZone instanceof  String) {
1927:                            tz = TimeZone.getTimeZone((String) timeZone);
1928:                        } else if (timeZone instanceof  TimeZone) {
1929:                            tz = (TimeZone) timeZone;
1930:                        } else {
1931:                            throw new IllegalArgumentException(
1932:                                    "Illegal timeZone value: \"" + timeZone
1933:                                            + "\"");
1934:                        }
1935:                    }
1936:                    if (tz != null) {
1937:                        formatter.setTimeZone(tz);
1938:                    }
1939:                    formatted = formatter.format(value);
1940:                    if (var != null) {
1941:                        jexl.getVars().put(var, formatted);
1942:                        jxp.getVariables().declareVariable(var, formatted);
1943:                        return null;
1944:                    }
1945:                    return formatted;
1946:                }
1947:
1948:                private DateFormat createFormatter(Locale loc, String type,
1949:                        String dateStyle, String timeStyle) throws Exception {
1950:                    DateFormat formatter = null;
1951:                    if ((type == null) || DATE.equalsIgnoreCase(type)) {
1952:                        formatter = DateFormat.getDateInstance(
1953:                                getStyle(dateStyle), loc);
1954:                    } else if (TIME.equalsIgnoreCase(type)) {
1955:                        formatter = DateFormat.getTimeInstance(
1956:                                getStyle(timeStyle), loc);
1957:                    } else if (DATETIME.equalsIgnoreCase(type)) {
1958:                        formatter = DateFormat.getDateTimeInstance(
1959:                                getStyle(dateStyle), getStyle(timeStyle), loc);
1960:                    } else {
1961:                        throw new IllegalArgumentException("Invalid type: \""
1962:                                + type + "\"");
1963:                    }
1964:                    return formatter;
1965:                }
1966:
1967:                private static final String DEFAULT = "default";
1968:                private static final String SHORT = "short";
1969:                private static final String MEDIUM = "medium";
1970:                private static final String LONG = "long";
1971:                private static final String FULL = "full";
1972:
1973:                private int getStyle(String style) {
1974:                    int ret = DateFormat.DEFAULT;
1975:                    if (style != null) {
1976:                        if (DEFAULT.equalsIgnoreCase(style)) {
1977:                            ret = DateFormat.DEFAULT;
1978:                        } else if (SHORT.equalsIgnoreCase(style)) {
1979:                            ret = DateFormat.SHORT;
1980:                        } else if (MEDIUM.equalsIgnoreCase(style)) {
1981:                            ret = DateFormat.MEDIUM;
1982:                        } else if (LONG.equalsIgnoreCase(style)) {
1983:                            ret = DateFormat.LONG;
1984:                        } else if (FULL.equalsIgnoreCase(style)) {
1985:                            ret = DateFormat.FULL;
1986:                        } else {
1987:                            throw new IllegalArgumentException(
1988:                                    "Invalid style: \""
1989:                                            + style
1990:                                            + "\": should be \"default\" or \"short\" or \"medium\" or \"long\" or \"full\"");
1991:                        }
1992:                    }
1993:                    return ret;
1994:                }
1995:            }
1996:
1997:            static class Parser implements  ContentHandler, LexicalHandler {
1998:
1999:                StartDocument startEvent;
2000:                Event lastEvent;
2001:                Stack stack = new Stack();
2002:                Locator locator;
2003:                Location charLocation;
2004:                StringBuffer charBuf;
2005:
2006:                public Parser() {
2007:                    // EMPTY
2008:                }
2009:
2010:                StartDocument getStartEvent() {
2011:                    return this .startEvent;
2012:                }
2013:
2014:                void recycle() {
2015:                    startEvent = null;
2016:                    lastEvent = null;
2017:                    stack.clear();
2018:                    locator = null;
2019:                    charLocation = null;
2020:                    charBuf = null;
2021:                }
2022:
2023:                private void addEvent(Event ev) throws SAXException {
2024:                    if (ev != null) {
2025:                        if (lastEvent == null) {
2026:                            lastEvent = startEvent = new StartDocument(
2027:                                    LocationUtils.getLocation(locator,
2028:                                            "template"));
2029:                        } else {
2030:                            flushChars();
2031:                        }
2032:                        lastEvent.next = ev;
2033:                        lastEvent = ev;
2034:                    } else {
2035:                        throw new NullPointerException("null event");
2036:                    }
2037:                }
2038:
2039:                void flushChars() throws SAXException {
2040:                    if (charBuf != null) {
2041:                        char[] chars = new char[charBuf.length()];
2042:                        charBuf.getChars(0, charBuf.length(), chars, 0);
2043:                        Characters ev = new Characters(charLocation, chars, 0,
2044:                                chars.length);
2045:                        lastEvent.next = ev;
2046:                        lastEvent = ev;
2047:                        charLocation = null;
2048:                        charBuf = null;
2049:                    }
2050:                }
2051:
2052:                public void characters(char[] ch, int start, int length)
2053:                        throws SAXException {
2054:                    if (charBuf == null) {
2055:                        charBuf = new StringBuffer(length);
2056:                        charLocation = LocationUtils.getLocation(locator,
2057:                                "[text]");
2058:                    }
2059:                    charBuf.append(ch, start, length);
2060:                }
2061:
2062:                public void endDocument() throws SAXException {
2063:                    StartDocument startDoc = (StartDocument) stack.pop();
2064:                    EndDocument endDoc = new EndDocument(LocationUtils
2065:                            .getLocation(locator, "template"));
2066:                    startDoc.endDocument = endDoc;
2067:                    addEvent(endDoc);
2068:                }
2069:
2070:                public void endElement(String namespaceURI, String localName,
2071:                        String raw) throws SAXException {
2072:                    Event start = (Event) stack.pop();
2073:                    Event newEvent = null;
2074:                    if (NS.equals(namespaceURI)) {
2075:                        StartInstruction startInstruction = (StartInstruction) start;
2076:                        EndInstruction endInstruction = new EndInstruction(
2077:                                LocationUtils.getLocation(locator, "<" + raw
2078:                                        + ">"), startInstruction);
2079:                        newEvent = endInstruction;
2080:                        if (start instanceof  StartWhen) {
2081:                            StartWhen startWhen = (StartWhen) start;
2082:                            StartChoose startChoose = (StartChoose) stack
2083:                                    .peek();
2084:                            if (startChoose.firstChoice != null) {
2085:                                StartWhen w = startChoose.firstChoice;
2086:                                while (w.nextChoice != null) {
2087:                                    w = w.nextChoice;
2088:                                }
2089:                                w.nextChoice = startWhen;
2090:                            } else {
2091:                                startChoose.firstChoice = startWhen;
2092:                            }
2093:                        } else if (start instanceof  StartOtherwise) {
2094:                            StartOtherwise startOtherwise = (StartOtherwise) start;
2095:                            StartChoose startChoose = (StartChoose) stack
2096:                                    .peek();
2097:                            startChoose.otherwise = startOtherwise;
2098:                        }
2099:                    } else {
2100:                        StartElement startElement = (StartElement) start;
2101:                        newEvent = startElement.endElement = new EndElement(
2102:                                LocationUtils.getLocation(locator, "<" + raw
2103:                                        + ">"), startElement);
2104:                    }
2105:                    addEvent(newEvent);
2106:                    if (start instanceof  StartDefine) {
2107:                        StartDefine startDefine = (StartDefine) start;
2108:                        startDefine.finish();
2109:                    }
2110:                }
2111:
2112:                public void endPrefixMapping(String prefix) throws SAXException {
2113:                    EndPrefixMapping endPrefixMapping = new EndPrefixMapping(
2114:                            LocationUtils.getLocation(locator, null), prefix);
2115:                    addEvent(endPrefixMapping);
2116:                }
2117:
2118:                public void ignorableWhitespace(char[] ch, int start, int length)
2119:                        throws SAXException {
2120:                    Event ev = new IgnorableWhitespace(LocationUtils
2121:                            .getLocation(locator, null), ch, start, length);
2122:                    addEvent(ev);
2123:                }
2124:
2125:                public void processingInstruction(String target, String data)
2126:                        throws SAXException {
2127:                    Event pi = new ProcessingInstruction(LocationUtils
2128:                            .getLocation(locator, null), target, data);
2129:                    addEvent(pi);
2130:                }
2131:
2132:                public void setDocumentLocator(Locator locator) {
2133:                    this .locator = locator;
2134:                }
2135:
2136:                public void skippedEntity(String name) throws SAXException {
2137:                    addEvent(new SkippedEntity(LocationUtils.getLocation(
2138:                            locator, null), name));
2139:                }
2140:
2141:                public void startDocument() {
2142:                    startEvent = new StartDocument(LocationUtils.getLocation(
2143:                            locator, null));
2144:                    lastEvent = startEvent;
2145:                    stack.push(lastEvent);
2146:                }
2147:
2148:                public void startElement(String namespaceURI, String localName,
2149:                        String qname, Attributes attrs) throws SAXException {
2150:                    Event newEvent = null;
2151:                    Location locator = LocationUtils.getLocation(this .locator,
2152:                            "<" + qname + ">");
2153:                    AttributesImpl elementAttributes = new AttributesImpl(attrs);
2154:                    int attributeCount = elementAttributes.getLength();
2155:                    for (int i = 0; i < attributeCount; i++) {
2156:                        String attributeURI = elementAttributes.getURI(i);
2157:                        if (StringUtils.equals(attributeURI, NS)) {
2158:                            getStartEvent().templateProperties.put(
2159:                                    elementAttributes.getLocalName(i),
2160:                                    compileExpr(elementAttributes.getValue(i),
2161:                                            null, locator));
2162:                            elementAttributes.removeAttribute(i--);
2163:                        }
2164:                    }
2165:                    StartElement startElement = new StartElement(locator,
2166:                            namespaceURI, localName, qname, elementAttributes);
2167:                    if (NS.equals(namespaceURI)) {
2168:                        if (localName.equals(FOR_EACH)) {
2169:                            String items = attrs.getValue("items");
2170:                            String select = attrs.getValue("select");
2171:                            JXTExpression begin = compileInt(attrs
2172:                                    .getValue("begin"), FOR_EACH, locator);
2173:                            JXTExpression end = compileInt(attrs
2174:                                    .getValue("end"), FOR_EACH, locator);
2175:                            JXTExpression step = compileInt(attrs
2176:                                    .getValue("step"), FOR_EACH, locator);
2177:                            JXTExpression var = compileExpr(attrs
2178:                                    .getValue("var"), null, locator);
2179:                            JXTExpression varStatus = compileExpr(attrs
2180:                                    .getValue("varStatus"), null, locator);
2181:                            if (items == null) {
2182:                                if (select == null
2183:                                        && (begin == null || end == null)) {
2184:                                    throw new JXTException(
2185:                                            "forEach: \"select\", \"items\", or both \"begin\" and \"end\" must be specified",
2186:                                            locator, null);
2187:                                }
2188:                            } else if (select != null) {
2189:                                throw new JXTException(
2190:                                        "forEach: only one of \"select\" or \"items\" may be specified",
2191:                                        locator, null);
2192:                            }
2193:                            JXTExpression expr = compileExpr(
2194:                                    items == null ? select : items, null,
2195:                                    locator);
2196:                            String lenientValue = attrs.getValue("lenient");
2197:                            Boolean lenient = (lenientValue == null) ? null
2198:                                    : Boolean.valueOf(lenientValue);
2199:                            StartForEach startForEach = new StartForEach(
2200:                                    startElement, expr, var, varStatus, begin,
2201:                                    end, step, lenient);
2202:                            newEvent = startForEach;
2203:                        } else if (localName.equals(FORMAT_NUMBER)) {
2204:                            JXTExpression value = compileExpr(attrs
2205:                                    .getValue("value"), null, locator);
2206:                            JXTExpression type = compileExpr(attrs
2207:                                    .getValue("type"), null, locator);
2208:                            JXTExpression pattern = compileExpr(attrs
2209:                                    .getValue("pattern"), null, locator);
2210:                            JXTExpression currencyCode = compileExpr(attrs
2211:                                    .getValue("currencyCode"), null, locator);
2212:                            JXTExpression currencySymbol = compileExpr(attrs
2213:                                    .getValue("currencySymbol"), null, locator);
2214:                            JXTExpression isGroupingUsed = compileBoolean(attrs
2215:                                    .getValue("isGroupingUsed"), null, locator);
2216:                            JXTExpression maxIntegerDigits = compileInt(attrs
2217:                                    .getValue("maxIntegerDigits"), null,
2218:                                    locator);
2219:                            JXTExpression minIntegerDigits = compileInt(attrs
2220:                                    .getValue("minIntegerDigits"), null,
2221:                                    locator);
2222:                            JXTExpression maxFractionDigits = compileInt(attrs
2223:                                    .getValue("maxFractionDigits"), null,
2224:                                    locator);
2225:                            JXTExpression minFractionDigits = compileInt(attrs
2226:                                    .getValue("minFractionDigits"), null,
2227:                                    locator);
2228:                            JXTExpression var = compileExpr(attrs
2229:                                    .getValue("var"), null, locator);
2230:                            JXTExpression locale = compileExpr(attrs
2231:                                    .getValue("locale"), null, locator);
2232:                            StartFormatNumber startFormatNumber = new StartFormatNumber(
2233:                                    startElement, var, value, type, pattern,
2234:                                    currencyCode, currencySymbol,
2235:                                    isGroupingUsed, maxIntegerDigits,
2236:                                    minIntegerDigits, maxFractionDigits,
2237:                                    minFractionDigits, locale);
2238:                            newEvent = startFormatNumber;
2239:                        } else if (localName.equals(FORMAT_DATE)) {
2240:                            JXTExpression var = compileExpr(attrs
2241:                                    .getValue("var"), null, locator);
2242:                            JXTExpression value = compileExpr(attrs
2243:                                    .getValue("value"), null, locator);
2244:                            JXTExpression type = compileExpr(attrs
2245:                                    .getValue("type"), null, locator);
2246:                            JXTExpression pattern = compileExpr(attrs
2247:                                    .getValue("pattern"), null, locator);
2248:                            JXTExpression timeZone = compileExpr(attrs
2249:                                    .getValue("timeZone"), null, locator);
2250:                            JXTExpression dateStyle = compileExpr(attrs
2251:                                    .getValue("dateStyle"), null, locator);
2252:                            JXTExpression timeStyle = compileExpr(attrs
2253:                                    .getValue("timeStyle"), null, locator);
2254:                            JXTExpression locale = compileExpr(attrs
2255:                                    .getValue("locale"), null, locator);
2256:                            StartFormatDate startFormatDate = new StartFormatDate(
2257:                                    startElement, var, value, type, pattern,
2258:                                    timeZone, dateStyle, timeStyle, locale);
2259:                            newEvent = startFormatDate;
2260:                        } else if (localName.equals(CHOOSE)) {
2261:                            StartChoose startChoose = new StartChoose(
2262:                                    startElement);
2263:                            newEvent = startChoose;
2264:                        } else if (localName.equals(WHEN)) {
2265:                            if (stack.size() == 0
2266:                                    || !(stack.peek() instanceof  StartChoose)) {
2267:                                throw new JXTException(
2268:                                        "<when> must be within <choose>",
2269:                                        locator, null);
2270:                            }
2271:                            String test = attrs.getValue("test");
2272:                            if (test != null) {
2273:                                JXTExpression expr = compileExpr(test,
2274:                                        "when: \"test\": ", locator);
2275:                                StartWhen startWhen = new StartWhen(
2276:                                        startElement, expr);
2277:                                newEvent = startWhen;
2278:                            } else {
2279:                                throw new JXTException(
2280:                                        "when: \"test\" is required", locator,
2281:                                        null);
2282:                            }
2283:                        } else if (localName.equals(OUT)) {
2284:                            String value = attrs.getValue("value");
2285:                            if (value != null) {
2286:                                JXTExpression expr = compileExpr(value,
2287:                                        "out: \"value\": ", locator);
2288:                                String lenientValue = attrs.getValue("lenient");
2289:                                Boolean lenient = lenientValue == null ? null
2290:                                        : Boolean.valueOf(lenientValue);
2291:                                newEvent = new StartOut(startElement, expr,
2292:                                        lenient);
2293:                            } else {
2294:                                throw new JXTException(
2295:                                        "out: \"value\" is required", locator,
2296:                                        null);
2297:                            }
2298:                        } else if (localName.equals(OTHERWISE)) {
2299:                            if (stack.size() != 0
2300:                                    && (stack.peek() instanceof  StartChoose)) {
2301:                                StartOtherwise startOtherwise = new StartOtherwise(
2302:                                        startElement);
2303:                                newEvent = startOtherwise;
2304:                            } else {
2305:                                throw new JXTException(
2306:                                        "<otherwise> must be within <choose>",
2307:                                        locator, null);
2308:                            }
2309:                        } else if (localName.equals(IF)) {
2310:                            String test = attrs.getValue("test");
2311:                            if (test != null) {
2312:                                JXTExpression expr = compileExpr(test,
2313:                                        "if: \"test\": ", locator);
2314:                                StartIf startIf = new StartIf(startElement,
2315:                                        expr);
2316:                                newEvent = startIf;
2317:                            } else {
2318:                                throw new JXTException(
2319:                                        "if: \"test\" is required", locator,
2320:                                        null);
2321:                            }
2322:                        } else if (localName.equals(MACRO)) {
2323:                            // <macro name="myTag" targetNamespace="myNamespace">
2324:                            // <parameter name="paramName" required="Boolean" default="value"/>
2325:                            // body
2326:                            // </macro>
2327:                            String namespace = StringUtils.defaultString(attrs
2328:                                    .getValue("targetNamespace"));
2329:                            String name = attrs.getValue("name");
2330:                            if (name != null) {
2331:                                StartDefine startDefine = new StartDefine(
2332:                                        startElement, namespace, name);
2333:                                newEvent = startDefine;
2334:                            } else {
2335:                                throw new JXTException(
2336:                                        "macro: \"name\" is required", locator,
2337:                                        null);
2338:                            }
2339:                        } else if (localName.equals(PARAMETER)) {
2340:                            if (stack.size() == 0
2341:                                    || !(stack.peek() instanceof  StartDefine)) {
2342:                                throw new JXTException(
2343:                                        "<parameter> not allowed here",
2344:                                        locator, null);
2345:                            } else {
2346:                                String name = attrs.getValue("name");
2347:                                String optional = attrs.getValue("optional");
2348:                                String default_ = attrs.getValue("default");
2349:                                if (name != null) {
2350:                                    StartParameter startParameter = new StartParameter(
2351:                                            startElement, name, optional,
2352:                                            default_);
2353:                                    newEvent = startParameter;
2354:                                } else {
2355:                                    throw new JXTException(
2356:                                            "parameter: \"name\" is required",
2357:                                            locator, null);
2358:                                }
2359:                            }
2360:                        } else if (localName.equals(EVALBODY)) {
2361:                            newEvent = new StartEvalBody(startElement);
2362:                        } else if (localName.equals(EVAL)) {
2363:                            String value = attrs.getValue("select");
2364:                            JXTExpression valueExpr = compileExpr(value,
2365:                                    "eval: \"select\":", locator);
2366:                            newEvent = new StartEval(startElement, valueExpr);
2367:                        } else if (localName.equals(SET)) {
2368:                            String var = attrs.getValue("var");
2369:                            String value = attrs.getValue("value");
2370:                            JXTExpression varExpr = null;
2371:                            JXTExpression valueExpr = null;
2372:                            if (var != null) {
2373:                                varExpr = compileExpr(var, "set: \"var\":",
2374:                                        locator);
2375:                            }
2376:                            if (value != null) {
2377:                                valueExpr = compileExpr(value,
2378:                                        "set: \"value\":", locator);
2379:                            }
2380:                            StartSet startSet = new StartSet(startElement,
2381:                                    varExpr, valueExpr);
2382:                            newEvent = startSet;
2383:                        } else if (localName.equals(IMPORT)) {
2384:                            // <import uri="${root}/foo/bar.xml" context="${foo}"/>
2385:                            AttributeEvent uri = null;
2386:                            Iterator iter = startElement.attributeEvents
2387:                                    .iterator();
2388:                            while (iter.hasNext()) {
2389:                                AttributeEvent e = (AttributeEvent) iter.next();
2390:                                if (e.localName.equals("uri")) {
2391:                                    uri = e;
2392:                                    break;
2393:                                }
2394:                            }
2395:                            if (uri != null) {
2396:                                // If "context" is present then its value will be used
2397:                                // as the context object in the imported template
2398:                                String select = attrs.getValue("context");
2399:                                JXTExpression expr = null;
2400:                                if (select != null) {
2401:                                    expr = compileExpr(select,
2402:                                            "import: \"context\": ", locator);
2403:                                }
2404:                                StartImport startImport = new StartImport(
2405:                                        startElement, uri, expr);
2406:                                newEvent = startImport;
2407:                            } else {
2408:                                throw new JXTException(
2409:                                        "import: \"uri\" is required", locator,
2410:                                        null);
2411:                            }
2412:                        } else if (localName.equals(TEMPLATE)) {
2413:                            StartTemplate startTemplate = new StartTemplate(
2414:                                    startElement);
2415:                            newEvent = startTemplate;
2416:                        } else if (localName.equals(COMMENT)) {
2417:                            // <jx:comment>This will be parsed</jx:comment>
2418:                            StartComment startJXComment = new StartComment(
2419:                                    startElement);
2420:                            newEvent = startJXComment;
2421:                        } else {
2422:                            throw new JXTException("unrecognized tag: "
2423:                                    + localName, locator, null);
2424:                        }
2425:                    } else {
2426:                        newEvent = startElement;
2427:                    }
2428:                    stack.push(newEvent);
2429:                    addEvent(newEvent);
2430:                }
2431:
2432:                public void startPrefixMapping(String prefix, String uri)
2433:                        throws SAXException {
2434:                    addEvent(new StartPrefixMapping(LocationUtils.getLocation(
2435:                            locator, null), prefix, uri));
2436:                }
2437:
2438:                public void comment(char ch[], int start, int length)
2439:                        throws SAXException {
2440:                    // DO NOTHING
2441:                }
2442:
2443:                public void endCDATA() throws SAXException {
2444:                    addEvent(new EndCDATA(LocationUtils.getLocation(locator,
2445:                            null)));
2446:                }
2447:
2448:                public void endDTD() throws SAXException {
2449:                    addEvent(new EndDTD(LocationUtils
2450:                            .getLocation(locator, null)));
2451:                }
2452:
2453:                public void endEntity(String name) throws SAXException {
2454:                    addEvent(new EndEntity(LocationUtils.getLocation(locator,
2455:                            null), name));
2456:                }
2457:
2458:                public void startCDATA() throws SAXException {
2459:                    addEvent(new StartCDATA(LocationUtils.getLocation(locator,
2460:                            null)));
2461:                }
2462:
2463:                public void startDTD(String name, String publicId,
2464:                        String systemId) throws SAXException {
2465:                    addEvent(new StartDTD(LocationUtils.getLocation(locator,
2466:                            null), name, publicId, systemId));
2467:                }
2468:
2469:                public void startEntity(String name) throws SAXException {
2470:                    addEvent(new StartEntity(LocationUtils.getLocation(locator,
2471:                            null), name));
2472:                }
2473:            }
2474:
2475:            /**
2476:             * Adapter that makes this generator usable as a transformer
2477:             * (Note there is a performance penalty for this however:
2478:             * you effectively recompile the template for every instance document)
2479:             */
2480:
2481:            public static class TransformerAdapter extends
2482:                    ServiceableTransformer {
2483:                static class TemplateConsumer extends Parser implements 
2484:                        XMLConsumer {
2485:
2486:                    public TemplateConsumer() {
2487:                        this .gen = new JXTemplateGenerator();
2488:                    }
2489:
2490:                    public void setup(SourceResolver resolver, Map objectModel,
2491:                            String src, Parameters parameters)
2492:                            throws ProcessingException, SAXException,
2493:                            IOException {
2494:                        this .gen.setup(resolver, objectModel, null, parameters);
2495:                    }
2496:
2497:                    public void service(ServiceManager manager)
2498:                            throws ServiceException {
2499:                        this .gen.service(manager);
2500:                    }
2501:
2502:                    public void endDocument() throws SAXException {
2503:                        super .endDocument();
2504:                        gen.performGeneration(gen.getConsumer(), gen
2505:                                .getJexlContext(), gen.getJXPathContext(),
2506:                                null, getStartEvent(), null);
2507:                    }
2508:
2509:                    void setConsumer(XMLConsumer consumer) {
2510:                        gen.setConsumer(consumer);
2511:                    }
2512:
2513:                    void recycle() {
2514:                        super .recycle();
2515:                        gen.recycle();
2516:                    }
2517:
2518:                    JXTemplateGenerator gen;
2519:                }
2520:
2521:                TemplateConsumer templateConsumer = new TemplateConsumer();
2522:
2523:                public void recycle() {
2524:                    super .recycle();
2525:                    templateConsumer.recycle();
2526:                }
2527:
2528:                public void setup(SourceResolver resolver, Map objectModel,
2529:                        String src, Parameters parameters)
2530:                        throws ProcessingException, SAXException, IOException {
2531:                    super .setup(resolver, objectModel, src, parameters);
2532:                    templateConsumer.setup(resolver, objectModel, src,
2533:                            parameters);
2534:                }
2535:
2536:                public void service(ServiceManager manager)
2537:                        throws ServiceException {
2538:                    super .service(manager);
2539:                    templateConsumer.service(manager);
2540:                }
2541:
2542:                public void setConsumer(XMLConsumer xmlConsumer) {
2543:                    super .setConsumer(templateConsumer);
2544:                    templateConsumer.setConsumer(xmlConsumer);
2545:                }
2546:            }
2547:
2548:            private JXPathContext jxpathContext;
2549:            private MyJexlContext globalJexlContext;
2550:            private Variables variables;
2551:            private static Map cache = new HashMap();
2552:            private Source inputSource;
2553:            private Map definitions;
2554:            private Map cocoon;
2555:
2556:            private JXPathContext getJXPathContext() {
2557:                return jxpathContext;
2558:            }
2559:
2560:            private MyJexlContext getJexlContext() {
2561:                return globalJexlContext;
2562:            }
2563:
2564:            /* (non-Javadoc)
2565:             * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
2566:             */
2567:            public void recycle() {
2568:                if (this .resolver != null) {
2569:                    this .resolver.release(this .inputSource);
2570:                }
2571:                this .inputSource = null;
2572:                this .jxpathContext = null;
2573:                this .globalJexlContext = null;
2574:                this .variables = null;
2575:                this .definitions = null;
2576:                this .cocoon = null;
2577:                this .namespaces.clear();
2578:                super .recycle();
2579:            }
2580:
2581:            /* (non-Javadoc)
2582:             * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
2583:             */
2584:            public void setup(SourceResolver resolver, Map objectModel,
2585:                    String src, Parameters parameters)
2586:                    throws ProcessingException, SAXException, IOException {
2587:
2588:                super .setup(resolver, objectModel, src, parameters);
2589:                if (src != null) {
2590:                    try {
2591:                        this .inputSource = resolver.resolveURI(src);
2592:                    } catch (SourceException se) {
2593:                        throw SourceUtil.handle("Error during resolving of '"
2594:                                + src + "'.", se);
2595:                    }
2596:                    final String uri = inputSource.getURI();
2597:                    boolean regenerate = false;
2598:                    StartDocument startEvent = null;
2599:                    synchronized (cache) {
2600:                        startEvent = (StartDocument) cache.get(uri);
2601:                        if (startEvent != null) {
2602:                            int valid = SourceValidity.UNKNOWN;
2603:                            if (startEvent.compileTime != null) {
2604:                                valid = startEvent.compileTime.isValid();
2605:                            }
2606:                            if (valid == SourceValidity.UNKNOWN
2607:                                    && startEvent.compileTime != null) {
2608:                                SourceValidity validity = inputSource
2609:                                        .getValidity();
2610:                                valid = startEvent.compileTime
2611:                                        .isValid(validity);
2612:                            }
2613:                            if (valid != SourceValidity.VALID) {
2614:                                regenerate = true;
2615:                            }
2616:                        } else {
2617:                            regenerate = true;
2618:                        }
2619:                    }
2620:                    if (regenerate) {
2621:                        Parser parser = new Parser();
2622:                        SourceUtil
2623:                                .parse(this .manager, this .inputSource, parser);
2624:                        startEvent = parser.getStartEvent();
2625:                        startEvent.compileTime = this .inputSource.getValidity();
2626:                        synchronized (cache) {
2627:                            cache.put(uri, startEvent);
2628:                        }
2629:                    }
2630:                }
2631:                Object bean = FlowHelper.getContextObject(objectModel);
2632:                WebContinuation kont = FlowHelper
2633:                        .getWebContinuation(objectModel);
2634:                setContexts(bean, kont, parameters, objectModel);
2635:                this .definitions = new HashMap();
2636:            }
2637:
2638:            private void fillContext(Object contextObject, Map map) {
2639:                if (contextObject != null) {
2640:                    // Hack: I use jxpath to populate the context object's properties
2641:                    // in the jexl context
2642:                    final JXPathBeanInfo bi = JXPathIntrospector
2643:                            .getBeanInfo(contextObject.getClass());
2644:                    if (bi.isDynamic()) {
2645:                        Class cl = bi.getDynamicPropertyHandlerClass();
2646:                        try {
2647:                            DynamicPropertyHandler h = (DynamicPropertyHandler) cl
2648:                                    .newInstance();
2649:                            String[] result = h.getPropertyNames(contextObject);
2650:                            int len = result.length;
2651:                            for (int i = 0; i < len; i++) {
2652:                                try {
2653:                                    map.put(result[i], h.getProperty(
2654:                                            contextObject, result[i]));
2655:                                } catch (Exception exc) {
2656:                                    exc.printStackTrace();
2657:                                }
2658:                            }
2659:                        } catch (Exception ignored) {
2660:                            ignored.printStackTrace();
2661:                        }
2662:                    } else {
2663:                        PropertyDescriptor[] props = bi
2664:                                .getPropertyDescriptors();
2665:                        int len = props.length;
2666:                        for (int i = 0; i < len; i++) {
2667:                            try {
2668:                                Method read = props[i].getReadMethod();
2669:                                if (read != null) {
2670:                                    map.put(props[i].getName(), read.invoke(
2671:                                            contextObject, null));
2672:                                }
2673:                            } catch (Exception ignored) {
2674:                                ignored.printStackTrace();
2675:                            }
2676:                        }
2677:                    }
2678:                }
2679:            }
2680:
2681:            private void setContexts(Object contextObject,
2682:                    WebContinuation kont, Parameters parameters, Map objectModel) {
2683:                final Request request = ObjectModelHelper
2684:                        .getRequest(objectModel);
2685:                final Object session = request.getSession(false);
2686:                final Object app = ObjectModelHelper.getContext(objectModel);
2687:                cocoon = new HashMap();
2688:                Object fomRequest = FOM_JavaScriptFlowHelper
2689:                        .getFOM_Request(objectModel);
2690:                cocoon
2691:                        .put("request", fomRequest != null ? fomRequest
2692:                                : request);
2693:                if (session != null) {
2694:                    cocoon.put("session", FOM_JavaScriptFlowHelper
2695:                            .getFOM_Session(objectModel));
2696:                }
2697:                cocoon.put("context", FOM_JavaScriptFlowHelper
2698:                        .getFOM_Context(objectModel));
2699:                cocoon.put("continuation", FOM_JavaScriptFlowHelper
2700:                        .getFOM_WebContinuation(objectModel));
2701:                cocoon.put("parameters", parameters);
2702:                this .variables = new MyVariables(cocoon, contextObject, kont,
2703:                        request, session, app, parameters);
2704:                Map map;
2705:                if (contextObject instanceof  Map) {
2706:                    map = (Map) contextObject;
2707:                } else {
2708:                    map = new HashMap();
2709:                    fillContext(contextObject, map);
2710:                }
2711:                jxpathContext = jxpathContextFactory.newContext(null,
2712:                        contextObject);
2713:                jxpathContext
2714:                        .setNamespaceContextPointer(new NamespacesTablePointer(
2715:                                namespaces));
2716:                jxpathContext.setVariables(variables);
2717:                jxpathContext.setLenient(parameters.getParameterAsBoolean(
2718:                        "lenient-xpath", false));
2719:                globalJexlContext = new MyJexlContext();
2720:                globalJexlContext.setVars(map);
2721:                map = globalJexlContext.getVars();
2722:                map.put("cocoon", cocoon);
2723:                if (contextObject != null) {
2724:                    map.put("flowContext", contextObject);
2725:                    // FIXME (VG): Is this required (what it's used for - examples)?
2726:                    // Here I use Rhino's live-connect objects to allow Jexl to call
2727:                    // java constructors
2728:                    Object javaPkg = FOM_JavaScriptFlowHelper
2729:                            .getJavaPackage(objectModel);
2730:                    Object pkgs = FOM_JavaScriptFlowHelper
2731:                            .getPackages(objectModel);
2732:                    map.put("java", javaPkg);
2733:                    map.put("Packages", pkgs);
2734:                }
2735:                if (kont != null) {
2736:                    map.put("continuation", kont);
2737:                }
2738:                map.put("request", request);
2739:                map.put("context", app);
2740:                map.put("parameters", parameters);
2741:                if (session != null) {
2742:                    map.put("session", session);
2743:                }
2744:            }
2745:
2746:            /* (non-Javadoc)
2747:             * @see org.apache.cocoon.generation.Generator#generate()
2748:             */
2749:            public void generate() throws IOException, SAXException,
2750:                    ProcessingException {
2751:                final String cacheKey = this .inputSource.getURI();
2752:
2753:                StartDocument startEvent;
2754:                synchronized (cache) {
2755:                    startEvent = (StartDocument) cache.get(cacheKey);
2756:                }
2757:                performGeneration(this .xmlConsumer, globalJexlContext,
2758:                        jxpathContext, null, startEvent, null);
2759:            }
2760:
2761:            private void performGeneration(final XMLConsumer consumer,
2762:                    MyJexlContext jexlContext, JXPathContext jxpathContext,
2763:                    StartElement macroCall, Event startEvent, Event endEvent)
2764:                    throws SAXException {
2765:                cocoon.put("consumer", consumer);
2766:                RedundantNamespacesFilter filter = new RedundantNamespacesFilter(
2767:                        this .xmlConsumer);
2768:                //        EventPrinterPipe log = new EventPrinterPipe();
2769:                //        log.setConsumer(filter);
2770:                execute(filter, globalJexlContext, jxpathContext, null,
2771:                        startEvent, null);
2772:            }
2773:
2774:            interface CharHandler {
2775:                public void characters(char[] ch, int offset, int length)
2776:                        throws SAXException;
2777:            }
2778:
2779:            private void characters(JexlContext jexlContext,
2780:                    JXPathContext jxpathContext, TextEvent event,
2781:                    CharHandler handler) throws SAXException {
2782:                Iterator iter = event.substitutions.iterator();
2783:                while (iter.hasNext()) {
2784:                    Object subst = iter.next();
2785:                    char[] chars;
2786:                    if (subst instanceof  char[]) {
2787:                        chars = (char[]) subst;
2788:                    } else {
2789:                        JXTExpression expr = (JXTExpression) subst;
2790:                        try {
2791:                            Object val = getValue(expr, jexlContext,
2792:                                    jxpathContext);
2793:                            chars = val != null ? val.toString().toCharArray()
2794:                                    : ArrayUtils.EMPTY_CHAR_ARRAY;
2795:                        } catch (Exception e) {
2796:                            throw new JXTException(e.getMessage(),
2797:                                    event.location, e);
2798:                        }
2799:                    }
2800:                    handler.characters(chars, 0, chars.length);
2801:                }
2802:            }
2803:
2804:            /** dump a DOM document, using an IncludeXMLConsumer to filter out start/end document events */
2805:            private void executeDOM(final XMLConsumer consumer,
2806:                    MyJexlContext jexlContext, JXPathContext jxpathContext,
2807:                    Node node) throws SAXException {
2808:                IncludeXMLConsumer includer = new IncludeXMLConsumer(consumer);
2809:                DOMStreamer streamer = new DOMStreamer(includer);
2810:                streamer.stream(node);
2811:            }
2812:
2813:            private void call(Location location, StartElement macroCall,
2814:                    final XMLConsumer consumer, MyJexlContext jexlContext,
2815:                    JXPathContext jxpathContext, Event startEvent,
2816:                    Event endEvent) throws SAXException {
2817:                try {
2818:                    execute(consumer, jexlContext, jxpathContext, macroCall,
2819:                            startEvent, endEvent);
2820:                } catch (Exception exc) {
2821:                    throw new JXTException(macroCall.localName + ": "
2822:                            + exc.getMessage(), location, exc);
2823:                }
2824:            }
2825:
2826:            public static class LoopTagStatus {
2827:                Object current;
2828:                int index;
2829:                int count;
2830:                boolean first;
2831:                boolean last;
2832:                int begin;
2833:                int end;
2834:                int step;
2835:
2836:                public Object getCurrent() {
2837:                    return current;
2838:                }
2839:
2840:                public int getIndex() {
2841:                    return index;
2842:                }
2843:
2844:                public int getCount() {
2845:                    return count;
2846:                }
2847:
2848:                public boolean isFirst() {
2849:                    return first;
2850:                }
2851:
2852:                public boolean isLast() {
2853:                    return last;
2854:                }
2855:
2856:                public int getBegin() {
2857:                    return begin;
2858:                }
2859:
2860:                public int getEnd() {
2861:                    return end;
2862:                }
2863:
2864:                public int getStep() {
2865:                    return step;
2866:                }
2867:            }
2868:
2869:            private void execute(final XMLConsumer consumer,
2870:                    MyJexlContext jexlContext, JXPathContext jxpathContext,
2871:                    StartElement macroCall, Event startEvent, Event endEvent)
2872:                    throws SAXException {
2873:                Event ev = startEvent;
2874:                LocationFacade loc = new LocationFacade(ev.location);
2875:                consumer.setDocumentLocator(loc);
2876:                while (ev != endEvent) {
2877:                    loc.setDocumentLocation(ev.location);
2878:                    if (ev instanceof  Characters) {
2879:                        TextEvent text = (TextEvent) ev;
2880:                        Iterator iter = text.substitutions.iterator();
2881:                        while (iter.hasNext()) {
2882:                            Object subst = iter.next();
2883:                            char[] chars;
2884:                            if (subst instanceof  char[]) {
2885:                                chars = (char[]) subst;
2886:                            } else {
2887:                                JXTExpression expr = (JXTExpression) subst;
2888:                                try {
2889:                                    Object val = getNode(expr, jexlContext,
2890:                                            jxpathContext);
2891:                                    if (val instanceof  Node) {
2892:                                        executeDOM(consumer, jexlContext,
2893:                                                jxpathContext, (Node) val);
2894:                                        continue;
2895:                                    } else if (val instanceof  NodeList) {
2896:                                        NodeList nodeList = (NodeList) val;
2897:                                        int len = nodeList.getLength();
2898:                                        for (int i = 0; i < len; i++) {
2899:                                            Node n = nodeList.item(i);
2900:                                            executeDOM(consumer, jexlContext,
2901:                                                    jxpathContext, n);
2902:                                        }
2903:                                        continue;
2904:                                    } else if (val instanceof  Node[]) {
2905:                                        Node[] nodeList = (Node[]) val;
2906:                                        int len = nodeList.length;
2907:                                        for (int i = 0; i < len; i++) {
2908:                                            Node n = nodeList[i];
2909:                                            executeDOM(consumer, jexlContext,
2910:                                                    jxpathContext, n);
2911:                                        }
2912:                                        continue;
2913:                                    } else if (val instanceof  XMLizable) {
2914:                                        ((XMLizable) val)
2915:                                                .toSAX(new IncludeXMLConsumer(
2916:                                                        consumer));
2917:                                        continue;
2918:                                    }
2919:                                    chars = val != null ? val.toString()
2920:                                            .toCharArray()
2921:                                            : ArrayUtils.EMPTY_CHAR_ARRAY;
2922:                                } catch (Exception e) {
2923:                                    throw new JXTException(e.getMessage(),
2924:                                            ev.location, e);
2925:                                }
2926:                            }
2927:                            consumer.characters(chars, 0, chars.length);
2928:                        }
2929:                    } else if (ev instanceof  EndElement) {
2930:                        EndElement endElement = (EndElement) ev;
2931:                        StartElement startElement = endElement.startElement;
2932:                        StartDefine def = (StartDefine) definitions
2933:                                .get(startElement.qname);
2934:                        if (def == null) {
2935:                            consumer.endElement(startElement.namespaceURI,
2936:                                    startElement.localName, startElement.raw);
2937:                            namespaces.leaveScope(consumer);
2938:                        }
2939:                    } else if (ev instanceof  EndPrefixMapping) {
2940:                        EndPrefixMapping endPrefixMapping = (EndPrefixMapping) ev;
2941:                        namespaces.removeDeclaration(endPrefixMapping.prefix);
2942:                    } else if (ev instanceof  IgnorableWhitespace) {
2943:                        TextEvent text = (TextEvent) ev;
2944:                        characters(jexlContext, jxpathContext, text,
2945:                                new CharHandler() {
2946:                                    public void characters(char[] ch,
2947:                                            int offset, int len)
2948:                                            throws SAXException {
2949:                                        consumer.ignorableWhitespace(ch,
2950:                                                offset, len);
2951:                                    }
2952:                                });
2953:                    } else if (ev instanceof  SkippedEntity) {
2954:                        SkippedEntity skippedEntity = (SkippedEntity) ev;
2955:                        consumer.skippedEntity(skippedEntity.name);
2956:                    } else if (ev instanceof  StartIf) {
2957:                        StartIf startIf = (StartIf) ev;
2958:                        Object val;
2959:                        try {
2960:                            val = getValue(startIf.test, jexlContext,
2961:                                    jxpathContext, Boolean.TRUE);
2962:                        } catch (Exception e) {
2963:                            throw new JXTException(e.getMessage(), ev.location,
2964:                                    e);
2965:                        }
2966:                        boolean result = false;
2967:                        if (val instanceof  Boolean) {
2968:                            result = ((Boolean) val).booleanValue();
2969:                        } else {
2970:                            result = (val != null);
2971:                        }
2972:                        if (!result) {
2973:                            ev = startIf.endInstruction.next;
2974:                            continue;
2975:                        }
2976:                    } else if (ev instanceof  StartForEach) {
2977:                        StartForEach startForEach = (StartForEach) ev;
2978:                        final Object items = startForEach.items;
2979:                        Iterator iter = null;
2980:                        int begin, end, step;
2981:                        String var, varStatus;
2982:                        try {
2983:                            if (items != null) {
2984:                                JXTExpression expr = (JXTExpression) items;
2985:                                if (expr.compiledExpression instanceof  CompiledExpression) {
2986:                                    CompiledExpression compiledExpression = (CompiledExpression) expr.compiledExpression;
2987:                                    Object val = compiledExpression.getPointer(
2988:                                            jxpathContext, expr.raw).getNode();
2989:                                    // FIXME: workaround for JXPath bug
2990:                                    iter = val instanceof  NativeArray ? new JSIntrospector.NativeArrayIterator(
2991:                                            (NativeArray) val)
2992:                                            : compiledExpression
2993:                                                    .iteratePointers(jxpathContext);
2994:                                } else if (expr.compiledExpression instanceof  Expression) {
2995:                                    Expression e = (Expression) expr.compiledExpression;
2996:                                    Object result = e.evaluate(jexlContext);
2997:                                    if (result != null) {
2998:                                        iter = Introspector
2999:                                                .getUberspect()
3000:                                                .getIterator(
3001:                                                        result,
3002:                                                        new Info(
3003:                                                                ev.location
3004:                                                                        .getURI(),
3005:                                                                ev.location
3006:                                                                        .getLineNumber(),
3007:                                                                ev.location
3008:                                                                        .getColumnNumber()));
3009:                                    }
3010:                                    if (iter == null) {
3011:                                        iter = EMPTY_ITER;
3012:                                    }
3013:                                } else {
3014:                                    // literal value
3015:                                    iter = new Iterator() {
3016:                                        Object val = items;
3017:
3018:                                        public boolean hasNext() {
3019:                                            return val != null;
3020:                                        }
3021:
3022:                                        public Object next() {
3023:                                            Object res = val;
3024:                                            val = null;
3025:                                            return res;
3026:                                        }
3027:
3028:                                        public void remove() {
3029:                                            // EMPTY
3030:                                        }
3031:                                    };
3032:                                }
3033:                            } else {
3034:                                iter = NULL_ITER;
3035:                            }
3036:                            begin = startForEach.begin == null ? 0
3037:                                    : getIntValue(startForEach.begin,
3038:                                            jexlContext, jxpathContext);
3039:                            end = startForEach.end == null ? Integer.MAX_VALUE
3040:                                    : getIntValue(startForEach.end,
3041:                                            jexlContext, jxpathContext);
3042:                            step = startForEach.step == null ? 1 : getIntValue(
3043:                                    startForEach.step, jexlContext,
3044:                                    jxpathContext);
3045:                            var = getStringValue(startForEach.var, jexlContext,
3046:                                    jxpathContext);
3047:                            varStatus = getStringValue(startForEach.varStatus,
3048:                                    jexlContext, jxpathContext);
3049:                        } catch (Exception exc) {
3050:                            throw new JXTException(exc.getMessage(),
3051:                                    ev.location, exc);
3052:                        }
3053:                        MyJexlContext localJexlContext = new MyJexlContext(
3054:                                jexlContext);
3055:                        MyVariables localJXPathVariables = new MyVariables(
3056:                                (MyVariables) jxpathContext.getVariables());
3057:                        int i = 0;
3058:                        // Move to the begin row
3059:                        while (i < begin && iter.hasNext()) {
3060:                            iter.next();
3061:                            i++;
3062:                        }
3063:                        LoopTagStatus status = null;
3064:                        if (varStatus != null) {
3065:                            status = new LoopTagStatus();
3066:                            status.begin = begin;
3067:                            status.end = end;
3068:                            status.step = step;
3069:                            status.first = true;
3070:                            localJexlContext.put(varStatus, status);
3071:                            localJXPathVariables.declareVariable(varStatus,
3072:                                    status);
3073:                        }
3074:                        int skipCounter, count = 1;
3075:                        JXPathContext localJXPathContext = null;
3076:                        while (i <= end && iter.hasNext()) {
3077:                            Object value = iter.next();
3078:                            if (value instanceof  Pointer) {
3079:                                Pointer ptr = (Pointer) value;
3080:                                localJXPathContext = jxpathContext
3081:                                        .getRelativeContext(ptr);
3082:                                localJXPathContext
3083:                                        .setNamespaceContextPointer(new NamespacesTablePointer(
3084:                                                namespaces));
3085:                                try {
3086:                                    value = ptr.getNode();
3087:                                } catch (Exception exc) {
3088:                                    throw new JXTException(exc.getMessage(),
3089:                                            ev.location, null);
3090:                                }
3091:                            } else {
3092:                                localJXPathContext = jxpathContextFactory
3093:                                        .newContext(jxpathContext, value);
3094:                                localJXPathContext
3095:                                        .setNamespaceContextPointer(new NamespacesTablePointer(
3096:                                                namespaces));
3097:                            }
3098:                            localJXPathContext
3099:                                    .setVariables(localJXPathVariables);
3100:                            if (var != null) {
3101:                                localJexlContext.put(var, value);
3102:                            }
3103:                            if (status != null) {
3104:                                status.index = i;
3105:                                status.count = count;
3106:                                status.first = i == begin;
3107:                                status.current = value;
3108:                                status.last = (i == end || !iter.hasNext());
3109:                            }
3110:                            execute(consumer, localJexlContext,
3111:                                    localJXPathContext, macroCall,
3112:                                    startForEach.next,
3113:                                    startForEach.endInstruction);
3114:                            // Skip rows
3115:                            skipCounter = step;
3116:                            while (--skipCounter > 0 && iter.hasNext()) {
3117:                                iter.next();
3118:                            }
3119:                            // Increase index
3120:                            i += step;
3121:                            count++;
3122:                        }
3123:                        ev = startForEach.endInstruction.next;
3124:                        continue;
3125:                    } else if (ev instanceof  StartChoose) {
3126:                        StartChoose startChoose = (StartChoose) ev;
3127:                        StartWhen startWhen = startChoose.firstChoice;
3128:                        while (startWhen != null) {
3129:                            Object val;
3130:                            try {
3131:                                val = getValue(startWhen.test, jexlContext,
3132:                                        jxpathContext, Boolean.TRUE);
3133:                            } catch (Exception e) {
3134:                                throw new JXTException(e.getMessage(),
3135:                                        ev.location, e);
3136:                            }
3137:                            boolean result;
3138:                            if (val instanceof  Boolean) {
3139:                                result = ((Boolean) val).booleanValue();
3140:                            } else {
3141:                                result = (val != null);
3142:                            }
3143:                            if (result) {
3144:                                execute(consumer, jexlContext, jxpathContext,
3145:                                        macroCall, startWhen.next,
3146:                                        startWhen.endInstruction);
3147:                                break;
3148:                            }
3149:                            startWhen = startWhen.nextChoice;
3150:                        }
3151:                        if (startWhen == null && startChoose.otherwise != null) {
3152:                            execute(consumer, jexlContext, jxpathContext,
3153:                                    macroCall, startChoose.otherwise.next,
3154:                                    startChoose.otherwise.endInstruction);
3155:                        }
3156:                        ev = startChoose.endInstruction.next;
3157:                        continue;
3158:                    } else if (ev instanceof  StartSet) {
3159:                        StartSet startSet = (StartSet) ev;
3160:                        Object value = null;
3161:                        String var = null;
3162:                        try {
3163:                            if (startSet.var != null) {
3164:                                var = getStringValue(startSet.var, jexlContext,
3165:                                        jxpathContext);
3166:                            }
3167:                            if (startSet.value != null) {
3168:                                value = getNode(startSet.value, jexlContext,
3169:                                        jxpathContext);
3170:                            }
3171:                        } catch (Exception exc) {
3172:                            throw new JXTException(exc.getMessage(),
3173:                                    ev.location, exc);
3174:                        }
3175:                        if (value == null) {
3176:                            NodeList nodeList = toDOMNodeList("set", startSet,
3177:                                    jexlContext, macroCall);
3178:                            // JXPath doesn't handle NodeList, so convert it to an array
3179:                            int len = nodeList.getLength();
3180:                            Node[] nodeArr = new Node[len];
3181:                            for (int i = 0; i < len; i++) {
3182:                                nodeArr[i] = nodeList.item(i);
3183:                            }
3184:                            value = nodeArr;
3185:                        }
3186:                        if (var != null) {
3187:                            jxpathContext.getVariables().declareVariable(var,
3188:                                    value);
3189:                            jexlContext.put(var, value);
3190:                        }
3191:                        ev = startSet.endInstruction.next;
3192:                        continue;
3193:                    } else if (ev instanceof  StartElement) {
3194:                        StartElement startElement = (StartElement) ev;
3195:                        StartDefine def = (StartDefine) definitions
3196:                                .get(startElement.qname);
3197:                        if (def != null) {
3198:                            Map attributeMap = new HashMap();
3199:                            Iterator i = startElement.attributeEvents
3200:                                    .iterator();
3201:                            while (i.hasNext()) {
3202:                                String attributeName;
3203:                                Object attributeValue;
3204:                                AttributeEvent attrEvent = (AttributeEvent) i
3205:                                        .next();
3206:                                attributeName = attrEvent.localName;
3207:                                if (attrEvent instanceof  CopyAttribute) {
3208:                                    CopyAttribute copy = (CopyAttribute) attrEvent;
3209:                                    attributeValue = copy.value;
3210:                                } else if (attrEvent instanceof  SubstituteAttribute) {
3211:                                    SubstituteAttribute substEvent = (SubstituteAttribute) attrEvent;
3212:                                    if (substEvent.substitutions.size() == 1
3213:                                            && substEvent.substitutions.get(0) instanceof  JXTExpression) {
3214:                                        JXTExpression expr = (JXTExpression) substEvent.substitutions
3215:                                                .get(0);
3216:                                        Object val;
3217:                                        try {
3218:                                            val = getNode(expr, jexlContext,
3219:                                                    jxpathContext);
3220:                                        } catch (Exception e) {
3221:                                            throw new JXTException(e
3222:                                                    .getMessage(), ev.location,
3223:                                                    e);
3224:                                        }
3225:                                        attributeValue = val != null ? val : "";
3226:                                    } else {
3227:                                        StringBuffer buf = new StringBuffer();
3228:                                        Iterator iterSubst = substEvent.substitutions
3229:                                                .iterator();
3230:                                        while (iterSubst.hasNext()) {
3231:                                            Subst subst = (Subst) iterSubst
3232:                                                    .next();
3233:                                            if (subst instanceof  Literal) {
3234:                                                Literal lit = (Literal) subst;
3235:                                                buf.append(lit.value);
3236:                                            } else if (subst instanceof  JXTExpression) {
3237:                                                JXTExpression expr = (JXTExpression) subst;
3238:                                                Object val;
3239:                                                try {
3240:                                                    val = getValue(expr,
3241:                                                            jexlContext,
3242:                                                            jxpathContext);
3243:                                                } catch (Exception e) {
3244:                                                    throw new JXTException(e
3245:                                                            .getMessage(),
3246:                                                            ev.location, e);
3247:                                                }
3248:                                                buf.append(val != null ? val
3249:                                                        .toString() : "");
3250:                                            }
3251:                                        }
3252:                                        attributeValue = buf.toString();
3253:                                    }
3254:                                } else {
3255:                                    throw new Error(
3256:                                            "this shouldn't have happened");
3257:                                }
3258:                                attributeMap.put(attributeName, attributeValue);
3259:                            }
3260:                            MyVariables parent = (MyVariables) jxpathContext
3261:                                    .getVariables();
3262:                            MyVariables vars = new MyVariables(parent);
3263:                            MyJexlContext localJexlContext = new MyJexlContext(
3264:                                    jexlContext);
3265:                            HashMap macro = new HashMap();
3266:                            macro.put("body", startElement);
3267:                            macro.put("arguments", attributeMap);
3268:                            localJexlContext.put("macro", macro);
3269:                            vars.declareVariable("macro", macro);
3270:                            Iterator iter = def.parameters.entrySet()
3271:                                    .iterator();
3272:                            while (iter.hasNext()) {
3273:                                Map.Entry e = (Map.Entry) iter.next();
3274:                                String key = (String) e.getKey();
3275:                                StartParameter startParam = (StartParameter) e
3276:                                        .getValue();
3277:                                Object default_ = startParam.default_;
3278:                                Object val = attributeMap.get(key);
3279:                                if (val == null) {
3280:                                    val = default_;
3281:                                }
3282:                                localJexlContext.put(key, val);
3283:                                vars.declareVariable(key, val);
3284:                            }
3285:                            JXPathContext localJXPathContext = jxpathContextFactory
3286:                                    .newContext(null, jxpathContext
3287:                                            .getContextBean());
3288:                            localJXPathContext
3289:                                    .setNamespaceContextPointer(new NamespacesTablePointer(
3290:                                            namespaces));
3291:                            localJXPathContext.setVariables(vars);
3292:                            call(ev.location, startElement, consumer,
3293:                                    localJexlContext, localJXPathContext,
3294:                                    def.body, def.endInstruction);
3295:                            ev = startElement.endElement.next;
3296:                            continue;
3297:                        }
3298:                        Iterator i = startElement.attributeEvents.iterator();
3299:                        AttributesImpl attrs = new AttributesImpl();
3300:                        while (i.hasNext()) {
3301:                            AttributeEvent attrEvent = (AttributeEvent) i
3302:                                    .next();
3303:                            if (attrEvent instanceof  CopyAttribute) {
3304:                                CopyAttribute copy = (CopyAttribute) attrEvent;
3305:                                attrs.addAttribute(copy.namespaceURI,
3306:                                        copy.localName, copy.raw, copy.type,
3307:                                        copy.value);
3308:                            } else if (attrEvent instanceof  SubstituteAttribute) {
3309:                                StringBuffer buf = new StringBuffer();
3310:                                SubstituteAttribute substEvent = (SubstituteAttribute) attrEvent;
3311:                                Iterator iterSubst = substEvent.substitutions
3312:                                        .iterator();
3313:                                while (iterSubst.hasNext()) {
3314:                                    Subst subst = (Subst) iterSubst.next();
3315:                                    if (subst instanceof  Literal) {
3316:                                        Literal lit = (Literal) subst;
3317:                                        buf.append(lit.value);
3318:                                    } else if (subst instanceof  JXTExpression) {
3319:                                        JXTExpression expr = (JXTExpression) subst;
3320:                                        Object val;
3321:                                        try {
3322:                                            val = getValue(expr, jexlContext,
3323:                                                    jxpathContext);
3324:                                        } catch (Exception e) {
3325:                                            throw new JXTException(e
3326:                                                    .getMessage(), ev.location,
3327:                                                    e);
3328:                                        }
3329:                                        buf.append(val != null ? val.toString()
3330:                                                : "");
3331:                                    }
3332:                                }
3333:                                attrs.addAttribute(attrEvent.namespaceURI,
3334:                                        attrEvent.localName, attrEvent.raw,
3335:                                        attrEvent.type, buf.toString());
3336:                            }
3337:                        }
3338:                        namespaces.enterScope(consumer);
3339:                        consumer
3340:                                .startElement(startElement.namespaceURI,
3341:                                        startElement.localName,
3342:                                        startElement.raw, attrs);
3343:                    } else if (ev instanceof  StartFormatNumber) {
3344:                        StartFormatNumber startFormatNumber = (StartFormatNumber) ev;
3345:                        try {
3346:                            String result = startFormatNumber.format(
3347:                                    jexlContext, jxpathContext);
3348:                            if (result != null) {
3349:                                char[] chars = result.toCharArray();
3350:                                consumer.characters(chars, 0, chars.length);
3351:                            }
3352:                        } catch (Exception e) {
3353:                            throw new JXTException(e.getMessage(), ev.location,
3354:                                    e);
3355:                        }
3356:                    } else if (ev instanceof  StartFormatDate) {
3357:                        StartFormatDate startFormatDate = (StartFormatDate) ev;
3358:                        try {
3359:                            String result = startFormatDate.format(jexlContext,
3360:                                    jxpathContext);
3361:                            if (result != null) {
3362:                                char[] chars = result.toCharArray();
3363:                                consumer.characters(chars, 0, chars.length);
3364:                            }
3365:                        } catch (Exception e) {
3366:                            throw new JXTException(e.getMessage(), ev.location,
3367:                                    e);
3368:                        }
3369:                    } else if (ev instanceof  StartPrefixMapping) {
3370:                        StartPrefixMapping startPrefixMapping = (StartPrefixMapping) ev;
3371:                        namespaces.addDeclaration(startPrefixMapping.prefix,
3372:                                startPrefixMapping.uri);
3373:                    } else if (ev instanceof  StartComment) {
3374:                        StartComment startJXComment = (StartComment) ev;
3375:                        // Parse the body of the comment
3376:                        NodeList nodeList = toDOMNodeList("comment",
3377:                                startJXComment, jexlContext, macroCall);
3378:                        // JXPath doesn't handle NodeList, so convert it to an array
3379:                        int len = nodeList.getLength();
3380:                        final StringBuffer buf = new StringBuffer();
3381:                        Properties omit = XMLUtils.createPropertiesForXML(true);
3382:                        for (int i = 0; i < len; i++) {
3383:                            try {
3384:                                buf.append(XMLUtils.serializeNode(nodeList
3385:                                        .item(i), omit));
3386:                            } catch (Exception e) {
3387:                                throw new JXTException(e.getMessage(),
3388:                                        startJXComment.location, e);
3389:                            }
3390:                        }
3391:                        char[] chars = new char[buf.length()];
3392:                        buf.getChars(0, chars.length, chars, 0);
3393:                        consumer.comment(chars, 0, chars.length);
3394:                        ev = startJXComment.endInstruction.next;
3395:                        continue;
3396:                    } else if (ev instanceof  EndCDATA) {
3397:                        consumer.endCDATA();
3398:                    } else if (ev instanceof  EndDTD) {
3399:                        consumer.endDTD();
3400:                    } else if (ev instanceof  EndEntity) {
3401:                        consumer.endEntity(((EndEntity) ev).name);
3402:                    } else if (ev instanceof  StartCDATA) {
3403:                        consumer.startCDATA();
3404:                    } else if (ev instanceof  StartDTD) {
3405:                        StartDTD startDTD = (StartDTD) ev;
3406:                        consumer.startDTD(startDTD.name, startDTD.publicId,
3407:                                startDTD.systemId);
3408:                    } else if (ev instanceof  StartEntity) {
3409:                        consumer.startEntity(((StartEntity) ev).name);
3410:                    } else if (ev instanceof  StartOut) {
3411:                        StartOut startOut = (StartOut) ev;
3412:                        Object val;
3413:                        try {
3414:                            val = getNode(startOut.compiledExpression,
3415:                                    jexlContext, jxpathContext,
3416:                                    startOut.lenient);
3417:                            if (val instanceof  Node) {
3418:                                executeDOM(consumer, jexlContext,
3419:                                        jxpathContext, (Node) val);
3420:                            } else if (val instanceof  NodeList) {
3421:                                NodeList nodeList = (NodeList) val;
3422:                                int len = nodeList.getLength();
3423:                                for (int i = 0; i < len; i++) {
3424:                                    Node n = nodeList.item(i);
3425:                                    executeDOM(consumer, jexlContext,
3426:                                            jxpathContext, n);
3427:                                }
3428:                            } else if (val instanceof  Node[]) {
3429:                                Node[] nodeList = (Node[]) val;
3430:                                int len = nodeList.length;
3431:                                for (int i = 0; i < len; i++) {
3432:                                    Node n = nodeList[i];
3433:                                    executeDOM(consumer, jexlContext,
3434:                                            jxpathContext, n);
3435:                                }
3436:                            } else if (val instanceof  XMLizable) {
3437:                                ((XMLizable) val).toSAX(new IncludeXMLConsumer(
3438:                                        consumer));
3439:                            } else {
3440:                                char[] ch = val == null ? ArrayUtils.EMPTY_CHAR_ARRAY
3441:                                        : val.toString().toCharArray();
3442:                                consumer.characters(ch, 0, ch.length);
3443:                            }
3444:                        } catch (Exception e) {
3445:                            throw new JXTException(e.getMessage(), ev.location,
3446:                                    e);
3447:                        }
3448:                    } else if (ev instanceof  StartTemplate) {
3449:                        // EMPTY
3450:                    } else if (ev instanceof  StartEval) {
3451:                        StartEval startEval = (StartEval) ev;
3452:                        JXTExpression expr = startEval.value;
3453:                        try {
3454:                            Object val = getNode(expr, jexlContext,
3455:                                    jxpathContext);
3456:                            if (!(val instanceof  StartElement)) {
3457:                                throw new Exception(
3458:                                        "macro invocation required instead of: "
3459:                                                + val);
3460:                            }
3461:                            StartElement call = (StartElement) val;
3462:                            execute(consumer, jexlContext, jxpathContext, call,
3463:                                    call.next, call.endElement);
3464:                        } catch (Exception exc) {
3465:                            throw new JXTException(exc.getMessage(),
3466:                                    ev.location, exc);
3467:                        }
3468:                        ev = startEval.endInstruction.next;
3469:                        continue;
3470:                    } else if (ev instanceof  StartEvalBody) {
3471:                        StartEvalBody startEval = (StartEvalBody) ev;
3472:                        try {
3473:                            execute(consumer, jexlContext, jxpathContext, null,
3474:                                    macroCall.next, macroCall.endElement);
3475:                        } catch (Exception exc) {
3476:                            throw new JXTException(exc.getMessage(),
3477:                                    ev.location, exc);
3478:                        }
3479:                        ev = startEval.endInstruction.next;
3480:                        continue;
3481:                    } else if (ev instanceof  StartDefine) {
3482:                        StartDefine startDefine = (StartDefine) ev;
3483:                        definitions.put(startDefine.qname, startDefine);
3484:                        ev = startDefine.endInstruction.next;
3485:                        continue;
3486:                    } else if (ev instanceof  StartImport) {
3487:                        StartImport startImport = (StartImport) ev;
3488:                        String uri;
3489:                        AttributeEvent e = startImport.uri;
3490:                        if (e instanceof  CopyAttribute) {
3491:                            CopyAttribute copy = (CopyAttribute) e;
3492:                            uri = copy.value;
3493:                        } else {
3494:                            StringBuffer buf = new StringBuffer();
3495:                            SubstituteAttribute substAttr = (SubstituteAttribute) e;
3496:                            Iterator i = substAttr.substitutions.iterator();
3497:                            while (i.hasNext()) {
3498:                                Subst subst = (Subst) i.next();
3499:                                if (subst instanceof  Literal) {
3500:                                    Literal lit = (Literal) subst;
3501:                                    buf.append(lit.value);
3502:                                } else if (subst instanceof  JXTExpression) {
3503:                                    JXTExpression expr = (JXTExpression) subst;
3504:                                    Object val;
3505:                                    try {
3506:                                        val = getValue(expr, jexlContext,
3507:                                                jxpathContext);
3508:                                    } catch (Exception exc) {
3509:                                        throw new JXTException(
3510:                                                exc.getMessage(), ev.location,
3511:                                                exc);
3512:                                    }
3513:                                    buf.append(val != null ? val.toString()
3514:                                            : "");
3515:                                }
3516:                            }
3517:                            uri = buf.toString();
3518:                        }
3519:                        Source input = null;
3520:                        StartDocument doc;
3521:                        try {
3522:                            input = resolver.resolveURI(uri);
3523:                            SourceValidity validity = null;
3524:                            synchronized (cache) {
3525:                                doc = (StartDocument) cache.get(input.getURI());
3526:                                if (doc != null) {
3527:                                    boolean recompile = false;
3528:                                    if (doc.compileTime == null) {
3529:                                        recompile = true;
3530:                                    } else {
3531:                                        int valid = doc.compileTime.isValid();
3532:                                        if (valid == SourceValidity.UNKNOWN) {
3533:                                            validity = input.getValidity();
3534:                                            valid = doc.compileTime
3535:                                                    .isValid(validity);
3536:                                        }
3537:                                        if (valid != SourceValidity.VALID) {
3538:                                            recompile = true;
3539:                                        }
3540:                                    }
3541:                                    if (recompile) {
3542:                                        doc = null; // recompile
3543:                                    }
3544:                                }
3545:                            }
3546:                            if (doc == null) {
3547:                                Parser parser = new Parser();
3548:                                // call getValidity before using the stream is faster if the source is a SitemapSource
3549:                                if (validity == null) {
3550:                                    validity = input.getValidity();
3551:                                }
3552:                                SourceUtil.parse(this .manager, input, parser);
3553:                                doc = parser.getStartEvent();
3554:                                doc.compileTime = validity;
3555:                                synchronized (cache) {
3556:                                    cache.put(input.getURI(), doc);
3557:                                }
3558:                            }
3559:                        } catch (Exception exc) {
3560:                            throw new JXTException(exc.getMessage(),
3561:                                    ev.location, exc);
3562:                        } finally {
3563:                            resolver.release(input);
3564:                        }
3565:                        JXPathContext selectJXPath = jxpathContext;
3566:                        MyJexlContext selectJexl = jexlContext;
3567:                        if (startImport.select != null) {
3568:                            try {
3569:                                Object obj = getValue(startImport.select,
3570:                                        jexlContext, jxpathContext);
3571:                                selectJXPath = jxpathContextFactory.newContext(
3572:                                        null, obj);
3573:                                selectJXPath
3574:                                        .setNamespaceContextPointer(new NamespacesTablePointer(
3575:                                                namespaces));
3576:                                selectJXPath.setVariables(variables);
3577:                                selectJexl = new MyJexlContext(jexlContext);
3578:                                fillContext(obj, selectJexl);
3579:                            } catch (Exception exc) {
3580:                                throw new JXTException(exc.getMessage(),
3581:                                        ev.location, exc);
3582:                            }
3583:                        }
3584:                        try {
3585:                            execute(consumer, selectJexl, selectJXPath,
3586:                                    macroCall, doc.next, doc.endDocument);
3587:                        } catch (Exception exc) {
3588:                            throw new JXTException(
3589:                                    "Exception occurred in imported template "
3590:                                            + uri + ": " + exc.getMessage(),
3591:                                    ev.location, exc);
3592:                        }
3593:                        ev = startImport.endInstruction.next;
3594:                        continue;
3595:                    } else if (ev instanceof  StartDocument) {
3596:                        if (((StartDocument) ev).endDocument != null) {
3597:                            // if this isn't a document fragment
3598:                            consumer.startDocument();
3599:                        }
3600:                    } else if (ev instanceof  EndDocument) {
3601:                        consumer.endDocument();
3602:                    } else if (ev instanceof  ProcessingInstruction) {
3603:                        ProcessingInstruction pi = (ProcessingInstruction) ev;
3604:                        consumer.processingInstruction(pi.target, pi.data);
3605:                    }
3606:                    ev = ev.next;
3607:                }
3608:            }
3609:
3610:            /* (non-Javadoc)
3611:             * @see org.apache.cocoon.caching.CacheableProcessingComponent#getKey()
3612:             */
3613:            public Serializable getKey() {
3614:                JXTExpression cacheKeyExpr = (JXTExpression) getCurrentTemplateProperty(CACHE_KEY);
3615:                try {
3616:                    final Serializable templateKey = (Serializable) getValue(
3617:                            cacheKeyExpr, globalJexlContext, jxpathContext);
3618:                    if (templateKey != null) {
3619:                        return new JXCacheKey(this .inputSource.getURI(),
3620:                                templateKey);
3621:                    }
3622:                } catch (Exception e) {
3623:                    getLogger().error("error evaluating cache key", e);
3624:                }
3625:                return null;
3626:            }
3627:
3628:            /* (non-Javadoc)
3629:             * @see org.apache.cocoon.caching.CacheableProcessingComponent#getValidity()
3630:             */
3631:            public SourceValidity getValidity() {
3632:                JXTExpression validityExpr = (JXTExpression) getCurrentTemplateProperty(VALIDITY);
3633:                try {
3634:                    final SourceValidity sourceValidity = this .inputSource
3635:                            .getValidity();
3636:                    final SourceValidity templateValidity = (SourceValidity) getValue(
3637:                            validityExpr, globalJexlContext, jxpathContext);
3638:                    if (sourceValidity != null && templateValidity != null) {
3639:                        return new JXSourceValidity(sourceValidity,
3640:                                templateValidity);
3641:                    }
3642:                } catch (Exception e) {
3643:                    getLogger().error("error evaluating cache validity", e);
3644:                }
3645:                return null;
3646:            }
3647:
3648:            private Object getCurrentTemplateProperty(String propertyName) {
3649:                final String uri = this .inputSource.getURI();
3650:                StartDocument startEvent;
3651:                synchronized (cache) {
3652:                    startEvent = (StartDocument) cache.get(uri);
3653:                }
3654:                return (startEvent != null) ? startEvent.templateProperties
3655:                        .get(propertyName) : null;
3656:            }
3657:
3658:            private NodeList toDOMNodeList(String elementName,
3659:                    StartInstruction si, MyJexlContext jexlContext,
3660:                    StartElement macroCall) throws SAXException {
3661:                DOMBuilder builder = new DOMBuilder();
3662:                builder.startDocument();
3663:                builder.startElement(NS, elementName, elementName, EMPTY_ATTRS);
3664:                execute(builder, jexlContext, jxpathContext, macroCall,
3665:                        si.next, si.endInstruction);
3666:                builder.endElement(NS, elementName, elementName);
3667:                builder.endDocument();
3668:                Node node = builder.getDocument().getDocumentElement();
3669:                return node.getChildNodes();
3670:            }
3671:
3672:            static final class JXCacheKey implements  Serializable {
3673:                private final String templateUri;
3674:                private final Serializable templateKey;
3675:
3676:                private JXCacheKey(String templateUri, Serializable templateKey) {
3677:                    this .templateUri = templateUri;
3678:                    this .templateKey = templateKey;
3679:                }
3680:
3681:                public int hashCode() {
3682:                    return templateUri.hashCode() + templateKey.hashCode();
3683:                }
3684:
3685:                public String toString() {
3686:                    return "TK:" + templateUri + "_" + templateKey;
3687:                }
3688:
3689:                public boolean equals(Object o) {
3690:                    if (o instanceof  JXCacheKey) {
3691:                        JXCacheKey jxck = (JXCacheKey) o;
3692:                        return this .templateUri.equals(jxck.templateUri)
3693:                                && this .templateKey.equals(jxck.templateKey);
3694:                    }
3695:                    return false;
3696:                }
3697:            }
3698:
3699:            static final class JXSourceValidity implements  SourceValidity,
3700:                    Serializable {
3701:                private final SourceValidity sourceValidity;
3702:                private final SourceValidity templateValidity;
3703:
3704:                private JXSourceValidity(SourceValidity sourceValidity,
3705:                        SourceValidity templateValidity) {
3706:                    this .sourceValidity = sourceValidity;
3707:                    this .templateValidity = templateValidity;
3708:                }
3709:
3710:                public int isValid() {
3711:                    switch (sourceValidity.isValid()) {
3712:                    case SourceValidity.INVALID:
3713:                        return SourceValidity.INVALID;
3714:
3715:                    case SourceValidity.UNKNOWN:
3716:                        if (templateValidity.isValid() == SourceValidity.INVALID) {
3717:                            return SourceValidity.INVALID;
3718:                        }
3719:                        return SourceValidity.UNKNOWN;
3720:
3721:                    case SourceValidity.VALID:
3722:                        return templateValidity.isValid();
3723:                    }
3724:
3725:                    return SourceValidity.UNKNOWN;
3726:                }
3727:
3728:                public int isValid(SourceValidity otherValidity) {
3729:                    if (otherValidity instanceof  JXSourceValidity) {
3730:                        JXSourceValidity otherJXValidity = (JXSourceValidity) otherValidity;
3731:                        switch (sourceValidity
3732:                                .isValid(otherJXValidity.sourceValidity)) {
3733:                        case SourceValidity.INVALID:
3734:                            return SourceValidity.INVALID;
3735:
3736:                        case SourceValidity.UNKNOWN:
3737:                            if (templateValidity
3738:                                    .isValid(otherJXValidity.templateValidity) == SourceValidity.INVALID) {
3739:                                return SourceValidity.INVALID;
3740:                            }
3741:                            return SourceValidity.UNKNOWN;
3742:
3743:                        case SourceValidity.VALID:
3744:                            return templateValidity
3745:                                    .isValid(otherJXValidity.templateValidity);
3746:                        }
3747:                    }
3748:                    return SourceValidity.UNKNOWN;
3749:                }
3750:            }
3751:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.