1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
109 private String perlScript = "perl-demo.cgi";
110 private String scriptPath = "cgi-bin";
111
112
113 private String applicationName = null;
114
115
116 private boolean bDemoMode = false;
117
118 private static final Log log = LogFactory.getLog(PerlPortlet.class);
119
120
121
122 private String lastQuery = null;
123
124
125 String lastPage = null;
126
127
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
141
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
174
175 if ( perlParameter != null && perlParameter.length() > 0)
176 {
177
178 PerlParameters cgi = new PerlParameters();
179 cgi.setApplicationName(this.applicationName);
180
181
182 int ixQuery = perlParameter.indexOf('?');
183 if ( ixQuery != -1)
184 {
185
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
205 actionRequest.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER, cgi, PortletSession.APPLICATION_SCOPE);
206 }
207 else
208 {
209
210 cgi.setScriptName(perlParameter);
211
212
213 Enumeration names = actionRequest.getParameterNames();
214 String name, value;
215 while (names.hasMoreElements())
216 {
217 name = (String)names.nextElement();
218
219 if (name.compareToIgnoreCase(PerlParameters.ACTION_PARAMETER_PERL) != 0)
220 {
221
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
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
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
258 response.setContentType("text/html");
259
260
261 HttpServletResponse httpResponse = (HttpServletResponse)((HttpServletResponseWrapper) response).getResponse();
262
263
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
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
289 if (perlParam.getApplicationName().compareToIgnoreCase(this.applicationName) == 0)
290 {
291 query = perlParam.getQueryString();
292 perlScript = perlParam.getScriptName();
293 }
294
295 if (this.applicationName == null )
296 {
297 this.applicationName = perlParam.getApplicationName();
298 }
299 else
300 {
301
302 if ( lastPage != null
303 && this.applicationName != null
304 && perlParam.getApplicationName().compareToIgnoreCase(this.applicationName) != 0)
305 {
306
307 writer.println(this.lastPage);
308 return;
309 }
310 }
311 }
312 else
313 {
314
315
316
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
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
335
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
343 if (name.compareToIgnoreCase("file") == 0)
344 {
345
346
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
372 queries.delete(0, queries.length());
373
374 System.out.println("Script [" + perlScript +"]");
375 System.out.println("Direct Query [" + queries.toString() +"]");
376 }
377
378
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
388 if (perlScript.startsWith("/") == false )
389 fullScriptPath += "/";
390 fullScriptPath += perlScript;
391
392
393 String command = null;
394
395
396 try
397 {
398 BufferedReader in= new BufferedReader(new FileReader(fullScriptPath));
399 String lnExecutable = in.readLine();
400
401 if (lnExecutable != null )
402 {
403
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
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
453
454
455 writer.println("<B><P>Perl Script:</B>" + fullScriptPath + "<BR>");
456
457 writer.println("<B>Query String:</B>" + query + "</P>");
458 }
459
460
461
462 if (command != null )
463 {
464
465
466 try
467 {
468 long timeStart =0;
469 long timeEnd = 0;
470
471 if ( bDemoMode == true)
472 {
473 timeStart = System.currentTimeMillis();
474 }
475
476 Process proc = Runtime.getRuntime().exec(command,env);
477
478
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
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;
505
506
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
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
526 perlResult.close();
527
528
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
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
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
608 writer.println(finalPage);
609
610
611
612
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
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
655 Writer htmlWriter = null;
656
657 ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
658
659 try
660 {
661 htmlWriter = new OutputStreamWriter(byteOutputStream, this.defaultEncoding);
662
663
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
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
698 while (ix != -1)
699 {
700 replacement += value.substring(0, ix);
701 replacement += replace;
702
703 if (value.length() > ix)
704 value = value.substring(ix+1);
705 else
706 value = "";
707
708
709 ix = value.indexOf(source);
710 }
711
712
713 replacement += value;
714
715 value = replacement;
716 }
717 return value;
718 }
719 }
720