1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
108 private String perlScript = "perl-demo.cgi";
109 private String scriptPath = "cgi-bin";
110
111
112 private String applicationName = null;
113
114
115 private boolean bDemoMode = false;
116
117 private static final Log log = LogFactory.getLog(PerlPortlet.class);
118
119
120
121 private String lastQuery = null;
122
123
124 String lastPage = null;
125
126
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
140
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
173
174 if ( perlParameter != null && perlParameter.length() > 0)
175 {
176
177 PerlParameters cgi = new PerlParameters();
178 cgi.setApplicationName(this.applicationName);
179
180
181 int ixQuery = perlParameter.indexOf('?');
182 if ( ixQuery != -1)
183 {
184
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
204 actionRequest.getPortletSession().setAttribute(PerlParameters.PERL_PARAMETER, cgi, PortletSession.APPLICATION_SCOPE);
205 }
206 else
207 {
208
209 cgi.setScriptName(perlParameter);
210
211
212 Enumeration names = actionRequest.getParameterNames();
213 String name, value;
214 while (names.hasMoreElements())
215 {
216 name = (String)names.nextElement();
217
218 if (name.compareToIgnoreCase(PerlParameters.ACTION_PARAMETER_PERL) != 0)
219 {
220
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
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
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
257 response.setContentType("text/html");
258
259
260 HttpServletResponse httpResponse = (HttpServletResponse)((HttpServletResponseWrapper) response).getResponse();
261
262
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
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
288 if (perlParam.getApplicationName().compareToIgnoreCase(this.applicationName) == 0)
289 {
290 query = perlParam.getQueryString();
291 perlScript = perlParam.getScriptName();
292 }
293
294 if (this.applicationName == null )
295 {
296 this.applicationName = perlParam.getApplicationName();
297 }
298 else
299 {
300
301 if ( lastPage != null
302 && this.applicationName != null
303 && perlParam.getApplicationName().compareToIgnoreCase(this.applicationName) != 0)
304 {
305
306 writer.println(this.lastPage);
307 return;
308 }
309 }
310 }
311 else
312 {
313
314
315
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
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
334
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
342 if (name.compareToIgnoreCase("file") == 0)
343 {
344
345
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
371 queries.delete(0, queries.length());
372
373 System.out.println("Script [" + perlScript +"]");
374 System.out.println("Direct Query [" + queries.toString() +"]");
375 }
376
377
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
387 if (perlScript.startsWith("/") == false )
388 fullScriptPath += "/";
389 fullScriptPath += perlScript;
390
391
392 String command = null;
393
394
395 try
396 {
397 BufferedReader in= new BufferedReader(new FileReader(fullScriptPath));
398 String lnExecutable = in.readLine();
399
400 if (lnExecutable != null )
401 {
402
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
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
452
453
454 writer.println("<B><P>Perl Script:</B>" + fullScriptPath + "<BR>");
455
456 writer.println("<B>Query String:</B>" + query + "</P>");
457 }
458
459
460
461 if (command != null )
462 {
463
464
465 try
466 {
467 long timeStart =0;
468 long timeEnd = 0;
469
470 if ( bDemoMode == true)
471 {
472 timeStart = System.currentTimeMillis();
473 }
474
475 Process proc = Runtime.getRuntime().exec(command,env);
476
477
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
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;
504
505
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
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
525 perlResult.close();
526
527
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
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 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
607 writer.println(finalPage);
608
609
610
611
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
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
654 Writer htmlWriter = null;
655
656 ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
657
658 try
659 {
660 htmlWriter = new OutputStreamWriter(byteOutputStream, this.defaultEncoding);
661
662
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
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
697 while (ix != -1)
698 {
699 replacement += value.substring(0, ix);
700 replacement += replace;
701
702 if (value.length() > ix)
703 value = value.substring(ix+1);
704 else
705 value = "";
706
707
708 ix = value.indexOf(source);
709 }
710
711
712 replacement += value;
713
714 value = replacement;
715 }
716 return value;
717 }
718 }
719