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