KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > iv > flash > servlet > GeneratorServlet


1 /*
2  * $Id: GeneratorServlet.java,v 1.8 2002/07/15 02:15:03 skavish Exp $
3  *
4  * ===========================================================================
5  *
6  * The JGenerator Software License, Version 1.0
7  *
8  * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if
22  * any, must include the following acknowlegement:
23  * "This product includes software developed by Dmitry Skavish
24  * (skavish@usa.net, http://www.flashgap.com/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The name "The JGenerator" must not be used to endorse or promote
29  * products derived from this software without prior written permission.
30  * For written permission, please contact skavish@usa.net.
31  *
32  * 5. Products derived from this software may not be called "The JGenerator"
33  * nor may "The JGenerator" appear in their names without prior written
34  * permission of Dmitry Skavish.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
40  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  */

50
51 package org.openlaszlo.iv.flash.servlet;
52
53 import java.rmi.RemoteException JavaDoc;
54 import java.io.*;
55 import java.net.*;
56 import java.util.*;
57
58 import javax.servlet.*;
59 import javax.servlet.http.*;
60
61 import org.openlaszlo.iv.flash.api.*;
62 import org.openlaszlo.iv.flash.util.*;
63 import org.openlaszlo.iv.flash.parser.*;
64 import org.openlaszlo.iv.flash.cache.*;
65
66 import org.openlaszlo.iv.flash.url.*;
67 import org.openlaszlo.iv.flash.api.image.*;
68 import org.openlaszlo.iv.flash.api.sound.*;
69 import org.openlaszlo.iv.flash.context.*;
70
71 import org.apache.log4j.*;
72 import org.apache.log4j.spi.*;
73
74 /**
75  * Generator servlet
76  * processes http requests from clients
77  */

