Coverage Report - org.mule.providers.jdbc.JdbcConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
JdbcConnector
66%
131/198
56%
63/112
2.5
 
 1  
 /*
 2  
  * $Id: JdbcConnector.java 11728 2008-05-13 07:31:11Z dirk.olmes $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.providers.jdbc;
 12  
 
 13  
 import org.mule.MuleManager;
 14  
 import org.mule.config.ExceptionHelper;
 15  
 import org.mule.config.i18n.CoreMessages;
 16  
 import org.mule.providers.AbstractConnector;
 17  
 import org.mule.providers.jdbc.i18n.JdbcMessages;
 18  
 import org.mule.providers.jdbc.xa.DataSourceWrapper;
 19  
 import org.mule.transaction.TransactionCoordination;
 20  
 import org.mule.umo.TransactionException;
 21  
 import org.mule.umo.UMOComponent;
 22  
 import org.mule.umo.UMOException;
 23  
 import org.mule.umo.UMOTransaction;
 24  
 import org.mule.umo.endpoint.UMOEndpoint;
 25  
 import org.mule.umo.endpoint.UMOImmutableEndpoint;
 26  
 import org.mule.umo.lifecycle.InitialisationException;
 27  
 import org.mule.umo.provider.UMOMessageReceiver;
 28  
 import org.mule.util.ClassUtils;
 29  
 import org.mule.util.ExceptionUtils;
 30  
 import org.mule.util.StringUtils;
 31  
 import org.mule.util.properties.BeanPropertyExtractor;
 32  
 import org.mule.util.properties.MapPropertyExtractor;
 33  
 import org.mule.util.properties.MessagePropertyExtractor;
 34  
 import org.mule.util.properties.PayloadPropertyExtractor;
 35  
 import org.mule.util.properties.PropertyExtractor;
 36  
 
 37  
 import java.sql.Connection;
 38  
 import java.util.HashSet;
 39  
 import java.util.Hashtable;
 40  
 import java.util.Iterator;
 41  
 import java.util.List;
 42  
 import java.util.Map;
 43  
 import java.util.Set;
 44  
 import java.util.StringTokenizer;
 45  
 import java.util.regex.Matcher;
 46  
 import java.util.regex.Pattern;
 47  
 
 48  
 import javax.naming.Context;
 49  
 import javax.naming.InitialContext;
 50  
 import javax.naming.NamingException;
 51  
 import javax.sql.DataSource;
 52  
 import javax.sql.XADataSource;
 53  
 
 54  
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
 55  
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
 56  
 import org.apache.commons.dbutils.QueryRunner;
 57  
 import org.apache.commons.dbutils.ResultSetHandler;
 58  
 
 59  32
 public class JdbcConnector extends AbstractConnector
 60  
 {
 61  
     // These are properties that can be overridden on the Receiver by the endpoint
 62  
     // declaration
 63  
     public static final String PROPERTY_POLLING_FREQUENCY = "pollingFrequency";
 64  
     public static final long DEFAULT_POLLING_FREQUENCY = 1000;
 65  
 
 66  
     private static final String DEFAULT_QUERY_RUNNER = "org.apache.commons.dbutils.QueryRunner";
 67  
     private static final String DEFAULT_RESULTSET_HANDLER = "org.apache.commons.dbutils.handlers.MapListHandler";
 68  
 
 69  2
     private static final Pattern STATEMENT_ARGS = Pattern.compile("\\$\\{[^\\}]*\\}");
 70  
     
 71  
     /* Register the SQL Exception reader if this class gets loaded */
 72  
     static
 73  
     {
 74  2
         ExceptionHelper.registerExceptionReader(new SQLExceptionReader());
 75  2
     }
 76  
 
 77  32
     protected long pollingFrequency = 0;
 78  
     protected DataSource dataSource;
 79  
     protected String dataSourceJndiName;
 80  
     protected Context jndiContext;
 81  
     protected String jndiInitialFactory;
 82  
     protected String jndiProviderUrl;
 83  
     protected Map providerProperties;
 84  
     protected Map queries;
 85  32
     protected String resultSetHandler = DEFAULT_RESULTSET_HANDLER;
 86  32
     protected String queryRunner = DEFAULT_QUERY_RUNNER;
 87  
     protected Set queryValueExtractors;
 88  
     protected Set propertyExtractors;
 89  
 
 90  32
     protected ConcurrentMap propertyExtractorCache = new ConcurrentHashMap();
 91  
 
 92  
     protected void doInitialise() throws InitialisationException
 93  
     {
 94  
         try
 95  
         {
 96  
             // If we have a dataSource, there is no need to initialise
 97  
             // the JndiContext
 98  32
             if (dataSource == null)
 99  
             {
 100  0
                 initJndiContext();
 101  0
                 createDataSource();
 102  
             }
 103  
 
 104  32
             if (dataSource != null && dataSource instanceof XADataSource)
 105  
             {
 106  0
                 if (MuleManager.getInstance().getTransactionManager() != null)
 107  
                 {
 108  0
                     dataSource = new DataSourceWrapper((XADataSource)dataSource, MuleManager.getInstance()
 109  
                         .getTransactionManager());
 110  
                 }
 111  
             }
 112  
 
 113  
             // setup property Extractors for queries
 114  32
             if (queryValueExtractors == null)
 115  
             {
 116  
                 // Add defaults
 117  32
                 queryValueExtractors = new HashSet();
 118  42
                 queryValueExtractors.add(MessagePropertyExtractor.class.getName());
 119  32
                 queryValueExtractors.add(NowPropertyExtractor.class.getName());
 120  32
                 queryValueExtractors.add(PayloadPropertyExtractor.class.getName());
 121  32
                 queryValueExtractors.add(MapPropertyExtractor.class.getName());
 122  32
                 queryValueExtractors.add(BeanPropertyExtractor.class.getName());
 123  
 
 124  32
                 if (ClassUtils.isClassOnPath("org.mule.util.properties.Dom4jPropertyExtractor", getClass()))
 125  
                 {
 126  32
                     queryValueExtractors.add("org.mule.util.properties.Dom4jPropertyExtractor");
 127  
                 }
 128  
 
 129  32
                 if (ClassUtils.isClassOnPath("org.mule.util.properties.JDomPropertyExtractor", getClass()))
 130  
                 {
 131  32
                     queryValueExtractors.add("org.mule.util.properties.JDomPropertyExtractor");
 132  
                 }
 133  
             }
 134  
 
 135  32
             propertyExtractors = new HashSet();
 136  32
             for (Iterator iterator = queryValueExtractors.iterator(); iterator.hasNext();)
 137  
             {
 138  224
                 String s = (String)iterator.next();
 139  224
                 propertyExtractors.add(ClassUtils.instanciateClass(s, ClassUtils.NO_ARGS));
 140  224
             }
 141  
         }
 142  0
         catch (Exception e)
 143  
         {
 144  0
             throw new InitialisationException(CoreMessages.failedToCreate("Jdbc Connector"), e, this);
 145  32
         }
 146  32
     }
 147  
 
 148  
     protected void doDispose()
 149  
     {
 150  
         // template method
 151  32
     }
 152  
 
 153  
     protected void doConnect() throws Exception
 154  
     {
 155  
         // template method
 156  18
     }
 157  
 
 158  
     protected void doDisconnect() throws Exception
 159  
     {
 160  
         // template method
 161  18
     }
 162  
 
 163  
     protected void doStart() throws UMOException
 164  
     {
 165  
         // template method
 166  18
     }
 167  
 
 168  
     protected void doStop() throws UMOException
 169  
     {
 170  
         // template method
 171  18
     }
 172  
 
 173  
     /*
 174  
      * (non-Javadoc)
 175  
      * 
 176  
      * @see org.mule.umo.provider.UMOConnector#getProtocol()
 177  
      */
 178  
     public String getProtocol()
 179  
     {
 180  120
         return "jdbc";
 181  
     }
 182  
 
 183  
     public UMOMessageReceiver createReceiver(UMOComponent component, UMOEndpoint endpoint) throws Exception
 184  
     {
 185  2
         Map props = endpoint.getProperties();
 186  2
         if (props != null)
 187  
         {
 188  2
             String tempPolling = (String) props.get(PROPERTY_POLLING_FREQUENCY);
 189  2
             if (tempPolling != null)
 190  
             {
 191  0
                 pollingFrequency = Long.parseLong(tempPolling);
 192  
             }
 193  
         }
 194  
 
 195  2
         if (pollingFrequency <= 0)
 196  
         {
 197  0
             pollingFrequency = DEFAULT_POLLING_FREQUENCY;
 198  
         }
 199  
 
 200  2
         String[] params = getReadAndAckStatements(endpoint);
 201  2
         return getServiceDescriptor().createMessageReceiver(this, component, endpoint, params);
 202  
     }
 203  
 
 204  
     protected void initJndiContext() throws NamingException
 205  
     {
 206  0
         if (this.jndiContext == null)
 207  
         {
 208  0
             Hashtable props = new Hashtable();
 209  0
             if (this.jndiInitialFactory != null)
 210  
             {
 211  0
                 props.put(Context.INITIAL_CONTEXT_FACTORY, this.jndiInitialFactory);
 212  
             }
 213  0
             if (this.jndiProviderUrl != null)
 214  
             {
 215  0
                 props.put(Context.PROVIDER_URL, jndiProviderUrl);
 216  
             }
 217  0
             if (this.providerProperties != null)
 218  
             {
 219  0
                 props.putAll(this.providerProperties);
 220  
             }
 221  0
             this.jndiContext = new InitialContext(props);
 222  
         }
 223  
 
 224  0
     }
 225  
 
 226  
     protected void createDataSource() throws InitialisationException, NamingException
 227  
     {
 228  0
         Object temp = this.jndiContext.lookup(this.dataSourceJndiName);
 229  0
         if (temp instanceof DataSource)
 230  
         {
 231  0
             dataSource = (DataSource)temp;
 232  
         }
 233  
         else
 234  
         {
 235  0
             throw new InitialisationException(
 236  
                 JdbcMessages.jndiResourceNotFound(this.dataSourceJndiName), this);
 237  
         }
 238  0
     }
 239  
 
 240  
     public String[] getReadAndAckStatements(UMOImmutableEndpoint endpoint)
 241  
     {
 242  
         String str;
 243  
         // Find read statement
 244  
         String readStmt;
 245  8
         if ((str = (String)endpoint.getProperty("sql")) != null)
 246  
         {
 247  2
             readStmt = str;
 248  
         }
 249  
         else
 250  
         {
 251  6
             readStmt = endpoint.getEndpointURI().getAddress();
 252  
         }
 253  
         // Find ack statement
 254  
         String ackStmt;
 255  8
         if ((str = (String)endpoint.getProperty("ack")) != null)
 256  
         {
 257  0
             ackStmt = str;
 258  0
             if ((str = getQuery(endpoint, ackStmt)) != null)
 259  
             {
 260  0
                 ackStmt = str;
 261  
             }
 262  
         }
 263  
         else
 264  
         {
 265  8
             ackStmt = readStmt + ".ack";
 266  8
             if ((str = getQuery(endpoint, ackStmt)) != null)
 267  
             {
 268  0
                 ackStmt = str;
 269  
             }
 270  
             else
 271  
             {
 272  8
                 ackStmt = null;
 273  
             }
 274  
         }
 275  
         // Translate both using queries map
 276  8
         if ((str = getQuery(endpoint, readStmt)) != null)
 277  
         {
 278  4
             readStmt = str;
 279  
         }
 280  8
         if (readStmt == null)
 281  
         {
 282  0
             throw new IllegalArgumentException("Read statement should not be null");
 283  
         }
 284  8
         if (!"select".equalsIgnoreCase(readStmt.substring(0, 6)) && !"call".equalsIgnoreCase(readStmt.substring(0, 4)))
 285  
         {
 286  0
             throw new IllegalArgumentException("Read statement should be a select sql statement or a stored procedure");
 287  
         }
 288  8
         if (ackStmt != null)
 289  
         {
 290  0
             if (!"insert".equalsIgnoreCase(ackStmt.substring(0, 6))
 291  
                 && !"update".equalsIgnoreCase(ackStmt.substring(0, 6))
 292  
                 && !"delete".equalsIgnoreCase(ackStmt.substring(0, 6)))
 293  
             {
 294  0
                 throw new IllegalArgumentException(
 295  
                     "Ack statement should be an insert / update / delete sql statement");
 296  
             }
 297  
         }
 298  8
         return new String[]{readStmt, ackStmt};
 299  
     }
 300  
 
 301  
     public String getQuery(UMOImmutableEndpoint endpoint, String stmt)
 302  
     {
 303  32
         Object query = null;
 304  32
         if (endpoint != null && endpoint.getProperties() != null)
 305  
         {
 306  32
             Object queries = endpoint.getProperties().get("queries");
 307  32
             if (queries instanceof Map)
 308  
             {
 309  0
                 query = ((Map)queries).get(stmt);
 310  
             }
 311  
         }
 312  32
         if (query == null)
 313  
         {
 314  32
             if (this.queries != null)
 315  
             {
 316  24
                 query = this.queries.get(stmt);
 317  
             }
 318  
         }
 319  32
         return query == null ? null : query.toString();
 320  
     }
 321  
 
 322  
     /**
 323  
      * @return Returns the dataSource.
 324  
      */
 325  
     public DataSource getDataSource()
 326  
     {
 327  32
         return dataSource;
 328  
     }
 329  
 
 330  
     /**
 331  
      * @param dataSource The dataSource to set.
 332  
      */
 333  
     public void setDataSource(DataSource dataSource)
 334  
     {
 335  32
         this.dataSource = dataSource;
 336  32
     }
 337  
 
 338  
     /**
 339  
      * @return Returns the pollingFrequency.
 340  
      */
 341  
     public long getPollingFrequency()
 342  
     {
 343  2
         return pollingFrequency;
 344  
     }
 345  
 
 346  
     /**
 347  
      * @param pollingFrequency The pollingFrequency to set.
 348  
      */
 349  
     public void setPollingFrequency(long pollingFrequency)
 350  
     {
 351  30
         this.pollingFrequency = pollingFrequency;
 352  30
     }
 353  
 
 354  
     /**
 355  
      * @return Returns the queries.
 356  
      */
 357  
     public Map getQueries()
 358  
     {
 359  0
         return queries;
 360  
     }
 361  
 
 362  
     /**
 363  
      * @param queries The queries to set.
 364  
      */
 365  
     public void setQueries(Map queries)
 366  
     {
 367  16
         this.queries = queries;
 368  16
     }
 369  
 
 370  
     /**
 371  
      * @return Returns the dataSourceJndiName.
 372  
      */
 373  
     public String getDataSourceJndiName()
 374  
     {
 375  0
         return dataSourceJndiName;
 376  
     }
 377  
 
 378  
     /**
 379  
      * @param dataSourceJndiName The dataSourceJndiName to set.
 380  
      */
 381  
     public void setDataSourceJndiName(String dataSourceJndiName)
 382  
     {
 383  0
         this.dataSourceJndiName = dataSourceJndiName;
 384  0
     }
 385  
 
 386  
     /**
 387  
      * @return Returns the jndiContext.
 388  
      */
 389  
     public Context getJndiContext()
 390  
     {
 391  0
         return jndiContext;
 392  
     }
 393  
 
 394  
     /**
 395  
      * @param jndiContext The jndiContext to set.
 396  
      */
 397  
     public void setJndiContext(Context jndiContext)
 398  
     {
 399  0
         this.jndiContext = jndiContext;
 400  0
     }
 401  
 
 402  
     /**
 403  
      * @return Returns the jndiInitialFactory.
 404  
      */
 405  
     public String getJndiInitialFactory()
 406  
     {
 407  0
         return jndiInitialFactory;
 408  
     }
 409  
 
 410  
     /**
 411  
      * @param jndiInitialFactory The jndiInitialFactory to set.
 412  
      */
 413  
     public void setJndiInitialFactory(String jndiInitialFactory)
 414  
     {
 415  0
         this.jndiInitialFactory = jndiInitialFactory;
 416  0
     }
 417  
 
 418  
     /**
 419  
      * @return Returns the jndiProviderUrl.
 420  
      */
 421  
     public String getJndiProviderUrl()
 422  
     {
 423  0
         return jndiProviderUrl;
 424  
     }
 425  
 
 426  
     /**
 427  
      * @param jndiProviderUrl The jndiProviderUrl to set.
 428  
      */
 429  
     public void setJndiProviderUrl(String jndiProviderUrl)
 430  
     {
 431  0
         this.jndiProviderUrl = jndiProviderUrl;
 432  0
     }
 433  
 
 434  
     /**
 435  
      * @return Returns the providerProperties.
 436  
      */
 437  
     public Map getProviderProperties()
 438  
     {
 439  0
         return providerProperties;
 440  
     }
 441  
 
 442  
     /**
 443  
      * @param providerProperties The providerProperties to set.
 444  
      */
 445  
     public void setProviderProperties(Map providerProperties)
 446  
     {
 447  0
         this.providerProperties = providerProperties;
 448  0
     }
 449  
 
 450  
     public Connection getConnection() throws Exception
 451  
     {
 452  144
         UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
 453  144
         if (tx != null)
 454  
         {
 455  0
             if (tx.hasResource(dataSource))
 456  
             {
 457  0
                 logger.debug("Retrieving connection from current transaction");
 458  0
                 return (Connection)tx.getResource(dataSource);
 459  
             }
 460  
         }
 461  144
         logger.debug("Retrieving new connection from data source");
 462  144
         Connection con = dataSource.getConnection();
 463  
 
 464  144
         if (tx != null)
 465  
         {
 466  0
             logger.debug("Binding connection to current transaction");
 467  
             try
 468  
             {
 469  0
                 tx.bindResource(dataSource, con);
 470  
             }
 471  0
             catch (TransactionException e)
 472  
             {
 473  0
                 JdbcUtils.close(con);
 474  0
                 throw new RuntimeException("Could not bind connection to current transaction", e);
 475  0
             }
 476  
         }
 477  144
         return con;
 478  
     }
 479  
 
 480  
     /**
 481  
      * @return Returns the resultSetHandler.
 482  
      */
 483  
     public String getResultSetHandler()
 484  
     {
 485  6
         return this.resultSetHandler;
 486  
     }
 487  
 
 488  
     /**
 489  
      * @param resultSetHandler The resultSetHandler class name to set.
 490  
      */
 491  
     public void setResultSetHandler(String resultSetHandler)
 492  
     {
 493  2
         this.resultSetHandler = resultSetHandler;
 494  2
     }
 495  
 
 496  
     /**
 497  
      * @return a new instance of the ResultSetHandler class as defined in the
 498  
      *         JdbcConnector
 499  
      */
 500  
     protected ResultSetHandler createResultSetHandler()
 501  
     {
 502  
         try
 503  
         {
 504  6
             return (ResultSetHandler) ClassUtils.instanciateClass(getResultSetHandler(),
 505  
                                                                   ClassUtils.NO_ARGS);
 506  
         }
 507  0
         catch (Exception e)
 508  
         {
 509  0
             throw new IllegalArgumentException("Error creating instance of the resultSetHandler class :"
 510  
                                                + getResultSetHandler() + System.getProperty("line.separator")
 511  
                                                + ExceptionUtils.getFullStackTrace(e));
 512  
         }
 513  
     }
 514  
 
 515  
     public Set getQueryValueExtractors()
 516  
     {
 517  0
         return queryValueExtractors;
 518  
     }
 519  
 
 520  
     public void setQueryValueExtractors(Set queryValueExtractors)
 521  
     {
 522  0
         this.queryValueExtractors = queryValueExtractors;
 523  0
     }
 524  
 
 525  
     /**
 526  
      * @return Returns the queryRunner.
 527  
      */
 528  
     public String getQueryRunner()
 529  
     {
 530  8
         return this.queryRunner;
 531  
     }
 532  
 
 533  
     /**
 534  
      * @param queryRunner The QueryRunner class name to set.
 535  
      */
 536  
     public void setQueryRunner(String queryRunner)
 537  
     {
 538  2
         this.queryRunner = queryRunner;
 539  2
     }
 540  
 
 541  
     /**
 542  
      * @return a new instance of the QueryRunner class as defined in the
 543  
      *         JdbcConnector
 544  
      */
 545  
     protected QueryRunner createQueryRunner()
 546  
     {
 547  
         try
 548  
         {
 549  8
             return (QueryRunner) ClassUtils.instanciateClass(getQueryRunner(),
 550  
                                                              ClassUtils.NO_ARGS);
 551  
         }
 552  0
         catch (Exception e)
 553  
         {
 554  0
             throw new IllegalArgumentException("Error creating instance of the queryRunner class :"
 555  
                                                + getQueryRunner() + System.getProperty("line.separator")
 556  
                                                + ExceptionUtils.getFullStackTrace(e));
 557  
         }
 558  
     }
 559  
 
 560  
     /**
 561  
      * Parse the given statement filling the parameter list and return the ready to
 562  
      * use statement.
 563  
      * 
 564  
      * @param stmt
 565  
      * @param params
 566  
      * @return
 567  
      */
 568  
     public String parseStatement(String stmt, List params)
 569  
     {
 570  28
         if (stmt == null)
 571  
         {
 572  8
             return stmt;
 573  
         }
 574  20
         Matcher m = STATEMENT_ARGS.matcher(stmt);
 575  20
         StringBuffer sb = new StringBuffer(200);
 576  68
         while (m.find())
 577  
         {
 578  48
             String key = m.group();
 579  48
             m.appendReplacement(sb, "?");
 580  48
             params.add(key);
 581  48
         }
 582  20
         m.appendTail(sb);
 583  20
         return sb.toString();
 584  
     }
 585  
 
 586  
     public Object[][] getParamsTypes(List params)
 587  
     {
 588  12
         Object[][] result = new Object[params.size()][3];
 589  12
         int k = 0;
 590  56
         for (Iterator iter = params.iterator(); iter.hasNext(); k++)
 591  
         {
 592  44
             String param = (String) iter.next();
 593  44
             param = param.substring(2, param.length() - 1);
 594  44
             StringTokenizer tokenizer = new StringTokenizer(param, ";");
 595  44
             int i = 0;
 596  118
             while (tokenizer.hasMoreTokens())
 597  
             {
 598  104
                 result[k][i] = tokenizer.nextToken();
 599  104
                 i++;
 600  104
                 if (i > 2)
 601  
                 {
 602  30
                     break;
 603  
                 }
 604  
             }
 605  
         }
 606  12
         return result;
 607  
     }
 608  
 
 609  
     public Object[] getParams(UMOImmutableEndpoint endpoint, List paramNames, Object message, String query)
 610  
         throws Exception
 611  
     {
 612  
         
 613  18
         Object[] params = new Object[paramNames.size()];
 614  66
         for (int i = 0; i < paramNames.size(); i++)
 615  
         {
 616  48
             String param = (String)paramNames.get(i);
 617  
             String name;
 618  
             int idx;
 619  48
             if ((idx = param.indexOf(";")) != -1)
 620  
             {
 621  30
                 name = param.substring(2, idx);
 622  
             }
 623  
             else
 624  
             {
 625  18
                 name = param.substring(2, param.length() - 1);
 626  
             }
 627  48
             Object value = null;
 628  
             // If we find a value and it happens to be null, thats acceptable
 629  48
             boolean foundValue = false;
 630  48
             if (message != null)
 631  
             {
 632  48
                 PropertyExtractor pe = (PropertyExtractor) propertyExtractorCache.get(query + param);
 633  48
                 if (pe == null) 
 634  
                 {
 635  48
                     for (Iterator iterator = propertyExtractors.iterator(); iterator.hasNext();)
 636  
                     {
 637  301
                         pe = (PropertyExtractor) iterator.next();
 638  301
                         value = pe.getProperty(name, message);
 639  301
                         if (value != null)
 640  
                         {                       
 641  16
                             foundValue = true;
 642  16
                             propertyExtractorCache.putIfAbsent(query + param, pe);
 643  16
                             break;
 644  
                         }    
 645  
                     }
 646  
                 }
 647  
                 else 
 648  
                 {
 649  0
                     value = pe.getProperty(name, message);
 650  0
                     foundValue = true;
 651  
                 }
 652  48
                 if (StringUtils.EMPTY.equals(value) && pe instanceof BeanPropertyExtractor)
 653  
                 {
 654  0
                     value = null;
 655  
                 }    
 656  
             }                
 657  48
             if (!foundValue)
 658  
             {
 659  32
                 value = endpoint.getProperty(name);
 660  
             }
 661  
 
 662  
             // Allow null values which may be acceptable to the user
 663  
             // Why shouldn't nulls be allowed? Otherwise every null parameter has to
 664  
             // be defined
 665  
             // if (value == null && !foundValue)
 666  
             // {
 667  
             // throw new IllegalArgumentException("Can not retrieve argument " +
 668  
             // name);
 669  
             // }
 670  48
             params[i] = value;
 671  
         }
 672  18
         return params;
 673  
     }
 674  
 }