Source code: jreceiver/client/rio/servlet/RioHostResults.java
1 /* $Header: /cvsroot/jreceiver/jreceiver/src/jreceiver/client/rio/servlet/RioHostResults.java,v 1.12 2003/05/14 06:24:28 reedesau Exp $ */
2
3 package jreceiver.client.rio.servlet;
4
5 import java.io.*;
6 import javax.servlet.*;
7 import javax.servlet.http.*;
8
9 import org.apache.commons.logging.*;
10
11 import jreceiver.client.common.servlet.*;
12 import jreceiver.client.rio.RioLauncher;
13 import jreceiver.client.rio.RioSettingCache;
14 import jreceiver.common.rpc.*;
15 import jreceiver.util.*;
16 import jreceiver.common.rec.util.TuneQuery;
17 import jreceiver.common.rec.util.TuneQueryRec;
18
19 /**
20 * Servlet answering 'result' requests from Rio Server.
21 * <p>
22 * Called by the Rio Receiver to retrieve tune fileids and
23 * titles (if text)
24 * <p>
25 * TEXT RESPONSE
26 * <p>
27 * A request for text will be made with the "_extended=1" option.
28 * All other responses will be in binary -- see below.
29 * <p>
30 * A text request like
31 * <p>
32 * http://...:12078/results?artist=&_extended=1
33 * <p>
34 * will return results for all known artists with song titles as
35 * <p>
36 * 160=TAll Of A Sudden (It's Too Late)
37 * 1c0=TBall And Chain
38 * 180=TEnglish Roundabout
39 * 1f0=TFly On The Wall
40 * 120=TIt's Nearly Africa
41 * 1d0=TSenses Working Overtime
42 * <p>
43 * The same goes if you replace 'artist' with 'title',
44 * 'source'(album) or 'genre'.
45 * <p>
46 * Add the exact artist name
47 * <p>
48 * http://...:12078/results?artist=Billie%20Holiday&_extended=1
49 * <p>
50 * BINARY RESPONSE
51 * <p>
52 * Two possibilities:
53 * <p>
54 * 1. Two DWORDs - this is used when the query contains
55 * "_extended=0" or if no "_extended" attribute is
56 * provided:
57 * <p>
58 * c001000 e5655000
59 * <p>
60 * where the first dword contains the src_id and
61 * the second contains the filesize
62 * <p>
63 * 2. Three DWORDs - this is used when the query contains
64 * "_extended=2"
65 * <p>
66 * c001000 e5655000 b5010000
67 * <p>
68 * where the first dword contains the src_id, the
69 * second contains the filesize, and the third
70 * contains what the mpeg data offset in the file.
71 * And you get results for only that artist. Note that the artist
72 * name has been encoded for use in the URI.
73 *
74 * @author Reed Esau
75 * @version $Revision: 1.12 $ $Date: 2003/05/14 06:24:28 $
76 */
77 public class RioHostResults extends RioHostBase {
78
79 /**
80 * the server which hosts the data
81 */
82 protected Tunes tune_rpc;
83
84 /**
85 */
86 public void init() throws ServletException {
87 super.init();
88
89 try {
90 tune_rpc = RpcFactory.newTunes();
91 }
92 catch (RpcException e) {
93 throw new ServletException("problem contacting remote server", e);
94 }
95 }
96
97
98 /**
99 * subclasses must define this
100 */
101 protected void handleRequest(HttpServletRequest req,
102 HttpServletResponse resp,
103 int src_id)
104 throws ServletException, IOException, RpcException {
105
106 RioSettingCache settings = RioSettingCache.getInstance();
107
108 int extended = HelperServlet.getIntParam(req, "_extended");
109
110 // set the range
111 int rec_offset = HelperServlet.getIntParam(req, "_begin", 0);
112 int rec_end = HelperServlet.getIntParam(req, "_end", -1);
113 if (rec_offset < 0)
114 rec_offset = 0;
115 int limit = rec_offset + settings.getResultEncodingLimit() - 1; //TODO: cache this value
116 if (rec_end < 0 || limit < rec_end)
117 rec_end = limit;
118 int rec_count = rec_end - rec_offset + 1;
119
120 String query = null;
121 int target;
122 for (target = 0; target < targets.length; target++) {
123 if ((query = req.getParameter(targets[target])) != null)
124 break;
125 }
126 if (target == targets.length)
127 throw new ServletException(invalid_target);
128
129 // new functionality: strip the " (18)" count off the end of the query, if present
130 // Note that it assumes that the paren, if present, is not required.
131 String regexp = null;
132 if (query != null) {
133 int pos = query.lastIndexOf(" (");
134 if (pos >= 0)
135 query = query.substring(0, pos);
136
137 // refine the regular expression query for use with REGEXP or similar
138 //String regexp = "^" + query + ".*";
139 if (query.length() > 0) {
140 regexp = "^" + query + "$"; // fix for [ 644489 ]
141 }
142 }
143
144 // respond based upon value of extended
145 if (extended == 1) {
146 //format: 0=src_id, 1=title of tune
147 //example: '1d0=TSenses Working Overtime\r\n'
148 final String pattern = "{0,hex}=T{1}\r\n";
149
150 textResponse(resp, pattern, target, regexp, rec_offset, rec_count);
151 }
152 else {
153 byte[] pattern;
154 if (extended == 2)
155 // [-src_id--][filesize-][data_offset]
156 pattern = "{0,word,le}{1,word,le}{2,word,le}".getBytes();
157 else // extended==0 or not specified
158 pattern = "{0,word,le}{1,word,le}".getBytes();
159
160 binaryResponse(resp, pattern, target, regexp, rec_offset, rec_count);
161 }
162 }
163
164
165 /**
166 * encode a response suitable retaining minimal playlist data in memory
167 */
168 protected void binaryResponse(HttpServletResponse resp,
169 byte[] pattern,
170 int target,
171 String query,
172 int rec_offset, int rec_count)
173 throws ServletException, IOException, RpcException {
174
175 TuneQuery tq = new TuneQueryRec();
176
177 switch (target) {
178 case TARGET_ARTIST:
179 tq.setArtistName(query, TuneQuery.IS_REG_EXP);
180 break;
181 case TARGET_ALBUM:
182 tq.setAlbumName(query, TuneQuery.IS_REG_EXP);
183 break;
184 case TARGET_GENRE:
185 tq.setGenreName(query, TuneQuery.IS_REG_EXP);
186 break;
187 case TARGET_TITLE:
188 tq.setTitle(query, TuneQuery.IS_REG_EXP);
189 break;
190 default:
191 throw new ServletException(invalid_target);
192 }
193
194 int driver_id = RioLauncher.getDriverId();
195 byte[] data = data = tune_rpc.encodeBinary(tq,
196 driver_id,
197 pattern,
198 rec_offset, rec_count);
199
200 ResponseStreamWriter writer = null;
201 try {
202 writer = new ResponseStreamWriter();
203 writer.write( data );
204 writer.respond(resp);
205 }
206 finally {
207 if (writer != null)
208 writer.close();
209 }
210 }
211
212
213 /**
214 * encode a response suitable for menu display
215 */
216 protected void textResponse(HttpServletResponse resp,
217 String pattern,
218 int target,
219 String query,
220 int rec_offset, int rec_count)
221 throws ServletException, IOException, RpcException {
222
223 TuneQuery tq = new TuneQueryRec();
224
225 switch (target) {
226 case TARGET_ARTIST:
227 tq.setArtistName(query, TuneQuery.IS_REG_EXP);
228 break;
229 case TARGET_ALBUM:
230 tq.setAlbumName(query, TuneQuery.IS_REG_EXP);
231 break;
232 case TARGET_GENRE:
233 tq.setGenreName(query, TuneQuery.IS_REG_EXP);
234 break;
235 case TARGET_TITLE:
236 tq.setTitle(query, TuneQuery.IS_REG_EXP);
237 break;
238 default:
239 throw new ServletException(invalid_target);
240 }
241
242 int driver_id = RioLauncher.getDriverId();
243 String data = tune_rpc.encodeText(tq,
244 driver_id,
245 pattern,
246 rec_offset, rec_count);
247
248 ResponseWriter writer = null;
249 try {
250 writer = new ResponseWriter();
251 writer.write( data );
252 writer.respond(resp);
253 }
254 finally {
255 if (writer != null)
256 writer.close();
257 }
258 }
259
260
261 /**
262 * DON'T implicitly fail if no src_id is provided in the * query
263 */
264 protected boolean requireMfileId() {
265 return false;
266 }
267
268 //
269 // internal data members and constants
270 //
271
272 protected static final String[] targets = {"artist","source","genre","title"};
273 protected static final int TARGET_ARTIST = 0;
274 protected static final int TARGET_ALBUM = 1;
275 protected static final int TARGET_GENRE = 2;
276 protected static final int TARGET_TITLE = 3;
277
278 protected static final String invalid_target = "invalid target";
279
280 /**
281 * logging object
282 */
283 protected static Log log = LogFactory.getLog(RioHostResults.class);
284 }
285 /*
286 JRECEIVER MODIFIED BSD LICENSE
287
288 Copyright (c) 2001-2002, Reed Esau (reed.esau@pobox.com) All rights reserved.
289
290 Redistribution and use in source and binary forms, with or without
291 modification, are permitted provided that the following conditions are
292 met:
293
294 Redistributions of source code must retain the above copyright notice,
295 this list of conditions and the following disclaimer.
296
297 Redistributions in binary form must reproduce the above copyright notice,
298 this list of conditions and the following disclaimer in the documentation
299 and/or other materials provided with the distribution.
300
301 Neither the name of the JReceiver Project
302 (http://jreceiver.sourceforge.net) nor the names of its contributors may
303 be used to endorse or promote products derived from this software without
304 specific prior written permission.
305
306 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
307 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
308 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
309 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
310 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
311 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
312 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
313 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
314 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
315 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
316 POSSIBILITY OF SUCH DAMAGE.
317 */
318