78 public class GeneratorServlet extends HttpServlet {
79
80     private String JavaDoc errorTemplateName = null;
81     private int currentThreadNum = 0;
82     private int maxThreads = 0;
83     private int gcAfterJobsCount = 0;
84     private int jobsCountSinceLastGC = 0;
85     private boolean wrapAssets = false;
86     private boolean createServletContext = false;
87
88     public void init( ServletConfig config ) throws ServletException {
89         super.init( config );
90
91         // initialize
92
String JavaDoc installDir = getInitParameter("org.openlaszlo.iv.flash.virtualInstallDir");
93         if( installDir != null ) {
94             installDir = config.getServletContext().getRealPath(installDir);
95         } else {
96             installDir = getInitParameter("org.openlaszlo.iv.flash.installDir");
97             if( installDir == null ) {
98                 installDir = config.getServletContext().getRealPath("/");
99             }
100         }
101
102         String JavaDoc propFileName = getInitParameter("org.openlaszlo.iv.flash.propertiesFile");
103
104         Util.init(installDir, propFileName);
105
106         // initialize stat manager
107
StatManager.init();
108
109         // set some control variables
110
createServletContext = PropertyManager.getBoolProperty( "org.openlaszlo.iv.flash.servletContext", false );
111         maxThreads = PropertyManager.getIntProperty( "org.openlaszlo.iv.flash.maxThreads", 0 );
112         gcAfterJobsCount = PropertyManager.getIntProperty( "org.openlaszlo.iv.flash.garbageCollectAfterJobCount", 0 );
113         wrapAssets = PropertyManager.getBoolProperty( "org.openlaszlo.iv.flash.wrapAssets", false );
114
115         // get name of error template
116
String JavaDoc fileName = PropertyManager.getProperty("org.openlaszlo.iv.flash.errorTemplate","bin/error.swt");
117         if( fileName != null ) {
118             File errFile = Util.getSysFile( fileName );
119             if( errFile.exists() ) {
120                 errorTemplateName = errFile.getAbsolutePath();
121             }
122         }
123
124         Log.info("");
125         Log.logRB(Resource.SERVERSTARTED);
126         Log.info("");
127     }
128
129     /**
130      * Send error to the client.
131      */

132     private void showTextError( String JavaDoc msg, HttpServletResponse res )
133         throws ServletException, IOException
134     {
135         res.setContentType("text/html");
136         PrintWriter pw = res.getWriter();
137         pw.print( "<html><body><font color=red>"+msg+"</font></body></html>" );
138         pw.close();
139     }
140
141     /**
142      * Wrap given exception in our error.swt end send to the client
143      */

144     private void showError( Throwable JavaDoc t, String JavaDoc fileName, HttpServletResponse res )
145         throws ServletException, IOException
146     {
147         String JavaDoc fullMessage = t.getLocalizedMessage();
148
149         if( errorTemplateName == null ) {
150             showTextError( fullMessage, res );
151         } else {
152             try {
153                 if( fullMessage == null ) fullMessage = t.getClass().getName();
154                 StandardContext context = new StandardContext();
155                 context.setValue( "bulkErrMessage", fullMessage );
156                 context.setValue( "template_name", fileName );
157                 FlashOutput fob = process(errorTemplateName, context, null);
158                 send( fob, res );
159             } catch( Throwable JavaDoc tt ) {
160                 Log.log( tt );
161                 showTextError( fullMessage, res );
162             }
163         }
164     }
165
166     /**
167      * Create generator context from servlet parameters
168      */

169     private Context createServletContext( HttpServletRequest req ) {
170         CommandExecutor executor = new OnlineCommandExecutor();
171         CommandContext context = new CommandContext( executor );
172         Enumeration e = req.getParameterNames();
173         while( e.hasMoreElements() ) {
174             String JavaDoc name = (String JavaDoc) e.nextElement();
175             String JavaDoc value = Util.processEscapes( req.getParameter(name) );
176             context.setValue(name, value);
177         }
178         return context;
179     }
180
181     protected long getLastModified( HttpServletRequest req ) {
182         return -1;
183     }
184
185     public void doGet( HttpServletRequest req, HttpServletResponse res )
186         throws ServletException, IOException
187     {
188         doGen( req, res );
189     }
190
191     public void doPost( HttpServletRequest req, HttpServletResponse res )
192         throws ServletException, IOException
193     {
194         doGen( req, res );
195     }
196
197     public void doGen( HttpServletRequest req, HttpServletResponse res )
198         throws ServletException, IOException
199     {
200         if( maxThreads > 0 && currentThreadNum >= maxThreads ) {
201             res.sendError( res.SC_SERVICE_UNAVAILABLE );
202             return;
203         }
204
205         try {
206             currentThreadNum++;
207
208             // create context
209
GeneratorServletContext context = null;
210             if( createServletContext ) {
211                 context = GeneratorServletContext.createContext();
212                 context.setHttpServletRequest( req );
213                 context.setHttpServletResponse( res );
214                 context.setServletConfig( getServletConfig() );
215             }
216
217
218             String JavaDoc fileName = getRequestedFileName( req );
219
220             // check for admin requests
221
if( fileName.endsWith( "__admin__.swt" ) ) {
222                 adminRequest( req, res );
223                 return;
224             }
225
226             processTemplate( fileName, req, res );
227
228         } finally {
229             currentThreadNum--;
230
231             // destroy context
232
if( createServletContext ) GeneratorServletContext.destroyContext();
233
234             jobsCountSinceLastGC++;
235             if( gcAfterJobsCount > 0 && jobsCountSinceLastGC >= gcAfterJobsCount ) {
236                 System.runFinalization();
237                 System.gc();
238                 jobsCountSinceLastGC = 0;
239             }
240         }
241     }
242
243     /**
244      * Process template
245      */

246     public void processTemplate( String JavaDoc fileName, HttpServletRequest req, HttpServletResponse res )
247         throws ServletException, IOException
248     {
249         long totalTime = System.currentTimeMillis();
250         long processTime = totalTime;
251
252         FlashOutput fob = null;
253
254         /*
255         Runtime rt = Runtime.getRuntime();
256         Log.debug("free memory="+rt.freeMemory()+", total memory="+rt.totalMemory()+", free/total="+(rt.freeMemory()*100L/rt.totalMemory())+"%");
257         long cache_size = FontCache.getInstance().getSize();
258         cache_size += MediaCache.getInstance().getSize();
259         cache_size += RequestCache.getInstance().getSize();
260         cache_size += XMLCache.getInstance().getSize();
261         Log.debug("cache size="+cache_size);
262         */

263
264         Log.logRB(Resource.REQUESTFROM, new Object JavaDoc[] {req.getRemoteHost()});
265
266         // check for request cache parameters
267
long lifespan = -1L;
268         String JavaDoc key = null;
269         boolean grc = Util.toBool( req.getParameter("grc"), false ); // request cache
270
grc = grc || RequestCache.getSettings().isForce();
271         if( grc ) {
272             lifespan = Util.toInt( req.getParameter("gre"), -1 )*1000L;
273             // try to retrieve file from cache
274
key = fileName+"?"+req.getQueryString();
275             fob = RequestCache.getRequest( key );
276         }
277
278
279         boolean needToCache = grc && fob == null;
280
281         // process template
282
if( fob == null ) {
283             try {
284                 Context context = createServletContext( req );
285
286                 String JavaDoc encoding = req.getParameter("genc");
287
288                 if( wrapAssets &&
289                     (fileName.endsWith( ".jpg.swt" ) ||
290                      fileName.endsWith( ".png.swt" ) ||
291                      fileName.endsWith( ".gif.swt" )) )
292                 {
293                     fob = wrapImage( fileName.substring(0, fileName.length()-4), context );
294                 } else if( wrapAssets && fileName.endsWith( ".mp3.swt" ) ) {
295                     fob = wrapSound( fileName.substring(0, fileName.length()-4), context );
296                 } else {
297                     fob = process( fileName, context, encoding );
298                 }
299
300             } catch( FileNotFoundException e ) {
301                 Log.logRB(Resource.FILENOTFOUND, new Object JavaDoc[] {fileName});
302                 res.sendError( res.SC_NOT_FOUND );
303                 return;
304             } catch( OutOfMemoryError JavaDoc e ) {
305                 // the only known possible problem with memory may be in a caches, so clean them up
306
FontCache.getInstance().clear();
307                 MediaCache.getInstance().clear();
308                 RequestCache.getInstance().clear();
309                 XMLCache.getInstance().clear();
310                 System.gc();
311                 Log.logRB(Resource.PROCESSERROR, new Object JavaDoc[] {fileName}, e);
312                 showError(e, fileName, res);
313                 return;
314             } catch( Throwable JavaDoc e ) {
315                 Log.logRB(Resource.PROCESSERROR, new Object JavaDoc[] {fileName}, e);
316                 showError(e, fileName, res);
317                 return;
318             }
319         }
320         processTime = System.currentTimeMillis()-processTime;
321
322         // cache the result
323
if( needToCache ) {
324             RequestCache.addRequest( key, fob, lifespan );
325         }
326
327         // everything is ok, send movie to the client
328
try {
329             send( fob, res );
330         } catch( Throwable JavaDoc t ) {
331             Log.logRB(Resource.SENDERROR, new Object JavaDoc[] {fileName}, t);
332             return;
333         }
334
335         // log
336
totalTime = System.currentTimeMillis()-totalTime;
337         Log.logRB( Resource.PROCESSREQUEST, new Object JavaDoc[] { fileName, new Integer JavaDoc(fob.getSize()), new Long JavaDoc(processTime), new Long JavaDoc(totalTime) } );
338
339         // generate statistics
340
StatManager.addRequest( fileName, fob.getSize(), processTime, totalTime );
341     }
342
343     /**
344      * Process template<BR>
345      * <UL>
346      * <LI>parse template
347      * <LI>process (perform substitutions and generator commands)
348      * <LI>generate movie
349      * </UL>
350      *
351      * @param fileName template file name
352      * @param context generator context
353      * @param encoding file encoding
354      * @return generated flash content
355      * @exception IVException
356      * @exception IOException
357      */

358     protected FlashOutput process( String JavaDoc fileName, Context context, String JavaDoc encoding )
359         throws IVException, IOException
360     {
361         FlashFile file = FlashFile.parse(fileName, false, encoding);
362
363         file.processFile( context );
364
365         return file.generate();
366     }
367
368     /**
369      * Wrap image into .swf file
370      * <p>
371      * possible parameters in request:<br>
372      * <CODE>
373      * http://host/image.jpg.swt?width=100&height=200&center=true
374      * </CODE><br><br>
375      * if there is no width and height then there is no scaling<br>
376      * if there is no center then there is no translating
377      *
378      * @param fileName file name to wrap
379      * @param context generator context
380      * @return wrapped resource
381      * @exception IVException
382      * @exception IOException
383      */

384     protected FlashOutput wrapImage( String JavaDoc fileName, Context context )
385         throws IVException, IOException
386     {
387         IVUrl url = IVUrl.newUrl(fileName);
388
389         Bitmap bitmap = (Bitmap) MediaCache.getMedia(url);
390         if( bitmap == null ) {
391             bitmap = Bitmap.newBitmap(url);
392         }
393         MediaCache.addMedia(url, bitmap, bitmap.getSize(), true);
394
395         int width = Util.toInt(context.getValue("width"), -1) * 20;
396         int height = Util.toInt(context.getValue("height"), -1) * 20;
397         boolean center = Util.toBool(context.getValue("center"), false);
398         boolean scale = width >= 0 && height >= 0;
399
400         Instance inst = bitmap.newInstance( width, height, scale, center );
401
402         Script script = new Script(1);
403         script.setMain();
404
405         script.newFrame().addInstance( inst, 1 );
406
407         FlashFile file = FlashFile.newFlashFile();
408
409         file.setFrameSize( inst.getBounds() );
410         file.setMainScript( script );
411
412         return file.generate();
413     }
414
415     /**
416      * Wrap sound into .swf file
417      * <p>
418      * possible parameters in request:<br>
419      * <code>http://host/image.mp3.swt?delay=100</code>
420      *
421      * @param fileName file name to wrap
422      * @param context generator context
423      * @return wrapped resource
424      * @exception IVException
425      * @exception IOException
426      */

427     protected FlashOutput wrapSound( String JavaDoc fileName, Context context )
428         throws IVException, IOException
429     {
430         Script script = new Script(1);
431         script.setMain();
432
433         IVUrl url = IVUrl.newUrl(fileName);
434
435         MP3Sound sound = (MP3Sound) MediaCache.getMedia(url);
436         if( sound == null ) {
437             sound = MP3Sound.newMP3Sound( url );
438         }
439         MediaCache.addMedia(url, sound, sound.getSize(), true);
440
441         // Set the delay if provided
442
int delay = Util.toInt(context.getValue("delay"), 0);
443
444         if( delay != 0 ) {
445             sound.setDelaySeek( delay );
446         }
447
448         SoundInfo soundInfo = SoundInfo.newSoundInfo( 0 );
449         StartSound startSound = StartSound.newStartSound( sound, soundInfo );
450
451         script.newFrame().addFlashObject( startSound );
452
453         FlashFile file = FlashFile.newFlashFile();
454
455         file.setFrameSize( GeomHelper.newRectangle(0,0,0,0) );
456         file.setMainScript( script );
457
458         return file.generate();
459     }
460
461     /**
462      * Send generator output buffer to the client
463      *
464      * @param fob flash data to send
465      * @param res response to send to
466      * @exception ServletException
467      * @exception IOException
468      */

469     protected void send( FlashOutput fob, HttpServletResponse res )
470         throws ServletException, IOException
471     {
472         res.setContentLength( fob.getSize() );
473         res.setContentType( "application/x-shockwave-flash" );
474
475         ServletOutputStream sos = res.getOutputStream();
476         try {
477             sos.write( fob.getBuf(), 0, fob.getSize() );
478         } finally {
479             sos.close();
480         }
481     }
482
483     /**
484      * Returns absolute path of requested template
485      */

486     protected String JavaDoc getRequestedFileName( HttpServletRequest req ) {
487         return getServletContext().getRealPath( req.getServletPath() );
488         //return req.getRealPath( req.getServletPath() );
489
}
490
491     private void debugInfo( HttpServletRequest req ) {
492         //Log.logRB(Resource.STR,"req.getPathInfo()="+req.getPathInfo());
493
//Log.logRB(Resource.STR,"req.getPathTranslated()="+req.getPathTranslated());
494
//Log.logRB(Resource.STR,"req.getQueryString()="+req.getQueryString());
495
//Log.logRB(Resource.STR,"req.getRealPath()="+req.getRealPath(""));
496
//Log.logRB(Resource.STR,"req.getRequestURI()="+req.getRequestURI());
497
//Log.logRB(Resource.STR,"req.getServletPath()="+req.getServletPath());
498

499 /* if( server == 0 ) {
500           String wwwRoot = req.getPathTranslated();
501           if( wwwRoot.endsWith( "\\" ) || wwwRoot.endsWith( "/" ) ) wwwRoot = wwwRoot.substring(0,wwwRoot.length()-1);
502           String fileName = wwwRoot+req.getRequestURI();
503           return fileName;
504         } else if( server == 1 ) {
505         }*/

506     }
507
508     /**
509      * Admin request
510      * <P>
511      * Admin requests come in form of: http://host/__admin__.swt?parm=value&parm=value...
512      * <P>
513      * possible parameters:<BR>
514      * <UL>
515      * <LI>showHTMLStat
516      * </UL>
517      *
518      * @param req
519      * @param res
520      * @exception ServletException
521      * @exception IOException
522      */

523     public void adminRequest( HttpServletRequest req, HttpServletResponse res )
524         throws ServletException, IOException
525     {
526         // very stupid and simple authentication
527
String JavaDoc userName = req.getParameter( "username" );
528         String JavaDoc password = req.getParameter( "password" );
529         String JavaDoc myUserName = PropertyManager.getProperty( "org.openlaszlo.iv.flash.adminUserName" );
530         String JavaDoc myPassword = PropertyManager.getProperty( "org.openlaszlo.iv.flash.adminPassword" );
531         if( myUserName == null || myPassword == null ||
532             userName == null || password == null ||
533             userName.length() == 0 || password.length() == 0 ||
534             !myUserName.equals(userName) ||
535             !myPassword.equals(password) )
536         {
537             res.sendError( res.SC_UNAUTHORIZED );
538             return;
539         }
540
541         // parse admin request
542
if( req.getParameter( "showHTMLStat" ) != null ) {
543             showHTMLStat( req, res );
544         } else if( req.getParameter( "getCurrentStat" ) != null ) {
545             getCurrentStat( req, res );
546         } else if( req.getParameter( "getServerXMLInfo" ) != null ) {
547             getServerXMLInfo( req, res );
548         } else {
549             showTextError( "unknown admin request", res );
550         }
551     }
552
553     /**
554      * Get current stat
555      */

556     public void getCurrentStat( HttpServletRequest req, HttpServletResponse res )
557         throws ServletException, IOException
558     {
559         res.setContentType( "application/x-www-urlformencoded" );
560         PrintWriter pw = res.getWriter();
561
562         pw.print( "threadsNum=" + currentThreadNum );
563         pw.print( "&serverInfo=" + URLEncoder.encode(getServletContext().getServerInfo()) );
564
565         StatUnit sinceStartup = StatManager.getSinceStartup();
566         long upTime = System.currentTimeMillis() - sinceStartup.getStartTime();
567         String JavaDoc upTimeStr = (upTime/3600000)+"h+"+((upTime/60000)%60)+"m+"+((upTime/1000)%60)+"s";
568         pw.print( "&upTime=" + upTimeStr );
569         sinceStartup.printVars(pw);
570         pw.close();
571     }
572
573     /**
574      * Show HTML stat
575      */

576     public void showHTMLStat( HttpServletRequest req, HttpServletResponse res )
577         throws ServletException, IOException
578     {
579         res.setContentType("text/html");
580         PrintWriter pw = res.getWriter();
581         pw.print( "<html><body>" );
582         pw.print( "Current number of threads running: "+currentThreadNum+"<br>" );
583         pw.print( "<hr>Since startup: " );
584         StatManager.getSinceStartup().print(pw);
585         Vector v = StatManager.getStatistic();
586         for( int i=0; i<v.size(); i++ ) {
587             pw.print("<hr>");
588             StatUnit su = (StatUnit) v.elementAt(i);
589             su.print(pw);
590         }
591         pw.print("<hr>");
592         pw.print( "</body></html>" );
593         pw.close();
594     }
595
596     /**
597      * Get server info in xml format
598      */

599     public void getServerXMLInfo( HttpServletRequest req, HttpServletResponse res )
600         throws ServletException, IOException
601     {
602         res.setContentType( "text/xml" );
603         PrintWriter pw = res.getWriter();
604
605         pw.println( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
606         pw.println( "<!-- generated by JGenerator servlet -->" );
607         //pw.println( "<!DOCTYPE jgenerator-server SYSTEM \"http://www.flashgap.com/jgenerator-server.dtd\">" );
608

609         pw.println( "<jgenerator-server>" );
610
611         StatUnit sinceStartup = StatManager.getSinceStartup();
612
613         // print server info
614
long upTime = System.currentTimeMillis() - sinceStartup.getStartTime();
615         String JavaDoc upTimeStr = (upTime/3600000)+"h+"+((upTime/60000)%60)+"m+"+((upTime/1000)%60)+"s";
616         pw.println( "<server-info>" );
617         pw.println( "<threads-num>"+currentThreadNum+"</threads-num>" );
618         pw.println( "<uptime>"+upTimeStr+"</uptime>" );
619         pw.println( "<description>"+getServletContext().getServerInfo()+"</description>" );
620         pw.println( "</server-info>" );
621
622         // print statistics
623
pw.println( "<statistics>" );
624         sinceStartup.printXML(pw,true);
625         Vector v = StatManager.getStatistic();
626         for( int i=0; i<v.size(); i++ ) {
627             StatUnit su = (StatUnit) v.elementAt(i);
628             su.printXML(pw,false);
629         }
630         pw.println( "</statistics>" );
631
632         // print properties
633
pw.println( "<properties>" );
634
635 /* PropertyManager.getIntProperty( "org.openlaszlo.iv.flash.maxThreads", 0 );
636         PropertyManager.getIntProperty( "org.openlaszlo.iv.flash.garbageCollectAfterJobCount", 0 );
637         PropertyManager.getBoolProperty( "org.openlaszlo.iv.flash.wrapAssets", false );
638         PropertyManager.getProperty("org.openlaszlo.iv.flash.errorTemplate","bin/error.swt");
639 */

640         pw.println( "</properties>" );
641
642         pw.println( "</jgenerator-server>" );
643
644         pw.close();
645     }
646
647     /**
648      * Online command executor.
649      * <P>
650      * Adds additional commands for online version of generator
651      */

652     public class OnlineCommandExecutor extends CommandExecutor {
653
654     }
655
656 }
657
658
Popular Tags