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
18 package org.apache.jasper.runtime;
19
20 import java.beans.PropertyEditor;
21 import java.beans.PropertyEditorManager;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.lang.reflect.Method;
26 import java.security.AccessController;
27 import java.security.PrivilegedActionException;
28 import java.security.PrivilegedExceptionAction;
29 import java.util.Enumeration;
30
31 import javax.servlet.RequestDispatcher;
32 import javax.servlet.ServletException;
33 import javax.servlet.ServletRequest;
34 import javax.servlet.ServletResponse;
35 import javax.servlet.http.HttpServletRequest;
36 import javax.servlet.jsp.JspWriter;
37 import javax.servlet.jsp.PageContext;
38 import javax.servlet.jsp.tagext.BodyContent;
39
40 import org.apache.jasper.Constants;
41 import org.apache.jasper.JasperException;
42 import org.apache.jasper.compiler.Localizer;
43
44 /**
45 * Bunch of util methods that are used by code generated for useBean,
46 * getProperty and setProperty.
47 *
48 * The __begin, __end stuff is there so that the JSP engine can
49 * actually parse this file and inline them if people don't want
50 * runtime dependencies on this class. However, I'm not sure if that
51 * works so well right now. It got forgotten at some point. -akv
52 *
53 * @author Mandar Raje
54 * @author Shawn Bayern
55 */
56 public class JspRuntimeLibrary {
57
58 private static final String SERVLET_EXCEPTION
59 = "javax.servlet.error.exception";
60 private static final String JSP_EXCEPTION
61 = "javax.servlet.jsp.jspException";
62
63 protected static class PrivilegedIntrospectHelper
64 implements PrivilegedExceptionAction {
65
66 private Object bean;
67 private String prop;
68 private String value;
69 private ServletRequest request;
70 private String param;
71 private boolean ignoreMethodNF;
72
73 PrivilegedIntrospectHelper(Object bean, String prop,
74 String value, ServletRequest request,
75 String param, boolean ignoreMethodNF)
76 {
77 this.bean = bean;
78 this.prop = prop;
79 this.value = value;
80 this.request = request;
81 this.param = param;
82 this.ignoreMethodNF = ignoreMethodNF;
83 }
84
85 public Object run() throws JasperException {
86 internalIntrospecthelper(
87 bean,prop,value,request,param,ignoreMethodNF);
88 return null;
89 }
90 }
91
92 /**
93 * Returns the value of the javax.servlet.error.exception request
94 * attribute value, if present, otherwise the value of the
95 * javax.servlet.jsp.jspException request attribute value.
96 *
97 * This method is called at the beginning of the generated servlet code
98 * for a JSP error page, when the "exception" implicit scripting language
99 * variable is initialized.
100 */
101 public static Throwable getThrowable(ServletRequest request) {
102 Throwable error = (Throwable) request.getAttribute(SERVLET_EXCEPTION);
103 if (error == null) {
104 error = (Throwable) request.getAttribute(JSP_EXCEPTION);
105 if (error != null) {
106 /*
107 * The only place that sets JSP_EXCEPTION is
108 * PageContextImpl.handlePageException(). It really should set
109 * SERVLET_EXCEPTION, but that would interfere with the
110 * ErrorReportValve. Therefore, if JSP_EXCEPTION is set, we
111 * need to set SERVLET_EXCEPTION.
112 */
113 request.setAttribute(SERVLET_EXCEPTION, error);
114 }
115 }
116
117 return error;
118 }
119
120 public static boolean coerceToBoolean(String s) {
121 if (s == null || s.length() == 0)
122 return false;
123 else
124 return Boolean.valueOf(s).booleanValue();
125 }
126
127 public static byte coerceToByte(String s) {
128 if (s == null || s.length() == 0)
129 return (byte) 0;
130 else
131 return Byte.valueOf(s).byteValue();
132 }
133
134 public static char coerceToChar(String s) {
135 if (s == null || s.length() == 0) {
136 return (char) 0;
137 } else {
138 // this trick avoids escaping issues
139 return (char)(int) s.charAt(0);
140 }
141 }
142
143 public static double coerceToDouble(String s) {
144 if (s == null || s.length() == 0)
145 return (double) 0;
146 else
147 return Double.valueOf(s).doubleValue();
148 }
149
150 public static float coerceToFloat(String s) {
151 if (s == null || s.length() == 0)
152 return (float) 0;
153 else
154 return Float.valueOf(s).floatValue();
155 }
156
157 public static int coerceToInt(String s) {
158 if (s == null || s.length() == 0)
159 return 0;
160 else
161 return Integer.valueOf(s).intValue();
162 }
163
164 public static short coerceToShort(String s) {
165 if (s == null || s.length() == 0)
166 return (short) 0;
167 else
168 return Short.valueOf(s).shortValue();
169 }
170
171 public static long coerceToLong(String s) {
172 if (s == null || s.length() == 0)
173 return (long) 0;
174 else
175 return Long.valueOf(s).longValue();
176 }
177
178 public static Object coerce(String s, Class target) {
179
180 boolean isNullOrEmpty = (s == null || s.length() == 0);
181
182 if (target == Boolean.class) {
183 if (isNullOrEmpty) {
184 s = "false";
185 }
186 return new Boolean(s);
187 } else if (target == Byte.class) {
188 if (isNullOrEmpty)
189 return new Byte((byte) 0);
190 else
191 return new Byte(s);
192 } else if (target == Character.class) {
193 if (isNullOrEmpty)
194 return new Character((char) 0);
195 else
196 return new Character(s.charAt(0));
197 } else if (target == Double.class) {
198 if (isNullOrEmpty)
199 return new Double(0);
200 else
201 return new Double(s);
202 } else if (target == Float.class) {
203 if (isNullOrEmpty)
204 return new Float(0);
205 else
206 return new Float(s);
207 } else if (target == Integer.class) {
208 if (isNullOrEmpty)
209 return new Integer(0);
210 else
211 return new Integer(s);
212 } else if (target == Short.class) {
213 if (isNullOrEmpty)
214 return new Short((short) 0);
215 else
216 return new Short(s);
217 } else if (target == Long.class) {
218 if (isNullOrEmpty)
219 return new Long(0);
220 else
221 return new Long(s);
222 } else {
223 return null;
224 }
225 }
226
227 // __begin convertMethod
228 public static Object convert(String propertyName, String s, Class t,
229 Class propertyEditorClass)
230 throws JasperException
231 {
232 try {
233 if (s == null) {
234 if (t.equals(Boolean.class) || t.equals(Boolean.TYPE))
235 s = "false";
236 else
237 return null;
238 }
239 if (propertyEditorClass != null) {
240 return getValueFromBeanInfoPropertyEditor(
241 t, propertyName, s, propertyEditorClass);
242 } else if ( t.equals(Boolean.class) || t.equals(Boolean.TYPE) ) {
243 if (s.equalsIgnoreCase("on") || s.equalsIgnoreCase("true"))
244 s = "true";
245 else
246 s = "false";
247 return new Boolean(s);
248 } else if ( t.equals(Byte.class) || t.equals(Byte.TYPE) ) {
249 return new Byte(s);
250 } else if (t.equals(Character.class) || t.equals(Character.TYPE)) {
251 return s.length() > 0 ? new Character(s.charAt(0)) : null;
252 } else if ( t.equals(Short.class) || t.equals(Short.TYPE) ) {
253 return new Short(s);
254 } else if ( t.equals(Integer.class) || t.equals(Integer.TYPE) ) {
255 return new Integer(s);
256 } else if ( t.equals(Float.class) || t.equals(Float.TYPE) ) {
257 return new Float(s);
258 } else if ( t.equals(Long.class) || t.equals(Long.TYPE) ) {
259 return new Long(s);
260 } else if ( t.equals(Double.class) || t.equals(Double.TYPE) ) {
261 return new Double(s);
262 } else if ( t.equals(String.class) ) {
263 return s;
264 } else if ( t.equals(java.io.File.class) ) {
265 return new java.io.File(s);
266 } else if (t.getName().equals("java.lang.Object")) {
267 return new Object[] {s};
268 } else {
269 return getValueFromPropertyEditorManager(
270 t, propertyName, s);
271 }
272 } catch (Exception ex) {
273 throw new JasperException(ex);
274 }
275 }
276 // __end convertMethod
277
278 // __begin introspectMethod
279 public static void introspect(Object bean, ServletRequest request)
280 throws JasperException
281 {
282 Enumeration e = request.getParameterNames();
283 while ( e.hasMoreElements() ) {
284 String name = (String) e.nextElement();
285 String value = request.getParameter(name);
286 introspecthelper(bean, name, value, request, name, true);
287 }
288 }
289 // __end introspectMethod
290
291 // __begin introspecthelperMethod
292 public static void introspecthelper(Object bean, String prop,
293 String value, ServletRequest request,
294 String param, boolean ignoreMethodNF)
295 throws JasperException
296 {
297 if( Constants.IS_SECURITY_ENABLED ) {
298 try {
299 PrivilegedIntrospectHelper dp =
300 new PrivilegedIntrospectHelper(
301 bean,prop,value,request,param,ignoreMethodNF);
302 AccessController.doPrivileged(dp);
303 } catch( PrivilegedActionException pe) {
304 Exception e = pe.getException();
305 throw (JasperException)e;
306 }
307 } else {
308 internalIntrospecthelper(
309 bean,prop,value,request,param,ignoreMethodNF);
310 }
311 }
312
313 private static void internalIntrospecthelper(Object bean, String prop,
314 String value, ServletRequest request,
315 String param, boolean ignoreMethodNF)
316 throws JasperException
317 {
318 Method method = null;
319 Class type = null;
320 Class propertyEditorClass = null;
321 try {
322 java.beans.BeanInfo info
323 = java.beans.Introspector.getBeanInfo(bean.getClass());
324 if ( info != null ) {
325 java.beans.PropertyDescriptor pd[]
326 = info.getPropertyDescriptors();
327 for (int i = 0 ; i < pd.length ; i++) {
328 if ( pd[i].getName().equals(prop) ) {
329 method = pd[i].getWriteMethod();
330 type = pd[i].getPropertyType();
331 propertyEditorClass = pd[i].getPropertyEditorClass();
332 break;
333 }
334 }
335 }
336 if ( method != null ) {
337 if (type.isArray()) {
338 if (request == null) {
339 throw new JasperException(
340 Localizer.getMessage("jsp.error.beans.setproperty.noindexset"));
341 }
342 Class t = type.getComponentType();
343 String[] values = request.getParameterValues(param);
344 //XXX Please check.
345 if(values == null) return;
346 if(t.equals(String.class)) {
347 method.invoke(bean, new Object[] { values });
348 } else {
349 Object tmpval = null;
350 createTypedArray (prop, bean, method, values, t,
351 propertyEditorClass);
352 }
353 } else {
354 if(value == null || (param != null && value.equals(""))) return;
355 Object oval = convert(prop, value, type, propertyEditorClass);
356 if ( oval != null )
357 method.invoke(bean, new Object[] { oval });
358 }
359 }
360 } catch (Exception ex) {
361 throw new JasperException(ex);
362 }
363 if (!ignoreMethodNF && (method == null)) {
364 if (type == null) {
365 throw new JasperException(
366 Localizer.getMessage("jsp.error.beans.noproperty",
367 prop,
368 bean.getClass().getName()));
369 } else {
370 throw new JasperException(
371 Localizer.getMessage("jsp.error.beans.nomethod.setproperty",
372 prop,
373 type.getName(),
374 bean.getClass().getName()));
375 }
376 }
377 }
378 // __end introspecthelperMethod
379
380 //-------------------------------------------------------------------
381 // functions to convert builtin Java data types to string.
382 //-------------------------------------------------------------------
383 // __begin toStringMethod
384 public static String toString(Object o) {
385 return String.valueOf(o);
386 }
387
388 public static String toString(byte b) {
389 return new Byte(b).toString();
390 }
391
392 public static String toString(boolean b) {
393 return new Boolean(b).toString();
394 }
395
396 public static String toString(short s) {
397 return new Short(s).toString();
398 }
399
400 public static String toString(int i) {
401 return new Integer(i).toString();
402 }
403
404 public static String toString(float f) {
405 return new Float(f).toString();
406 }
407
408 public static String toString(long l) {
409 return new Long(l).toString();
410 }
411
412 public static String toString(double d) {
413 return new Double(d).toString();
414 }
415
416 public static String toString(char c) {
417 return new Character(c).toString();
418 }
419 // __end toStringMethod
420
421
422 /**
423 * Create a typed array.
424 * This is a special case where params are passed through
425 * the request and the property is indexed.
426 */
427 public static void createTypedArray(String propertyName,
428 Object bean,
429 Method method,
430 String[] values,
431 Class t,
432 Class propertyEditorClass)
433 throws JasperException {
434
435 try {
436 if (propertyEditorClass != null) {
437 Object[] tmpval = new Integer[values.length];
438 for (int i=0; i<values.length; i++) {
439 tmpval[i] = getValueFromBeanInfoPropertyEditor(
440 t, propertyName, values[i], propertyEditorClass);
441 }
442 method.invoke (bean, new Object[] {tmpval});
443 } else if (t.equals(Integer.class)) {
444 Integer []tmpval = new Integer[values.length];
445 for (int i = 0 ; i < values.length; i++)
446 tmpval[i] = new Integer (values[i]);
447 method.invoke (bean, new Object[] {tmpval});
448 } else if (t.equals(Byte.class)) {
449 Byte[] tmpval = new Byte[values.length];
450 for (int i = 0 ; i < values.length; i++)
451 tmpval[i] = new Byte (values[i]);
452 method.invoke (bean, new Object[] {tmpval});
453 } else if (t.equals(Boolean.class)) {
454 Boolean[] tmpval = new Boolean[values.length];
455 for (int i = 0 ; i < values.length; i++)
456 tmpval[i] = new Boolean (values[i]);
457 method.invoke (bean, new Object[] {tmpval});
458 } else if (t.equals(Short.class)) {
459 Short[] tmpval = new Short[values.length];
460 for (int i = 0 ; i < values.length; i++)
461 tmpval[i] = new Short (values[i]);
462 method.invoke (bean, new Object[] {tmpval});
463 } else if (t.equals(Long.class)) {
464 Long[] tmpval = new Long[values.length];
465 for (int i = 0 ; i < values.length; i++)
466 tmpval[i] = new Long (values[i]);
467 method.invoke (bean, new Object[] {tmpval});
468 } else if (t.equals(Double.class)) {
469 Double[] tmpval = new Double[values.length];
470 for (int i = 0 ; i < values.length; i++)
471 tmpval[i] = new Double (values[i]);
472 method.invoke (bean, new Object[] {tmpval});
473 } else if (t.equals(Float.class)) {
474 Float[] tmpval = new Float[values.length];
475 for (int i = 0 ; i < values.length; i++)
476 tmpval[i] = new Float (values[i]);
477 method.invoke (bean, new Object[] {tmpval});
478 } else if (t.equals(Character.class)) {
479 Character[] tmpval = new Character[values.length];
480 for (int i = 0 ; i < values.length; i++)
481 tmpval[i] = new Character(values[i].charAt(0));
482 method.invoke (bean, new Object[] {tmpval});
483 } else if (t.equals(int.class)) {
484 int []tmpval = new int[values.length];
485 for (int i = 0 ; i < values.length; i++)
486 tmpval[i] = Integer.parseInt (values[i]);
487 method.invoke (bean, new Object[] {tmpval});
488 } else if (t.equals(byte.class)) {
489 byte[] tmpval = new byte[values.length];
490 for (int i = 0 ; i < values.length; i++)
491 tmpval[i] = Byte.parseByte (values[i]);
492 method.invoke (bean, new Object[] {tmpval});
493 } else if (t.equals(boolean.class)) {
494 boolean[] tmpval = new boolean[values.length];
495 for (int i = 0 ; i < values.length; i++)
496 tmpval[i] = (Boolean.valueOf(values[i])).booleanValue();
497 method.invoke (bean, new Object[] {tmpval});
498 } else if (t.equals(short.class)) {
499 short[] tmpval = new short[values.length];
500 for (int i = 0 ; i < values.length; i++)
501 tmpval[i] = Short.parseShort (values[i]);
502 method.invoke (bean, new Object[] {tmpval});
503 } else if (t.equals(long.class)) {
504 long[] tmpval = new long[values.length];
505 for (int i = 0 ; i < values.length; i++)
506 tmpval[i] = Long.parseLong (values[i]);
507 method.invoke (bean, new Object[] {tmpval});
508 } else if (t.equals(double.class)) {
509 double[] tmpval = new double[values.length];
510 for (int i = 0 ; i < values.length; i++)
511 tmpval[i] = Double.valueOf(values[i]).doubleValue();
512 method.invoke (bean, new Object[] {tmpval});
513 } else if (t.equals(float.class)) {
514 float[] tmpval = new float[values.length];
515 for (int i = 0 ; i < values.length; i++)
516 tmpval[i] = Float.valueOf(values[i]).floatValue();
517 method.invoke (bean, new Object[] {tmpval});
518 } else if (t.equals(char.class)) {
519 char[] tmpval = new char[values.length];
520 for (int i = 0 ; i < values.length; i++)
521 tmpval[i] = values[i].charAt(0);
522 method.invoke (bean, new Object[] {tmpval});
523 } else {
524 Object[] tmpval = new Integer[values.length];
525 for (int i=0; i<values.length; i++) {
526 tmpval[i] =
527 getValueFromPropertyEditorManager(
528 t, propertyName, values[i]);
529 }
530 method.invoke (bean, new Object[] {tmpval});
531 }
532 } catch (Exception ex) {
533 throw new JasperException ("error in invoking method", ex);
534 }
535 }
536
537 /**
538 * Escape special shell characters.
539 * @param unescString The string to shell-escape
540 * @return The escaped shell string.
541 */
542
543 public static String escapeQueryString(String unescString) {
544 if ( unescString == null )
545 return null;
546
547 String escString = "";
548 String shellSpChars = "&;`'\"|*?~<>^()[]{}$\\\n";
549
550 for(int index=0; index<unescString.length(); index++) {
551 char nextChar = unescString.charAt(index);
552
553 if( shellSpChars.indexOf(nextChar) != -1 )
554 escString += "\\";
555
556 escString += nextChar;
557 }
558 return escString;
559 }
560
561 /**
562 * Decode an URL formatted string.
563 * @param encoded The string to decode.
564 * @return The decoded string.
565 */
566
567 public static String decode(String encoded) {
568 // speedily leave if we're not needed
569 if (encoded == null) return null;
570 if (encoded.indexOf('%') == -1 && encoded.indexOf('+') == -1)
571 return encoded;
572
573 //allocate the buffer - use byte[] to avoid calls to new.
574 byte holdbuffer[] = new byte[encoded.length()];
575
576 char holdchar;
577 int bufcount = 0;
578
579 for (int count = 0; count < encoded.length(); count++) {
580 char cur = encoded.charAt(count);
581 if (cur == '%') {
582 holdbuffer[bufcount++] =
583 (byte)Integer.parseInt(encoded.substring(count+1,count+3),16);
584 if (count + 2 >= encoded.length())
585 count = encoded.length();
586 else
587 count += 2;
588 } else if (cur == '+') {
589 holdbuffer[bufcount++] = (byte) ' ';
590 } else {
591 holdbuffer[bufcount++] = (byte) cur;
592 }
593 }
594 // REVISIT -- remedy for Deprecated warning.
595 //return new String(holdbuffer,0,0,bufcount);
596 return new String(holdbuffer,0,bufcount);
597 }
598
599 // __begin lookupReadMethodMethod
600 public static Object handleGetProperty(Object o, String prop)
601 throws JasperException {
602 if (o == null) {
603 throw new JasperException(
604 Localizer.getMessage("jsp.error.beans.nullbean"));
605 }
606 Object value = null;
607 try {
608 Method method = getReadMethod(o.getClass(), prop);
609 value = method.invoke(o, (Object[]) null);
610 } catch (Exception ex) {
611 throw new JasperException (ex);
612 }
613 return value;
614 }
615 // __end lookupReadMethodMethod
616
617 // handles <jsp:setProperty> with EL expression for 'value' attribute
618 /** Use proprietaryEvaluate
619 public static void handleSetPropertyExpression(Object bean,
620 String prop, String expression, PageContext pageContext,
621 VariableResolver variableResolver, FunctionMapper functionMapper )
622 throws JasperException
623 {
624 try {
625 Method method = getWriteMethod(bean.getClass(), prop);
626 method.invoke(bean, new Object[] {
627 pageContext.getExpressionEvaluator().evaluate(
628 expression,
629 method.getParameterTypes()[0],
630 variableResolver,
631 functionMapper,
632 null )
633 });
634 } catch (Exception ex) {
635 throw new JasperException(ex);
636 }
637 }
638 **/
639 public static void handleSetPropertyExpression(Object bean,
640 String prop, String expression, PageContext pageContext,
641 ProtectedFunctionMapper functionMapper )
642 throws JasperException
643 {
644 try {
645 Method method = getWriteMethod(bean.getClass(), prop);
646 method.invoke(bean, new Object[] {
647 PageContextImpl.proprietaryEvaluate(
648 expression,
649 method.getParameterTypes()[0],
650 pageContext,
651 functionMapper,
652 false )
653 });
654 } catch (Exception ex) {
655 throw new JasperException(ex);
656 }
657 }
658
659 public static void handleSetProperty(Object bean, String prop,
660 Object value)
661 throws JasperException
662 {
663 try {
664 Method method = getWriteMethod(bean.getClass(), prop);
665 method.invoke(bean, new Object[] { value });
666 } catch (Exception ex) {
667 throw new JasperException(ex);
668 }
669 }
670
671 public static void handleSetProperty(Object bean, String prop,
672 int value)
673 throws JasperException
674 {
675 try {
676 Method method = getWriteMethod(bean.getClass(), prop);
677 method.invoke(bean, new Object[] { new Integer(value) });
678 } catch (Exception ex) {
679 throw new JasperException(ex);
680 }
681 }
682
683 public static void handleSetProperty(Object bean, String prop,
684 short value)
685 throws JasperException
686 {
687 try {
688 Method method = getWriteMethod(bean.getClass(), prop);
689 method.invoke(bean, new Object[] { new Short(value) });
690 } catch (Exception ex) {
691 throw new JasperException(ex);
692 }
693 }
694
695 public static void handleSetProperty(Object bean, String prop,
696 long value)
697 throws JasperException
698 {
699 try {
700 Method method = getWriteMethod(bean.getClass(), prop);
701 method.invoke(bean, new Object[] { new Long(value) });
702 } catch (Exception ex) {
703 throw new JasperException(ex);
704 }
705 }
706
707 public static void handleSetProperty(Object bean, String prop,
708 double value)
709 throws JasperException
710 {
711 try {
712 Method method = getWriteMethod(bean.getClass(), prop);
713 method.invoke(bean, new Object[] { new Double(value) });
714 } catch (Exception ex) {
715 throw new JasperException(ex);
716 }
717 }
718
719 public static void handleSetProperty(Object bean, String prop,
720 float value)
721 throws JasperException
722 {
723 try {
724 Method method = getWriteMethod(bean.getClass(), prop);
725 method.invoke(bean, new Object[] { new Float(value) });
726 } catch (Exception ex) {
727 throw new JasperException(ex);
728 }
729 }
730
731 public static void handleSetProperty(Object bean, String prop,
732 char value)
733 throws JasperException
734 {
735 try {
736 Method method = getWriteMethod(bean.getClass(), prop);
737 method.invoke(bean, new Object[] { new Character(value) });
738 } catch (Exception ex) {
739 throw new JasperException(ex);
740 }
741 }
742
743 public static void handleSetProperty(Object bean, String prop,
744 byte value)
745 throws JasperException
746 {
747 try {
748 Method method = getWriteMethod(bean.getClass(), prop);
749 method.invoke(bean, new Object[] { new Byte(value) });
750 } catch (Exception ex) {
751 throw new JasperException(ex);
752 }
753 }
754
755 public static void handleSetProperty(Object bean, String prop,
756 boolean value)
757 throws JasperException
758 {
759 try {
760 Method method = getWriteMethod(bean.getClass(), prop);
761 method.invoke(bean, new Object[] { new Boolean(value) });
762 } catch (Exception ex) {
763 throw new JasperException(ex);
764 }
765 }
766
767 public static Method getWriteMethod(Class beanClass, String prop)
768 throws JasperException {
769 Method method = null;
770 Class type = null;
771 try {
772 java.beans.BeanInfo info
773 = java.beans.Introspector.getBeanInfo(beanClass);
774 if ( info != null ) {
775 java.beans.PropertyDescriptor pd[]
776 = info.getPropertyDescriptors();
777 for (int i = 0 ; i < pd.length ; i++) {
778 if ( pd[i].getName().equals(prop) ) {
779 method = pd[i].getWriteMethod();
780 type = pd[i].getPropertyType();
781 break;
782 }
783 }
784 } else {
785 // just in case introspection silently fails.
786 throw new JasperException(
787 Localizer.getMessage("jsp.error.beans.nobeaninfo",
788 beanClass.getName()));
789 }
790 } catch (Exception ex) {
791 throw new JasperException (ex);
792 }
793 if (method == null) {
794 if (type == null) {
795 throw new JasperException(
796 Localizer.getMessage("jsp.error.beans.noproperty",
797 prop,
798 beanClass.getName()));
799 } else {
800 throw new JasperException(
801 Localizer.getMessage("jsp.error.beans.nomethod.setproperty",
802 prop,
803 type.getName(),
804 beanClass.getName()));
805 }
806 }
807 return method;
808 }
809
810 public static Method getReadMethod(Class beanClass, String prop)
811 throws JasperException {
812
813 Method method = null;
814 Class type = null;
815 try {
816 java.beans.BeanInfo info
817 = java.beans.Introspector.getBeanInfo(beanClass);
818 if ( info != null ) {
819 java.beans.PropertyDescriptor pd[]
820 = info.getPropertyDescriptors();
821 for (int i = 0 ; i < pd.length ; i++) {
822 if ( pd[i].getName().equals(prop) ) {
823 method = pd[i].getReadMethod();
824 type = pd[i].getPropertyType();
825 break;
826 }
827 }
828 } else {
829 // just in case introspection silently fails.
830 throw new JasperException(
831 Localizer.getMessage("jsp.error.beans.nobeaninfo",
832 beanClass.getName()));
833 }
834 } catch (Exception ex) {
835 throw new JasperException (ex);
836 }
837 if (method == null) {
838 if (type == null) {
839 throw new JasperException(
840 Localizer.getMessage("jsp.error.beans.noproperty", prop,
841 beanClass.getName()));
842 } else {
843 throw new JasperException(
844 Localizer.getMessage("jsp.error.beans.nomethod", prop,
845 beanClass.getName()));
846 }
847 }
848
849 return method;
850 }
851
852 //*********************************************************************
853 // PropertyEditor Support
854
855 public static Object getValueFromBeanInfoPropertyEditor(
856 Class attrClass, String attrName, String attrValue,
857 Class propertyEditorClass)
858 throws JasperException
859 {
860 try {
861 PropertyEditor pe = (PropertyEditor)propertyEditorClass.newInstance();
862 pe.setAsText(attrValue);
863 return pe.getValue();
864 } catch (Exception ex) {
865 throw new JasperException(
866 Localizer.getMessage("jsp.error.beans.property.conversion",
867 attrValue, attrClass.getName(), attrName,
868 ex.getMessage()));
869 }
870 }
871
872 public static Object getValueFromPropertyEditorManager(
873 Class attrClass, String attrName, String attrValue)
874 throws JasperException
875 {
876 try {
877 PropertyEditor propEditor =
878 PropertyEditorManager.findEditor(attrClass);
879 if (propEditor != null) {
880 propEditor.setAsText(attrValue);
881 return propEditor.getValue();
882 } else {
883 throw new IllegalArgumentException(
884 Localizer.getMessage("jsp.error.beans.propertyeditor.notregistered"));
885 }
886 } catch (IllegalArgumentException ex) {
887 throw new JasperException(
888 Localizer.getMessage("jsp.error.beans.property.conversion",
889 attrValue, attrClass.getName(), attrName,
890 ex.getMessage()));
891 }
892 }
893
894
895 // ************************************************************************
896 // General Purpose Runtime Methods
897 // ************************************************************************
898
899
900 /**
901 * Convert a possibly relative resource path into a context-relative
902 * resource path that starts with a '/'.
903 *
904 * @param request The servlet request we are processing
905 * @param relativePath The possibly relative resource path
906 */
907 public static String getContextRelativePath(ServletRequest request,
908 String relativePath) {
909
910 if (relativePath.startsWith("/"))
911 return (relativePath);
912 if (!(request instanceof HttpServletRequest))
913 return (relativePath);
914 HttpServletRequest hrequest = (HttpServletRequest) request;
915 String uri = (String)
916 request.getAttribute("javax.servlet.include.servlet_path");
917 if (uri != null) {
918 String pathInfo = (String)
919 request.getAttribute("javax.servlet.include.path_info");
920 if (pathInfo == null) {
921 if (uri.lastIndexOf('/') >= 0)
922 uri = uri.substring(0, uri.lastIndexOf('/'));
923 }
924 }
925 else {
926 uri = hrequest.getServletPath();
927 if (uri.lastIndexOf('/') >= 0)
928 uri = uri.substring(0, uri.lastIndexOf('/'));
929 }
930 return uri + '/' + relativePath;
931
932 }
933
934
935 /**
936 * Perform a RequestDispatcher.include() operation, with optional flushing
937 * of the response beforehand.
938 *
939 * @param request The servlet request we are processing
940 * @param response The servlet response we are processing
941 * @param relativePath The relative path of the resource to be included
942 * @param out The Writer to whom we are currently writing
943 * @param flush Should we flush before the include is processed?
944 *
945 * @exception IOException if thrown by the included servlet
946 * @exception ServletException if thrown by the included servlet
947 */
948 public static void include(ServletRequest request,
949 ServletResponse response,
950 String relativePath,
951 JspWriter out,
952 boolean flush)
953 throws IOException, ServletException {
954
955 if (flush && !(out instanceof BodyContent))
956 out.flush();
957
958 // FIXME - It is tempting to use request.getRequestDispatcher() to
959 // resolve a relative path directly, but Catalina currently does not
960 // take into account whether the caller is inside a RequestDispatcher
961 // include or not. Whether Catalina *should* take that into account
962 // is a spec issue currently under review. In the mean time,
963 // replicate Jasper's previous behavior
964
965 String resourcePath = getContextRelativePath(request, relativePath);
966 RequestDispatcher rd = request.getRequestDispatcher(resourcePath);
967
968 rd.include(request,
969 new ServletResponseWrapperInclude(response, out));
970
971 }
972
973 /**
974 * URL encodes a string, based on the supplied character encoding.
975 * This performs the same function as java.next.URLEncode.encode
976 * in J2SDK1.4, and should be removed if the only platform supported
977 * is 1.4 or higher.
978 * @param s The String to be URL encoded.
979 * @param enc The character encoding
980 * @return The URL encoded String
981 */
982 public static String URLEncode(String s, String enc) {
983
984 if (s == null) {
985 return "null";
986 }
987
988 if (enc == null) {
989 enc = "ISO-8859-1"; // The default request encoding
990 }
991
992 StringBuffer out = new StringBuffer(s.length());
993 ByteArrayOutputStream buf = new ByteArrayOutputStream();
994 OutputStreamWriter writer = null;
995 try {
996 writer = new OutputStreamWriter(buf, enc);
997 } catch (java.io.UnsupportedEncodingException ex) {
998 // Use the default encoding?
999 writer = new OutputStreamWriter(buf);
1000 }
1001
1002 for (int i = 0; i < s.length(); i++) {
1003 int c = s.charAt(i);
1004 if (c == ' ') {
1005 out.append('+');
1006 } else if (isSafeChar(c)) {
1007 out.append((char)c);
1008 } else {
1009 // convert to external encoding before hex conversion
1010 try {
1011 writer.write(c);
1012 writer.flush();
1013 } catch(IOException e) {
1014 buf.reset();
1015 continue;
1016 }
1017 byte[] ba = buf.toByteArray();
1018 for (int j = 0; j < ba.length; j++) {
1019 out.append('%');
1020 // Converting each byte in the buffer
1021 out.append(Character.forDigit((ba[j]>>4) & 0xf, 16));
1022 out.append(Character.forDigit(ba[j] & 0xf, 16));
1023 }
1024 buf.reset();
1025 }
1026 }
1027 return out.toString();
1028 }
1029
1030 private static boolean isSafeChar(int c) {
1031 if (c >= 'a' && c <= 'z') {
1032 return true;
1033 }
1034 if (c >= 'A' && c <= 'Z') {
1035 return true;
1036 }
1037 if (c >= '0' && c <= '9') {
1038 return true;
1039 }
1040 if (c == '-' || c == '_' || c == '.' || c == '!' ||
1041 c == '~' || c == '*' || c == '\'' || c == '(' || c == ')') {
1042 return true;
1043 }
1044 return false;
1045 }
1046
1047 }