Package org.apache.portals.bridges.perl

Source Code of org.apache.portals.bridges.perl.PerlPortlet

/*
* Copyright 2000-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.portals.bridges.perl;

import javax.portlet.GenericPortlet;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.PortletSession;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jetspeed.rewriter.JetspeedRewriterController;
import org.apache.jetspeed.rewriter.RewriterController;
import org.apache.jetspeed.rewriter.RewriterException;
import org.apache.jetspeed.rewriter.RulesetRewriter;
import org.apache.jetspeed.rewriter.html.SwingParserAdaptor;
import org.apache.jetspeed.rewriter.rules.Ruleset;
import org.apache.jetspeed.rewriter.xml.SaxParserAdaptor;

import org.apache.portals.bridges.common.ScriptPostProcess;


/**
* This portlet is executes a Perl/cgi files in a portlet.
*
* Note:
* The Perl Portlet uses the rewriter component that requires config xml files.
* Make sre that the portlet application using the Perl Portlet has the following files included
* in WEB-INF/conf: rewriter-rules-mapping.xml and default-rewriter-rules.xml
*
* @author <a href="mailto:rogerrut@apache.org">Roger Ruttimann</a>
* @version $Id: PerlPortlet.java 354869 2005-12-07 22:49:17 +0100 (Wed, 07 Dec 2005) rogerrut $
*/

public class PerlPortlet extends GenericPortlet {
  /**
   * INIT parameters required by the Perl Portlet:PerlScript, ScriptPath, DemoMode
   *
   * Name of the scrip to to execute
   */
  public static final String PARAM_PERL_SCRIPT  =  "PerlScript";

  /**
   * Name of the Script Path where the perl scripts (among others) are located
   */
  public static final String PARAM_SCRIPT_PATH  =  "ScriptPath";
 
  /**
   * DemoMode on or off
   */
  public static final String PARAM_DEMO_MODE  =  "DemoMode";
 
  /**
   * PARAM_APPLICATION
   *
     * ApplicationName identifies the caller so that the portlet only refreshes
     * content that was supposed for the portlet.
     * If the application name is undefined the portlet will process the request.
     * If you have more than one perl-portlet for the same user/session all the portlets
     * will be refreshed with the same content.
   */
  public static final String PARAM_APPLICATION = "Application";

//  Local variables
  private String perlScript  =  "perl-demo.cgi";
    private String  scriptPath  =  "cgi-bin";
   
   
    private String applicationName = null;
   
    // Switch that shows basic information about the perl script to run
    private boolean bDemoMode  =  false;
   
    private static final Log log = LogFactory.getLog(PerlPortlet.class);
   
      
    // caching status -- cache the last query   
    private String lastQuery = null;
   
    // Cache the last generated page
    String lastPage = null;
   
    /* PerlContent rewriter */
    RulesetRewriter    rewriter = null;
    RewriterController  rewriteController = null;
   
