1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.nordija.tapestry.bayeux.stream;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.apache.hivemind.ApplicationRuntimeException;
21 import org.apache.hivemind.util.Defense;
22 import org.apache.tapestry.IComponent;
23 import org.apache.tapestry.IPage;
24 import org.apache.tapestry.IRequestCycle;
25 import org.apache.tapestry.StaleSessionException;
26 import org.apache.tapestry.engine.EngineMessages;
27 import org.apache.tapestry.engine.IEngineService;
28 import org.apache.tapestry.engine.ILink;
29 import org.apache.tapestry.services.LinkFactory;
30 import org.apache.tapestry.services.ServiceConstants;
31 import org.apache.tapestry.spec.IApplicationSpecification;
32 import org.apache.tapestry.web.WebRequest;
33 import org.apache.tapestry.web.WebSession;
34
35 import javax.servlet.http.HttpServletResponse;
36 import java.io.IOException;
37 import java.io.OutputStream;
38 import java.util.HashMap;
39 import java.util.Map;
40
41
42
43
44
45
46
47
48
49
50
51 public class StreamService implements IEngineService {
52
53 public static final String SERVICE_NAME = "stream";
54
55 public static final String RESOURCE_ID_PARAM_NAME = "resourceId";
56 public static final String STREAM_RESOURCE_SOURCE_EXT_PARAM_NAME = "streamResourceSourceExtentionName";
57 public static final String BAYEUX_STREAM_EXTENTIONS_PREFIX = "bayeux.stream.";
58 public static final String DEFAULT_RESOURCE_SOURCE_NAME = "resourcesource";
59
60 private static final Log LOG = LogFactory.getLog(StreamService.class);
61
62 private HttpServletResponse response;
63
64 private LinkFactory linkFactory;
65
66 private IRequestCycle requestCycle;
67
68 private WebRequest webRequest;
69
70 public void setResponse(HttpServletResponse response) {
71 this.response = response;
72 }
73
74 public void setLinkFactory(LinkFactory linkFactory) {
75 this.linkFactory = linkFactory;
76 }
77
78 public String getName() {
79 return SERVICE_NAME;
80 }
81
82 public ILink getLink(boolean post, Object parameter) {
83 Defense.isAssignable(parameter, StreamServiceParameter.class, "parameter");
84
85 StreamServiceParameter ssp = (StreamServiceParameter) parameter;
86
87 IComponent component = ssp.getStream();
88
89
90
91
92
93
94
95
96
97 IPage activePage = requestCycle.getPage();
98 IPage componentPage = component.getPage();
99
100 Map parameters = new HashMap();
101
102 boolean stateful = webRequest.getSession(false) != null;
103
104 parameters.put(ServiceConstants.PAGE, activePage.getPageName());
105 parameters.put(ServiceConstants.COMPONENT, component.getIdPath());
106 parameters.put(ServiceConstants.CONTAINER, componentPage == activePage ? null
107 : componentPage.getPageName());
108 parameters.put(ServiceConstants.SESSION, stateful ? "T" : null);
109
110
111 parameters.put(STREAM_RESOURCE_SOURCE_EXT_PARAM_NAME, ssp.getStreamResourceSourceExtentionName());
112
113
114 if (ssp.isAsync() || ssp.isJson()) {
115 if (ssp.getUpdateParts() != null && ssp.getUpdateParts().length > 0)
116 parameters.put(ServiceConstants.UPDATE_PARTS, ssp.getUpdateParts());
117
118 if (ssp.isJson())
119 parameters.put("json", String.valueOf(ssp.isJson()));
120
121
122 }
123
124 parameters.put(ServiceConstants.PARAMETER, ssp.getServiceParameters());
125
126 return linkFactory.constructLink(this, post, parameters, true);
127 }
128
129 public void service(IRequestCycle cycle) throws IOException {
130 String componentId = cycle.getParameter(ServiceConstants.COMPONENT);
131 String componentPageName = cycle.getParameter(ServiceConstants.CONTAINER);
132 String activePageName = cycle.getParameter(ServiceConstants.PAGE);
133 boolean activeSession = cycle.getParameter(ServiceConstants.SESSION) != null;
134
135
136 String streamResourceSourceExtName = cycle.getParameter(STREAM_RESOURCE_SOURCE_EXT_PARAM_NAME);
137
138 IPage page = cycle.getPage(activePageName);
139
140 cycle.activate(page);
141
142 IPage componentPage = componentPageName == null ? page : cycle.getPage(componentPageName);
143
144 IComponent component = componentPage.getNestedComponent(componentId);
145
146 IStream stream;
147
148 try {
149 stream = (IStream) component;
150 }
151 catch (ClassCastException ex) {
152 throw new ApplicationRuntimeException(EngineMessages.wrongComponentType(
153 component,
154 IStream.class), component, null, ex);
155 }
156
157
158
159
160 if (activeSession && stream.isStateful()) {
161 WebSession session = webRequest.getSession(false);
162
163 if (session == null || session.isNew())
164 throw new StaleSessionException(EngineMessages.requestStateSession(stream),
165 componentPage);
166 }
167
168 Object[] parameters = linkFactory.extractListenerParameters(cycle);
169
170
171 triggerComponent(cycle, stream, streamResourceSourceExtName, parameters);
172 }
173
174 protected void triggerComponent(IRequestCycle cycle, IStream stream, String streamResourceSourceExtName, Object[] parameters) throws IOException {
175 IApplicationSpecification specification = cycle.getInfrastructure().getApplicationSpecification();
176
177 if (streamResourceSourceExtName == null) {
178 streamResourceSourceExtName = DEFAULT_RESOURCE_SOURCE_NAME;
179 }
180
181 StreamResourceSource source = (StreamResourceSource) specification.getExtension(BAYEUX_STREAM_EXTENTIONS_PREFIX + streamResourceSourceExtName, StreamResourceSource.class);
182
183 if (LOG.isDebugEnabled()) {
184 int noParameters = 0;
185 if (parameters != null) {
186 noParameters = parameters.length;
187 }
188 LOG.debug("going to process stream resource with " + noParameters + " parameter(s)");
189 }
190
191
192 StreamResource streamResource = source.getStreamResource(cycle, parameters);
193 if (streamResource == null) {
194 throw new ApplicationRuntimeException("unable to process stream, no suitable resource found.");
195 }
196
197 streamResource(streamResource);
198
199 }
200
201 protected void streamResource(StreamResource resource) throws IOException {
202 if (LOG.isDebugEnabled()) {
203 LOG.debug("streaming resource with content-type '" + resource.getContentType() + "' and content-disposition '" + resource.getContentDisposition() + "'");
204 }
205 response.setContentType(resource.getContentType());
206 String contentDisposition = resource.getContentDisposition();
207 if (contentDisposition != null) {
208 response.setHeader("Content-disposition", contentDisposition);
209 }
210 OutputStream out = response.getOutputStream();
211 resource.writeTo(out);
212 }
213
214 public void setRequest(WebRequest webRequest) {
215 this.webRequest = webRequest;
216 }
217
218 public void setRequestCycle(IRequestCycle requestCycle) {
219 this.requestCycle = requestCycle;
220 }
221 }