    001    //  Copyright 2008, 2009 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    //     http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.internal.services;
    016
    017    import org.apache.tapestry5.ComponentEventCallback;
    018    import org.apache.tapestry5.EventConstants;
    019    import org.apache.tapestry5.internal.structure.ComponentPageElement;
    020    import org.apache.tapestry5.internal.structure.Page;
    021    import org.apache.tapestry5.internal.util.Holder;
    022    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    023    import org.apache.tapestry5.ioc.services.TypeCoercer;
    024    import org.apache.tapestry5.model.ComponentModel;
    025    import org.apache.tapestry5.services.InvalidationListener;
    026
    027    import java.util.Map;
    028
    029    public class PageActivationContextCollectorImpl implements PageActivationContextCollector, InvalidationListener
    030    {
    031        private final Object[] EMPTY = new Object[0];
    032
    033        private final TypeCoercer typeCoercer;
    034
    035        private final ComponentModelSource modelSource;
    036
    037        private final RequestPageCache requestPageCache;
    038
    039        /**
    040         * Keyed on *canonical* page name, value indicates whether the page has a passivate event handler.
    041         */
    042        private final Map<String, Boolean> cache = CollectionFactory.newConcurrentMap();
    043
    044        public PageActivationContextCollectorImpl(TypeCoercer typeCoercer, RequestPageCache requestPageCache,
    045                                                  ComponentModelSource modelSource)
    046        {
    047            this.typeCoercer = typeCoercer;
    048            this.requestPageCache = requestPageCache;
    049            this.modelSource = modelSource;
    050        }
    051
    052        public void objectWasInvalidated()
    053        {
    054            cache.clear();
    055        }
    056
    057        public Object[] collectPageActivationContext(String pageName)
    058        {
    059            Boolean hasHandler = cache.get(pageName);
    060
    061            if (hasHandler == null)
    062            {
    063                ComponentModel model = modelSource.getPageModel(pageName);
    064
    065                hasHandler = model.handlesEvent(EventConstants.PASSIVATE);
    066
    067                cache.put(pageName, hasHandler);
    068            }
    069
    070            // If no handler for the event, then no need to fire the event (and more importantly,
    071            // no need to obtain a page instance!)
    072
    073            if (!hasHandler)
    074                return EMPTY;
    075
    076            // Get or create a page instance and trigger the event.
    077
    078            Page page = requestPageCache.get(pageName);
    079
    080            ComponentPageElement element = page.getRootElement();
    081
    082            final Holder<Object[]> holder = Holder.create();
    083
    084            ComponentEventCallback callback = new ComponentEventCallback()
    085            {
    086                public boolean handleResult(Object result)
    087                {
    088                    holder.put(typeCoercer.coerce(result, Object[].class));
    089
    090                    // We've got the value, stop the event.
    091
    092                    return true;
    093                }
    094            };
    095
    096            element.triggerEvent(EventConstants.PASSIVATE, null, callback);
    097
    098            if (!holder.hasValue()) return EMPTY;
    099
    100            return holder.get();
    101        }
    102    }