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 }