    /** Default encoding */
    public String defaultEncoding = "UTF-8";
   
   
    public void init(PortletConfig config) throws PortletException
    {
   
        super.init(config);
       
        // Get the INIT PARAMETERS for this portlet. If the values are missing
        // throw an exception
        scriptPath    =  config.getInitParameter(PARAM_SCRIPT_PATH);
        perlScript    =  config.getInitParameter(PARAM_PERL_SCRIPT);
        String demoMode =  config.getInitParameter(PARAM_DEMO_MODE);
        applicationName = config.getInitParameter(PARAM_APPLICATION);
       
        if (demoMode != null && demoMode.compareToIgnoreCase("on") == 0)
          bDemoMode = true;
       
        if (scriptPath == null)
            throw new PortletException("Portlet " + config.getPortletName()
                    + " is incorrectly configured. Init parameter "
                    + PARAM_SCRIPT_PATH + " not specified");
       
        if (perlScript == null)
            throw new PortletException("Portlet " + config.getPortletName()
                    + " is incorrectly configured. Init parameter "
                    + PARAM_PERL_SCRIPT + " not specified");
    
   
    /**
     * processAction()
     * Checks action initiated by the perl portlet (invoking other perl scripts)
     * @param actionRequest
     * @param actionResponse
     * @throws PortletException
     * @throws IOException
     */
    public void processAction(ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException, IOException
  {
      String perlParameter = actionRequest.getParameter(PerlParameters.ACTION_PARAMETER_PERL);
       /*
       * If the perlParameter is not empty create a PerlParameter object and attach it to the session
       */
      if ( perlParameter != null && perlParameter.length() > 0)
      {
        // Perl Parameter Object
        PerlParameters cgi = new PerlParameters();
        cgi.setApplicationName(this.applicationName);
          
        // Separate the values before and after the Query Mark ?
        int ixQuery = perlParameter.indexOf('?');
        if ( ixQuery != -1)
        {
          // Remove leading slash
          if (perlParameter.charAt(0) == '/')
            cgi.setScriptName(perlParameter.substring(1,ixQuery));
          else
            cgi.setScriptName(perlParameter.substring(0,ixQuery));
         
          String queryArguments = perlParameter.substring(ixQuery+1);
          System.out.println("ProcessRequest -- Script " + perlParameter.substring(0,ixQuery) + " Query string " + queryArguments);
         
          int ixQuerySeparator = queryArguments.indexOf('&');
          while ( ixQuerySeparator != -1)
          {
            cgi.addQueryArgument(queryArguments.substring(0, ixQuerySeparator));
            queryArguments = queryArguments.substring(ixQuerySeparator+1);
            ixQuerySeparator = queryArguments.indexOf('&');
          }
         
          cgi.addQueryArgument(queryArguments);
         
          // Add the PerlParameters to the session
          actionRequest.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER, cgi, PortletSession.APPLICATION_SCOPE);
        }
        else
        {
          // No query string just the script name
          cgi.setScriptName(perlParameter);
         
          // Get all the parameters from the request and add them as query arguments
          Enumeration names = actionRequest.getParameterNames();
          String name, value;
          while (names.hasMoreElements())
          {
            name = (String)names.nextElement();
            // PERL_PARAMETER already processed just ignore it
            if (name.compareToIgnoreCase(PerlParameters.ACTION_PARAMETER_PERL) != 0)
            {
                // Same parameter name can have multiple values (multi select view box)
                String [] values = actionRequest. getParameterValues(name);
               
                for (int ii=0; ii < values.length; ii++)
                {
               
                value = values[ii];
               
                if (value !=null && value.length() > 0)
                {
                    /*
                     * If the query parameter contains any & replace it with %26 (URL encoding)
                     */
                  value = urlEncoding(value, "&", "%26");
                  value = urlEncoding(value, "+", "%2b");
                  value = urlEncoding(value, "\\", "%5c");
                 
                  cgi.addQueryArgument(name + "=" + value);
                 
                }
                }
            }
          }
          // Add the PerlParameters to the session
          actionRequest.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER, cgi, PortletSession.APPLICATION_SCOPE);
         }
      }
  }
    /**
     * doView
     * Executes the perl script that is defined by the property PerlScript.
     * If the incoming request has the query perl-script= defined this script will be executed.
     */
    public void doView(RenderRequest request, RenderResponse response)
    throws PortletException, IOException
  {
      // Set the content type
      response.setContentType("text/html");
     
      // Get a writer object that can be used to generate the output
      HttpServletResponse httpResponse = (HttpServletResponse)((HttpServletResponseWrapper) response).getResponse();
     
      //PrintWriter writer = response.getWriter();
      PrintWriter writer = httpResponse.getWriter();
          
      String query    = null;
      String scriptName  = null;
      PerlParameters perlParam = null;
     
      /**
       * The Perl parameters are either passed by a session attribute (invoked from a different portlet) or as an action which is replaced
       * with a session while processing actions..
       */
           
    try
    {
        perlParam = (PerlParameters)request.getPortletSession().getAttribute(PerlParameters.PERL_PARAMETER, PortletSession.APPLICATION_SCOPE);
        // Remove perl object from session.
        request.getPortletSession().removeAttribute(PerlParameters.PERL_PARAMETER, PortletSession.APPLICATION_SCOPE);
    }
      catch (Exception e )
    {
        perlParam = null;
    }
     
      if (perlParam != null)
      {
          // Only use the values if the call is designated to this script
          if (perlParam.getApplicationName().compareToIgnoreCase(this.applicationName) == 0)
          {
          query = perlParam.getQueryString();
          perlScript = perlParam.getScriptName();
          }
         
        if (this.applicationName == null ) // not yet initialized
        {
          this.applicationName = perlParam.getApplicationName();
        }
        else
        {
          // If the application name doesn't match just use the cached version and return
          if (         lastPage != null               // has run at least once
              && this.applicationName != null  // No filtering runs for any perl request
              && perlParam.getApplicationName().compareToIgnoreCase(this.applicationName) != 0)
          {
            // Use cache
            writer.println(this.lastPage);
            return;
          }
        }
      }
      else
      {
        /*
         *   Check for a query string since the portlet could be invoked form JAVA Script and therefore
         *  the parameters are not encoded in a Portlet Action or Perl Session.
        */
        StringBuffer queries = new StringBuffer();
       
        Enumeration names = request. getParameterNames();
        for (Enumeration e = request. getParameterNames() ; e.hasMoreElements() ;) {
          String name = (String)e.nextElement();
         
        //Same parameter name can have multiple values (multi select view box)
          String [] values = request. getParameterValues(name);
         
          for (int ii=0; ii < values.length; ii++)
          {
            String value = values[ii];
           
            if (queries.length() > 0)
              queries.append("&");
           
          // Make sure that any ? are replaced with & since JAVA SCRIPT
            // might patch different elements together.
            int ix = value.indexOf("?");
          if (ix > -1)
          {
            String tmp = value.substring(0,ix) + "&" + value.substring(ix+1);
            value = tmp;
          }
          // Check if the query string defines the argument file
          if (name.compareToIgnoreCase("file") == 0)
          {
            /* file=hello&arg=hello */
            /* file=test.cgi */
            String reminder = "";
           
            int ixEnd = value.indexOf("&");
            if (ixEnd > -1)
            {
              reminder = value.substring(ixEnd +1);
              perlScript = value.substring(0,ixEnd);
            }
            else
            {
              perlScript = value;
            }
           
            if (reminder.length() > 0)
              queries.append(reminder);
          }
          else
          {
            queries.append(name).append("=").append(value);
          }
          }
        }
        query = queries.toString();
       
        //Cleanup of Buffer
        queries.delete(0, queries.length());
       
        System.out.println("Script [" + perlScript +"]");
        System.out.println("Direct Query [" + queries.toString() +"]");
      }
     
      // Open the perl script and extract the perl executable path. It's the same way as apache HTTP executes PERL
      String perlExecutable = null;
     
       PortletContext portletApplication = getPortletContext();
        String path = portletApplication.getRealPath("/WEB-INF");
        String contextPath = path + "/";
        String fullScriptPath = contextPath + scriptPath;
   
      // Build full path to scripts
      if (perlScript.startsWith("/") == false )
          fullScriptPath += "/";
      fullScriptPath += perlScript;
     
      // command to execute
      String command = null;
       
      // Open the script and read the first line to get the executable !/usr/bin/perl OR !c:\bin\perl\perl.exe
      try
    {
        BufferedReader in= new BufferedReader(new FileReader(fullScriptPath));
        String lnExecutable = in.readLine();
       
        if (lnExecutable != null )
        {
          // Make sure that the executable is defined -- could be a compiled cgi with no executable defined
          String lnExecutableLower = lnExecutable.toLowerCase();
          int px = lnExecutableLower.indexOf("perl");
          int ix = lnExecutable.indexOf('!');
          if ( ix != -1 && px != -1 )
          {
                    int ex = lnExecutable.indexOf(' ',ix);
                    if ( ex >= 0 )
                    {
                        perlExecutable = lnExecutable.substring(ix+1, ex);
                    }
                    else
                    {
                        perlExecutable = lnExecutable.substring(ix+1);
                    }
          }
        }
        //Close file
        in.close();
       
        StringBuffer commandBuffer = new StringBuffer();
        if (perlExecutable == null)
          commandBuffer.append(fullScriptPath);
        else
          commandBuffer.append(perlExecutable).append(' ').append(fullScriptPath);
       
        command = new String(commandBuffer.toString());
       
    }
      catch(FileNotFoundException e)
    {
        writer.println("<P><B>File doesn't exist (" + fullScriptPath + ")</B></P>");
    }
      catch(IOException e)
    {
        writer.println("<P><B>IO Exception (" + e.getMessage() + ")</B></P>");
    }
    catch(Exception e)
    {
      writer.println("<P><B>IO Exception (" + e.getMessage() + ")</B></P>");
    }
     
    String envQuery = "QUERY_STRING=" + query ;
   
    String[] env = null;
    env = new String[]{"REQUEST_METHOD=GET", envQuery, "LD_LIBRARY_PATH=/usr/local/groundwork/lib"};
   
    if ( bDemoMode == true)
    {
      // Script info. This is for the Demo only
      //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.");
      //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>");
      writer.println("<B><P>Perl Script:</B>" + fullScriptPath + "<BR>");
      //writer.println("<B>Perl executable:</B>" + perlExecutable + "<BR>");
      writer.println("<B>Query String:</B>" + query + "</P>");
    }    
     
   
    //Execute the perl script from the command line
    if (command != null )
    {
     
      // Execute command in a separate process. The perl output is written to the stdout
      try
     
        long timeStart =0;
        long timeEnd = 0;
       
        if ( bDemoMode == true)
        {
          timeStart = System.currentTimeMillis();
        }
        // Start process
        Process proc = Runtime.getRuntime().exec(command,env);
                 
        // Get stdout of process and create a buffered reader
        InputStream in = proc.getInputStream();
        BufferedReader perlResult = new BufferedReader(new InputStreamReader(in));
        StringBuffer page = new StringBuffer();
       
        if ( bDemoMode == true)
        {
          timeEnd = System.currentTimeMillis();
          writer.println("<B>Execution Time create process: </B>" + (timeEnd -timeStart) + " ms </P>");
          timeStart = System.currentTimeMillis();
        }
       
        int BLOCK_SIZE = 8192;
        char[] bytes = new char[BLOCK_SIZE];
       
        //Wait until proc is done
        boolean bProcDone = false;
        while (bProcDone == false)
        {
          try
          {
            proc.exitValue() ;
            bProcDone = true;
          }
          catch(IllegalThreadStateException e)
          {
            bProcDone = false; //Not done yet
           
            // Read the buffer otherwise the process will be blocked because it can't write to the stdout (max size of buffer)           
            int len = perlResult.read(bytes, 0, BLOCK_SIZE);
           
            while (len > 0)
            {
              page.append(bytes, 0, len);
              len = perlResult.read(bytes, 0, BLOCK_SIZE);
            }
          }
        }
       
        // Perl execution done read the remaining  buffer
        int len = perlResult.read(bytes, 0, BLOCK_SIZE);
        while (len > 0)
        {
            page.append(bytes, 0, len);
            len = perlResult.read(bytes, 0, BLOCK_SIZE);
        }
       
        // Close stream
        perlResult.close()
       
        //Make sure process is destroyed
        try
        {
          proc.destroy();
        }
        catch(Exception e)
        {
          System.out.println("Error killing perl subprocess. Error " + e);
        }
       
        if ( bDemoMode == true)
        {
          timeEnd = System.currentTimeMillis();
          writer.println("<B>Loading output of perl: </B>" + (timeEnd -timeStart) + " ms </P>");
          timeStart = System.currentTimeMillis();
       
        /*
         * Use rewriter for replacing all URL's with portlet actions
         */
        /*
            if (rewriteController == null)
            {
                try
                {
                    // Create rewriter adaptor
                    rewriteController = getController(contextPath);
                }
                catch (Exception e)
                {
                    // Failed to create rewriter controller
                    throw new PortletException("WebContentProtlet failed to create rewriter controller. Error:"
                            + e.getMessage());
                }
            }
           
            //  Any HREFs and Form actions should be extended with the ActionURL
        PortletURL actionURL = response.createActionURL();
        byte[] content = this.doWebContent(page, actionURL, PerlParameters.ACTION_PARAMETER_PERL);
        ByteArrayInputStream bais = new ByteArrayInputStream(content);
        OutputStream oswriter = response.getPortletOutputStream();
       
        int BLOCK_SIZE = 4096;
        byte[] bytes = new byte[BLOCK_SIZE];
            try
            {
                int length = bais.read(bytes);
                while (length != -1)
                {
                    if (length != 0)
                    {
                        oswriter.write(bytes, 0, length);
                    }
                    length = bais.read(bytes);
                }
            }
            finally
            {
                bytes = null;
            }
       
        //  Cache page
        lastPage = new String(content);
        */
       
       
       
        // Post Process for generated page   
        PortletURL actionURL = response.createActionURL();
        ScriptPostProcess processor = new ScriptPostProcess();
        processor.setInitalPage(page);
        processor.postProcessPage(actionURL, PerlParameters.ACTION_PARAMETER_PERL);
        String finalPage = processor.getFinalizedPage();
       
        if ( bDemoMode == true)
        {
          timeEnd = System.currentTimeMillis();
          writer.println("<P><B>Rewriting perl: </B>" + (timeEnd - timeStart) + " ms </P>");
        }
       
        // Write the page
        writer.println(finalPage);
       
       
        // Cache page
        //lastPage = new String(finalPage);
       
      }
      catch(IOException ioe)
      {
        writer.println("<P><B>Exception while reading perl output" + ioe.getMessage() + "</B></P>");
      }
      catch(Exception e)
      {
        writer.println("<P><B>Exception while reading perl output" + e + "</B></P>");
      }
    }
    else
    {
      writer.println("<P><B>Error. Failed to run perl script [" + perlScript + "]</B></P>");
    }
  }
   
