/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.jasper.runtime; import java.beans.PropertyEditor; import java.beans.PropertyEditorManager; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.lang.reflect.Method; import java.util.Enumeration; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyContent; import javax.servlet.jsp.tagext.BodyTag; import javax.servlet.jsp.tagext.Tag; import org.apache.jasper.JasperException; import org.apache.jasper.compiler.Localizer; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.InstanceManager; /** * Bunch of util methods that are used by code generated for useBean, * getProperty and setProperty. * * The __begin, __end stuff is there so that the JSP engine can * actually parse this file and inline them if people don't want * runtime dependencies on this class. However, I'm not sure if that * works so well right now. It got forgotten at some point. -akv * * @author Mandar Raje * @author Shawn Bayern */ public class JspRuntimeLibrary { private static final Log log = LogFactory.getLog(JspRuntimeLibrary.class); /** * Returns the value of the javax.servlet.error.exception request * attribute value, if present, otherwise the value of the * javax.servlet.jsp.jspException request attribute value. * * This method is called at the beginning of the generated servlet code * for a JSP error page, when the "exception" implicit scripting language * variable is initialized. * @param request The Servlet request * @return the throwable in the error attribute if any */ public static Throwable getThrowable(ServletRequest request) { Throwable error = (Throwable) request.getAttribute( RequestDispatcher.ERROR_EXCEPTION); if (error == null) { error = (Throwable) request.getAttribute(PageContext.EXCEPTION); if (error != null) { /* * The only place that sets JSP_EXCEPTION is * PageContextImpl.handlePageException(). It really should set * SERVLET_EXCEPTION, but that would interfere with the * ErrorReportValve. Therefore, if JSP_EXCEPTION is set, we * need to set SERVLET_EXCEPTION. */ request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, error); } } return error; } public static boolean coerceToBoolean(String s) { if (s == null || s.length() == 0) return false; else return Boolean.parseBoolean(s); } public static byte coerceToByte(String s) { if (s == null || s.length() == 0) return (byte) 0; else return Byte.parseByte(s); } public static char coerceToChar(String s) { if (s == null || s.length() == 0) { return (char) 0; } else { return s.charAt(0); } } public static double coerceToDouble(String s) { if (s == null || s.length() == 0) return 0; else return Double.parseDouble(s); } public static float coerceToFloat(String s) { if (s == null || s.length() == 0) return 0; else return Float.parseFloat(s); } public static int coerceToInt(String s) { if (s == null || s.length() == 0) return 0; else return Integer.parseInt(s); } public static short coerceToShort(String s) { if (s == null || s.length() == 0) return (short) 0; else return Short.parseShort(s); } public static long coerceToLong(String s) { if (s == null || s.length() == 0) return 0; else return Long.parseLong(s); } public static Object coerce(String s, Class<?> target) { boolean isNullOrEmpty = (s == null || s.length() == 0); if (target == Boolean.class) { if (isNullOrEmpty) { s = "false"; } return Boolean.valueOf(s); } else if (target == Byte.class) { if (isNullOrEmpty) return Byte.valueOf((byte) 0); else return Byte.valueOf(s); } else if (target == Character.class) { if (isNullOrEmpty) return Character.valueOf((char) 0); else { @SuppressWarnings("null") Character result = Character.valueOf(s.charAt(0)); return result; } } else if (target == Double.class) { if (isNullOrEmpty) return Double.valueOf(0); else return Double.valueOf(s); } else if (target == Float.class) { if (isNullOrEmpty) return Float.valueOf(0); else return Float.valueOf(s); } else if (target == Integer.class) { if (isNullOrEmpty) return Integer.valueOf(0); else return Integer.valueOf(s); } else if (target == Short.class) { if (isNullOrEmpty) return Short.valueOf((short) 0); else return Short.valueOf(s); } else if (target == Long.class) { if (isNullOrEmpty) return Long.valueOf(0); else return Long.valueOf(s); } else { return null; } } // __begin convertMethod public static Object convert(String propertyName, String s, Class<?> t, Class<?> propertyEditorClass) throws JasperException { try { if (s == null) { if (t.equals(Boolean.class) || t.equals(Boolean.TYPE)) s = "false"; else return null; } if (propertyEditorClass != null) { return getValueFromBeanInfoPropertyEditor( t, propertyName, s, propertyEditorClass); } else if ( t.equals(Boolean.class) || t.equals(Boolean.TYPE) ) { if (s.equalsIgnoreCase("on") || s.equalsIgnoreCase("true")) s = "true"; else s = "false"; return Boolean.valueOf(s); } else if ( t.equals(Byte.class) || t.equals(Byte.TYPE) ) { return Byte.valueOf(s); } else if (t.equals(Character.class) || t.equals(Character.TYPE)) { return s.length() > 0 ? Character.valueOf(s.charAt(0)) : null; } else if ( t.equals(Short.class) || t.equals(Short.TYPE) ) { return Short.valueOf(s); } else if ( t.equals(Integer.class) || t.equals(Integer.TYPE) ) { return Integer.valueOf(s); } else if ( t.equals(Float.class) || t.equals(Float.TYPE) ) { return Float.valueOf(s); } else if ( t.equals(Long.class) || t.equals(Long.TYPE) ) { return Long.valueOf(s); } else if ( t.equals(Double.class) || t.equals(Double.TYPE) ) { return Double.valueOf(s); } else if ( t.equals(String.class) ) { return s; } else if ( t.equals(java.io.File.class) ) { return new java.io.File(s); } else if (t.getName().equals("java.lang.Object")) { return new Object[] {s}; } else { return getValueFromPropertyEditorManager( t, propertyName, s); } } catch (Exception ex) { throw new JasperException(ex); } } // __end convertMethod // __begin introspectMethod public static void introspect(Object bean, ServletRequest request) throws JasperException { Enumeration<String> e = request.getParameterNames(); while ( e.hasMoreElements() ) { String name = e.nextElement(); String value = request.getParameter(name); introspecthelper(bean, name, value, request, name, true); } } // __end introspectMethod // __begin introspecthelperMethod public static void introspecthelper(Object bean, String prop, String value, ServletRequest request, String param, boolean ignoreMethodNF) throws JasperException { Method method = null; Class<?> type = null; Class<?> propertyEditorClass = null; try { java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean.getClass()); if ( info != null ) { java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors(); for (int i = 0 ; i < pd.length ; i++) { if ( pd[i].getName().equals(prop) ) { method = pd[i].getWriteMethod(); type = pd[i].getPropertyType(); propertyEditorClass = pd[i].getPropertyEditorClass(); break; } } } if (method != null && type != null) { if (type.isArray()) { if (request == null) { throw new JasperException( Localizer.getMessage("jsp.error.beans.setproperty.noindexset")); } Class<?> t = type.getComponentType(); String[] values = request.getParameterValues(param); //XXX Please check. if(values == null) return; if(t.equals(String.class)) { method.invoke(bean, new Object[] { values }); } else { createTypedArray (prop, bean, method, values, t, propertyEditorClass); } } else { if(value == null || (param != null && value.equals(""))) return; Object oval = convert(prop, value, type, propertyEditorClass); if ( oval != null ) method.invoke(bean, new Object[] { oval }); } } } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } if (!ignoreMethodNF && (method == null)) { if (type == null) { throw new JasperException( Localizer.getMessage("jsp.error.beans.noproperty", prop, bean.getClass().getName())); } else { throw new JasperException( Localizer.getMessage("jsp.error.beans.nomethod.setproperty", prop, type.getName(), bean.getClass().getName())); } } } // __end introspecthelperMethod //------------------------------------------------------------------- // functions to convert builtin Java data types to string. //------------------------------------------------------------------- // __begin toStringMethod public static String toString(Object o) { return String.valueOf(o); } public static String toString(byte b) { return Byte.toString(b); } public static String toString(boolean b) { return Boolean.toString(b); } public static String toString(short s) { return Short.toString(s); } public static String toString(int i) { return Integer.toString(i); } public static String toString(float f) { return Float.toString(f); } public static String toString(long l) { return Long.toString(l); } public static String toString(double d) { return Double.toString(d); } public static String toString(char c) { return Character.toString(c); } // __end toStringMethod /** * Create a typed array. * This is a special case where params are passed through * the request and the property is indexed. * @param propertyName The property name * @param bean The bean * @param method The method * @param values Array values * @param t The class * @param propertyEditorClass The editor for the property * @throws JasperException An error occurred */ public static void createTypedArray(String propertyName, Object bean, Method method, String[] values, Class<?> t, Class<?> propertyEditorClass) throws JasperException { try { if (propertyEditorClass != null) { Object[] tmpval = new Integer[values.length]; for (int i=0; i<values.length; i++) { tmpval[i] = getValueFromBeanInfoPropertyEditor( t, propertyName, values[i], propertyEditorClass); } method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(Integer.class)) { Integer []tmpval = new Integer[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Integer.valueOf(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(Byte.class)) { Byte[] tmpval = new Byte[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Byte.valueOf(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(Boolean.class)) { Boolean[] tmpval = new Boolean[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Boolean.valueOf(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(Short.class)) { Short[] tmpval = new Short[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Short.valueOf(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(Long.class)) { Long[] tmpval = new Long[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Long.valueOf(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(Double.class)) { Double[] tmpval = new Double[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Double.valueOf(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(Float.class)) { Float[] tmpval = new Float[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Float.valueOf(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(Character.class)) { Character[] tmpval = new Character[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Character.valueOf(values[i].charAt(0)); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(int.class)) { int []tmpval = new int[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Integer.parseInt (values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(byte.class)) { byte[] tmpval = new byte[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Byte.parseByte (values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(boolean.class)) { boolean[] tmpval = new boolean[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Boolean.parseBoolean(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(short.class)) { short[] tmpval = new short[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Short.parseShort (values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(long.class)) { long[] tmpval = new long[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Long.parseLong (values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(double.class)) { double[] tmpval = new double[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Double.parseDouble(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(float.class)) { float[] tmpval = new float[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = Float.parseFloat(values[i]); method.invoke (bean, new Object[] {tmpval}); } else if (t.equals(char.class)) { char[] tmpval = new char[values.length]; for (int i = 0 ; i < values.length; i++) tmpval[i] = values[i].charAt(0); method.invoke (bean, new Object[] {tmpval}); } else { Object[] tmpval = new Integer[values.length]; for (int i=0; i<values.length; i++) { tmpval[i] = getValueFromPropertyEditorManager( t, propertyName, values[i]); } method.invoke (bean, new Object[] {tmpval}); } } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException ("error in invoking method", ex); } } /** * Escape special shell characters. * @param unescString The string to shell-escape * @return The escaped shell string. */ public static String escapeQueryString(String unescString) { if (unescString == null) { return null; } StringBuilder escStringBuilder = new StringBuilder(); String shellSpChars = "&;`'\"|*?~<>^()[]{}$\\\n"; for (int index = 0; index < unescString.length(); index++) { char nextChar = unescString.charAt(index); if (shellSpChars.indexOf(nextChar) != -1) { escStringBuilder.append('\\'); } escStringBuilder.append(nextChar); } return escStringBuilder.toString(); } // __begin lookupReadMethodMethod public static Object handleGetProperty(Object o, String prop) throws JasperException { if (o == null) { throw new JasperException( Localizer.getMessage("jsp.error.beans.nullbean")); } Object value = null; try { Method method = getReadMethod(o.getClass(), prop); value = method.invoke(o, (Object[]) null); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException (ex); } return value; } // __end lookupReadMethodMethod // handles <jsp:setProperty> with EL expression for 'value' attribute public static void handleSetPropertyExpression(Object bean, String prop, String expression, PageContext pageContext, ProtectedFunctionMapper functionMapper ) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { PageContextImpl.proprietaryEvaluate( expression, method.getParameterTypes()[0], pageContext, functionMapper) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, Object value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { value }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, int value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { Integer.valueOf(value) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, short value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { Short.valueOf(value) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, long value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { Long.valueOf(value) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, double value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { Double.valueOf(value) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, float value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { Float.valueOf(value) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, char value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { Character.valueOf(value) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, byte value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { Byte.valueOf(value) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static void handleSetProperty(Object bean, String prop, boolean value) throws JasperException { try { Method method = getWriteMethod(bean.getClass(), prop); method.invoke(bean, new Object[] { Boolean.valueOf(value) }); } catch (Exception ex) { Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex); ExceptionUtils.handleThrowable(thr); throw new JasperException(ex); } } public static Method getWriteMethod(Class<?> beanClass, String prop) throws JasperException { Method method = null; Class<?> type = null; try { java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(beanClass); if ( info != null ) { java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors(); for (int i = 0 ; i < pd.length ; i++) { if ( pd[i].getName().equals(prop) ) { method = pd[i].getWriteMethod(); type = pd[i].getPropertyType(); break; } } } else { // just in case introspection silently fails. throw new JasperException( Localizer.getMessage("jsp.error.beans.nobeaninfo", beanClass.getName())); } } catch (Exception ex) { throw new JasperException (ex); } if (method == null) { if (type == null) { throw new JasperException( Localizer.getMessage("jsp.error.beans.noproperty", prop, beanClass.getName())); } else { throw new JasperException( Localizer.getMessage("jsp.error.beans.nomethod.setproperty", prop, type.getName(), beanClass.getName())); } } return method; } public static Method getReadMethod(Class<?> beanClass, String prop) throws JasperException { Method method = null; Class<?> type = null; try { java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(beanClass); if ( info != null ) { java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors(); for (int i = 0 ; i < pd.length ; i++) { if ( pd[i].getName().equals(prop) ) { method = pd[i].getReadMethod(); type = pd[i].getPropertyType(); break; } } } else { // just in case introspection silently fails. throw new JasperException( Localizer.getMessage("jsp.error.beans.nobeaninfo", beanClass.getName())); } } catch (Exception ex) { throw new JasperException (ex); } if (method == null) { if (type == null) { throw new JasperException( Localizer.getMessage("jsp.error.beans.noproperty", prop, beanClass.getName())); } else { throw new JasperException( Localizer.getMessage("jsp.error.beans.nomethod", prop, beanClass.getName())); } } return method; } //********************************************************************* // PropertyEditor Support public static Object getValueFromBeanInfoPropertyEditor( Class<?> attrClass, String attrName, String attrValue, Class<?> propertyEditorClass) throws JasperException { try { PropertyEditor pe = (PropertyEditor)propertyEditorClass.newInstance(); pe.setAsText(attrValue); return pe.getValue(); } catch (Exception ex) { throw new JasperException( Localizer.getMessage("jsp.error.beans.property.conversion", attrValue, attrClass.getName(), attrName, ex.getMessage())); } } public static Object getValueFromPropertyEditorManager( Class<?> attrClass, String attrName, String attrValue) throws JasperException { try { PropertyEditor propEditor = PropertyEditorManager.findEditor(attrClass); if (propEditor != null) { propEditor.setAsText(attrValue); return propEditor.getValue(); } else { throw new IllegalArgumentException( Localizer.getMessage("jsp.error.beans.propertyeditor.notregistered")); } } catch (IllegalArgumentException ex) { throw new JasperException( Localizer.getMessage("jsp.error.beans.property.conversion", attrValue, attrClass.getName(), attrName, ex.getMessage())); } } // ************************************************************************ // General Purpose Runtime Methods // ************************************************************************ /** * Convert a possibly relative resource path into a context-relative * resource path that starts with a '/'. * * @param request The servlet request we are processing * @param relativePath The possibly relative resource path * @return an absolute path */ public static String getContextRelativePath(ServletRequest request, String relativePath) { if (relativePath.startsWith("/")) return relativePath; if (!(request instanceof HttpServletRequest)) return relativePath; HttpServletRequest hrequest = (HttpServletRequest) request; String uri = (String) request.getAttribute( RequestDispatcher.INCLUDE_SERVLET_PATH); if (uri != null) { String pathInfo = (String) request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO); if (pathInfo == null) { if (uri.lastIndexOf('/') >= 0) uri = uri.substring(0, uri.lastIndexOf('/')); } } else { uri = hrequest.getServletPath(); if (uri.lastIndexOf('/') >= 0) uri = uri.substring(0, uri.lastIndexOf('/')); } return uri + '/' + relativePath; } /** * Perform a RequestDispatcher.include() operation, with optional flushing * of the response beforehand. * * @param request The servlet request we are processing * @param response The servlet response we are processing * @param relativePath The relative path of the resource to be included * @param out The Writer to whom we are currently writing * @param flush Should we flush before the include is processed? * * @exception IOException if thrown by the included servlet * @exception ServletException if thrown by the included servlet */ public static void include(ServletRequest request, ServletResponse response, String relativePath, JspWriter out, boolean flush) throws IOException, ServletException { if (flush && !(out instanceof BodyContent)) out.flush(); // FIXME - It is tempting to use request.getRequestDispatcher() to // resolve a relative path directly, but Catalina currently does not // take into account whether the caller is inside a RequestDispatcher // include or not. Whether Catalina *should* take that into account // is a spec issue currently under review. In the mean time, // replicate Jasper's previous behavior String resourcePath = getContextRelativePath(request, relativePath); RequestDispatcher rd = request.getRequestDispatcher(resourcePath); rd.include(request, new ServletResponseWrapperInclude(response, out)); } /** * URL encodes a string, based on the supplied character encoding. * This performs the same function as java.next.URLEncode.encode * in J2SDK1.4, and should be removed if the only platform supported * is 1.4 or higher. * @param s The String to be URL encoded. * @param enc The character encoding * @return The URL encoded String */ public static String URLEncode(String s, String enc) { if (s == null) { return "null"; } if (enc == null) { enc = "ISO-8859-1"; // The default request encoding } StringBuilder out = new StringBuilder(s.length()); ByteArrayOutputStream buf = new ByteArrayOutputStream(); OutputStreamWriter writer = null; try { writer = new OutputStreamWriter(buf, enc); } catch (java.io.UnsupportedEncodingException ex) { // Use the default encoding? writer = new OutputStreamWriter(buf); } for (int i = 0; i < s.length(); i++) { int c = s.charAt(i); if (c == ' ') { out.append('+'); } else if (isSafeChar(c)) { out.append((char)c); } else { // convert to external encoding before hex conversion try { writer.write(c); writer.flush(); } catch(IOException e) { buf.reset(); continue; } byte[] ba = buf.toByteArray(); for (int j = 0; j < ba.length; j++) { out.append('%'); // Converting each byte in the buffer out.append(Character.forDigit((ba[j]>>4) & 0xf, 16)); out.append(Character.forDigit(ba[j] & 0xf, 16)); } buf.reset(); } } return out.toString(); } private static boolean isSafeChar(int c) { if (c >= 'a' && c <= 'z') { return true; } if (c >= 'A' && c <= 'Z') { return true; } if (c >= '0' && c <= '9') { return true; } if (c == '-' || c == '_' || c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' || c == ')') { return true; } return false; } public static JspWriter startBufferedBody(PageContext pageContext, BodyTag tag) throws JspException { BodyContent out = pageContext.pushBody(); tag.setBodyContent(out); tag.doInitBody(); return out; } public static void releaseTag(Tag tag, InstanceManager instanceManager, boolean reused) { // Caller ensures pool is non-null if reuse is true if (!reused) { releaseTag(tag, instanceManager); } } protected static void releaseTag(Tag tag, InstanceManager instanceManager) { try { tag.release(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn("Error processing release on tag instance of " + tag.getClass().getName(), t); } try { instanceManager.destroyInstance(tag); } catch (Exception e) { Throwable t = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); log.warn("Error processing preDestroy on tag instance of " + tag.getClass().getName(), t); } } }