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 org.apache.hivemind.ApplicationRuntimeException; 018 import org.apache.hivemind.util.Defense; 019 import org.apache.tapestry.*; 020 import org.apache.tapestry.event.BrowserEvent; 021 import org.apache.tapestry.services.LinkFactory; 022 import org.apache.tapestry.services.ResponseRenderer; 023 import org.apache.tapestry.services.ServiceConstants; 024 import org.apache.tapestry.web.WebRequest; 025 import org.apache.tapestry.web.WebSession; 026 027 import java.io.IOException; 028 import java.util.HashMap; 029 import java.util.Map; 030 031 /** 032 * Implementation of the direct event service, which encodes the page and component id in the service 033 * context, and passes application-defined parameters as well. 034 * 035 * @author jkuhnert 036 * @since 4.1 037 */ 038 039 public class DirectEventService implements IEngineService 040 { 041 /** @since 4.0 */ 042 private ResponseRenderer _responseRenderer; 043 044 /** @since 4.0 */ 045 private LinkFactory _linkFactory; 046 047 /** @since 4.0 */ 048 private WebRequest _request; 049 050 /** @since 4.0 */ 051 private IRequestCycle _requestCycle; 052 053 public ILink getLink(boolean post, Object parameter) 054 { 055 Defense.isAssignable(parameter, DirectEventServiceParameter.class, "parameter"); 056 057 DirectEventServiceParameter dsp = (DirectEventServiceParameter) parameter; 058 059 IComponent component = dsp.getDirect(); 060 061 // New since 1.0.1, we use the component to determine 062 // the page, not the cycle. Through the use of tricky 063 // things such as Block/InsertBlock, it is possible 064 // that a component from a page different than 065 // the response page will render. 066 // In 1.0.6, we start to record *both* the render page 067 // and the component page (if different). 068 069 IPage activePage = _requestCycle.getPage(); 070 IPage componentPage = component.getPage(); 071 072 Map parameters = new HashMap(); 073 074 boolean stateful = _request.getSession(false) != null; 075 076 parameters.put(ServiceConstants.PAGE, activePage.getPageName()); 077 parameters.put(ServiceConstants.COMPONENT, component.getIdPath()); 078 parameters.put(ServiceConstants.CONTAINER, componentPage == activePage ? null : componentPage.getPageName()); 079 parameters.put(ServiceConstants.SESSION, stateful ? "T" : null); 080 081 if (dsp.getUpdateParts() != null && dsp.getUpdateParts().length > 0) 082 { 083 parameters.put(ServiceConstants.UPDATE_PARTS, dsp.getUpdateParts()); 084 } 085 086 if (dsp.isJSON()) 087 { 088 parameters.put("json", String.valueOf(dsp.isJSON())); 089 } 090 091 parameters.put(ServiceConstants.PARAMETER, dsp.getServiceParameters()); 092 093 return _linkFactory.constructLink(this, post, parameters, true); 094 } 095 096 public void service(IRequestCycle cycle) throws IOException 097 { 098 String componentId = cycle.getParameter(ServiceConstants.COMPONENT); 099 String componentPageName = cycle.getParameter(ServiceConstants.CONTAINER); 100 String activePageName = cycle.getParameter(ServiceConstants.PAGE); 101 boolean activeSession = cycle.getParameter(ServiceConstants.SESSION) != null; 102 103 IPage page = cycle.getPage(activePageName); 104 105 cycle.activate(page); 106 107 IPage componentPage = componentPageName == null ? page : cycle.getPage(componentPageName); 108 109 IComponent component = componentPage.getNestedComponent(componentId); 110 111 IDirectEvent direct = null; 112 113 try 114 { 115 direct = (IDirectEvent) component; 116 } 117 catch (ClassCastException ex) 118 { 119 throw new ApplicationRuntimeException(EngineMessages.wrongComponentType( 120 component, 121 IDirectEvent.class), component, null, ex); 122 } 123 124 // Check for a StaleSession only when the session was stateful when 125 // the link was created. 126 127 if (activeSession && direct.isStateful()) 128 { 129 WebSession session = _request.getSession(false); 130 131 if (session == null || session.isNew()) 132 throw new StaleSessionException(EngineMessages.requestStateSession(direct), 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 }