Source Code Cross Referenced for UiEngineImpl.java in  » Ajax » zk » org » zkoss » zk » ui » impl » 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 » Ajax » zk » org.zkoss.zk.ui.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* UiEngineImpl.java
0002:
0003:        {{IS_NOTE
0004:        	Purpose:
0005:        		
0006:        	Description:
0007:        		
0008:        	History:
0009:        		Thu Jun  9 13:05:28     2005, Created by tomyeh
0010:        }}IS_NOTE
0011:
0012:        Copyright (C) 2005 Potix Corporation. All Rights Reserved.
0013:
0014:        {{IS_RIGHT
0015:        	This program is distributed under GPL Version 2.0 in the hope that
0016:        	it will be useful, but WITHOUT ANY WARRANTY.
0017:        }}IS_RIGHT
0018:         */
0019:        package org.zkoss.zk.ui.impl;
0020:
0021:        import java.util.Iterator;
0022:        import java.util.Map;
0023:        import java.util.HashMap;
0024:        import java.util.LinkedHashMap;
0025:        import java.util.IdentityHashMap;
0026:        import java.util.Set;
0027:        import java.util.HashSet;
0028:        import java.util.List;
0029:        import java.util.LinkedList;
0030:        import java.util.Collections;
0031:        import java.util.Collection;
0032:        import java.io.Writer;
0033:        import java.io.IOException;
0034:
0035:        import org.zkoss.lang.D;
0036:        import org.zkoss.lang.Classes;
0037:        import org.zkoss.lang.Objects;
0038:        import org.zkoss.lang.Threads;
0039:        import org.zkoss.lang.Exceptions;
0040:        import org.zkoss.lang.Expectable;
0041:        import org.zkoss.mesg.Messages;
0042:        import org.zkoss.util.logging.Log;
0043:
0044:        import org.zkoss.zk.mesg.MZk;
0045:        import org.zkoss.zk.ui.*;
0046:        import org.zkoss.zk.ui.sys.*;
0047:        import org.zkoss.zk.ui.event.*;
0048:        import org.zkoss.zk.ui.metainfo.*;
0049:        import org.zkoss.zk.ui.ext.AfterCompose;
0050:        import org.zkoss.zk.ui.ext.Native;
0051:        import org.zkoss.zk.ui.util.*;
0052:        import org.zkoss.zk.scripting.*;
0053:        import org.zkoss.zk.au.*;
0054:        import org.zkoss.zk.au.out.*;
0055:
0056:        /**
0057:         * An implementation of {@link UiEngine}.
0058:         *
0059:         * @author tomyeh
0060:         */
0061:        public class UiEngineImpl implements  UiEngine {
0062:            private static final Log log = Log.lookup(UiEngineImpl.class);
0063:
0064:            /** The Web application this engine belongs to. */
0065:            private WebApp _wapp;
0066:            /** A pool of idle EventProcessingThreadImpl. */
0067:            private final List _idles = new LinkedList();
0068:            /** A map of suspended processing:
0069:             * (Desktop desktop, IdentityHashMap(Object mutex, List(EventProcessingThreadImpl)).
0070:             */
0071:            private final Map _suspended = new HashMap();
0072:            /** A map of resumed processing
0073:             * (Desktop desktop, List(EventProcessingThreadImpl)).
0074:             */
0075:            private final Map _resumed = new HashMap();
0076:            /** # of suspended event processing threads.
0077:             */
0078:            private int _suspCnt;
0079:
0080:            public UiEngineImpl() {
0081:            }
0082:
0083:            //-- UiEngine --//
0084:            public void start(WebApp wapp) {
0085:                _wapp = wapp;
0086:            }
0087:
0088:            public void stop(WebApp wapp) {
0089:                synchronized (_idles) {
0090:                    for (Iterator it = _idles.iterator(); it.hasNext();)
0091:                        ((EventProcessingThreadImpl) it.next())
0092:                                .cease("Stop application");
0093:                    _idles.clear();
0094:                }
0095:
0096:                synchronized (_suspended) {
0097:                    for (Iterator it = _suspended.values().iterator(); it
0098:                            .hasNext();) {
0099:                        final Map map = (Map) it.next();
0100:                        synchronized (map) {
0101:                            for (Iterator i2 = map.values().iterator(); i2
0102:                                    .hasNext();) {
0103:                                final List list = (List) i2.next();
0104:                                for (Iterator i3 = list.iterator(); i3
0105:                                        .hasNext();)
0106:                                    ((EventProcessingThreadImpl) i3.next())
0107:                                            .cease("Stop application");
0108:                            }
0109:                        }
0110:                    }
0111:                    _suspended.clear();
0112:                }
0113:                synchronized (_resumed) {
0114:                    for (Iterator it = _resumed.values().iterator(); it
0115:                            .hasNext();) {
0116:                        final List list = (List) it.next();
0117:                        synchronized (list) {
0118:                            for (Iterator i2 = list.iterator(); i2.hasNext();)
0119:                                ((EventProcessingThreadImpl) i2.next())
0120:                                        .cease("Stop application");
0121:                        }
0122:                    }
0123:                    _resumed.clear();
0124:                }
0125:            }
0126:
0127:            public boolean hasSuspendedThread() {
0128:                if (!_suspended.isEmpty()) {
0129:                    synchronized (_suspended) {
0130:                        for (Iterator it = _suspended.values().iterator(); it
0131:                                .hasNext();) {
0132:                            final Map map = (Map) it.next();
0133:                            if (!map.isEmpty())
0134:                                return true;
0135:                        }
0136:                    }
0137:                }
0138:                return false;
0139:            }
0140:
0141:            public Collection getSuspendedThreads(Desktop desktop) {
0142:                final Map map;
0143:                synchronized (_suspended) {
0144:                    map = (Map) _suspended.get(desktop);
0145:                }
0146:                return map == null || map.isEmpty() ? Collections.EMPTY_LIST
0147:                        : Collections.synchronizedMap(map).values();
0148:            }
0149:
0150:            public boolean ceaseSuspendedThread(Desktop desktop,
0151:                    EventProcessingThread evtthd, String cause) {
0152:                final Map map;
0153:                synchronized (_suspended) {
0154:                    map = (Map) _suspended.get(desktop);
0155:                }
0156:                if (map == null)
0157:                    return false;
0158:
0159:                boolean found = false;
0160:                synchronized (map) {
0161:                    for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
0162:                        final Map.Entry me = (Map.Entry) it.next();
0163:                        final List list = (List) me.getValue();
0164:                        found = list.remove(evtthd); //found
0165:                        if (found) {
0166:                            if (list.isEmpty())
0167:                                it.remove(); //(mutex, list) no longer useful
0168:                            break; //DONE
0169:                        }
0170:                    }
0171:                }
0172:                if (found)
0173:                    ((EventProcessingThreadImpl) evtthd).cease(cause);
0174:                return found;
0175:            }
0176:
0177:            public void desktopDestroyed(Desktop desktop) {
0178:                //		if (log.debugable()) log.debug("destroy "+desktop);
0179:
0180:                final Configuration conf = _wapp.getConfiguration();
0181:                final Map map;
0182:                synchronized (_suspended) {
0183:                    map = (Map) _suspended.remove(desktop);
0184:                }
0185:                if (map != null) {
0186:                    synchronized (map) {
0187:                        for (Iterator it = map.values().iterator(); it
0188:                                .hasNext();) {
0189:                            final List list = (List) it.next();
0190:                            for (Iterator i2 = list.iterator(); i2.hasNext();) {
0191:                                final EventProcessingThreadImpl evtthd = (EventProcessingThreadImpl) i2
0192:                                        .next();
0193:                                evtthd.ceaseSilently("Destroy desktop "
0194:                                        + desktop);
0195:                                conf.invokeEventThreadResumeAborts(evtthd
0196:                                        .getComponent(), evtthd.getEvent());
0197:                            }
0198:                        }
0199:                    }
0200:                }
0201:
0202:                final List list;
0203:                synchronized (_resumed) {
0204:                    list = (List) _resumed.remove(desktop);
0205:                }
0206:                if (list != null) {
0207:                    synchronized (list) {
0208:                        for (Iterator it = list.iterator(); it.hasNext();) {
0209:                            final EventProcessingThreadImpl evtthd = (EventProcessingThreadImpl) it
0210:                                    .next();
0211:                            evtthd.ceaseSilently("Destroy desktop " + desktop);
0212:                            conf.invokeEventThreadResumeAborts(evtthd
0213:                                    .getComponent(), evtthd.getEvent());
0214:                        }
0215:                    }
0216:                }
0217:
0218:                ((DesktopCtrl) desktop).destroy();
0219:            }
0220:
0221:            private static UiVisualizer getCurrentVisualizer() {
0222:                final ExecutionCtrl execCtrl = ExecutionsCtrl.getCurrentCtrl();
0223:                if (execCtrl == null)
0224:                    throw new IllegalStateException(
0225:                            "Components can be accessed only in event listeners");
0226:                return (UiVisualizer) execCtrl.getVisualizer();
0227:            }
0228:
0229:            public void pushOwner(Component comp) {
0230:                getCurrentVisualizer().pushOwner(comp);
0231:            }
0232:
0233:            public void popOwner() {
0234:                getCurrentVisualizer().popOwner();
0235:            }
0236:
0237:            public void addInvalidate(Page page) {
0238:                if (page == null)
0239:                    throw new IllegalArgumentException();
0240:                getCurrentVisualizer().addInvalidate(page);
0241:            }
0242:
0243:            public void addInvalidate(Component comp) {
0244:                if (comp == null)
0245:                    throw new IllegalArgumentException();
0246:                getCurrentVisualizer().addInvalidate(comp);
0247:            }
0248:
0249:            public void addSmartUpdate(Component comp, String attr, String value) {
0250:                if (comp == null)
0251:                    throw new IllegalArgumentException();
0252:                getCurrentVisualizer().addSmartUpdate(comp, attr, value);
0253:            }
0254:
0255:            public void addSmartUpdate(Component comp, String attr,
0256:                    DeferredValue value) {
0257:                if (comp == null)
0258:                    throw new IllegalArgumentException();
0259:                getCurrentVisualizer().addSmartUpdate(comp, attr, value);
0260:            }
0261:
0262:            public void addResponse(String key, AuResponse response) {
0263:                getCurrentVisualizer().addResponse(key, response);
0264:            }
0265:
0266:            public void addMoved(Component comp, Component oldparent,
0267:                    Page oldpg, Page newpg) {
0268:                if (comp == null)
0269:                    throw new IllegalArgumentException();
0270:                getCurrentVisualizer().addMoved(comp, oldparent, oldpg, newpg);
0271:            }
0272:
0273:            /** Called before changing the component's UUID.
0274:             *
0275:             * @param addOnlyMoved if true, it is added only if it was moved
0276:             * before (see {@link #addMoved}).
0277:             */
0278:            public void addUuidChanged(Component comp, boolean addOnlyMoved) {
0279:                if (comp == null)
0280:                    throw new IllegalArgumentException();
0281:                getCurrentVisualizer().addUuidChanged(comp, addOnlyMoved);
0282:            }
0283:
0284:            //-- Creating a new page --//
0285:            public void execNewPage(Execution exec, Richlet richlet, Page page,
0286:                    Writer out) throws IOException {
0287:                execNewPage0(exec, null, richlet, page, out);
0288:            }
0289:
0290:            public void execNewPage(Execution exec, PageDefinition pagedef,
0291:                    Page page, Writer out) throws IOException {
0292:                execNewPage0(exec, pagedef, null, page, out);
0293:            }
0294:
0295:            /** It assumes exactly one of pagedef and richlet is not null.
0296:             */
0297:            public void execNewPage0(final Execution exec,
0298:                    final PageDefinition pagedef, final Richlet richlet,
0299:                    final Page page, final Writer out) throws IOException {
0300:                //Update the device type first. If this is the second page and not
0301:                //belonging to the same device type, an exception is thrown
0302:                final Desktop desktop = exec.getDesktop();
0303:                final LanguageDefinition langdef = //default page
0304:                pagedef != null ? pagedef.getLanguageDefinition()
0305:                        : richlet != null ? richlet.getLanguageDefinition()
0306:                                : null;
0307:                if (langdef != null)
0308:                    desktop.setDeviceType(langdef.getDeviceType()); //set and check!
0309:
0310:                //It is possible this method is invoked when processing other exec
0311:                final Execution oldexec = Executions.getCurrent();
0312:                final ExecutionCtrl oldexecCtrl = (ExecutionCtrl) oldexec;
0313:                final UiVisualizer olduv = oldexecCtrl != null ? (UiVisualizer) oldexecCtrl
0314:                        .getVisualizer()
0315:                        : null;
0316:
0317:                final UiVisualizer uv;
0318:                if (olduv != null)
0319:                    uv = doReactivate(exec, olduv);
0320:                else
0321:                    uv = doActivate(exec, null, false);
0322:
0323:                final ExecutionCtrl execCtrl = (ExecutionCtrl) exec;
0324:                final Page old = execCtrl.getCurrentPage();
0325:                final PageDefinition olddef = execCtrl
0326:                        .getCurrentPageDefinition();
0327:                execCtrl.setCurrentPage(page);
0328:                execCtrl.setCurrentPageDefinition(pagedef);
0329:
0330:                final Configuration config = _wapp.getConfiguration();
0331:                AbortingReason abrn = null;
0332:                boolean cleaned = false;
0333:                try {
0334:                    config.invokeExecutionInits(exec, oldexec);
0335:
0336:                    if (olduv != null) {
0337:                        final Component owner = olduv.getOwner();
0338:                        if (owner != null) {
0339:                            ((PageCtrl) page).setOwner(owner);
0340:                            //					if (D.ON && log.finerable()) log.finer("Set owner of "+page+" to "+owner);
0341:                        }
0342:                    }
0343:
0344:                    //Cycle 1: Creates all components
0345:
0346:                    //Note:
0347:                    //1) stylesheet, tablib are inited in Page's contructor
0348:                    //2) we add variable resolvers before init because
0349:                    //init's zscirpt might depend on it.
0350:                    if (pagedef != null) {
0351:                        pagedef.initXelContext(page);
0352:
0353:                        final Initiators inits = Initiators.doInit(pagedef,
0354:                                page);
0355:                        try {
0356:                            //Request 1472813: sendRedirect in init; test: sendRedirectNow.zul
0357:                            pagedef.init(page, !uv.isEverAsyncUpdate()
0358:                                    && !uv.isAborting());
0359:
0360:                            final Component[] comps;
0361:                            final String uri = pagedef.getForwardURI(page);
0362:                            if (uri != null) {
0363:                                comps = new Component[0];
0364:                                exec.forward(uri);
0365:                            } else {
0366:                                comps = uv.isAborting() || exec.isVoided() ? null
0367:                                        : execCreate(new CreateInfo(
0368:                                                ((WebAppCtrl) _wapp)
0369:                                                        .getUiFactory(), exec,
0370:                                                page), pagedef, null);
0371:                            }
0372:
0373:                            inits.doAfterCompose(page, comps);
0374:                        } catch (Throwable ex) {
0375:                            if (!inits.doCatch(ex))
0376:                                throw UiException.Aide.wrap(ex);
0377:                        } finally {
0378:                            inits.doFinally();
0379:                        }
0380:                    } else {
0381:                        //FUTURE: a way to allow richlet to set page ID
0382:                        ((PageCtrl) page).init(new PageConfig() {
0383:                            public String getId() {
0384:                                return null;
0385:                            }
0386:
0387:                            public String getUuid() {
0388:                                return null;
0389:                            }
0390:
0391:                            public String getTitle() {
0392:                                return null;
0393:                            }
0394:
0395:                            public String getStyle() {
0396:                                return null;
0397:                            }
0398:
0399:                            public String getHeaders() {
0400:                                return null;
0401:                            }
0402:
0403:                            public String getRootAttributes() {
0404:                                return null;
0405:                            }
0406:
0407:                            public String getContentType() {
0408:                                return null;
0409:                            }
0410:
0411:                            public String getDocType() {
0412:                                return null;
0413:                            }
0414:
0415:                            public String getFirstLine() {
0416:                                return null;
0417:                            }
0418:
0419:                            public Boolean getCacheable() {
0420:                                return null;
0421:                            }
0422:                        });
0423:                        richlet.service(page);
0424:                    }
0425:                    if (exec.isVoided())
0426:                        return; //don't generate any output
0427:
0428:                    //Cycle 2: process pending events
0429:                    //Unlike execUpdate, execution is aborted here if any exception
0430:                    Event event = nextEvent(uv);
0431:                    do {
0432:                        for (; event != null; event = nextEvent(uv))
0433:                            process(desktop, event);
0434:                        resumeAll(desktop, uv, null);
0435:                    } while ((event = nextEvent(uv)) != null);
0436:
0437:                    //Cycle 2a: Handle aborting reason
0438:                    abrn = uv.getAbortingReason();
0439:                    if (abrn != null)
0440:                        abrn.execute(); //always execute even if !isAborting
0441:
0442:                    //Cycle 3: Redraw the page (and responses)
0443:                    List responses = uv.getResponses();
0444:
0445:                    if (olduv != null && olduv.addToFirstAsyncUpdate(responses))
0446:                        responses = null;
0447:                    //A new ZK page might be included by an async update
0448:                    //(example: ZUL's include).
0449:                    //If so, we cannot generate the responses in the page.
0450:                    //Rather, we shall add them to the async update.
0451:
0452:                    ((PageCtrl) page).redraw(responses, out);
0453:                } catch (Throwable ex) {
0454:                    cleaned = true;
0455:                    final List errs = new LinkedList();
0456:                    errs.add(ex);
0457:                    config.invokeExecutionCleanups(exec, oldexec, errs);
0458:                    //CONSIDER: whether to pass cleanup's error to users
0459:
0460:                    if (!errs.isEmpty()) {
0461:                        ex = (Throwable) errs.get(0);
0462:                        if (ex instanceof  IOException)
0463:                            throw (IOException) ex;
0464:                        throw UiException.Aide.wrap(ex);
0465:                    }
0466:                } finally {
0467:                    if (!cleaned)
0468:                        config.invokeExecutionCleanups(exec, oldexec, null);
0469:                    //CONSIDER: whether to pass cleanup's error to users
0470:                    if (abrn != null) {
0471:                        try {
0472:                            abrn.finish();
0473:                        } catch (Throwable t) {
0474:                            log.warning(t);
0475:                        }
0476:                    }
0477:
0478:                    execCtrl.setCurrentPage(old); //restore it
0479:                    execCtrl.setCurrentPageDefinition(olddef); //restore it
0480:
0481:                    if (olduv != null)
0482:                        doDereactivate(exec, olduv);
0483:                    else
0484:                        doDeactivate(exec);
0485:                }
0486:            }
0487:
0488:            private static final Event nextEvent(UiVisualizer uv) {
0489:                final Event evt = ((ExecutionCtrl) uv.getExecution())
0490:                        .getNextEvent();
0491:                return evt != null && !uv.isAborting() ? evt : null;
0492:            }
0493:
0494:            /** Cycle 1:
0495:             * Creates all child components defined in the specified definition.
0496:             * @return the first component being created.
0497:             */
0498:            private static final Component[] execCreate(CreateInfo ci,
0499:                    NodeInfo parentInfo, Component parent) throws IOException {
0500:                if (parentInfo instanceof  ComponentInfo) {
0501:                    final ComponentInfo pi = (ComponentInfo) parentInfo;
0502:                    final String fulfill = pi.getFulfill();
0503:                    if (fulfill != null && fulfill.length() > 0) { //defer the creation of children
0504:                        new FulfillListener(fulfill, pi, parent);
0505:                        return new Component[0];
0506:                    }
0507:                }
0508:                return execCreate0(ci, parentInfo, parent);
0509:            }
0510:
0511:            private static final Component[] execCreate0(CreateInfo ci,
0512:                    NodeInfo parentInfo, Component parent) throws IOException {
0513:                final List created = new LinkedList();
0514:                final Page page = ci.page;
0515:                final PageDefinition pagedef = parentInfo.getPageDefinition();
0516:                //note: don't use page.getDefinition because createComponents
0517:                //might be called from a page other than instance's
0518:                for (Iterator it = parentInfo.getChildren().iterator(); it
0519:                        .hasNext();) {
0520:                    final Object meta = it.next();
0521:                    if (meta instanceof  ComponentInfo) {
0522:                        final ComponentInfo childInfo = (ComponentInfo) meta;
0523:                        final ForEach forEach = childInfo.getForEach(page,
0524:                                parent);
0525:                        if (forEach == null) {
0526:                            if (isEffective(childInfo, page, parent)) {
0527:                                final Component[] children = execCreateChild(
0528:                                        ci, parent, childInfo);
0529:                                for (int j = 0; j < children.length; ++j)
0530:                                    created.add(children[j]);
0531:                            }
0532:                        } else {
0533:                            while (forEach.next()) {
0534:                                if (isEffective(childInfo, page, parent)) {
0535:                                    final Component[] children = execCreateChild(
0536:                                            ci, parent, childInfo);
0537:                                    for (int j = 0; j < children.length; ++j)
0538:                                        created.add(children[j]);
0539:                                }
0540:                            }
0541:                        }
0542:                    } else if (meta instanceof  TextInfo) {
0543:                        //parent must be a native component
0544:                        final String s = ((TextInfo) meta).getValue(parent);
0545:                        if (s != null && s.length() > 0)
0546:                            parent.appendChild(((Native) parent).getHelper()
0547:                                    .newNative(s));
0548:                    } else {
0549:                        execNonComponent(ci, parent, meta);
0550:                    }
0551:                }
0552:                return (Component[]) created.toArray(new Component[created
0553:                        .size()]);
0554:            }
0555:
0556:            private static Component[] execCreateChild(CreateInfo ci,
0557:                    Component parent, ComponentInfo childInfo)
0558:                    throws IOException {
0559:                final ComponentDefinition childdef = childInfo
0560:                        .getComponentDefinition();
0561:                if (ComponentDefinition.ZK == childdef) {
0562:                    return execCreate(ci, childInfo, parent);
0563:                } else if (childdef.isInlineMacro()) {
0564:                    final Map props = new HashMap();
0565:                    props.put("includer", parent);
0566:                    childInfo.evalProperties(props, ci.page, parent, true);
0567:                    return new Component[] { ci.exec.createComponents(childdef
0568:                            .getMacroURI(), parent, props) };
0569:                } else {
0570:                    final Component child = execCreateChild0(ci, parent,
0571:                            childInfo);
0572:                    return child != null ? new Component[] { child }
0573:                            : new Component[0];
0574:                }
0575:            }
0576:
0577:            private static Component execCreateChild0(CreateInfo ci,
0578:                    Component parent, ComponentInfo childInfo)
0579:                    throws IOException {
0580:                final Composer composer = childInfo
0581:                        .getComposer(ci.page, parent);
0582:                final ComposerExt composerExt = composer instanceof  ComposerExt ? (ComposerExt) composer
0583:                        : null;
0584:                Component child = null;
0585:                try {
0586:                    if (composerExt != null) {
0587:                        childInfo = composerExt.doBeforeCompose(ci.page,
0588:                                parent, childInfo);
0589:                        if (childInfo == null)
0590:                            return null;
0591:                    }
0592:
0593:                    child = ci.uf.newComponent(ci.page, parent, childInfo);
0594:
0595:                    final boolean bNative = childInfo instanceof  NativeInfo;
0596:                    if (bNative)
0597:                        setProlog(ci, child, (NativeInfo) childInfo);
0598:
0599:                    if (composerExt != null)
0600:                        composerExt.doBeforeComposeChildren(child);
0601:
0602:                    execCreate(ci, childInfo, child); //recursive
0603:
0604:                    if (bNative)
0605:                        setEpilog(ci, child, (NativeInfo) childInfo);
0606:
0607:                    if (child instanceof  AfterCompose)
0608:                        ((AfterCompose) child).afterCompose();
0609:                    if (composer != null)
0610:                        composer.doAfterCompose(child);
0611:
0612:                    ComponentsCtrl.applyForward(child, childInfo.getForward());
0613:                    //applies the forward condition
0614:                    //1) we did it after all child created, so it may reference
0615:                    //to it child (thought rarely happens)
0616:                    //2) we did it after afterCompose, so what specified
0617:                    //here has higher priority than class defined by app dev
0618:
0619:                    if (Events.isListened(child, Events.ON_CREATE, false))
0620:                        Events.postEvent(new CreateEvent(Events.ON_CREATE,
0621:                                child, ci.exec.getArg()));
0622:
0623:                    return child;
0624:                } catch (Throwable ex) {
0625:                    boolean ignore = false;
0626:                    if (composerExt != null) {
0627:                        try {
0628:                            ignore = composerExt.doCatch(ex);
0629:                        } catch (Throwable t) {
0630:                            log.error("Failed to invoke doCatch for "
0631:                                    + childInfo, t);
0632:                        }
0633:                    }
0634:                    if (!ignore)
0635:                        throw UiException.Aide.wrap(ex);
0636:
0637:                    return child != null && child.getPage() != null ? child
0638:                            : null;
0639:                    //return child only if attached successfully
0640:                } finally {
0641:                    if (composerExt != null) {
0642:                        try {
0643:                            composerExt.doFinally();
0644:                        } catch (Throwable ex) {
0645:                            throw UiException.Aide.wrap(ex);
0646:                        }
0647:                    }
0648:                }
0649:            }
0650:
0651:            /** Executes a non-component object, such as ZScript, AttributesInfo...
0652:             */
0653:            private static final void execNonComponent(CreateInfo ci,
0654:                    Component comp, Object meta) {
0655:                final Page page = ci.page;
0656:                if (meta instanceof  ZScript) {
0657:                    final ZScript zscript = (ZScript) meta;
0658:                    if (zscript.isDeferred()) {
0659:                        ((PageCtrl) page).addDeferredZScript(comp, zscript);
0660:                        //isEffective is handled later
0661:                    } else if (isEffective(zscript, page, comp)) {
0662:                        final Map backup = new HashMap();
0663:                        final Namespace ns = comp != null ? Namespaces
0664:                                .beforeInterpret(backup, comp, false)
0665:                                : Namespaces.beforeInterpret(backup, page,
0666:                                        false);
0667:                        try {
0668:                            page.interpret(zscript.getLanguage(), zscript
0669:                                    .getContent(page, comp), ns);
0670:                        } finally {
0671:                            Namespaces.afterInterpret(backup, ns, false);
0672:                        }
0673:                    }
0674:                } else if (meta instanceof  AttributesInfo) {
0675:                    final AttributesInfo attrs = (AttributesInfo) meta;
0676:                    if (comp != null)
0677:                        attrs.apply(comp); //it handles isEffective
0678:                    else
0679:                        attrs.apply(page);
0680:                } else if (meta instanceof  VariablesInfo) {
0681:                    final VariablesInfo vars = (VariablesInfo) meta;
0682:                    if (comp != null)
0683:                        vars.apply(comp); //it handles isEffective
0684:                    else
0685:                        vars.apply(page);
0686:                } else {
0687:                    throw new IllegalStateException("Unknown metainfo: " + meta);
0688:                }
0689:            }
0690:
0691:            private static final boolean isEffective(Condition cond, Page page,
0692:                    Component comp) {
0693:                return comp != null ? cond.isEffective(comp) : cond
0694:                        .isEffective(page);
0695:            }
0696:
0697:            public Component[] createComponents(Execution exec,
0698:                    PageDefinition pagedef, Page page, Component parent, Map arg) {
0699:                if (pagedef == null)
0700:                    throw new IllegalArgumentException("pagedef");
0701:                if (parent != null) {
0702:                    if (parent.getPage() != null)
0703:                        page = parent.getPage();
0704:                } else if (page != null) {
0705:                    parent = ((PageCtrl) page).getDefaultParent();
0706:                }
0707:                if (page == null)
0708:                    page = getCurrentPage(exec);
0709:
0710:                final ExecutionCtrl execCtrl = (ExecutionCtrl) exec;
0711:                if (!execCtrl.isActivated())
0712:                    throw new IllegalStateException("Not activated yet");
0713:
0714:                final Page old = execCtrl.getCurrentPage();
0715:                final PageDefinition olddef = execCtrl
0716:                        .getCurrentPageDefinition();
0717:                if (page != null && page != old)
0718:                    execCtrl.setCurrentPage(page);
0719:                execCtrl.setCurrentPageDefinition(pagedef);
0720:                exec.pushArg(arg != null ? arg : Collections.EMPTY_MAP);
0721:
0722:                //Note: we add taglib, stylesheets and var-resolvers to the page
0723:                //it might cause name pollution but we got no choice since they
0724:                //are used as long as components created by this method are alive
0725:                if (page != null)
0726:                    pagedef.initXelContext(page);
0727:
0728:                //Note: the forward directives are ignore in this case
0729:
0730:                final Initiators inits = Initiators.doInit(pagedef, page);
0731:                try {
0732:                    final Component[] comps = execCreate(new CreateInfo(
0733:                            ((WebAppCtrl) exec.getDesktop().getWebApp())
0734:                                    .getUiFactory(), exec, page), pagedef,
0735:                            parent);
0736:                    inits.doAfterCompose(page, comps);
0737:                    return comps;
0738:                } catch (Throwable ex) {
0739:                    inits.doCatch(ex);
0740:                    throw UiException.Aide.wrap(ex);
0741:                } finally {
0742:                    exec.popArg();
0743:                    execCtrl.setCurrentPage(old); //restore it
0744:                    execCtrl.setCurrentPageDefinition(olddef); //restore it
0745:
0746:                    inits.doFinally();
0747:                }
0748:            }
0749:
0750:            public void sendRedirect(String uri, String target) {
0751:                if (uri != null && uri.length() == 0)
0752:                    uri = null;
0753:                final UiVisualizer uv = getCurrentVisualizer();
0754:                uv.setAbortingReason(new AbortBySendRedirect(uri != null ? uv
0755:                        .getExecution().encodeURL(uri) : "", target));
0756:            }
0757:
0758:            public void setAbortingReason(AbortingReason aborting) {
0759:                final UiVisualizer uv = getCurrentVisualizer();
0760:                uv.setAbortingReason(aborting);
0761:            }
0762:
0763:            //-- Recovering desktop --//
0764:            public void execRecover(Execution exec, FailoverManager failover) {
0765:                final Desktop desktop = exec.getDesktop();
0766:                final Session sess = desktop.getSession();
0767:
0768:                doActivate(exec, null, true); //it must not return null
0769:                try {
0770:                    failover.recover(sess, exec, desktop);
0771:                } finally {
0772:                    doDeactivate(exec);
0773:                }
0774:            }
0775:
0776:            //-- Asynchronous updates --//
0777:            public void execUpdate(Execution exec, List requests, AuWriter out)
0778:                    throws IOException {
0779:                execUpdate(exec, requests, null, out);
0780:            }
0781:
0782:            public Collection execUpdate(Execution exec, List requests,
0783:                    String reqId, AuWriter out) throws IOException {
0784:                if (requests == null)
0785:                    throw new IllegalArgumentException("null requests");
0786:                assert D.OFF || ExecutionsCtrl.getCurrentCtrl() == null : "Impossible to re-activate for update: old="
0787:                        + ExecutionsCtrl.getCurrentCtrl()
0788:                        + ", new="
0789:                        + exec
0790:                        + ", reqs=" + requests;
0791:
0792:                final UiVisualizer uv = doActivate(exec, requests, false);
0793:                if (uv == null)
0794:                    return null; //done (request is added to the exec currently activated)
0795:
0796:                final Desktop desktop = exec.getDesktop();
0797:                final Configuration config = desktop.getWebApp()
0798:                        .getConfiguration();
0799:                final Monitor monitor = config.getMonitor();
0800:                if (monitor != null) {
0801:                    try {
0802:                        monitor.beforeUpdate(desktop, requests);
0803:                    } catch (Throwable ex) {
0804:                        log.error(ex);
0805:                    }
0806:                }
0807:
0808:                Collection doneReqIds = null; //request IDs that have been processed
0809:                AbortingReason abrn = null;
0810:                boolean cleaned = false;
0811:                try {
0812:                    config.invokeExecutionInits(exec, null);
0813:                    final RequestQueue rque = ((DesktopCtrl) desktop)
0814:                            .getRequestQueue();
0815:                    if (reqId != null)
0816:                        rque.addRequestId(reqId);
0817:
0818:                    final List errs = new LinkedList();
0819:                    final long tmexpired = System.currentTimeMillis()
0820:                            + config.getMaxProcessTime();
0821:                    //Tom Yeh: 20060120
0822:                    //Don't process all requests if this thread has processed
0823:                    //a while. Thus, user could see the response sooner.
0824:                    for (AuRequest request; System.currentTimeMillis() < tmexpired
0825:                            && (request = rque.nextRequest()) != null;) {
0826:                        //Cycle 1: Process one request
0827:                        //Don't process more such that requests will be queued
0828:                        //adn we have the chance to optimize them
0829:                        try {
0830:                            process(exec, request, !errs.isEmpty());
0831:                        } catch (ComponentNotFoundException ex) {
0832:                            //possible because the previous might remove some comp
0833:                            //so ignore it
0834:                            //					if (log.finable()) log.fine("Component not found: "+request);
0835:                        } catch (Throwable ex) {
0836:                            handleError(ex, uv, errs);
0837:                            //we don't skip request to avoid mis-match between c/s
0838:                        }
0839:
0840:                        //Cycle 2: Process any pending events posted by components
0841:                        Event event = nextEvent(uv);
0842:                        do {
0843:                            for (; event != null; event = nextEvent(uv)) {
0844:                                try {
0845:                                    process(desktop, event);
0846:                                } catch (Throwable ex) {
0847:                                    handleError(ex, uv, errs);
0848:                                    break; //skip the rest of events! 
0849:                                }
0850:                            }
0851:
0852:                            resumeAll(desktop, uv, errs);
0853:                        } while ((event = nextEvent(uv)) != null);
0854:                    }
0855:
0856:                    //Cycle 2a: Handle aborting reason
0857:                    abrn = uv.getAbortingReason();
0858:                    if (abrn != null)
0859:                        abrn.execute(); //always execute even if !isAborting
0860:
0861:                    //Cycle 3: Generate output
0862:                    List responses;
0863:                    try {
0864:                        //Note: we have to call visualizeErrors before uv.getResponses,
0865:                        //since it might create/update components
0866:                        if (!errs.isEmpty())
0867:                            visualizeErrors(exec, uv, errs);
0868:
0869:                        responses = uv.getResponses();
0870:                    } catch (Throwable ex) {
0871:                        responses = new LinkedList();
0872:                        responses.add(new AuAlert(Exceptions.getMessage(ex)));
0873:
0874:                        log.error(ex);
0875:                    }
0876:
0877:                    if (rque.endWithRequest()) //stop accept another request
0878:                        responses.add(new AuEcho(desktop)); //ask client to echo if any pending
0879:                    else
0880:                        doneReqIds = rque.clearRequestIds();
0881:
0882:                    out.writeSequenceId(desktop);
0883:                    out.write(responses);
0884:
0885:                    //			if (log.debugable())
0886:                    //				if (responses.size() < 5 || log.finerable()) log.finer("Responses: "+responses);
0887:                    //				else log.debug("Responses: "+responses.subList(0, 5)+"...");
0888:
0889:                    cleaned = true;
0890:                    config.invokeExecutionCleanups(exec, null, errs);
0891:                } catch (Throwable ex) {
0892:                    if (!cleaned) {
0893:                        cleaned = true;
0894:                        final List errs = new LinkedList();
0895:                        errs.add(ex);
0896:                        config.invokeExecutionCleanups(exec, null, errs);
0897:                        ex = errs.isEmpty() ? null : (Throwable) errs.get(0);
0898:                    }
0899:
0900:                    if (ex != null) {
0901:                        if (ex instanceof  IOException)
0902:                            throw (IOException) ex;
0903:                        throw UiException.Aide.wrap(ex);
0904:                    }
0905:                } finally {
0906:                    if (!cleaned)
0907:                        config.invokeExecutionCleanups(exec, null, null);
0908:
0909:                    if (abrn != null) {
0910:                        try {
0911:                            abrn.finish();
0912:                        } catch (Throwable t) {
0913:                            log.warning(t);
0914:                        }
0915:                    }
0916:
0917:                    doDeactivate(exec);
0918:
0919:                    if (monitor != null) {
0920:                        try {
0921:                            monitor.afterUpdate(desktop);
0922:                        } catch (Throwable ex) {
0923:                            log.error(ex);
0924:                        }
0925:                    }
0926:
0927:                    return doneReqIds;
0928:                }
0929:            }
0930:
0931:            /** Handles each error. The erros will be queued to the errs list
0932:             * and processed later by {@link #visualizeErrors}.
0933:             */
0934:            private static final void handleError(Throwable ex,
0935:                    UiVisualizer uv, List errs) {
0936:                final Throwable err = ex;
0937:                final Throwable t = Exceptions.findCause(ex, Expectable.class);
0938:                if (t == null) {
0939:                    log.realCauseBriefly(ex);
0940:                } else {
0941:                    ex = t;
0942:                    if (log.debugable())
0943:                        log.debug(Exceptions.getRealCause(ex));
0944:                }
0945:
0946:                if (ex instanceof  WrongValueException) {
0947:                    WrongValueException wve = (WrongValueException) ex;
0948:                    final Component comp = wve.getComponent();
0949:                    if (comp != null) {
0950:                        wve = ((ComponentCtrl) comp).onWrongValue(wve);
0951:                        if (wve != null)
0952:                            uv.addResponse("wrongValue", new AuWrongValue(comp,
0953:                                    Exceptions.getMessage(wve)));
0954:                        return;
0955:                    }
0956:                }
0957:
0958:                errs.add(err);
0959:            }
0960:
0961:            /** Post-process the errors to represent them to the user.
0962:             * Note: errs must be non-empty
0963:             */
0964:            private final void visualizeErrors(Execution exec, UiVisualizer uv,
0965:                    List errs) {
0966:                final StringBuffer sb = new StringBuffer(128);
0967:                for (Iterator it = errs.iterator(); it.hasNext();) {
0968:                    final Throwable t = (Throwable) it.next();
0969:                    if (sb.length() > 0)
0970:                        sb.append('\n');
0971:                    sb.append(Exceptions.getMessage(t));
0972:                }
0973:                final String msg = sb.toString();
0974:
0975:                final Throwable err = (Throwable) errs.get(0);
0976:                final Desktop desktop = exec.getDesktop();
0977:                final Configuration config = desktop.getWebApp()
0978:                        .getConfiguration();
0979:                final String location = config.getErrorPage(desktop
0980:                        .getDeviceType(), err);
0981:                if (location != null) {
0982:                    try {
0983:                        exec.setAttribute("javax.servlet.error.message", msg);
0984:                        exec.setAttribute("javax.servlet.error.exception", err);
0985:                        exec.setAttribute("javax.servlet.error.exception_type",
0986:                                err.getClass());
0987:                        exec.setAttribute("javax.servlet.error.status_code",
0988:                                new Integer(500));
0989:
0990:                        //Future: consider to go thru UiFactory for the richlet
0991:                        //for the error page.
0992:                        //Challenge: how to call UiFactory.isRichlet
0993:                        final Richlet richlet = config
0994:                                .getRichletByPath(location);
0995:                        if (richlet != null)
0996:                            richlet.service(getCurrentPage(exec));
0997:                        else
0998:                            exec.createComponents(location, null, null);
0999:
1000:                        //process pending events
1001:                        //the execution is aborted if an exception is thrown
1002:                        Event event = nextEvent(uv);
1003:                        do {
1004:                            for (; event != null; event = nextEvent(uv)) {
1005:                                try {
1006:                                    process(desktop, event);
1007:                                } catch (SuspendNotAllowedException ex) {
1008:                                    //ignore it (possible and reasonable)
1009:                                }
1010:                            }
1011:                            resumeAll(desktop, uv, null);
1012:                        } while ((event = nextEvent(uv)) != null);
1013:                        return; //done
1014:                    } catch (Throwable ex) {
1015:                        log.realCause("Unable to generate custom error page, "
1016:                                + location, ex);
1017:                    }
1018:                }
1019:
1020:                uv.addResponse(null, new AuAlert(msg)); //default handling
1021:            }
1022:
1023:            private static final Page getCurrentPage(Execution exec) {
1024:                final Page page = ((ExecutionCtrl) exec).getCurrentPage();
1025:                return page != null ? page : (Page) exec.getDesktop()
1026:                        .getPages().iterator().next();
1027:            }
1028:
1029:            /** Processing the request and stores result into UiVisualizer.
1030:             * @param everError whether any error ever occured before processing this
1031:             * request.
1032:             */
1033:            private void process(Execution exec, AuRequest request,
1034:                    boolean everError) {
1035:                //		if (log.finable()) log.finer("Processing request: "+request);
1036:
1037:                final ExecutionCtrl execCtrl = (ExecutionCtrl) exec;
1038:                execCtrl.setCurrentPage(request.getPage());
1039:                request.getCommand().process(request, everError);
1040:            }
1041:
1042:            /** Processing the event and stores result into UiVisualizer. */
1043:            private void process(Desktop desktop, Event event) {
1044:                //		if (log.finable()) log.finer("Processing event: "+event);
1045:
1046:                final Component comp = event.getTarget();
1047:                if (comp != null) {
1048:                    processEvent(desktop, comp, event);
1049:                } else {
1050:                    //since an event might change the page/desktop/component relation,
1051:                    //we copy roots first
1052:                    final List roots = new LinkedList();
1053:                    for (Iterator it = desktop.getPages().iterator(); it
1054:                            .hasNext();) {
1055:                        roots.addAll(((Page) it.next()).getRoots());
1056:                    }
1057:                    for (Iterator it = roots.iterator(); it.hasNext();) {
1058:                        final Component c = (Component) it.next();
1059:                        if (c.getPage() != null) //might be removed, so check first
1060:                            processEvent(desktop, c, event);
1061:                    }
1062:                }
1063:            }
1064:
1065:            public void wait(Object mutex) throws InterruptedException,
1066:                    SuspendNotAllowedException {
1067:                if (mutex == null)
1068:                    throw new IllegalArgumentException("null mutex");
1069:
1070:                final Thread thd = Thread.currentThread();
1071:                if (!(thd instanceof  EventProcessingThreadImpl))
1072:                    throw new UiException(
1073:                            "This method can be called only in an event listener, not in paging loading.");
1074:                //		if (log.finerable()) log.finer("Suspend "+thd+" on "+mutex);
1075:
1076:                final EventProcessingThreadImpl evtthd = (EventProcessingThreadImpl) thd;
1077:                evtthd.newEventThreadSuspends(mutex);
1078:                //it may throw an exception, so process it before updating _suspended
1079:
1080:                final Execution exec = Executions.getCurrent();
1081:                final Desktop desktop = exec.getDesktop();
1082:
1083:                incSuspended();
1084:
1085:                Map map;
1086:                synchronized (_suspended) {
1087:                    map = (Map) _suspended.get(desktop);
1088:                    if (map == null)
1089:                        _suspended.put(desktop, map = new IdentityHashMap(3));
1090:                    //note: we have to use IdentityHashMap because user might
1091:                    //use Integer or so as mutex
1092:                }
1093:                synchronized (map) {
1094:                    List list = (List) map.get(mutex);
1095:                    if (list == null)
1096:                        map.put(mutex, list = new LinkedList());
1097:                    list.add(evtthd);
1098:                }
1099:
1100:                try {
1101:                    EventProcessingThreadImpl.doSuspend(mutex);
1102:                } catch (Throwable ex) {
1103:                    //error recover
1104:                    synchronized (map) {
1105:                        final List list = (List) map.get(mutex);
1106:                        if (list != null) {
1107:                            list.remove(evtthd);
1108:                            if (list.isEmpty())
1109:                                map.remove(mutex);
1110:                        }
1111:                    }
1112:
1113:                    if (ex instanceof  InterruptedException)
1114:                        throw (InterruptedException) ex;
1115:                    throw UiException.Aide.wrap(ex, "Unable to suspend "
1116:                            + evtthd);
1117:                } finally {
1118:                    decSuspended();
1119:                }
1120:            }
1121:
1122:            private void incSuspended() {
1123:                final int v = _wapp.getConfiguration().getMaxSuspendedThreads();
1124:                synchronized (this ) {
1125:                    if (v >= 0 && _suspCnt >= v)
1126:                        throw new SuspendNotAllowedException(
1127:                                MZk.TOO_MANY_SUSPENDED);
1128:                    ++_suspCnt;
1129:                }
1130:            }
1131:
1132:            private void decSuspended() {
1133:                synchronized (this ) {
1134:                    --_suspCnt;
1135:                }
1136:            }
1137:
1138:            public void notify(Object mutex) {
1139:                notify(Executions.getCurrent().getDesktop(), mutex);
1140:            }
1141:
1142:            public void notify(Desktop desktop, Object mutex) {
1143:                if (desktop == null || mutex == null)
1144:                    throw new IllegalArgumentException(
1145:                            "desktop and mutex cannot be null");
1146:
1147:                final Map map;
1148:                synchronized (_suspended) {
1149:                    map = (Map) _suspended.get(desktop);
1150:                }
1151:                if (map == null)
1152:                    return; //nothing to notify
1153:
1154:                final EventProcessingThreadImpl evtthd;
1155:                synchronized (map) {
1156:                    final List list = (List) map.get(mutex);
1157:                    if (list == null)
1158:                        return; //nothing to notify
1159:
1160:                    //Note: list is never empty
1161:                    evtthd = (EventProcessingThreadImpl) list.remove(0);
1162:                    if (list.isEmpty())
1163:                        map.remove(mutex); //clean up
1164:                }
1165:                addResumed(desktop, evtthd);
1166:            }
1167:
1168:            public void notifyAll(Object mutex) {
1169:                final Execution exec = Executions.getCurrent();
1170:                if (exec == null)
1171:                    throw new UiException(
1172:                            "resume can be called only in processing a request");
1173:                notifyAll(exec.getDesktop(), mutex);
1174:            }
1175:
1176:            public void notifyAll(Desktop desktop, Object mutex) {
1177:                if (desktop == null || mutex == null)
1178:                    throw new IllegalArgumentException(
1179:                            "desktop and mutex cannot be null");
1180:
1181:                final Map map;
1182:                synchronized (_suspended) {
1183:                    map = (Map) _suspended.get(desktop);
1184:                }
1185:                if (map == null)
1186:                    return; //nothing to notify
1187:
1188:                final List list;
1189:                synchronized (map) {
1190:                    list = (List) map.remove(mutex);
1191:                    if (list == null)
1192:                        return; //nothing to notify
1193:                }
1194:                for (Iterator it = list.iterator(); it.hasNext();)
1195:                    addResumed(desktop, (EventProcessingThreadImpl) it.next());
1196:            }
1197:
1198:            /** Adds to _resumed */
1199:            private void addResumed(Desktop desktop,
1200:                    EventProcessingThreadImpl evtthd) {
1201:                //		if (log.finerable()) log.finer("Ready to resume "+evtthd);
1202:
1203:                List list;
1204:                synchronized (_resumed) {
1205:                    list = (List) _resumed.get(desktop);
1206:                    if (list == null)
1207:                        _resumed.put(desktop, list = new LinkedList());
1208:                }
1209:                synchronized (list) {
1210:                    list.add(evtthd);
1211:                }
1212:            }
1213:
1214:            /** Does the real resume.
1215:             * <p>Note 1: the current thread will wait until the resumed threads, if any, complete
1216:             * <p>Note 2: {@link #resume} only puts a thread into a resume queue in execution.
1217:             */
1218:            private void resumeAll(Desktop desktop, UiVisualizer uv, List errs) {
1219:                //We have to loop because a resumed thread might resume others
1220:                for (;;) {
1221:                    final List list;
1222:                    synchronized (_resumed) {
1223:                        list = (List) _resumed.remove(desktop);
1224:                        if (list == null)
1225:                            return; //nothing to resume; done
1226:                    }
1227:
1228:                    synchronized (list) {
1229:                        for (Iterator it = list.iterator(); it.hasNext();) {
1230:                            final EventProcessingThreadImpl evtthd = (EventProcessingThreadImpl) it
1231:                                    .next();
1232:                            if (uv.isAborting()) {
1233:                                evtthd.ceaseSilently("Resume aborted");
1234:                            } else {
1235:                                //						if (log.finerable()) log.finer("Resume "+evtthd);
1236:                                try {
1237:                                    if (evtthd.doResume()) //wait it complete or suspend again
1238:                                        recycleEventThread(evtthd); //completed
1239:                                } catch (Throwable ex) {
1240:                                    recycleEventThread(evtthd);
1241:                                    if (errs == null) {
1242:                                        log.error("Unable to resume " + evtthd,
1243:                                                ex);
1244:                                        throw UiException.Aide.wrap(ex);
1245:                                    }
1246:                                    handleError(ex, uv, errs);
1247:                                }
1248:                            }
1249:                        }
1250:                    }
1251:                }
1252:            }
1253:
1254:            /** Process an event. */
1255:            private void processEvent(Desktop desktop, Component comp,
1256:                    Event event) {
1257:                final Configuration config = desktop.getWebApp()
1258:                        .getConfiguration();
1259:                if (config.isEventThreadEnabled()) {
1260:                    EventProcessingThreadImpl evtthd = null;
1261:                    synchronized (_idles) {
1262:                        if (!_idles.isEmpty())
1263:                            evtthd = (EventProcessingThreadImpl) _idles
1264:                                    .remove(0);
1265:                    }
1266:
1267:                    if (evtthd == null)
1268:                        evtthd = new EventProcessingThreadImpl();
1269:
1270:                    try {
1271:                        if (evtthd.processEvent(desktop, comp, event))
1272:                            recycleEventThread(evtthd);
1273:                    } catch (Throwable ex) {
1274:                        recycleEventThread(evtthd);
1275:                        throw UiException.Aide.wrap(ex);
1276:                    }
1277:                } else { //event thread disabled
1278:                    //Note: we don't need to call proc.setup() and cleanup(),
1279:                    //since they are in the same thread
1280:                    EventProcessor proc = new EventProcessor(desktop, comp,
1281:                            event);
1282:                    //Note: it also checks the correctness
1283:                    List cleanups = null, errs = null;
1284:                    try {
1285:                        final List inits = config.newEventThreadInits(comp,
1286:                                event);
1287:                        EventProcessor.inEventListener(true);
1288:                        if (config.invokeEventThreadInits(inits, comp, event)) //false measn ignore
1289:                            proc.process();
1290:                    } catch (Throwable ex) {
1291:                        errs = new LinkedList();
1292:                        errs.add(ex);
1293:                        cleanups = config.newEventThreadCleanups(comp, event,
1294:                                errs);
1295:
1296:                        throw UiException.Aide.wrap(ex);
1297:                    } finally {
1298:                        EventProcessor.inEventListener(false);
1299:                        if (errs == null) //not cleanup yet
1300:                            cleanups = config.newEventThreadCleanups(comp,
1301:                                    event, null);
1302:                        config.invokeEventThreadCompletes(cleanups, comp,
1303:                                event, errs);
1304:                    }
1305:                }
1306:            }
1307:
1308:            private void recycleEventThread(EventProcessingThreadImpl evtthd) {
1309:                if (!evtthd.isCeased()) {
1310:                    if (evtthd.isIdle()) {
1311:                        final int max = _wapp.getConfiguration()
1312:                                .getMaxSpareThreads();
1313:                        synchronized (_idles) {
1314:                            if (max < 0 || _idles.size() < max) {
1315:                                _idles.add(evtthd); //return to pool
1316:                                return; //done
1317:                            }
1318:                        }
1319:                    }
1320:                    evtthd.ceaseSilently("Recycled");
1321:                }
1322:            }
1323:
1324:            public void activate(Execution exec) {
1325:                assert D.OFF || ExecutionsCtrl.getCurrentCtrl() == null : "Impossible to re-activate for update: old="
1326:                        + ExecutionsCtrl.getCurrentCtrl() + ", new=" + exec;
1327:                doActivate(exec, null, false);
1328:            }
1329:
1330:            public void deactivate(Execution exec) {
1331:                doDeactivate(exec);
1332:            }
1333:
1334:            //-- Common private utilities --//
1335:            /** Activates the specified execution for processing.
1336:             *
1337:             * @param requests a list of requests to process.
1338:             * Activation assumes it is asynchronous update if it is not null.
1339:             * @param recovering whether it is in recovering, i.e.,
1340:             * cause by {@link FailoverManager#recover}.
1341:             * If true, the requests argument must be null.
1342:             * @return the exec info if the execution is granted;
1343:             * null if request has been added to the exec currently activated
1344:             */
1345:            private static UiVisualizer doActivate(Execution exec,
1346:                    List requests, boolean recovering) {
1347:                if (Executions.getCurrent() != null)
1348:                    throw new IllegalStateException("Use doReactivate instead");
1349:
1350:                final Desktop desktop = exec.getDesktop();
1351:                final DesktopCtrl desktopCtrl = (DesktopCtrl) desktop;
1352:                final Session sess = desktop.getSession();
1353:                //		if (log.finerable()) log.finer("Activating "+desktop);
1354:
1355:                final boolean asyncupd = requests != null;
1356:                assert D.OFF || !recovering || !asyncupd;
1357:                //to simplify the following codes, asyncupd and recovering
1358:                //cannot be both true
1359:
1360:                final boolean inProcess = asyncupd && !isRecovering(desktop)
1361:                        && desktopCtrl.getRequestQueue().addRequests(requests);
1362:                //used as flag to know whether to add the requests
1363:                //to the previous execution, if any.
1364:
1365:                //lock desktop
1366:                final UiVisualizer uv;
1367:                final Map eis = getVisualizers(sess);
1368:                synchronized (eis) {
1369:                    for (;;) {
1370:                        final UiVisualizer old = (UiVisualizer) eis
1371:                                .get(desktop);
1372:                        if (old == null)
1373:                            break; //grantable
1374:
1375:                        if (inProcess)
1376:                            return null; //done
1377:
1378:                        try {
1379:                            eis.wait(120 * 1000);
1380:                        } catch (InterruptedException ex) {
1381:                            throw UiException.Aide.wrap(ex);
1382:                        }
1383:                    }
1384:
1385:                    //grant
1386:                    if (asyncupd)
1387:                        desktopCtrl.getRequestQueue().setInProcess();
1388:                    //set the flag asap to free more following executions
1389:                    eis.put(desktop, uv = new UiVisualizer(exec, asyncupd,
1390:                            recovering));
1391:                    desktopCtrl.setExecution(exec);
1392:                }
1393:
1394:                final ExecutionCtrl execCtrl = (ExecutionCtrl) exec;
1395:                execCtrl.setVisualizer(uv);
1396:                ExecutionsCtrl.setCurrent(exec);
1397:                execCtrl.onActivate();
1398:                return uv;
1399:            }
1400:
1401:            /** Returns whether the desktop is being recovered.
1402:             */
1403:            private static final boolean isRecovering(Desktop desktop) {
1404:                final Execution exec = desktop.getExecution();
1405:                return exec != null && ((ExecutionCtrl) exec).isRecovering();
1406:            }
1407:
1408:            /** Deactivates the execution. */
1409:            private static final void doDeactivate(Execution exec) {
1410:                final Desktop desktop = exec.getDesktop();
1411:                final Session sess = desktop.getSession();
1412:                //		if (log.finerable()) log.finer("Deactivating "+desktop);
1413:
1414:                final ExecutionCtrl execCtrl = (ExecutionCtrl) exec;
1415:                try {
1416:                    //Unlock desktop
1417:                    final Map eis = getVisualizers(sess);
1418:                    synchronized (eis) {
1419:                        final Object o = eis.remove(desktop);
1420:                        assert D.OFF || o != null;
1421:                        ((DesktopCtrl) desktop).setExecution(null);
1422:                        eis.notify(); //wakeup doActivate's wait
1423:                    }
1424:                } finally {
1425:                    execCtrl.onDeactivate();
1426:                    execCtrl.setCurrentPage(null);
1427:                    execCtrl.setVisualizer(null);
1428:                    ExecutionsCtrl.setCurrent(null);
1429:                }
1430:
1431:                final SessionCtrl sessCtrl = (SessionCtrl) sess;
1432:                if (sessCtrl.isInvalidated())
1433:                    sessCtrl.invalidateNow();
1434:            }
1435:
1436:            /** Re-activates for another execution. It is callable only for
1437:             * creating new page (execNewPage). It is not allowed for async-update.
1438:             * <p>Note: doActivate cannot handle reactivation. In other words,
1439:             * the caller has to detect which method to use.
1440:             */
1441:            private static UiVisualizer doReactivate(Execution curExec,
1442:                    UiVisualizer olduv) {
1443:                final Desktop desktop = curExec.getDesktop();
1444:                final Session sess = desktop.getSession();
1445:                //		if (log.finerable()) log.finer("Re-activating "+desktop);
1446:
1447:                assert D.OFF || olduv.getExecution().getDesktop() == desktop : "old dt: "
1448:                        + olduv.getExecution().getDesktop()
1449:                        + ", new:"
1450:                        + desktop;
1451:
1452:                final UiVisualizer uv = new UiVisualizer(olduv, curExec);
1453:                final Map eis = getVisualizers(sess);
1454:                synchronized (eis) {
1455:                    final Object o = eis.put(desktop, uv);
1456:                    if (o != olduv)
1457:                        throw new InternalError(); //wrong olduv
1458:                    ((DesktopCtrl) desktop).setExecution(curExec);
1459:                }
1460:
1461:                final ExecutionCtrl curCtrl = (ExecutionCtrl) curExec;
1462:                curCtrl.setVisualizer(uv);
1463:                ExecutionsCtrl.setCurrent(curExec);
1464:                curCtrl.onActivate();
1465:                return uv;
1466:            }
1467:
1468:            /** De-reactivated exec. Work with {@link #doReactivate}.
1469:             */
1470:            private static void doDereactivate(Execution curExec,
1471:                    UiVisualizer olduv) {
1472:                if (olduv == null)
1473:                    throw new IllegalArgumentException("null");
1474:
1475:                final Desktop desktop = curExec.getDesktop();
1476:                final Session sess = desktop.getSession();
1477:                //		if (log.finerable()) log.finer("Deactivating "+desktop);
1478:
1479:                final ExecutionCtrl curCtrl = (ExecutionCtrl) curExec;
1480:                curCtrl.onDeactivate();
1481:                curCtrl.setCurrentPage(null);
1482:                curCtrl.setVisualizer(null); //free memory
1483:
1484:                final Execution oldexec = olduv.getExecution();
1485:                final Map eis = getVisualizers(sess);
1486:                synchronized (eis) {
1487:                    eis.put(desktop, olduv);
1488:                    ((DesktopCtrl) desktop).setExecution(oldexec);
1489:                }
1490:                ExecutionsCtrl.setCurrent(oldexec);
1491:            }
1492:
1493:            /** Returns a map of (Page, UiVisualizer). */
1494:            private static Map getVisualizers(Session sess) {
1495:                synchronized (sess) {
1496:                    final String attr = "org.zkoss.zk.ui.Visualizers";
1497:                    Map eis = (Map) sess.getAttribute(attr);
1498:                    if (eis == null)
1499:                        sess.setAttribute(attr, eis = new HashMap());
1500:                    return eis;
1501:                }
1502:            }
1503:
1504:            //Handling Native Component//
1505:            /** Sets the prolog of the specified native component.
1506:             */
1507:            private static final void setProlog(CreateInfo ci, Component comp,
1508:                    NativeInfo compInfo) {
1509:                final Native nc = (Native) comp;
1510:                StringBuffer sb = null;
1511:                final List prokids = compInfo.getPrologChildren();
1512:                if (!prokids.isEmpty()) {
1513:                    sb = new StringBuffer(256);
1514:                    getNativeContent(ci, sb, comp, prokids);
1515:                }
1516:
1517:                final NativeInfo splitInfo = compInfo.getSplitChild();
1518:                if (splitInfo != null && splitInfo.isEffective(comp)) {
1519:                    if (sb == null)
1520:                        sb = new StringBuffer(256);
1521:                    getNativeFirstHalf(ci, sb, comp, splitInfo);
1522:                }
1523:
1524:                if (sb != null && sb.length() > 0)
1525:                    nc.setPrologContent(sb.insert(0,
1526:                            (String) nc.getPrologContent()).toString());
1527:            }
1528:
1529:            /** Sets the epilog of the specified native component.
1530:             * @param comp the native component
1531:             */
1532:            private static final void setEpilog(CreateInfo ci, Component comp,
1533:                    NativeInfo compInfo) {
1534:                final Native nc = (Native) comp;
1535:                StringBuffer sb = null;
1536:                final NativeInfo splitInfo = compInfo.getSplitChild();
1537:                if (splitInfo != null && splitInfo.isEffective(comp)) {
1538:                    sb = new StringBuffer(256);
1539:                    getNativeSecondHalf(ci, sb, comp, splitInfo);
1540:                }
1541:
1542:                final List epikids = compInfo.getEpilogChildren();
1543:                if (!epikids.isEmpty()) {
1544:                    if (sb == null)
1545:                        sb = new StringBuffer(256);
1546:                    getNativeContent(ci, sb, comp, epikids);
1547:                }
1548:
1549:                if (sb != null && sb.length() > 0)
1550:                    nc.setEpilogContent(sb.append(nc.getEpilogContent())
1551:                            .toString());
1552:            }
1553:
1554:            /**
1555:             * @param comp the native component
1556:             */
1557:            private static final void getNativeContent(CreateInfo ci,
1558:                    StringBuffer sb, Component comp, List children) {
1559:                for (Iterator it = children.iterator(); it.hasNext();) {
1560:                    final Object meta = it.next();
1561:                    if (meta instanceof  NativeInfo) {
1562:                        final NativeInfo childInfo = (NativeInfo) meta;
1563:                        final ForEach forEach = childInfo.getForEach(ci.page,
1564:                                comp);
1565:                        if (forEach == null) {
1566:                            if (childInfo.isEffective(comp)) {
1567:                                getNativeFirstHalf(ci, sb, comp, childInfo);
1568:                                getNativeSecondHalf(ci, sb, comp, childInfo);
1569:                            }
1570:                        } else {
1571:                            while (forEach.next()) {
1572:                                if (childInfo.isEffective(comp)) {
1573:                                    getNativeFirstHalf(ci, sb, comp, childInfo);
1574:                                    getNativeSecondHalf(ci, sb, comp, childInfo);
1575:                                }
1576:                            }
1577:                        }
1578:                    } else if (meta instanceof  TextInfo) {
1579:                        final String s = ((TextInfo) meta).getValue(comp);
1580:                        ((Native) comp).getHelper().appendText(sb, s);
1581:                    } else {
1582:                        execNonComponent(ci, comp, meta);
1583:                    }
1584:                }
1585:            }
1586:
1587:            /** Before calling this method, childInfo.isEffective must be examined
1588:             */
1589:            private static final void getNativeFirstHalf(CreateInfo ci,
1590:                    StringBuffer sb, Component comp, NativeInfo childInfo) {
1591:                ((Native) comp).getHelper().getFirstHalf(sb,
1592:                        childInfo.getTag(),
1593:                        evalProperties(comp, childInfo.getProperties()),
1594:                        childInfo.getDeclaredNamespaces());
1595:
1596:                final List prokids = childInfo.getPrologChildren();
1597:                if (!prokids.isEmpty())
1598:                    getNativeContent(ci, sb, comp, prokids);
1599:
1600:                final NativeInfo splitInfo = childInfo.getSplitChild();
1601:                if (splitInfo != null && splitInfo.isEffective(comp))
1602:                    getNativeFirstHalf(ci, sb, comp, splitInfo); //recursive
1603:            }
1604:
1605:            /** Before calling this method, childInfo.isEffective must be examined
1606:             */
1607:            private static final void getNativeSecondHalf(CreateInfo ci,
1608:                    StringBuffer sb, Component comp, NativeInfo childInfo) {
1609:                final NativeInfo splitInfo = childInfo.getSplitChild();
1610:                if (splitInfo != null && splitInfo.isEffective(comp))
1611:                    getNativeSecondHalf(ci, sb, comp, splitInfo); //recursive
1612:
1613:                final List epikids = childInfo.getEpilogChildren();
1614:                if (!epikids.isEmpty())
1615:                    getNativeContent(ci, sb, comp, epikids);
1616:
1617:                ((Native) comp).getHelper().getSecondHalf(sb,
1618:                        childInfo.getTag());
1619:            }
1620:
1621:            /** Returns a map of properties, (String name, String value).
1622:             */
1623:            private static final Map evalProperties(Component comp, List props) {
1624:                if (props == null || props.isEmpty())
1625:                    return Collections.EMPTY_MAP;
1626:
1627:                final Map map = new LinkedHashMap(props.size() * 2);
1628:                for (Iterator it = props.iterator(); it.hasNext();) {
1629:                    final Property prop = (Property) it.next();
1630:                    if (prop.isEffective(comp))
1631:                        map.put(prop.getName(), Classes.coerce(String.class,
1632:                                prop.getValue(comp)));
1633:                }
1634:                return map;
1635:            }
1636:
1637:            //Supporting Classes//
1638:            /** The listener to create children when the fulfill condition is
1639:             * satisfied.
1640:             */
1641:            private static class FulfillListener implements  EventListener,
1642:                    Express, java.io.Serializable, Cloneable,
1643:                    ComponentSerializationListener, ComponentCloneListener {
1644:                private transient String[] _evtnms;
1645:                private transient Component[] _targets;
1646:                private transient Component _comp;
1647:                private final ComponentInfo _compInfo;
1648:                private final String _fulfill;
1649:
1650:                private FulfillListener(String fulfill, ComponentInfo compInfo,
1651:                        Component comp) {
1652:                    _fulfill = fulfill;
1653:                    _compInfo = compInfo;
1654:                    _comp = comp;
1655:
1656:                    init();
1657:
1658:                    for (int j = _targets.length; --j >= 0;)
1659:                        _targets[j].addEventListener(_evtnms[j], this );
1660:                }
1661:
1662:                private void init() {
1663:                    final List results = new LinkedList();
1664:                    for (int j = 0, len = _fulfill.length();;) {
1665:                        int k = _fulfill.indexOf(',', j);
1666:                        String sub = (k >= 0 ? _fulfill.substring(j, k)
1667:                                : _fulfill.substring(j)).trim();
1668:                        if (sub.length() > 0)
1669:                            results.add(ComponentsCtrl.parseEventExpression(
1670:                                    _comp, sub, _comp, false));
1671:
1672:                        if (k < 0 || (j = k + 1) >= len)
1673:                            break;
1674:                    }
1675:
1676:                    int j = results.size();
1677:                    _targets = new Component[j];
1678:                    _evtnms = new String[j];
1679:                    j = 0;
1680:                    for (Iterator it = results.iterator(); it.hasNext(); ++j) {
1681:                        final Object[] result = (Object[]) it.next();
1682:                        _targets[j] = (Component) result[0];
1683:                        _evtnms[j] = (String) result[1];
1684:                    }
1685:                }
1686:
1687:                public void onEvent(Event evt) throws Exception {
1688:                    for (int j = _targets.length; --j >= 0;)
1689:                        _targets[j].removeEventListener(_evtnms[j], this ); //one shot only
1690:
1691:                    final Execution exec = Executions.getCurrent();
1692:                    execCreate0(
1693:                            new CreateInfo(((WebAppCtrl) exec.getDesktop()
1694:                                    .getWebApp()).getUiFactory(), exec, _comp
1695:                                    .getPage()), _compInfo, _comp);
1696:                }
1697:
1698:                //ComponentSerializationListener//
1699:                public void willSerialize(Component comp) {
1700:                }
1701:
1702:                public void didDeserialize(Component comp) {
1703:                    _comp = comp;
1704:                    init();
1705:                }
1706:
1707:                //ComponentCloneListener//
1708:                public Object clone(Component comp) {
1709:                    final FulfillListener clone;
1710:                    try {
1711:                        clone = (FulfillListener) clone();
1712:                    } catch (CloneNotSupportedException e) {
1713:                        throw new InternalError();
1714:                    }
1715:                    clone._comp = comp;
1716:                    clone.init();
1717:                    return clone;
1718:                }
1719:            }
1720:
1721:            /** Info used with execCreate
1722:             */
1723:            private static class CreateInfo {
1724:                private final Execution exec;
1725:                private final Page page;
1726:                private final UiFactory uf;
1727:
1728:                private CreateInfo(UiFactory uf, Execution exec, Page page) {
1729:                    this.exec = exec;
1730:                    this.page = page;
1731:                    this.uf = uf;
1732:                }
1733:            }
1734:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.