Coverage Report - org.apache.fulcrum.parser.DefaultParserService
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultParserService
66%
112/168
59%
50/84
5,143
DefaultParserService$1
100%
1/1
N/A
5,143
 
 1  
 package org.apache.fulcrum.parser;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.IOException;
 23  
 import java.util.ArrayList;
 24  
 import java.util.List;
 25  
 
 26  
 import javax.servlet.ServletException;
 27  
 import javax.servlet.http.HttpServletRequest;
 28  
 import javax.servlet.http.Part;
 29  
 
 30  
 import org.apache.avalon.framework.configuration.Configurable;
 31  
 import org.apache.avalon.framework.configuration.Configuration;
 32  
 import org.apache.avalon.framework.configuration.ConfigurationException;
 33  
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 34  
 import org.apache.avalon.framework.logger.LogEnabled;
 35  
 import org.apache.avalon.framework.service.ServiceException;
 36  
 import org.apache.avalon.framework.service.ServiceManager;
 37  
 import org.apache.avalon.framework.service.Serviceable;
 38  
 import org.apache.commons.lang3.StringUtils;
 39  
 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
 40  
 import org.apache.fulcrum.parser.ValueParser.URLCaseFolding;
 41  
 import org.apache.fulcrum.parser.pool.BaseValueParserFactory;
 42  
 import org.apache.fulcrum.parser.pool.BaseValueParserPool;
 43  
 import org.apache.fulcrum.parser.pool.CookieParserFactory;
 44  
 import org.apache.fulcrum.parser.pool.CookieParserPool;
 45  
 import org.apache.fulcrum.parser.pool.DefaultParameterParserFactory;
 46  
 import org.apache.fulcrum.parser.pool.DefaultParameterParserPool;
 47  
 import org.apache.fulcrum.pool.PoolException;
 48  
 import org.apache.fulcrum.pool.PoolService;
 49  
 
 50  
 
 51  
 /**
 52  
  * The DefaultParserService provides the default implementation
 53  
  * of a {@link ParserService}.
 54  
  *
 55  
  * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
 56  
  * @version $Id: BaseValueParser.java 542062 2007-05-28 00:29:43Z seade $
 57  
  */
 58  
 public class DefaultParserService
 59  
     extends AbstractLogEnabled
 60  
     implements ParserService,
 61  
                Configurable, Serviceable
 62  
 {
 63  
 
 64  
     /** The folding from the configuration */
 65  138
     private URLCaseFolding folding = URLCaseFolding.NONE;
 66  
 
 67  
     /** The automaticUpload setting from the configuration */
 68  138
     private boolean automaticUpload = AUTOMATIC_DEFAULT;
 69  
 
 70  
     /**
 71  
      * The parameter encoding to use when parsing parameter strings
 72  
      */
 73  138
     private String parameterEncoding = PARAMETER_ENCODING_DEFAULT;
 74  
     
 75  
     /**
 76  
      * reintroduced fulcrum, may be used in the case, that 
 77  
      * commons pool2 is not configured exactly as needed properly as fast fall back.
 78  
      */
 79  138
     private boolean useFulcrumPool = FULCRUM_POOL_DEFAULT;
 80  
     
 81  
     
 82  
     /**
 83  
      * The Fulcrum pool service component to use (optional), by default it is deactivated and commons pool is used.
 84  
      */
 85  138
     private PoolService fulcrumPoolService = null;
 86  
 
 87  
     /** 
 88  
      * Use commons pool to manage value parsers 
 89  
      */
 90  
     private BaseValueParserPool valueParserPool;
 91  
 
 92  
     /** 
 93  
      * Use commons pool to manage parameter parsers 
 94  
      */
 95  
     private DefaultParameterParserPool parameterParserPool;
 96  
 
 97  
     /** 
 98  
      * Use commons pool to manage cookie parsers 
 99  
      */
 100  
     private CookieParserPool cookieParserPool;
 101  
 
 102  
 
 103  
     public DefaultParserService() 
 104  138
     {
 105  138
     }
 106  
     
 107  
     public DefaultParserService(GenericObjectPoolConfig<?> config) 
 108  0
     {
 109  
             // init the pool
 110  0
             valueParserPool 
 111  
                     = new BaseValueParserPool(new BaseValueParserFactory(), config);
 112  
 
 113  0
             parameterParserPool 
 114  
                     = new DefaultParameterParserPool(new DefaultParameterParserFactory(), config);
 115  0
     }
 116  
 
 117  
     
 118  
     /**
 119  
      * Get the character encoding that will be used by this ValueParser.
 120  
      */
 121  
     @Override
 122  
     public String getParameterEncoding()
 123  
     {
 124  2
         return parameterEncoding;
 125  
     }
 126  
     
 127  
     /**
 128  
      * Set the character encoding that will be used by this ValueParser.
 129  
      */
 130  
     public void setParameterEncoding(String encoding)
 131  
     {
 132  0
         parameterEncoding = encoding;
 133  0
     }
 134  
 
 135  
     /**
 136  
      * Trims the string data and applies the conversion specified in
 137  
      * the property given by URL_CASE_FOLDING.  It returns a new
 138  
      * string so that it does not destroy the value data.
 139  
      *
 140  
      * @param value A String to be processed.
 141  
      * @return A new String converted to the case as specified by URL_CASE_FOLDING and trimmed.
 142  
      */
 143  
     @Override
 144  
     public String convert(String value)
 145  
     {
 146  0
         return convertAndTrim(value);
 147  
     }
 148  
 
 149  
     /**
 150  
      * Convert a String value according to the url-case-folding property.
 151  
      *
 152  
      * @param value the String to convert
 153  
      *
 154  
      * @return a new String.
 155  
      *
 156  
      */
 157  
     @Override
 158  
     public String convertAndTrim(String value)
 159  
     {
 160  1450
         return convertAndTrim(value, getUrlFolding());
 161  
     }
 162  
 
 163  
     /**
 164  
      * A static version of the convert method, which
 165  
      * trims the string data and applies the conversion specified in
 166  
      * the property given by URL_CASE_FOLDING.  It returns a new
 167  
      * string so that it does not destroy the value data.
 168  
      *
 169  
      * @param value A String to be processed.
 170  
      * @return A new String converted to lowercase and trimmed.
 171  
      */
 172  
     @Override
 173  
     public String convertAndTrim(String value, URLCaseFolding fold)
 174  
     {
 175  1462
         if (value == null)
 176  
         {
 177  2
             return "";
 178  
         }
 179  
 
 180  1460
         String tmp = value.trim();
 181  
 
 182  1460
         switch (fold)
 183  
         {
 184  
             case NONE:
 185  
             {
 186  1452
                 break;
 187  
             }
 188  
 
 189  
             case LOWER:
 190  
             {
 191  4
                 tmp = tmp.toLowerCase();
 192  4
                 break;
 193  
             }
 194  
 
 195  
             case UPPER:
 196  
             {
 197  4
                 tmp = tmp.toUpperCase();
 198  4
                 break;
 199  
             }
 200  
 
 201  
             default:
 202  
             {
 203  0
                 getLogger().error("Passed " + fold + " as fold rule, which is illegal!");
 204  
                 break;
 205  
             }
 206  
         }
 207  1460
         return tmp;
 208  
     }
 209  
 
 210  
     /**
 211  
      * Gets the folding value from the configuration
 212  
      *
 213  
      * @return The current Folding Value
 214  
      */
 215  
     @Override
 216  
     public URLCaseFolding getUrlFolding()
 217  
     {
 218  1454
         return folding;
 219  
     }
 220  
 
 221  
     /**
 222  
      * Gets the automaticUpload value from the configuration
 223  
      *
 224  
      * @return The current automaticUpload Value
 225  
      */
 226  
     @Override
 227  
     public boolean getAutomaticUpload()
 228  
     {
 229  12
         return automaticUpload;
 230  
     }
 231  
 
 232  
     /**
 233  
      * Parse the given request for uploaded files
 234  
      *
 235  
      * @return A list of {@link javax.servlet.http.Part}s
 236  
      *
 237  
      * @throws ServiceException if parsing fails
 238  
      */
 239  
     @Override
 240  
     public List<Part> parseUpload(HttpServletRequest request) throws ServiceException
 241  
     {
 242  
         try
 243  
         {
 244  6
             return new ArrayList<Part>(request.getParts());
 245  
         }
 246  0
         catch (IOException | ServletException e)
 247  
         {
 248  0
             throw new ServiceException(ParserService.ROLE, "Could not parse upload request", e);
 249  
         }
 250  
     }
 251  
 
 252  
     /**
 253  
      * Get a {@link ValueParser} instance from the service. Use the
 254  
      * given Class to create the object.
 255  
      *
 256  
      * @return An object that implements ValueParser
 257  
      *
 258  
      * @throws InstantiationException if the instance could not be created
 259  
      */
 260  
     @SuppressWarnings("unchecked")
 261  
         @Override
 262  
     public <P extends ValueParser> P getParser(Class<P> ppClass) throws InstantiationException
 263  
     {
 264  142
         P vp = null;
 265  
 
 266  
         try
 267  
         {
 268  142
             if (useFulcrumPool) {
 269  
                 try
 270  
                 {
 271  16
                     P parserInstance = (P) fulcrumPoolService.getInstance(ppClass);
 272  16
                     vp = parserInstance;
 273  
                 }
 274  0
                 catch (PoolException pe)
 275  
                 {
 276  0
                     throw new InstantiationException("Parser class '" + ppClass + "' is illegal. " + pe.getMessage());
 277  16
                 }
 278  126
             } else if ( ppClass.equals(BaseValueParser.class) )
 279  
             {
 280  100
                     BaseValueParser parserInstance = null;
 281  
                                 try {
 282  100
                                     parserInstance = valueParserPool.borrowObject();
 283  100
                                         vp = (P) parserInstance;
 284  100
                                         if (vp == null) {
 285  0
                         throw new InstantiationException("Could not borrow object from pool: " + valueParserPool);
 286  
                     }
 287  0
                                 } catch (Exception e) {
 288  
                     try {
 289  0
                         valueParserPool.invalidateObject(parserInstance);
 290  0
                         parserInstance = null;
 291  0
                     } catch (Exception e1) {
 292  0
                         throw new InstantiationException("Could not invalidate object " + e1.getMessage() + " after exception: " + e.getMessage());
 293  0
                     }
 294  100
                                 }
 295  100
             } else if ( ppClass.equals(DefaultParameterParser.class) )
 296  
             {
 297  24
                 DefaultParameterParser parserInstance = null;
 298  
                 try {
 299  24
                     parserInstance = parameterParserPool.borrowObject();
 300  24
                         vp = (P) parserInstance;
 301  24
                         if (vp == null) {
 302  0
                         throw new InstantiationException("Could not borrow object from pool: " + parameterParserPool);
 303  
                     }
 304  0
                 } catch (Exception e) {
 305  
                     try {
 306  0
                         parameterParserPool.invalidateObject(parserInstance);
 307  0
                         parserInstance = null;
 308  0
                     } catch (Exception e1) {
 309  0
                         throw new InstantiationException("Could not invalidate object " + e1.getMessage() + " after exception: " + e.getMessage());
 310  0
                     }
 311  24
                 }
 312  24
             } else if ( ppClass.equals(DefaultCookieParser.class) )
 313  
             {
 314  2
                 DefaultCookieParser parserInstance = null;
 315  
                 try {
 316  2
                     parserInstance = cookieParserPool.borrowObject();
 317  2
                         vp = (P) parserInstance;
 318  2
                     if (vp == null) {
 319  0
                           throw new InstantiationException("Could not borrow object from pool: " + cookieParserPool);
 320  
                     }
 321  0
                 } catch (Exception e) {
 322  
                     try {
 323  0
                         cookieParserPool.invalidateObject(parserInstance);
 324  0
                         parserInstance = null;
 325  0
                     } catch (Exception e1) {
 326  0
                         throw new InstantiationException("Could not invalidate object " + e1.getMessage() + " after exception: " + e.getMessage());
 327  0
                     }
 328  2
                 }
 329  
             }
 330  
             
 331  142
             if (vp != null && vp instanceof ParserServiceSupport ) {
 332  142
                 ((ParserServiceSupport)vp).setParserService(this);
 333  
             } else {
 334  0
                 throw new InstantiationException("Could not set parser");
 335  
             }
 336  142
             if (vp instanceof LogEnabled) 
 337  
             {
 338  142
                 ((LogEnabled)vp).enableLogging(getLogger().getChildLogger(ppClass.getSimpleName()));
 339  
             }
 340  
         }
 341  0
         catch (ClassCastException x)
 342  
         {
 343  0
             throw new InstantiationException("Parser class '" + ppClass + "' is illegal. " + x.getMessage());
 344  142
         }
 345  
 
 346  142
         return vp;
 347  
     }
 348  
 
 349  
     /**
 350  
      * Clears the parse and puts it back into
 351  
      * the pool service. This allows for pooling 
 352  
      * and recycling
 353  
      * 
 354  
      * As we are not yet using org.apache.fulcrum.pool.Recyclable, we call insteda {@link ValueParser#dispose()}.
 355  
      *
 356  
      * @param parser The value parser to use
 357  
      */
 358  
     @Override
 359  
     public void putParser(ValueParser parser)
 360  
     {
 361  134
         parser.clear();
 362  134
         parser.dispose(); 
 363  
     
 364  134
         if (useFulcrumPool) {
 365  
             
 366  16
             fulcrumPoolService.putInstance(parser);
 367  
             
 368  118
         } else if( parser.getClass().equals(BaseValueParser.class) )
 369  
         {
 370  100
             valueParserPool.returnObject( (BaseValueParser) parser );
 371  
         
 372  18
         } else if ( parser.getClass().equals(DefaultParameterParser.class) ||
 373  
                 parser instanceof DefaultParameterParser)
 374  
         {
 375  16
             parameterParserPool.returnObject( (DefaultParameterParser) parser );
 376  
                 
 377  2
         } else if ( parser.getClass().equals(DefaultCookieParser.class) ||
 378  
                 parser instanceof DefaultCookieParser)
 379  
         {
 380  2
             cookieParserPool.returnObject( (DefaultCookieParser) parser );
 381  
                 
 382  
         } else {
 383  
             // log
 384  0
             getLogger().warn(parser.getClass() + " could not be put back into any pool exhausting some pool");
 385  
             // log even borrowed count of each pool?: cookieParserPool.getBorrowedCount())
 386  
             }
 387  134
     }
 388  
 
 389  
     /**
 390  
      * Avalon component lifecycle method
 391  
      * 
 392  
      * @param conf the configuration
 393  
      * @throws ConfigurationException Generic exception
 394  
      */
 395  
     @Override
 396  
     public void configure(Configuration conf) throws ConfigurationException
 397  
     {
 398  138
         String foldString = conf.getChild(URL_CASE_FOLDING_KEY).getValue(URLCaseFolding.NONE.name()).toLowerCase();
 399  
 
 400  138
         folding = URLCaseFolding.NONE;
 401  
 
 402  138
         getLogger().debug("Setting folding from " + foldString);
 403  
 
 404  138
         if (StringUtils.isNotEmpty(foldString))
 405  
         {
 406  
             try
 407  
             {
 408  138
                 folding = URLCaseFolding.valueOf(foldString.toUpperCase());
 409  
             }
 410  0
             catch (IllegalArgumentException e)
 411  
             {
 412  0
                 getLogger().error("Got " + foldString + " from " + URL_CASE_FOLDING_KEY + " property, which is illegal!");
 413  0
                 throw new ConfigurationException("Value " + foldString + " is illegal!", e);
 414  138
             }
 415  
         }
 416  
 
 417  138
         parameterEncoding = conf.getChild(PARAMETER_ENCODING_KEY)
 418  138
                             .getValue(PARAMETER_ENCODING_DEFAULT).toLowerCase();
 419  
 
 420  138
         automaticUpload = conf.getChild(AUTOMATIC_KEY).getValueAsBoolean(AUTOMATIC_DEFAULT);
 421  
         
 422  138
         useFulcrumPool = conf.getChild(FULCRUM_POOL_KEY).getValueAsBoolean(FULCRUM_POOL_DEFAULT);
 423  
         
 424  138
         if (useFulcrumPool) {
 425  12
             if (fulcrumPoolService == null) 
 426  
             {
 427  
                     // only for fulcrum  pool, need to call internal service, if role pool service is set
 428  0
                     throw new ConfigurationException("Fulcrum Pool is activated", new ServiceException(ParserService.ROLE,
 429  
                             "Fulcrum enabled Pool Service requires " +
 430  
                             PoolService.ROLE + " to be available"));
 431  
             }
 432  12
             getLogger().info("Using Fulcrum Pool Service: "+ fulcrumPoolService);
 433  
         } else {
 434  
             // reset not used fulcrum pool
 435  126
             fulcrumPoolService = null;
 436  
             
 437  
             // Define the default configuration
 438  126
             GenericObjectPoolConfig config = new GenericObjectPoolConfig();
 439  126
             config.setMaxIdle(DEFAULT_MAX_IDLE);
 440  126
             config.setMaxTotal(DEFAULT_POOL_CAPACITY);
 441  
 
 442  
             // init the pool
 443  126
             valueParserPool 
 444  
                 = new BaseValueParserPool(new BaseValueParserFactory(), config);
 445  
 
 446  
             // init the pool
 447  126
             parameterParserPool 
 448  
                 = new DefaultParameterParserPool(new DefaultParameterParserFactory(), config);
 449  
             
 450  
             // init the pool
 451  126
             cookieParserPool 
 452  
                 = new CookieParserPool(new CookieParserFactory(), config);
 453  
             
 454  126
             getLogger().info("Init Commons2 Pool Services.." );
 455  126
             getLogger().info(valueParserPool.getClass().getName());
 456  126
             getLogger().info(parameterParserPool.getClass().getName());
 457  126
             getLogger().info(cookieParserPool.getClass().getName());
 458  
         }
 459  
         
 460  138
         Configuration[] poolChildren = conf.getChild(POOL_KEY).getChildren();
 461  138
         if (poolChildren.length > 0) {
 462  126
             GenericObjectPoolConfig genObjPoolConfig = new GenericObjectPoolConfig();
 463  126
             genObjPoolConfig.setMaxIdle(DEFAULT_MAX_IDLE);
 464  126
             genObjPoolConfig.setMaxTotal(DEFAULT_POOL_CAPACITY);
 465  504
             for (Configuration poolConf : poolChildren) {
 466  
                 // use common pool2 configuration names
 467  378
                 switch (poolConf.getName()) {
 468  
                 case "maxTotal":
 469  126
                     int defaultCapacity = poolConf.getValueAsInteger();
 470  126
                     genObjPoolConfig.setMaxTotal(defaultCapacity);
 471  126
                     break;
 472  
                 case "maxWaitMillis":
 473  126
                     int maxWaitMillis = poolConf.getValueAsInteger();
 474  126
                     genObjPoolConfig.setMaxWaitMillis(maxWaitMillis);
 475  126
                     break;
 476  
                 case "blockWhenExhausted":
 477  126
                     boolean blockWhenExhausted = poolConf.getValueAsBoolean();
 478  126
                     genObjPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
 479  126
                     break;
 480  
                 case "maxIdle":
 481  0
                     int maxIdle = poolConf.getValueAsInteger();
 482  0
                     genObjPoolConfig.setMaxIdle(maxIdle);
 483  0
                     break;
 484  
                 case "minIdle":
 485  0
                     int minIdle = poolConf.getValueAsInteger();
 486  0
                     genObjPoolConfig.setMinIdle(minIdle);
 487  0
                     break;
 488  
                 case "testOnReturn":
 489  0
                     boolean testOnReturn = poolConf.getValueAsBoolean();
 490  0
                     genObjPoolConfig.setTestOnReturn(testOnReturn);
 491  0
                     break;
 492  
                 case "testOnBorrow":
 493  0
                     boolean testOnBorrow = poolConf.getValueAsBoolean();
 494  0
                     genObjPoolConfig.setTestOnBorrow(testOnBorrow);
 495  0
                     break;
 496  
                 case "testOnCreate":
 497  0
                     boolean testOnCreate = poolConf.getValueAsBoolean();
 498  0
                     genObjPoolConfig.setTestOnCreate(testOnCreate);
 499  0
                     break;
 500  
                 default:
 501  
                     
 502  
                     break;
 503  
                 }  
 504  
             }    
 505  
             // reinit the pools
 506  126
             valueParserPool.setConfig(genObjPoolConfig);
 507  126
             parameterParserPool.setConfig(genObjPoolConfig);
 508  126
             cookieParserPool.setConfig(genObjPoolConfig);
 509  
             
 510  126
             getLogger().debug(valueParserPool.toString());
 511  126
             getLogger().debug(parameterParserPool.toString());
 512  126
             getLogger().debug(cookieParserPool.toString());
 513  
         }
 514  
                 
 515  138
     }
 516  
 
 517  
     // ---------------- Avalon Lifecycle Methods ---------------------
 518  
     /**
 519  
      * Avalon component lifecycle method
 520  
      * 
 521  
      * @param manager The service manager instance
 522  
      * @throws ServiceException generic exception
 523  
      * 
 524  
      */
 525  
     @Override
 526  
     public void service(ServiceManager manager) throws ServiceException
 527  
     {
 528  
         // only for fulcrum  pool, need to call internal service, if role pool service is set
 529  138
         if (manager.hasService(PoolService.ROLE))
 530  
         {
 531  12
             fulcrumPoolService = (PoolService)manager.lookup(PoolService.ROLE);
 532  
         } 
 533  
         // no check here, until configuration is read
 534  138
     }
 535  
 }