Author: jboynes
Date: Sat Oct 23 16:44:03 2010
New Revision: 1026644
URL: http://svn.apache.org/viewvc?rev=1026644&view=rev
Log:
refactor c:set to resolve memory leak from bug #33934
Modified:
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/SetSupport.java
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/rt/core/SetTag.java
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/core/SetSupportTest.java
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/tag/el/core/SetTag.java
Modified:
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/SetSupport.java
URL:
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/SetSupport.java?rev=1026644&r1=1026643&r2=1026644&view=diff
==============================================================================
---
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/SetSupport.java
(original)
+++
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/SetSupport.java
Sat Oct 23 16:44:03 2010
@@ -26,6 +26,7 @@ import java.lang.reflect.Method;
import java.util.Map;
+import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.JspTagException;
@@ -44,22 +45,13 @@ import org.apache.taglibs.standard.resou
/**
* <p>Support for handlers of the <set> tag.</p>
*
- * <p>The protected <code>value</code> and <code>valueSpecified</code>
- * attributes must be set in sync. That is, if you set the value then
- * you should set <code>valueSpecified</code> to <code>true<code>, if you
unset the value, then
- * you should set <code>valueSpecified</code> to <code>false<code>. </p>
- *
* @author Shawn Bayern
*/
-public class SetSupport extends BodyTagSupport {
+public abstract class SetSupport extends BodyTagSupport {
//*********************************************************************
// Internal state
- protected Object value; // tag attribute
- protected boolean valueSpecified; // status
- protected Object target; // tag attribute
- protected String property; // tag attribute
private String var; // tag attribute
private String scope; // tag attribute
@@ -71,20 +63,14 @@ public class SetSupport extends BodyTagS
* not provide other constructors and are expected to call the
* superclass constructor.
*/
- public SetSupport() {
+ protected SetSupport() {
super();
- init();
- }
-
- // resets local state
- private void init() {
- value = target = property = var = scope = null;
- valueSpecified = false;
}
// Releases any resources we may have (or inherit)
public void release() {
- init();
+ var = null;
+ scope = null;
super.release();
}
@@ -94,27 +80,30 @@ public class SetSupport extends BodyTagS
public int doEndTag() throws JspException {
- // what we'll store in scope:var
- Object result = getResult();
-
// decide what to do with the result
if (var != null) {
- exportToVariable(result);
- } else if (target == null) {
- // can happen if target evaluates to null
- throw new
JspTagException(Resources.getMessage("SET_INVALID_TARGET"));
- } else if (target instanceof Map) {
- exportToMapProperty(result);
+ exportToVariable(getResult());
} else {
- exportToBeanProperty(result);
+ Object target = evalTarget();
+ if (target == null) {
+ // can happen if target evaluates to null
+ throw new
JspTagException(Resources.getMessage("SET_INVALID_TARGET"));
+ }
+
+ String property = evalProperty();
+ if (target instanceof Map) {
+ exportToMapProperty(target, property, getResult());
+ } else {
+ exportToBeanProperty(target, property, getResult());
+ }
}
return EVAL_PAGE;
}
- Object getResult() {
- if (valueSpecified) {
- return value;
+ Object getResult() throws JspException {
+ if (isValueSpecified()) {
+ return evalValue();
} else if (bodyContent == null) {
return "";
} else {
@@ -128,6 +117,38 @@ public class SetSupport extends BodyTagS
}
/**
+ * Indicates that the value attribute was specified.
+ * If no value attribute is supplied then the value is taken from the
tag's body content.
+ *
+ * @return true if the value attribute was specified
+ */
+ protected abstract boolean isValueSpecified();
+
+ /**
+ * Evaluate the value attribute.
+ *
+ * @return the result of evaluating the value attribute
+ * @throws JspException if there was a problem evaluating the expression
+ */
+ protected abstract Object evalValue() throws JspException;
+
+ /**
+ * Evaluate the target attribute.
+ *
+ * @return the result of evaluating the target attribute
+ * @throws JspException if there was a problem evaluating the expression
+ */
+ protected abstract Object evalTarget() throws JspException;
+
+ /**
+ * Evaluate the property attribute.
+ *
+ * @return the result of evaluating the property attribute
+ * @throws JspException if there was a problem evaluating the expression
+ */
+ protected abstract String evalProperty() throws JspException;
+
+ /**
* Export the result into a scoped variable.
*
* @param result the value to export
@@ -173,9 +194,11 @@ public class SetSupport extends BodyTagS
/**
* Export the result into a Map.
*
+ * @param target the Map to export into
+ * @param property the key to export into
* @param result the value to export
*/
- void exportToMapProperty(Object result) {
+ void exportToMapProperty(Object target, String property, Object result) {
@SuppressWarnings("unchecked")
Map<Object, Object> map = (Map<Object, Object>) target;
if (result == null) {
@@ -188,10 +211,12 @@ public class SetSupport extends BodyTagS
/**
* Export the result into a bean property.
*
+ * @param target the bean to export into
+ * @param property the bean property to set
* @param result the value to export
* @throws JspTagException if there was a problem exporting the result
*/
- void exportToBeanProperty(Object result) throws JspTagException {
+ void exportToBeanProperty(Object target, String property, Object result)
throws JspTagException {
PropertyDescriptor[] descriptors;
try {
descriptors =
Introspector.getBeanInfo(target.getClass()).getPropertyDescriptors();
@@ -234,9 +259,12 @@ public class SetSupport extends BodyTagS
return null;
}
Class<?> expectedType = m.getParameterTypes()[0];
- JspFactory jspFactory = JspFactory.getDefaultFactory();
- ExpressionFactory expressionFactory =
jspFactory.getJspApplicationContext(pageContext.getServletContext()).getExpressionFactory();
- return expressionFactory.coerceToType(value, expectedType);
+ return getExpressionFactory().coerceToType(value, expectedType);
+ }
+
+ protected ExpressionFactory getExpressionFactory() {
+ JspApplicationContext appContext =
JspFactory.getDefaultFactory().getJspApplicationContext(pageContext.getServletContext());
+ return appContext.getExpressionFactory();
}
//*********************************************************************
Modified:
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/rt/core/SetTag.java
URL:
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/rt/core/SetTag.java?rev=1026644&r1=1026643&r2=1026644&view=diff
==============================================================================
---
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/rt/core/SetTag.java
(original)
+++
tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/rt/core/SetTag.java
Sat Oct 23 16:44:03 2010
@@ -20,29 +20,59 @@ package org.apache.taglibs.standard.tag.
import org.apache.taglibs.standard.tag.common.core.SetSupport;
/**
- * <p>Tag handler for <set> in JSTL's rtexprvalue library.</p>
+ * JSTL 1.1 compatible version of <set> that accepts expression results
for attribute values.
*
* @author Shawn Bayern
*/
public class SetTag extends SetSupport {
+ private boolean valueSpecified;
+ private Object value;
+ private Object target;
+ private String property;
- //*********************************************************************
- // Accessors
+ public SetTag() {
+ }
- // for tag attribute
public void setValue(Object value) {
this.value = value;
this.valueSpecified = true;
}
- // for tag attribute
public void setTarget(Object target) {
this.target = target;
}
- // for tag attribute
public void setProperty(String property) {
this.property = property;
}
+
+ @Override
+ public void release() {
+ value = null;
+ target = null;
+ property = null;
+ valueSpecified = false;
+ super.release();
+ }
+
+ @Override
+ protected boolean isValueSpecified() {
+ return valueSpecified;
+ }
+
+ @Override
+ protected Object evalValue() {
+ return value;
+ }
+
+ @Override
+ protected Object evalTarget() {
+ return target;
+ }
+
+ @Override
+ protected String evalProperty() {
+ return property;
+ }
}
Modified:
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/core/SetSupportTest.java
URL:
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/core/SetSupportTest.java?rev=1026644&r1=1026643&r2=1026644&view=diff
==============================================================================
---
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/core/SetSupportTest.java
(original)
+++
tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/core/SetSupportTest.java
Sat Oct 23 16:44:03 2010
@@ -64,8 +64,6 @@ public class SetSupportTest {
bean = new Bean();
- tag = new SetSupport();
- tag.setPageContext(pageContext);
ExpressionFactory expressionFactory =
createMock(ExpressionFactory.class);
JspApplicationContext applicationContext =
createMock(JspApplicationContext.class);
@@ -85,9 +83,9 @@ public class SetSupportTest {
@Test
public void testSyntax1WithNoScope() throws JspException {
+ tag = new MockSetSupport(VALUE);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
- tag.valueSpecified = true;
- tag.value = VALUE;
// verify mapper is checked but that no action is taken
expect(vm.resolveVariable(VAR)).andReturn(null);
@@ -99,10 +97,10 @@ public class SetSupportTest {
@Test
public void testSyntax1WithNullScope() throws JspException {
+ tag = new MockSetSupport(VALUE);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
tag.setScope(null);
- tag.valueSpecified = true;
- tag.value = VALUE;
// verify mapper is checked but that no action is taken
expect(vm.resolveVariable(VAR)).andReturn(null);
@@ -114,10 +112,10 @@ public class SetSupportTest {
@Test
public void testSyntax1WithPageScope() throws JspException {
+ tag = new MockSetSupport(VALUE);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
tag.setScope("page");
- tag.valueSpecified = true;
- tag.value = VALUE;
// verify mapper is checked but that no action is taken
expect(vm.resolveVariable(VAR)).andReturn(null);
@@ -129,10 +127,10 @@ public class SetSupportTest {
@Test
public void testSyntax1WithNonPageScope() throws JspException {
+ tag = new MockSetSupport(VALUE);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
tag.setScope("request");
- tag.valueSpecified = true;
- tag.value = VALUE;
// verify mapper is not checked
pageContext.setAttribute(VAR, VALUE, PageContext.REQUEST_SCOPE);
@@ -143,9 +141,9 @@ public class SetSupportTest {
@Test
public void testSyntax1WithNullValueAndNoScope() throws JspException {
+ tag = new MockSetSupport(null);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
- tag.valueSpecified = true;
- tag.value = null;
// verify mapper is checked but that no action is taken
expect(vm.resolveVariable(VAR)).andReturn(null);
@@ -157,10 +155,10 @@ public class SetSupportTest {
@Test
public void testSyntax1WithNullValueAndNonPageScope() throws JspException {
+ tag = new MockSetSupport(null);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
tag.setScope("request");
- tag.valueSpecified = true;
- tag.value = null;
// verify mapper is checked but that no action is taken
expect(vm.resolveVariable(VAR)).andReturn(null);
@@ -174,11 +172,9 @@ public class SetSupportTest {
public void testSyntax3WithMap() throws JspException {
@SuppressWarnings("unchecked")
Map<String, Object> target = createMock(Map.class);
- tag.target = target;
- tag.property = PROPERTY;
- tag.valueSpecified = true;
- tag.value = VALUE;
-
+ tag = new MockSetSupport(VALUE, target, PROPERTY);
+ tag.setPageContext(pageContext);
+
expect(target.put(PROPERTY, VALUE)).andStubReturn(null);
replay(target);
tag.doEndTag();
@@ -189,10 +185,8 @@ public class SetSupportTest {
public void testSyntax3WithMapWhenPropertyIsNull() throws JspException {
@SuppressWarnings("unchecked")
Map<String, Object> target = createMock(Map.class);
- tag.target = target;
- tag.property = null;
- tag.valueSpecified = true;
- tag.value = VALUE;
+ tag = new MockSetSupport(VALUE, target, null);
+ tag.setPageContext(pageContext);
expect(target.put(null, VALUE)).andStubReturn(null);
replay(target);
@@ -204,10 +198,8 @@ public class SetSupportTest {
public void testSyntax3WithMapWhenValueIsNull() throws JspException {
@SuppressWarnings("unchecked")
Map<String, Object> target = createMock(Map.class);
- tag.target = target;
- tag.property = PROPERTY;
- tag.valueSpecified = true;
- tag.value = null;
+ tag = new MockSetSupport(null, target, PROPERTY);
+ tag.setPageContext(pageContext);
expect(target.remove(PROPERTY)).andStubReturn(null);
replay(target);
@@ -217,10 +209,8 @@ public class SetSupportTest {
@Test
public void testSyntax3WithBean() throws JspException {
- tag.target = bean;
- tag.property = PROPERTY;
- tag.valueSpecified = true;
- tag.value = VALUE;
+ tag = new MockSetSupport(VALUE, bean, PROPERTY);
+ tag.setPageContext(pageContext);
tag.doEndTag();
Assert.assertEquals(VALUE, bean.getProperty());
@@ -228,10 +218,8 @@ public class SetSupportTest {
@Test
public void testSyntax3WithBeanAndNullValue() throws JspException {
- tag.target = bean;
- tag.property = PROPERTY;
- tag.valueSpecified = true;
- tag.value = null;
+ tag = new MockSetSupport(null, bean, PROPERTY);
+ tag.setPageContext(pageContext);
tag.doEndTag();
Assert.assertNull(bean.getProperty());
@@ -239,10 +227,8 @@ public class SetSupportTest {
@Test
public void testSyntax3WithBeanAndUndefinedProperty() throws JspException {
- tag.target = bean;
- tag.property = "undefined";
- tag.valueSpecified = true;
- tag.value = VALUE;
+ tag = new MockSetSupport(VALUE, bean, "undefined");
+ tag.setPageContext(pageContext);
try {
tag.doEndTag();
@@ -253,10 +239,8 @@ public class SetSupportTest {
@Test
public void testSyntax3WithBeanAndReadOnlyProperty() throws JspException {
- tag.target = bean;
- tag.property = "readOnly";
- tag.valueSpecified = true;
- tag.value = VALUE;
+ tag = new MockSetSupport(VALUE, bean, "readOnly");
+ tag.setPageContext(pageContext);
try {
tag.doEndTag();
@@ -267,10 +251,8 @@ public class SetSupportTest {
@Test
public void testSyntax3WhenTargetIsNull() throws JspException {
- tag.target = null;
- tag.property = PROPERTY;
- tag.valueSpecified = true;
- tag.value = VALUE;
+ tag = new MockSetSupport(VALUE, null, PROPERTY);
+ tag.setPageContext(pageContext);
try {
tag.doEndTag();
@@ -287,9 +269,9 @@ public class SetSupportTest {
*/
@Test
public void test49526WhenNotMapped() throws JspException {
+ tag = new MockSetSupport(VALUE);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
- tag.valueSpecified = true;
- tag.value = VALUE;
// verify mapper is checked but that no action is taken
expect(vm.resolveVariable(VAR)).andReturn(null);
@@ -306,9 +288,9 @@ public class SetSupportTest {
*/
@Test
public void test49526WhenAlreadyMapped() throws JspException {
+ tag = new MockSetSupport(VALUE);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
- tag.valueSpecified = true;
- tag.value = VALUE;
// verify mapper is checked and the mapped variable removed
ValueExpression ve = createMock(ValueExpression.class);
@@ -327,9 +309,9 @@ public class SetSupportTest {
*/
@Test
public void test49526WhenNotUsingPageContext() throws JspException {
+ tag = new MockSetSupport(VALUE);
+ tag.setPageContext(pageContext);
tag.setVar(VAR);
- tag.valueSpecified = true;
- tag.value = VALUE;
tag.setScope("request");
// verify mapper is not checked
@@ -340,22 +322,20 @@ public class SetSupportTest {
}
@Test
- public void testResultFromValueAttribute() {
- tag.valueSpecified = true;
- tag.value = VALUE;
+ public void testResultFromValueAttribute() throws JspException {
+ tag = new MockSetSupport(VALUE);
Assert.assertSame(VALUE, tag.getResult());
}
@Test
- public void testResultFromNullValueAttribute() {
- tag.valueSpecified = true;
- tag.value = null;
+ public void testResultFromNullValueAttribute() throws JspException {
+ tag = new MockSetSupport(null);
Assert.assertNull(tag.getResult());
}
@Test
- public void testResultFromBodyContent() {
- tag.valueSpecified = false;
+ public void testResultFromBodyContent() throws JspException {
+ tag = new MockSetSupport();
BodyContent bodyContent = createMock(BodyContent.class);
expect(bodyContent.getString()).andStubReturn(" Hello ");
replay(bodyContent);
@@ -364,20 +344,68 @@ public class SetSupportTest {
}
@Test
- public void testResultFromNullBodyContent() {
- tag.valueSpecified = false;
+ public void testResultFromNullBodyContent() throws JspException {
+ tag = new MockSetSupport();
tag.setBodyContent(null);
- Assert.assertEquals("", tag.getResult());
+ Assert.assertEquals(tag.getResult(), "");
}
@Test
- public void testResultFromEmptyBodyContent() {
- tag.valueSpecified = false;
+ public void testResultFromEmptyBodyContent() throws JspException {
+ tag = new MockSetSupport();
BodyContent bodyContent = createMock(BodyContent.class);
expect(bodyContent.getString()).andStubReturn(null);
Assert.assertEquals("", tag.getResult());
}
+ public static class MockSetSupport extends SetSupport {
+ private final boolean valueSpecified;
+ private final Object value;
+ private final Object target;
+ private final String property;
+
+ public MockSetSupport() {
+ this.value = null;
+ this.valueSpecified = false;
+ this.target = null;
+ this.property = null;
+ }
+
+ public MockSetSupport(Object value, Object target, String property) {
+ this.value = value;
+ this.valueSpecified = true;
+ this.target = target;
+ this.property = property;
+ }
+
+ public MockSetSupport(Object value) {
+ this.value = value;
+ this.valueSpecified = true;
+ this.target = null;
+ this.property = null;
+ }
+
+ @Override
+ protected boolean isValueSpecified() {
+ return valueSpecified;
+ }
+
+ @Override
+ protected Object evalValue() {
+ return value;
+ }
+
+ @Override
+ protected Object evalTarget() {
+ return target;
+ }
+
+ @Override
+ protected String evalProperty() {
+ return property;
+ }
+ }
+
public static class Bean {
private String property;
Modified:
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/tag/el/core/SetTag.java
URL:
http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/tag/el/core/SetTag.java?rev=1026644&r1=1026643&r2=1026644&view=diff
==============================================================================
---
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/tag/el/core/SetTag.java
(original)
+++
tomcat/taglibs/standard/trunk/jstlel/src/main/java/org/apache/taglibs/standard/tag/el/core/SetTag.java
Sat Oct 23 16:44:03 2010
@@ -13,7 +13,7 @@
* 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.taglibs.standard.tag.el.core;
@@ -23,108 +23,70 @@ import org.apache.taglibs.standard.tag.c
import org.apache.taglibs.standard.tag.common.core.SetSupport;
/**
- * <p>A handler for <set>, which redirects the browser to a
- * new URL.
+ * JSTL 1.0 compatible version of <set> that accepts expressions for
attribute values.
*
* @author Shawn Bayern
*/
public class SetTag extends SetSupport {
- //*********************************************************************
- // 'Private' state (implementation details)
-
- private String value_; // stores EL-based property
- private String target_; // stores EL-based property
- private String property_; // stores EL-based property
-
-
- //*********************************************************************
- // Constructor
+ private boolean valueSpecified;
+ private String valueExpression;
+ private String targetExpression;
+ private String propertyExpression;
public SetTag() {
- super();
- init();
}
+ public void setValue(String value) {
+ this.valueExpression = value;
+ this.valueSpecified = true;
+ }
- //*********************************************************************
- // Tag logic
-
- // evaluates expression and chains to parent
- public int doStartTag() throws JspException {
-
- // evaluate any expressions we were passed, once per invocation
- evaluateExpressions();
-
- // chain to the parent implementation
- return super.doStartTag();
+ public void setTarget(String target) {
+ this.targetExpression = target;
}
+ public void setProperty(String property) {
+ this.propertyExpression = property;
+ }
- // Releases any resources we may have (or inherit)
+ @Override
public void release() {
+ valueExpression = null;
+ targetExpression = null;
+ propertyExpression = null;
+ valueSpecified = false;
super.release();
- init();
- }
-
-
- //*********************************************************************
- // Accessor methods
-
- public void setValue(String value_) {
- this.value_ = value_;
- this.valueSpecified = true;
}
- public void setTarget(String target_) {
- this.target_ = target_;
+ @Override
+ protected boolean isValueSpecified() {
+ return valueSpecified;
}
- public void setProperty(String property_) {
- this.property_ = property_;
+ @Override
+ protected Object evalValue() throws JspException {
+ try {
+ return ExpressionUtil.evalNotNull("set", "value", valueExpression,
Object.class, this, pageContext);
+ } catch (NullAttributeException ex) {
+ // explicitly let 'value' be null
+ return null;
+ }
}
-
- //*********************************************************************
- // Private (utility) methods
-
- // (re)initializes state (during release() or construction)
- private void init() {
- // null implies "no expression"
- value_ = target_ = property_ = null;
+ @Override
+ protected Object evalTarget() throws JspException {
+ return ExpressionUtil.evalNotNull("set", "target", targetExpression,
Object.class, this, pageContext);
}
- /* Evaluates expressions as necessary */
- private void evaluateExpressions() throws JspException {
- /*
- * Note: we don't check for type mismatches here; we assume
- * the expression evaluator will return the expected type
- * (by virtue of knowledge we give it about what that type is).
- * A ClassCastException here is truly unexpected, so we let it
- * propagate up.
- */
-
- // 'value'
- try {
- value = ExpressionUtil.evalNotNull(
- "set", "value", value_, Object.class, this, pageContext);
- } catch (NullAttributeException ex) {
- // explicitly let 'value' be null
- value = null;
- }
-
- // 'target'
- target = ExpressionUtil.evalNotNull(
- "set", "target", target_, Object.class, this, pageContext);
-
- // 'property'
- try {
- property = (String) ExpressionUtil.evalNotNull(
- "set", "property", property_, String.class, this, pageContext);
+ @Override
+ protected String evalProperty() throws JspException {
+ try {
+ return (String) ExpressionUtil.evalNotNull("set", "property",
propertyExpression, String.class, this, pageContext);
} catch (NullAttributeException ex) {
// explicitly let 'property' be null
- property = null;
+ return null;
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]