Author: rjung Date: Wed Jan 28 19:51:33 2015 New Revision: 1655445 URL: http://svn.apache.org/r1655445 Log: Enhance our naming BeanFactory.
If a bean property exists which the Introspector presents us with a type that we don't have a string conversion for, but the bean actually has a method to set the property from a string, allow to provide this information to the BeanFactory. New attribute "forceString" taking a comma separated list of items as values. Each item is either a bean property name (e.g. "foo") meaning that there is a setter function "setFoo(String)" for that property. Or the item is of the form "foo=method" meaning that property "foo" can be set by calling "method(String)". This should make writing a custom bean factory obsolete in quite a few cases. Concrete use case was tibco TibjmsConnectionFactory which has an attribute SSLIdentity detected by Introspector as byte[] but which can be set by setSSLIdentity(String). Existing BeanFactory throws NamingException. Backport of r1655312, r1655438 and r1655441 from trunk. Modified: tomcat/tc8.0.x/trunk/ (props changed) tomcat/tc8.0.x/trunk/java/org/apache/naming/factory/BeanFactory.java tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml tomcat/tc8.0.x/trunk/webapps/docs/jndi-resources-howto.xml Propchange: tomcat/tc8.0.x/trunk/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Wed Jan 28 19:51:33 2015 @@ -1 +1 @@ -/tomcat/trunk:1636524,1637156,1637176,1637188,1637331,1637684,1637695,1638720-1638725,1639653,1640010,1640083-1640084,1640088,1640275,1640322,1640347,1640361,1640365,1640403,1640410,1640652,1640655-1640658,1640688,1640700-1640883,1640903,1640976,1640978,1641000,1641026,1641038-1641039,1641051-1641052,1641058,1641064,1641300,1641369,1641374,1641380,1641486,1641634,1641656-1641692,1641704,1641707-1641718,1641720-1641722,1641735,1641981,1642233,1642280,1642554,1642564,1642595,1642606,1642668,1642679,1642697,1642699,1642766,1643002,1643045,1643054-1643055,1643066,1643121,1643128,1643206,1643209-1643210,1643216,1643249,1643270,1643283,1643309-1643310,1643323,1643365-1643366,1643370-1643371,1643465,1643474,1643536,1643570,1643634,1643649,1643651,1643654,1643675,1643731,1643733-1643734,1643761,1643766,1643814,1643937,1643963,1644017,1644169,1644201-1644203,1644321,1644323,1644516,1644523,1644529,1644535,1644730,1644768,1644784-1644785,1644790,1644793,1644815,1644884,1644886,1644890,1644892 ,1644910,1644924,1644929-1644930,1644935,1644989,1645011,1645247,1645355,1645357-1645358,1645455,1645465,1645469,1645471,1645473,1645475,1645486-1645488,1645626,1645641,1645685,1645743,1645763,1645951-1645953,1645955,1645993,1646098-1646106,1646178,1646220,1646302,1646304,1646420,1646470-1646471,1646476,1646559,1646717-1646723,1646773,1647026,1647042,1647530,1647655,1648304,1648815,1648907,1650081,1650365,1651116,1651120,1651280,1651470,1652938,1652970,1653041,1653471,1653550,1653574,1653797,1653815-1653816,1653819,1653840,1653857,1653888,1653972,1654013,1654030,1654050,1654123,1654148,1654159,1654513,1654515,1654517,1654522,1654524,1654725,1654735,1654766,1654785,1654851-1654852,1654978,1655122-1655124,1655126-1655127,1655129-1655130,1655132-1655133 +/tomcat/trunk:1636524,1637156,1637176,1637188,1637331,1637684,1637695,1638720-1638725,1639653,1640010,1640083-1640084,1640088,1640275,1640322,1640347,1640361,1640365,1640403,1640410,1640652,1640655-1640658,1640688,1640700-1640883,1640903,1640976,1640978,1641000,1641026,1641038-1641039,1641051-1641052,1641058,1641064,1641300,1641369,1641374,1641380,1641486,1641634,1641656-1641692,1641704,1641707-1641718,1641720-1641722,1641735,1641981,1642233,1642280,1642554,1642564,1642595,1642606,1642668,1642679,1642697,1642699,1642766,1643002,1643045,1643054-1643055,1643066,1643121,1643128,1643206,1643209-1643210,1643216,1643249,1643270,1643283,1643309-1643310,1643323,1643365-1643366,1643370-1643371,1643465,1643474,1643536,1643570,1643634,1643649,1643651,1643654,1643675,1643731,1643733-1643734,1643761,1643766,1643814,1643937,1643963,1644017,1644169,1644201-1644203,1644321,1644323,1644516,1644523,1644529,1644535,1644730,1644768,1644784-1644785,1644790,1644793,1644815,1644884,1644886,1644890,1644892 ,1644910,1644924,1644929-1644930,1644935,1644989,1645011,1645247,1645355,1645357-1645358,1645455,1645465,1645469,1645471,1645473,1645475,1645486-1645488,1645626,1645641,1645685,1645743,1645763,1645951-1645953,1645955,1645993,1646098-1646106,1646178,1646220,1646302,1646304,1646420,1646470-1646471,1646476,1646559,1646717-1646723,1646773,1647026,1647042,1647530,1647655,1648304,1648815,1648907,1650081,1650365,1651116,1651120,1651280,1651470,1652938,1652970,1653041,1653471,1653550,1653574,1653797,1653815-1653816,1653819,1653840,1653857,1653888,1653972,1654013,1654030,1654050,1654123,1654148,1654159,1654513,1654515,1654517,1654522,1654524,1654725,1654735,1654766,1654785,1654851-1654852,1654978,1655122-1655124,1655126-1655127,1655129-1655130,1655132-1655133,1655312,1655438,1655441 Modified: tomcat/tc8.0.x/trunk/java/org/apache/naming/factory/BeanFactory.java URL: http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/java/org/apache/naming/factory/BeanFactory.java?rev=1655445&r1=1655444&r2=1655445&view=diff ============================================================================== --- tomcat/tc8.0.x/trunk/java/org/apache/naming/factory/BeanFactory.java (original) +++ tomcat/tc8.0.x/trunk/java/org/apache/naming/factory/BeanFactory.java Wed Jan 28 19:51:33 2015 @@ -20,9 +20,12 @@ package org.apache.naming.factory; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Enumeration; +import java.util.HashMap; import java.util.Hashtable; +import java.util.Map; import javax.naming.Context; import javax.naming.Name; @@ -143,22 +146,78 @@ public class BeanFactory Object bean = beanClass.newInstance(); + /* Look for properties with explicitly configured setter */ + RefAddr ra = ref.get("forceString"); + Map<String, Method> forced = new HashMap<String, Method>(); + String value; + + if (ra != null) { + value = (String)ra.getContent(); + Class<?> paramTypes[] = new Class[1]; + paramTypes[0] = String.class; + String setterName; + int index; + + /* Items are given as comma separated list */ + for (String param: value.split(",")) { + param = param.trim(); + /* A single item can either be of the form name=method + * or just a property name (and we will use a standard + * setter) */ + index = param.indexOf('='); + if (index >= 0) { + setterName = param.substring(index + 1).trim(); + param = param.substring(0, index).trim(); + } else { + setterName = "set" + + param.substring(0, 1).toUpperCase() + + param.substring(1); + } + try { + forced.put(param, + beanClass.getMethod(setterName, paramTypes)); + } catch (NoSuchMethodException|SecurityException ex) { + throw new NamingException + ("Forced String setter " + setterName + + " not found for property " + param); + } + } + } + Enumeration<RefAddr> e = ref.getAll(); + while (e.hasMoreElements()) { - RefAddr ra = e.nextElement(); + ra = e.nextElement(); String propName = ra.getType(); if (propName.equals(Constants.FACTORY) || propName.equals("scope") || propName.equals("auth") || + propName.equals("forceString") || propName.equals("singleton")) { continue; } - String value = (String)ra.getContent(); + value = (String)ra.getContent(); Object[] valueArray = new Object[1]; + /* Shortcut for properties with explicitly configured setter */ + Method method = forced.get(propName); + if (method != null) { + valueArray[0] = value; + try { + method.invoke(bean, valueArray); + } catch (IllegalAccessException| + IllegalArgumentException| + InvocationTargetException ex) { + throw new NamingException + ("Forced String setter " + method.getName() + + " threw exception for property " + propName); + } + continue; + } + int i = 0; for (i = 0; i<pda.length; i++) { @@ -195,8 +254,9 @@ public class BeanFactory valueArray[0] = Boolean.valueOf(value); } else { throw new NamingException - ("String conversion for property type '" - + propType.getName() + "' not available"); + ("String conversion for property " + propName + + " of type '" + propType.getName() + + "' not available"); } Method setProp = pda[i].getWriteMethod(); Modified: tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml?rev=1655445&r1=1655444&r2=1655445&view=diff ============================================================================== --- tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc8.0.x/trunk/webapps/docs/changelog.xml Wed Jan 28 19:51:33 2015 @@ -93,6 +93,11 @@ </subsection> <subsection name="Other"> <changelog> + <add> + Enhance bean factory used for JNDI resources. New attribute + <code>forceString</code> allows to support non-standard + string argument property setters. (rjung) + </add> <fix> Assign newly created stream to field instead of leaking it uselessly. Issue reported by Coverity Scan. (fschumacher) Modified: tomcat/tc8.0.x/trunk/webapps/docs/jndi-resources-howto.xml URL: http://svn.apache.org/viewvc/tomcat/tc8.0.x/trunk/webapps/docs/jndi-resources-howto.xml?rev=1655445&r1=1655444&r2=1655445&view=diff ============================================================================== --- tomcat/tc8.0.x/trunk/webapps/docs/jndi-resources-howto.xml (original) +++ tomcat/tc8.0.x/trunk/webapps/docs/jndi-resources-howto.xml Wed Jan 28 19:51:33 2015 @@ -328,6 +328,103 @@ writer.println("foo = " + bean.getFoo() <code>foo</code> property (although we could have), the bean will contain whatever default value is set up by its constructor.</p> + <p>Some beans have properties with types that can not automatically be + converted from a string value. Setting such properties using the Tomcat + BeanFactory will fail with a NamingException. In cases were those beans + provide methods to set the properties from a string value, the Tomcat + BeanFactory can be configured to use these methods. The configuration is + done with the <code>forceString</code> attribute.</p> + + <p>Assume our bean looks like this:</p> + +<source><![CDATA[package com.mycompany; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class MyBean2 { + + private InetAddress local = null; + + public InetAddress getLocal() { + return local; + } + + public void setLocal(InetAddress ip) { + local = ip; + } + + public void setLocal(String localHost) { + try { + local = InetAddress.getByName(localHost); + } catch (UnknownHostException ex) { + } + } + + private InetAddress remote = null; + + public InetAddress getRemote() { + return remote; + } + + public void setRemote(InetAddress ip) { + remote = ip; + } + + public void host(String remoteHost) { + try { + remote = InetAddress.getByName(remoteHost); + } catch (UnknownHostException ex) { + } + } + +}]]></source> + + <p>The bean has two properties, both are of type <code>InetAddress</code>. + The first property <code>local</code> has an additional setter taking a + string argument. By default the Tomcat BeanFactory would try to use the + automatically detected setter with the same argument type as the property + type and then throw a NamingException, because it is not prepared to convert + the given string attribute value to <code>InetAddress</code>. + We can tell the Tomcat BeanFactory to use the other setter like that:</p> + +<source><![CDATA[<Context ...> + ... + <Resource name="bean/MyBeanFactory" auth="Container" + type="com.mycompany.MyBean2" + factory="org.apache.naming.factory.BeanFactory" + forceString="local" + local="localhost"/> + ... +</Context>]]></source> + + <p>The bean property <code>remote</code> can also be set from a string, + but one has to use the non-standard method name <code>host</code>. + To set <code>local</code> and <code>remote</code> use the following + configuration:</p> + +<source><![CDATA[<Context ...> + ... + <Resource name="bean/MyBeanFactory" auth="Container" + type="com.mycompany.MyBean2" + factory="org.apache.naming.factory.BeanFactory" + forceString="local,remote=host" + local="localhost" + remote="tomcat.apache.org"/> + ... +</Context>]]></source> + + <p>Multiple property descriptions can be combined in + <code>forceString</code> by concatenation with comma as a separator. + Each property description consists of either only the property name + in which case the BeanFactory calls the setter method. Or it consist + of <code>name=method</code> in which case the property named + <code>name</code> is set by calling method <code>method</code>. + For properties of types <code>String</code> or of primitive type + or of their associated primitive wrapper classes using + <code>forceString</code> is not needed. The correct setter will be + automatically detected and argument conversion will be applied.</p> + </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org