001 // Copyright 2004, 2005 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.tapestry.engine; 016 017 import java.io.IOException; 018 import java.util.HashMap; 019 import java.util.Map; 020 021 import org.apache.hivemind.ApplicationRuntimeException; 022 import org.apache.hivemind.util.Defense; 023 import org.apache.tapestry.IComponent; 024 import org.apache.tapestry.IDirectEvent; 025 import org.apache.tapestry.IPage; 026 import org.apache.tapestry.IRequestCycle; 027 import org.apache.tapestry.StaleSessionException; 028 import org.apache.tapestry.Tapestry; 029 import org.apache.tapestry.event.BrowserEvent; 030 import org.apache.tapestry.services.LinkFactory; 031 import org.apache.tapestry.services.ResponseRenderer; 032 import org.apache.tapestry.services.ServiceConstants; 033 import org.apache.tapestry.web.WebRequest; 034 import org.apache.tapestry.web.WebSession; 035 036 /** 037 * Implementation of the direct event service, which encodes the page and component id in the service 038 * context, and passes application-defined parameters as well. 039 * 040 * @author jkuhnert 041 * @since 4.1 042 */ 043 044 public class DirectEventService implements IEngineService 045 { 046 /** @since 4.0 */ 047 private ResponseRenderer _responseRenderer; 048 049 /** @since 4.0 */ 050 private LinkFactory _linkFactory; 051 052 /** @since 4.0 */ 053 private WebRequest _request; 054 055 /** @since 4.0 */ 056 private IRequestCycle _requestCycle; 057 058 public ILink getLink(boolean post, Object parameter) 059 { 060 Defense.isAssignable(parameter, DirectEventServiceParameter.class, "parameter"); 061 062 DirectEventServiceParameter dsp = (DirectEventServiceParameter) parameter; 063 064 IComponent component = dsp.getDirect(); 065 066 // New since 1.0.1, we use the component to determine 067 // the page, not the cycle. Through the use of tricky 068 // things such as Block/InsertBlock, it is possible 069 // that a component from a page different than 070 // the response page will render. 071 // In 1.0.6, we start to record *both* the render page 072 // and the component page (if different). 073 074 IPage activePage = _requestCycle.getPage(); 075 IPage componentPage = component.getPage(); 076 077 Map parameters = new HashMap(); 078 079 boolean stateful = _request.getSession(false) != null; 080 081 parameters.put(ServiceConstants.PAGE, activePage.getPageName()); 082 parameters.put(ServiceConstants.COMPONENT, component.getIdPath()); 083 parameters.put(ServiceConstants.CONTAINER, componentPage == activePage ? null 084 : componentPage.getPageName()); 085 parameters.put(ServiceConstants.SESSION, stateful ? "T" : null); 086 if (dsp.getUpdateParts() != null && dsp.getUpdateParts().length > 0) 087 parameters.put(ServiceConstants.UPDATE_PARTS, dsp.getUpdateParts()); 088 if (dsp.isJSON()) 089 parameters.put("json", String.valueOf(dsp.isJSON())); 090 parameters.put(ServiceConstants.PARAMETER, dsp.getServiceParameters()); 091 092 return _linkFactory.constructLink(this, post, parameters, true); 093 } 094 095 public void service(IRequestCycle cycle) throws IOException 096 { 097 String componentId = cycle.getParameter(ServiceConstants.COMPONENT); 098 String componentPageName = cycle.getParameter(ServiceConstants.CONTAINER); 099 String activePageName = cycle.getParameter(ServiceConstants.PAGE); 100 boolean activeSession = cycle.getParameter(ServiceConstants.SESSION) != null; 101 102 IPage page = cycle.getPage(activePageName); 103 104 cycle.activate(page); 105 106 IPage componentPage = componentPageName == null ? page : cycle.getPage(componentPageName); 107 108 IComponent component = componentPage.getNestedComponent(componentId); 109 110 IDirectEvent direct = null; 111 112 try 113 { 114 direct = (IDirectEvent) component; 115 } 116 catch (ClassCastException ex) 117 { 118 throw new ApplicationRuntimeException(EngineMessages.wrongComponentType( 119 component, 120 IDirectEvent.class), component, null, ex); 121 } 122 123 // Check for a StaleSession only when the session was stateful when 124 // the link was created. 125 126 if (activeSession && direct.isStateful()) 127 { 128 WebSession session = _request.getSession(false); 129 130 if (session == null || session.isNew()) 131 throw new StaleSessionException(EngineMessages.requestStateSession(direct), 132 componentPage); 133 } 134 135 Object[] parameters = _linkFactory.extractListenerParameters(cycle); 136 137 triggerComponent(cycle, direct, parameters); 138 139 // Render the response. This will be the active page 140 // unless the direct component (or its delegate) changes it. 141 142 _responseRenderer.renderResponse(cycle); 143 } 144 145 /** @since 4.0 */ 146 147 protected void triggerComponent(IRequestCycle cycle, IDirectEvent direct, Object[] parameters) 148 { 149 if (!BrowserEvent.hasBrowserEvent(cycle)) 150 throw new ApplicationRuntimeException(EngineMessages.noBrowserEvent()); 151 152 BrowserEvent event = new BrowserEvent(cycle); 153 154 Object[] parms = new Object[parameters.length + 1]; 155 System.arraycopy(parameters, 0, parms, 0, parameters.length); 156 parms[parms.length - 1] = event; 157 158 cycle.setListenerParameters(parms); 159 160 direct.triggerEvent(cycle, event); 161 } 162 163 public String getName() 164 { 165 return Tapestry.DIRECT_EVENT_SERVICE; 166 } 167 168 /** @since 4.0 */ 169 public void setResponseRenderer(ResponseRenderer responseRenderer) 170 { 171 _responseRenderer = responseRenderer; 172 } 173 174 /** @since 4.0 */ 175 public void setLinkFactory(LinkFactory linkFactory) 176 { 177 _linkFactory = linkFactory; 178 } 179 180 /** @since 4.0 */ 181 public void setRequest(WebRequest request) 182 { 183 _request = request; 184 } 185 186 /** @since 4.0 */ 187 public void setRequestCycle(IRequestCycle requestCycle) 188 { 189 _requestCycle = requestCycle; 190 } 191 }