View Javadoc

1    /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.portals.bridges.perl;
18  
19  import javax.portlet.GenericPortlet;
20  
21  import java.io.BufferedReader;
22  import java.io.ByteArrayInputStream;
23  import java.io.ByteArrayOutputStream;
24  import java.io.FileNotFoundException;
25  import java.io.FileReader;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.OutputStream;
30  import java.io.OutputStreamWriter;
31  import java.io.PrintWriter;
32  import java.io.StringReader;
33  import java.io.UnsupportedEncodingException;
34  import java.io.Writer;
35  import java.util.Arrays;
36  import java.util.Enumeration;
37  
38  import javax.servlet.http.HttpServletRequestWrapper;
39  import javax.servlet.http.HttpServletResponse;
40  import javax.servlet.http.HttpServletResponseWrapper;
41  
42  import javax.portlet.PortletConfig;
43  import javax.portlet.PortletContext;
44  import javax.portlet.PortletException;
45  import javax.portlet.PortletURL;
46  import javax.portlet.RenderRequest;
47  import javax.portlet.RenderResponse;
48  import javax.portlet.PortletSession;
49  import javax.portlet.ActionRequest;
50  import javax.portlet.ActionResponse;
51  
52  import javax.servlet.http.HttpServletRequest;
53  
54  import org.apache.commons.logging.Log;
55  import org.apache.commons.logging.LogFactory;
56  import org.apache.jetspeed.rewriter.JetspeedRewriterController;
57  import org.apache.jetspeed.rewriter.RewriterController;
58  import org.apache.jetspeed.rewriter.RewriterException;
59  import org.apache.jetspeed.rewriter.RulesetRewriter;
60  import org.apache.jetspeed.rewriter.html.SwingParserAdaptor;
61  import org.apache.jetspeed.rewriter.rules.Ruleset;
62  import org.apache.jetspeed.rewriter.xml.SaxParserAdaptor;
63  
64  import org.apache.portals.bridges.common.ScriptPostProcess;
65  
66  
67  /***
68  * This portlet is executes a Perl/cgi files in a portlet.
69  * 
70  * Note:
71  * The Perl Portlet uses the rewriter component that requires config xml files.
72  * Make sre that the portlet application using the Perl Portlet has the following files included
73  * in WEB-INF/conf: rewriter-rules-mapping.xml and default-rewriter-rules.xml
74  *
75  * @author <a href="mailto:rogerrut@apache.org">Roger Ruttimann</a>
76  * @version $Id: PerlPortlet.java 517068 2007-03-12 01:44:37Z ate $
77  */
78  
79  public class PerlPortlet extends GenericPortlet {
80  	/***
81  	 * INIT parameters required by the Perl Portlet:PerlScript, ScriptPath, DemoMode
82  	 *
83  	 * Name of the scrip to to execute
84  	 */
85  	public static final String PARAM_PERL_SCRIPT	=	"PerlScript";
86  
87  	/***
88  	 * Name of the Script Path where the perl scripts (among others) are located
89  	 */
90  	public static final String PARAM_SCRIPT_PATH	=	"ScriptPath";
91  	
92  	/***
93  	 * DemoMode on or off
94  	 */
95  	public static final String PARAM_DEMO_MODE	=	"DemoMode";
96  	
97  	/***
98  	 * PARAM_APPLICATION
99  	 * 
100      * ApplicationName identifies the caller so that the portlet only refreshes
101      * content that was supposed for the portlet.
102      * If the application name is undefined the portlet will process the request.
103      * If you have more than one perl-portlet for the same user/session all the portlets
104      * will be refreshed with the same content.
105 	 */
106 	public static final String PARAM_APPLICATION = "Application";
107 
108 //  Local variables
109 	private String perlScript	=	"perl-demo.cgi";
110     private String	scriptPath	=	"cgi-bin";
111     
112     
113     private String applicationName = null;
114     
115     // Switch that shows basic information about the perl script to run
116     private boolean bDemoMode	=	false;
117     
118     private static final Log log = LogFactory.getLog(PerlPortlet.class);
119     
120        
121     // caching status -- cache the last query    
122     private String lastQuery = null;
123     
124     // Cache the last generated page
125     String lastPage = null;
126     
127     /* PerlContent rewriter */
128     RulesetRewriter		rewriter = null;
129     RewriterController	rewriteController = null;
130     
131     /*** Default encoding */
132     public String defaultEncoding = "UTF-8";
133     
134     
135     public void init(PortletConfig config) throws PortletException
136     {
137     
138         super.init(config);
139         
140         // Get the INIT PARAMETERS for this portlet. If the values are missing
141         // throw an exception
142         scriptPath		=	config.getInitParameter(PARAM_SCRIPT_PATH);
143         perlScript		=	config.getInitParameter(PARAM_PERL_SCRIPT);
144         String demoMode =	config.getInitParameter(PARAM_DEMO_MODE); 
145         applicationName = config.getInitParameter(PARAM_APPLICATION);
146         
147         if (demoMode != null && demoMode.compareToIgnoreCase("on") == 0)
148         	bDemoMode = true;
149         
150         if (scriptPath == null)
151             throw new PortletException("Portlet " + config.getPortletName()
152                     + " is incorrectly configured. Init parameter "
153                     + PARAM_SCRIPT_PATH + " not specified");
154         
155         if (perlScript == null)
156             throw new PortletException("Portlet " + config.getPortletName()
157                     + " is incorrectly configured. Init parameter "
158                     + PARAM_PERL_SCRIPT + " not specified");
159      }	
160     
161     /***
162      * processAction()
163      * Checks action initiated by the perl portlet (invoking other perl scripts)
164      * @param actionRequest
165      * @param actionResponse
166      * @throws PortletException
167      * @throws IOException
168      */
169     public void processAction(ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException, IOException
170 	{
171     	String perlParameter = actionRequest.getParameter(PerlParameters.ACTION_PARAMETER_PERL);
172      	/*
173     	 * If the perlParameter is not empty create a PerlParameter object and attach it to the session
174     	 */
175     	if ( perlParameter != null && perlParameter.length() > 0)
176     	{
177     		// Perl Parameter Object
178     		PerlParameters cgi = new PerlParameters();
179     		cgi.setApplicationName(this.applicationName);
180        		
181     		// Separate the values before and after the Query Mark ?
182     		int ixQuery = perlParameter.indexOf('?');
183     		if ( ixQuery != -1)
184     		{
185     			// Remove leading slash
186     			if (perlParameter.charAt(0) == '/')
187     				cgi.setScriptName(perlParameter.substring(1,ixQuery));
188     			else
189     				cgi.setScriptName(perlParameter.substring(0,ixQuery));
190     			
191     			String queryArguments = perlParameter.substring(ixQuery+1);
192     			System.out.println("ProcessRequest -- Script " + perlParameter.substring(0,ixQuery) + " Query string " + queryArguments);
193     			
194     			int ixQuerySeparator = queryArguments.indexOf('&');
195     			while ( ixQuerySeparator != -1)
196     			{
197     				cgi.addQueryArgument(queryArguments.substring(0, ixQuerySeparator));
198     				queryArguments = queryArguments.substring(ixQuerySeparator+1);
199     				ixQuerySeparator = queryArguments.indexOf('&');
200     			}
201     			
202     			cgi.addQueryArgument(queryArguments);
203     			
204     			// Add the PerlParameters to the session
205     			actionRequest.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER, cgi, PortletSession.APPLICATION_SCOPE);
206     		}
207     		else
208     		{
209     			// No query string just the script name
210     			cgi.setScriptName(perlParameter);
211     			
212     			// Get all the parameters from the request and add them as query arguments
213     			Enumeration names = actionRequest.getParameterNames();
214     			String name, value;
215     			while (names.hasMoreElements())
216     			{
217     				name = (String)names.nextElement();
218     				// PERL_PARAMETER already processed just ignore it
219     				if (name.compareToIgnoreCase(PerlParameters.ACTION_PARAMETER_PERL) != 0)
220     				{
221     				    // Same parameter name can have multiple values (multi select view box)
222     				    String [] values = actionRequest. getParameterValues(name);
223     				    
224     				    for (int ii=0; ii < values.length; ii++)
225     				    {
226     				    
227 	    					value = values[ii];
228 	    					
229 	    					if (value !=null && value.length() > 0)
230 	    					{
231 	    					    /*
232 	    					     * If the query parameter contains any & replace it with %26 (URL encoding)
233 	    					     */
234 	    						value = urlEncoding(value, "&", "%26");
235 	    						value = urlEncoding(value, "+", "%2b");
236 	    						value = urlEncoding(value, "//", "%5c");
237 	    						
238 		    					cgi.addQueryArgument(name + "=" + value);
239 		    					
240 	    					}
241     				    }
242     				}
243     			}
244     			// Add the PerlParameters to the session
245     			actionRequest.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER, cgi, PortletSession.APPLICATION_SCOPE);
246      		}
247     	}
248 	}
249     /***
250      * doView
251      * Executes the perl script that is defined by the property PerlScript.
252      * If the incoming request has the query perl-script= defined this script will be executed.
253      */
254     public void doView(RenderRequest request, RenderResponse response)
255     throws PortletException, IOException
256 	{
257     	// Set the content type
258     	response.setContentType("text/html");
259     	
260     	// Get a writer object that can be used to generate the output
261     	HttpServletResponse httpResponse = (HttpServletResponse)((HttpServletResponseWrapper) response).getResponse();
262     	
263     	//PrintWriter writer = response.getWriter();
264     	PrintWriter writer = httpResponse.getWriter();
265     	   	
266     	String query		= null;
267     	String scriptName	= null;
268     	PerlParameters perlParam = null;
269     	
270     	/***
271     	 * The Perl parameters are either passed by a session attribute (invoked from a different portlet) or as an action which is replaced
272     	 * with a session while processing actions..
273     	 */
274     	    	
275 		try
276 		{
277     		perlParam = (PerlParameters)request.getPortletSession().getAttribute(PerlParameters.PERL_PARAMETER, PortletSession.APPLICATION_SCOPE);
278     		// Remove perl object from session.
279     		request.getPortletSession().removeAttribute(PerlParameters.PERL_PARAMETER, PortletSession.APPLICATION_SCOPE);
280 		}
281     	catch (Exception e )
282 		{
283     		perlParam = null;
284 		}
285     	
286     	if (perlParam != null)
287     	{
288     	    // Only use the values if the call is designated to this script
289     	    if (perlParam.getApplicationName().compareToIgnoreCase(this.applicationName) == 0)
290     	    {
291 	    		query = perlParam.getQueryString();
292 	    		perlScript = perlParam.getScriptName();
293     	    }
294     	    
295     		if (this.applicationName == null ) // not yet initialized
296     		{
297     			this.applicationName = perlParam.getApplicationName();
298     		}
299     		else
300     		{
301 	    		// If the application name doesn't match just use the cached version and return
302 	    		if (         lastPage != null 							// has run at least once
303 	    				&& this.applicationName != null	// No filtering runs for any perl request
304 	    				&& perlParam.getApplicationName().compareToIgnoreCase(this.applicationName) != 0)
305 	    		{
306 	    			// Use cache
307 	    			writer.println(this.lastPage);
308 	    			return;
309 	    		}
310     		}
311     	}
312     	else
313     	{
314     		/*
315     		 * 	Check for a query string since the portlet could be invoked form JAVA Script and therefore
316     		 *	the parameters are not encoded in a Portlet Action or Perl Session.
317     		*/
318     		StringBuffer queries = new StringBuffer();
319     		
320     		Enumeration names = request. getParameterNames();
321     		for (Enumeration e = request. getParameterNames() ; e.hasMoreElements() ;) {
322     			String name = (String)e.nextElement();
323     			
324 				//Same parameter name can have multiple values (multi select view box)
325 			    String [] values = request. getParameterValues(name);
326 			    
327 			    for (int ii=0; ii < values.length; ii++)
328 			    {
329 			    	String value = values[ii];
330 			    	
331 			    	if (queries.length() > 0)
332 			    		queries.append("&");
333 			    	
334 					// Make sure that any ? are replaced with & since JAVA SCRIPT
335 			    	// might patch different elements together.
336 			    	int ix = value.indexOf("?");
337 					if (ix > -1)
338 					{
339 						String tmp = value.substring(0,ix) + "&" + value.substring(ix+1);
340 						value = tmp;
341 					}
342 					// Check if the query string defines the argument file
343 					if (name.compareToIgnoreCase("file") == 0)
344 					{
345 						/* file=hello&arg=hello */
346 						/* file=test.cgi */
347 						String reminder = "";
348 						
349 						int ixEnd = value.indexOf("&");
350 						if (ixEnd > -1)
351 						{
352 							reminder = value.substring(ixEnd +1);
353 							perlScript = value.substring(0,ixEnd);
354 						}
355 						else
356 						{
357 							perlScript = value;
358 						}
359 						
360 						if (reminder.length() > 0)
361 							queries.append(reminder);
362 					}
363 					else
364 					{
365 						queries.append(name).append("=").append(value);
366 					}
367 			    }
368     		}
369     		query = queries.toString();
370     		
371     		//Cleanup of Buffer
372     		queries.delete(0, queries.length());
373     		
374     		System.out.println("Script [" + perlScript +"]");
375     		System.out.println("Direct Query [" + queries.toString() +"]");
376     	}
377     	
378     	// Open the perl script and extract the perl executable path. It's the same way as apache HTTP executes PERL
379     	String perlExecutable = null;
380     	
381      	PortletContext portletApplication = getPortletContext(); 
382         String path = portletApplication.getRealPath("/WEB-INF");
383         String contextPath = path + "/";
384  
385         String fullScriptPath = contextPath + scriptPath;
386     
387     	// Build full path to scripts
388     	if (perlScript.startsWith("/") == false )
389     	    fullScriptPath += "/";
390     	fullScriptPath += perlScript;
391     	
392     	// command to execute
393     	String command = null;
394     		
395     	// Open the script and read the first line to get the executable !/usr/bin/perl OR !c:\bin\perl\perl.exe
396     	try
397 		{
398     		BufferedReader in= new BufferedReader(new FileReader(fullScriptPath));
399     		String lnExecutable = in.readLine();
400     		
401     		if (lnExecutable != null )
402     		{
403     			// Make sure that the executable is defined -- could be a compiled cgi with no executable defined
404     			String lnExecutableLower = lnExecutable.toLowerCase();
405     			int px = lnExecutableLower.indexOf("perl");
406     			int ix = lnExecutable.indexOf('!');
407     			if ( ix != -1 && px != -1 )
408     			{
409                     int ex = lnExecutable.indexOf(' ',ix);
410                     if ( ex >= 0 )
411                     {
412                         perlExecutable = lnExecutable.substring(ix+1, ex);
413                     }
414                     else
415                     {
416                         perlExecutable = lnExecutable.substring(ix+1);
417                     }
418     			} 
419     		}
420     		//Close file
421     		in.close();
422     		
423     		StringBuffer commandBuffer = new StringBuffer();
424     		if (perlExecutable == null)
425     			commandBuffer.append(fullScriptPath);
426     		else
427     			commandBuffer.append(perlExecutable).append(' ').append(fullScriptPath);
428     		
429     		command = new String(commandBuffer.toString());
430     		
431 		}
432     	catch(FileNotFoundException e)
433 		{
434     		writer.println("<P><B>File doesn't exist (" + fullScriptPath + ")</B></P>");
435 		}
436     	catch(IOException e)
437 		{
438     		writer.println("<P><B>IO Exception (" + e.getMessage() + ")</B></P>");
439 		}
440 		catch(Exception e)
441 		{
442 			writer.println("<P><B>IO Exception (" + e.getMessage() + ")</B></P>");
443 		}
444 			
445 		String envQuery = "QUERY_STRING=" + query ;
446 		
447 		String[] env = null;
448 		env = new String[]{"REQUEST_METHOD=GET", envQuery, "LD_LIBRARY_PATH=/usr/local/groundwork/lib"};
449 		
450 		if ( bDemoMode == true)
451 		{
452 			// Script info. This is for the Demo only
453 			//writer.println("<P>The portlet executes the perl script defined by the init-params. If you don't get an output make sure that the perl executable defined in the script is valid.");
454 			//writer.println("The executable is defined on the first line of your script.</P>Examples<ul><li><B>UNIX/Linux:</B>!/usr/bin/perl</li><li><B>Windows:</B>!c://bin//perl//perl.exe</li></ul>");
455 			writer.println("<B><P>Perl Script:</B>" + fullScriptPath + "<BR>");
456 			//writer.println("<B>Perl executable:</B>" + perlExecutable + "<BR>");
457 			writer.println("<B>Query String:</B>" + query + "</P>");
458 		}   	
459     	
460 		
461 		//Execute the perl script from the command line
462 		if (command != null )
463 		{
464 			
465 			// Execute command in a separate process. The perl output is written to the stdout
466 			try
467 			{	
468 				long timeStart =0;
469 				long timeEnd = 0;
470 				
471 				if ( bDemoMode == true)
472 				{
473 					timeStart = System.currentTimeMillis();
474 				}
475 				// Start process
476 				Process proc = Runtime.getRuntime().exec(command,env);
477 									
478 				// Get stdout of process and create a buffered reader
479 				InputStream in = proc.getInputStream();
480 				BufferedReader perlResult = new BufferedReader(new InputStreamReader(in));
481 				StringBuffer page = new StringBuffer();
482 				
483 				if ( bDemoMode == true)
484 				{
485 					timeEnd = System.currentTimeMillis();
486 					writer.println("<B>Execution Time create process: </B>" + (timeEnd -timeStart) + " ms </P>");
487 					timeStart = System.currentTimeMillis();
488 				}
489 				
490 				int BLOCK_SIZE = 8192;
491 				char[] bytes = new char[BLOCK_SIZE];
492 				
493 				//Wait until proc is done
494 				boolean bProcDone = false;
495 				while (bProcDone == false)
496 				{
497 					try
498 					{
499 						proc.exitValue() ;
500 						bProcDone = true;
501 					}
502 					catch(IllegalThreadStateException e)
503 					{
504 						bProcDone = false; //Not done yet
505 						
506 						// Read the buffer otherwise the process will be blocked because it can't write to the stdout (max size of buffer)						
507 						int len = perlResult.read(bytes, 0, BLOCK_SIZE);
508 						
509 						while (len > 0)
510 						{
511 							page.append(bytes, 0, len);
512 							len = perlResult.read(bytes, 0, BLOCK_SIZE);
513 						}
514 					}
515 				}
516 				
517 				// Perl execution done read the remaining  buffer
518 				int len = perlResult.read(bytes, 0, BLOCK_SIZE);
519 				while (len > 0)
520 				{
521 						page.append(bytes, 0, len);
522 						len = perlResult.read(bytes, 0, BLOCK_SIZE);
523 				}
524 				
525 				// Close stream
526 				perlResult.close();	
527 				
528 				//Make sure process is destroyed
529 				try
530 				{
531 					proc.destroy();
532 				}
533 				catch(Exception e)
534 				{
535 					System.out.println("Error killing perl subprocess. Error " + e);
536 				}
537 				
538 				if ( bDemoMode == true)
539 				{
540 					timeEnd = System.currentTimeMillis();
541 					writer.println("<B>Loading output of perl: </B>" + (timeEnd -timeStart) + " ms </P>");
542 					timeStart = System.currentTimeMillis();
543 				}	
544 				/*
545 				 * Use rewriter for replacing all URL's with portlet actions
546 				 */
547 				/*
548 		        if (rewriteController == null)
549 		        {
550 		            try
551 		            {
552 		                // Create rewriter adaptor
553 		                rewriteController = getController(contextPath);
554 		            }
555 		            catch (Exception e)
556 		            {
557 		                // Failed to create rewriter controller
558 		                throw new PortletException("WebContentProtlet failed to create rewriter controller. Error:"
559 		                        + e.getMessage());
560 		            }
561 		        }
562 		        
563 		        //	Any HREFs and Form actions should be extended with the ActionURL
564 				PortletURL actionURL = response.createActionURL();
565 				byte[] content = this.doWebContent(page, actionURL, PerlParameters.ACTION_PARAMETER_PERL);
566 				ByteArrayInputStream bais = new ByteArrayInputStream(content);
567 				OutputStream oswriter = response.getPortletOutputStream();
568 				
569 				int BLOCK_SIZE = 4096;
570 				byte[] bytes = new byte[BLOCK_SIZE];
571 		        try
572 		        {
573 		            int length = bais.read(bytes);
574 		            while (length != -1)
575 		            {
576 		                if (length != 0)
577 		                {
578 		                    oswriter.write(bytes, 0, length);
579 		                }
580 		                length = bais.read(bytes);
581 		            }
582 		        }
583 		        finally
584 		        {
585 		            bytes = null;
586 		        }
587 				
588 				//	Cache page
589 				lastPage = new String(content);
590 				*/
591 				
592 				
593 				
594 				// Post Process for generated page		
595 				PortletURL actionURL = response.createActionURL();
596 				ScriptPostProcess processor = new ScriptPostProcess();
597 				processor.setInitalPage(page);
598 				processor.postProcessPage(actionURL, PerlParameters.ACTION_PARAMETER_PERL);
599 				String finalPage = processor.getFinalizedPage();
600 				
601 				if ( bDemoMode == true)
602 				{
603 					timeEnd = System.currentTimeMillis();
604 					writer.println("<P><B>Rewriting perl: </B>" + (timeEnd - timeStart) + " ms </P>");
605 				}
606 				
607 				// Write the page
608 				writer.println(finalPage);
609 				
610 				
611 				// Cache page
612 				//lastPage = new String(finalPage);
613 				
614 			}
615 			catch(IOException ioe)
616 			{
617 				writer.println("<P><B>Exception while reading perl output" + ioe.getMessage() + "</B></P>");
618 			}
619 			catch(Exception e)
620 			{
621 				writer.println("<P><B>Exception while reading perl output" + e + "</B></P>");
622 			}
623 		}
624 		else
625 		{
626 			writer.println("<P><B>Error. Failed to run perl script [" + perlScript + "]</B></P>");
627 		}
628 	} 
629     
630     /*
631      * Generate a rewrite controller using the basic rules file
632      */
633     private RewriterController getController(String contextPath) throws Exception
634     {
635         Class[] rewriterClasses = new Class[]
636         { PerlContentRewriter.class, PerlContentRewriter.class};
637         
638         Class[] adaptorClasses = new Class[]
639         { SwingParserAdaptor.class, SaxParserAdaptor.class};
640         RewriterController rwc = new JetspeedRewriterController(contextPath + "conf/rewriter-rules-mapping.xml", Arrays
641                 .asList(rewriterClasses), Arrays.asList(adaptorClasses));
642 
643         FileReader reader = new FileReader(contextPath + "conf/default-rewriter-rules.xml");
644 
645         Ruleset ruleset = rwc.loadRuleset(reader);
646         reader.close();
647         rewriter = rwc.createRewriter(ruleset);
648         return rwc;
649     }
650     
651     protected byte[] doWebContent(StringBuffer perlRenderedPage, PortletURL actionURL, String actionParameterName)
652     throws PortletException
653 	{
654 		// Initialization
655 		Writer htmlWriter = null;
656 		
657 		ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
658 		
659 		try
660 		{
661 		    htmlWriter = new OutputStreamWriter(byteOutputStream, this.defaultEncoding);
662 		
663 		    // Set the action URL in the rewriter
664 		   
665 		   ((PerlContentRewriter) rewriter).setActionURL(actionURL);
666 		   ((PerlContentRewriter) rewriter).setActionParameterName(actionParameterName);
667 		   
668 		    StringReader perlReader = new StringReader(perlRenderedPage.toString());
669 		    rewriter.rewrite(rewriteController.createParserAdaptor("text/html"), perlReader, htmlWriter);
670 		    htmlWriter.flush();
671 		}
672 		catch (UnsupportedEncodingException ueex)
673 		{
674 		    throw new PortletException("Encoding " + defaultEncoding + " not supported. Error: " + ueex.getMessage());
675 		}
676 		catch (RewriterException rwe)
677 		{
678 		    throw new PortletException("Failed to rewrite Perl ouput. Error: " + rwe.getMessage());
679 		}
680 		catch (Exception e)
681 		{
682 		    throw new PortletException("Exception while rewritting Perl output. Error: " + e.getMessage());
683 		}
684 		
685 		return byteOutputStream.toByteArray();
686 	}
687     
688     // Helper
689     private String urlEncoding(String url, String source, String replace)
690     {
691     	String value = url;
692     	int ix = value.indexOf(source);
693 	    if (ix != -1)
694 	    {
695 	        String replacement = "";
696 		    
697 	        // Replace all & in the value
698 		    while (ix != -1)
699 		    {
700 		        replacement += value.substring(0, ix);
701 		        replacement += replace;
702 		        // Check if the & was the last char
703 		        if (value.length() > ix)
704 		            value = value.substring(ix+1);
705 		        else
706 		            value = "";	// End of string
707 		        
708 		        // Check again
709 		        ix = value.indexOf(source);
710 		    }
711 		    
712 	        // Reminder
713 	        replacement += value;
714 	        // Assignement
715 	        value = replacement;
716 	    }
717 	    return value;
718     }
719 }
720