    /*
     * Generate a rewrite controller using the basic rules file
     */
    private RewriterController getController(String contextPath) throws Exception
    {
        Class[] rewriterClasses = new Class[]
        { PerlContentRewriter.class, PerlContentRewriter.class};
       
        Class[] adaptorClasses = new Class[]
        { SwingParserAdaptor.class, SaxParserAdaptor.class};
        RewriterController rwc = new JetspeedRewriterController(contextPath + "conf/rewriter-rules-mapping.xml", Arrays
                .asList(rewriterClasses), Arrays.asList(adaptorClasses));

        FileReader reader = new FileReader(contextPath + "conf/default-rewriter-rules.xml");

        Ruleset ruleset = rwc.loadRuleset(reader);
        reader.close();
        rewriter = rwc.createRewriter(ruleset);
        return rwc;
    }
   
    protected byte[] doWebContent(StringBuffer perlRenderedPage, PortletURL actionURL, String actionParameterName)
    throws PortletException
  {
    // Initialization
    Writer htmlWriter = null;
   
    ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
   
    try
    {
        htmlWriter = new OutputStreamWriter(byteOutputStream, this.defaultEncoding);
   
        // Set the action URL in the rewriter
      
       ((PerlContentRewriter) rewriter).setActionURL(actionURL);
       ((PerlContentRewriter) rewriter).setActionParameterName(actionParameterName);
      
        StringReader perlReader = new StringReader(perlRenderedPage.toString());
        rewriter.rewrite(rewriteController.createParserAdaptor("text/html"), perlReader, htmlWriter);
        htmlWriter.flush();
    }
    catch (UnsupportedEncodingException ueex)
    {
        throw new PortletException("Encoding " + defaultEncoding + " not supported. Error: " + ueex.getMessage());
    }
    catch (RewriterException rwe)
    {
        throw new PortletException("Failed to rewrite Perl ouput. Error: " + rwe.getMessage());
    }
    catch (Exception e)
    {
        throw new PortletException("Exception while rewritting Perl output. Error: " + e.getMessage());
    }
   
    return byteOutputStream.toByteArray();
  }
   
    // Helper
    private String urlEncoding(String url, String source, String replace)
    {
      String value = url;
      int ix = value.indexOf(source);
      if (ix != -1)
      {
          String replacement = "";
       
          // Replace all & in the value
        while (ix != -1)
        {
            replacement += value.substring(0, ix);
            replacement += replace;
            // Check if the & was the last char
            if (value.length() > ix)
                value = value.substring(ix+1);
            else
                value = ""// End of string
           
            // Check again
            ix = value.indexOf(source);
        }
       
          // Reminder
          replacement += value;
          // Assignement
          value = replacement;
      }
      return value;
    }
}
  
TOP

Related Classes of org.apache.portals.bridges.perl.PerlPortlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.