1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.struts.flow.core.source.impl;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.UnsupportedEncodingException;
22 import java.net.HttpURLConnection;
23 import java.net.URL;
24 import java.net.URLConnection;
25 import java.net.URLDecoder;
26 import java.util.Iterator;
27 import java.util.Map;
28
29 import org.apache.struts.flow.core.source.Source;
30 import org.apache.struts.flow.core.source.SourceException;
31 import org.apache.struts.flow.core.source.SourceParameters;
32 import org.apache.struts.flow.core.source.SourceResolver;
33 import org.apache.struts.flow.core.source.SourceUtil;
34 import org.apache.struts.flow.core.source.SourceValidity;
35 import org.apache.struts.flow.core.source.impl.validity.TimeStampValidity;
36
37 /***
38 * Description of a source which is described by an URL.
39 *
40 * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
41 * @version CVS $Revision: 1.5 $ $Date: 2004/02/28 11:47:24 $
42 */
43 public class URLSource extends AbstractSource implements Source
44 {
45
46 /*** The URL of the source */
47 protected URL m_url;
48
49 /*** The connection for a real URL */
50 protected URLConnection m_connection;
51
52 /*** The <code>SourceParameters</code> used for a post*/
53 protected SourceParameters m_parameters;
54
55 /*** The encoding of the <code>SourceParameters</code>*/
56 protected String m_encoding;
57
58 /*** Is this a post? */
59 protected boolean m_isPost = false;
60
61 /*** Does this source exist ? */
62 protected boolean m_exists = false;
63
64 /*** the prev returned SourceValidity */
65 protected SourceValidity m_cachedValidity;
66
67 protected long m_cachedLastModificationDate;
68
69 /*** The content type (if known) */
70 protected String m_mimeType;
71
72 /***
73 * Constructor
74 */
75 public URLSource()
76 {
77 }
78
79 /***
80 * Initialize a new object from a <code>URL</code>.
81 * @param parameters This is optional
82 */
83 public void init(URL url, Map parameters) throws IOException
84 {
85 String systemId = url.toExternalForm();
86 setSystemId(systemId);
87 setScheme(SourceUtil.getScheme(systemId));
88
89 m_url = url;
90 m_isPost = false;
91
92 try {
93 m_encoding = System.getProperty("file.property", "ISO-8859-1");
94 } catch (SecurityException e) {
95 m_encoding = "ISO-8859-1";
96 }
97
98 if (null != parameters)
99 {
100 m_parameters = (SourceParameters) parameters.get(SourceResolver.URI_PARAMETERS);
101 final String method = (String) parameters.get(SourceResolver.METHOD);
102
103 if ("POST".equalsIgnoreCase(method))
104 m_isPost = true;
105
106 final String encoding = (String) parameters.get(SourceResolver.URI_ENCODING);
107 if (encoding != null && !"".equals(encoding))
108 m_encoding = encoding;
109 }
110
111 if (null != m_parameters && m_parameters.hasParameters() && !m_isPost)
112 {
113 StringBuffer urlBuffer = new StringBuffer(systemId);
114 String key;
115 final Iterator i = m_parameters.getParameterNames();
116 Iterator values;
117 String value;
118 boolean first = (systemId.indexOf('?') == -1);
119 if (first == true)
120 urlBuffer.append('?');
121 while (i.hasNext())
122 {
123 key = (String) i.next();
124 values = m_parameters.getParameterValues(key);
125 while (values.hasNext() == true)
126 {
127 value = SourceUtil.encode((String) values.next(), m_encoding);
128 if (first == false)
129 urlBuffer.append('&');
130 first = false;
131 urlBuffer.append(key);
132 urlBuffer.append('=');
133 urlBuffer.append(value);
134 }
135 }
136
137 m_url = new URL(urlBuffer.toString());
138 m_parameters = null;
139 }
140 }
141
142 /***
143 * Get the last modification date and content length of the source.
144 * Any exceptions are ignored.
145 * Override this to get the real information
146 */
147 protected void getInfos()
148 {
149
150 m_exists = false;
151
152 if (!m_isPost)
153 {
154 try
155 {
156 if (null == m_connection)
157 {
158 m_connection = m_url.openConnection();
159 String userInfo = getUserInfo();
160 if (m_url.getProtocol().startsWith("http") && userInfo != null){
161 m_connection.setRequestProperty("Authorization", "Basic " + SourceUtil.encodeBASE64(userInfo));
162 }
163 }
164 setLastModified(m_connection.getLastModified());
165 m_mimeType = m_connection.getContentType();
166 int contentLength = m_connection.getContentLength();
167 setContentLength(contentLength);
168 if ( m_connection instanceof HttpURLConnection )
169 {
170
171
172 try
173 {
174 final int statusCode = ((HttpURLConnection)m_connection).getResponseCode();
175 if ( statusCode == 200 || statusCode == 304 )
176 {
177 m_exists = true;
178 }
179 else
180 {
181 m_exists = false;
182 }
183 }
184 catch (IOException ignore)
185 {
186 m_exists = false;
187 }
188
189 }
190 else
191 {
192 m_exists = contentLength > 0;
193 }
194 }
195 catch (IOException ignore)
196 {
197 super.getInfos();
198 }
199 }
200 else
201 {
202
203 super.getInfos();
204 }
205 }
206
207 /***
208 * Does this source exist ?
209 */
210 public boolean exists()
211 {
212 checkInfos();
213 return m_exists;
214 }
215
216 /***
217 * Return an <code>InputStream</code> object to read from the source.
218 *
219 * The returned stream must be closed by the calling code.
220 *
221 * @throws SourceException if file not found or
222 * HTTP location does not exist.
223 * @throws IOException if I/O error occured.
224 */
225 public InputStream getInputStream() throws IOException, SourceException
226 {
227 checkInfos();
228 InputStream input = null;
229 if (m_connection == null)
230 {
231 m_connection = m_url.openConnection();
232
233 String userInfo = getUserInfo();
234 if (m_url.getProtocol().startsWith("http") && userInfo != null)
235 {
236 m_connection.setRequestProperty("Authorization", "Basic " + SourceUtil.encodeBASE64(userInfo));
237 }
238
239
240 if (m_connection instanceof HttpURLConnection && m_isPost)
241 {
242 StringBuffer buffer = new StringBuffer(2000);
243 String key;
244 Iterator i = m_parameters.getParameterNames();
245 Iterator values;
246 String value;
247 boolean first = true;
248 while (i.hasNext())
249 {
250 key = (String) i.next();
251 values = m_parameters.getParameterValues(key);
252 while (values.hasNext() == true)
253 {
254 value = SourceUtil.encode((String) values.next(), m_encoding);
255 if (first == false)
256 buffer.append('&');
257 first = false;
258 buffer.append(key.toString());
259 buffer.append('=');
260 buffer.append(value);
261 }
262 }
263 HttpURLConnection httpCon = (HttpURLConnection) m_connection;
264 httpCon.setDoInput(true);
265
266 if (buffer.length() > 1)
267 {
268 String postString = buffer.toString();
269 httpCon.setRequestMethod("POST");
270 httpCon.setDoOutput(true);
271 httpCon.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
272
273
274 httpCon.setRequestProperty("Content-length", Integer.toString(postString.length()));
275 java.io.OutputStream out = new java.io.BufferedOutputStream(httpCon.getOutputStream());
276 out.write(postString.getBytes());
277 out.close();
278 }
279 input = httpCon.getInputStream();
280 m_connection = null;
281 return input;
282 }
283 }
284 input = m_connection.getInputStream();
285 m_connection = null;
286 return input;
287 }
288
289 /***
290 * Get the Validity object. This can either wrap the last modification
291 * date or the expires information or...
292 * If it is currently not possible to calculate such an information
293 * <code>null</code> is returned.
294 */
295 public SourceValidity getValidity()
296 {
297 final long lm = getLastModified();
298 if (lm > 0)
299 {
300 if (lm == m_cachedLastModificationDate)
301 return m_cachedValidity;
302
303 m_cachedLastModificationDate = lm;
304 m_cachedValidity = new TimeStampValidity(lm);
305 return m_cachedValidity;
306 }
307 return null;
308 }
309
310 /***
311 * Refresh this object and update the last modified date
312 * and content length.
313 */
314 public void refresh()
315 {
316
317 m_connection = null;
318 super.refresh();
319 }
320
321 /***
322 * The mime-type of the content described by this object.
323 * If the source is not able to determine the mime-type by itself
324 * this can be null.
325 */
326 public String getMimeType()
327 {
328 return m_mimeType;
329 }
330
331 /***
332 * The decoded userinfo for this source.
333 * null, if no userinfo exists
334 */
335 protected String getUserInfo()
336 {
337 if (m_url == null) return null;
338 String ui = m_url.getUserInfo();
339 if (ui == null) return null;
340
341 try
342 {
343 ui = URLDecoder.decode(ui,"UTF-8");
344 }
345 catch (UnsupportedEncodingException e)
346 {
347
348
349 }
350 return ui;
351 }
352 }