View Javadoc

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