Input: Returns a valid HTTP contentType s for a given filename with charset . It first relies on the custom defaultContentTypeMap and if not found it will fall back to defaultFileTypeMap from javax . activation . FileTypeMap . Examples : - ( somefile . css UTF - 8 ) resolves to text / css ; charset = UTF - 8 . - ( somefile . js . png UTF - 8 ) resolves to image / png - ( / blah / index . html UTF - 8 ) resolves to text / html ; charset = 8 [CODESPLIT] public static String get ( final String fileName , final String encoding ) { final String contentType = get ( fileName ) ; if ( requiresCharset . contains ( contentType ) ) { return contentType + "; charset=" + encoding ; } return contentType ; }


Input: { [CODESPLIT] public InputStream locate ( final String uri ) throws IOException { Validate . notNull ( uri , "URI cannot be NULL!" ) ; // replace prefix & clean path by removing '..' characters if exists and // normalizing the location to use. String location = StringUtils . cleanPath ( uri . replaceFirst ( PREFIX , "" ) ) . trim ( ) ; if ( getWildcardStreamLocator ( ) . hasWildcard ( location ) ) { try { return locateWildcardStream ( uri , location ) ; } catch ( final IOException e ) { if ( location . contains ( "?" ) ) { location = DefaultWildcardStreamLocator . stripQueryPath ( location ) ; LOG . debug ( "Trying fallback location: {}" , location ) ; } } } final InputStream is = Thread . currentThread ( ) . getContextClassLoader ( ) . getResourceAsStream ( location ) ; if ( is == null ) { throw new IOException ( "Couldn't get InputStream from this resource: " + uri ) ; } return is ; }


Input: Builds a { [CODESPLIT] @ Override public WildcardStreamLocator newWildcardStreamLocator ( ) { return new JarWildcardStreamLocator ( ) { @ Override public boolean hasWildcard ( final String uri ) { return isEnableWildcards ( ) && super . hasWildcard ( uri ) ; } } ; }


Input: { [CODESPLIT] public Map < String , NamingStrategy > provideNamingStrategies ( ) { final Map < String , NamingStrategy > map = new HashMap < String , NamingStrategy > ( ) ; map . put ( TimestampNamingStrategy . ALIAS , new TimestampNamingStrategy ( ) ) ; map . put ( NoOpNamingStrategy . ALIAS , new NoOpNamingStrategy ( ) ) ; map . put ( DefaultHashEncoderNamingStrategy . ALIAS , new DefaultHashEncoderNamingStrategy ( ) ) ; map . put ( FolderHashEncoderNamingStrategy . ALIAS , new FolderHashEncoderNamingStrategy ( ) ) ; return map ; }


Input: Use an empty stream to avoid container writing unwanted message when a resource is missing . [CODESPLIT] private void onError ( final int sc , final String msg ) { LOG . debug ( "Error detected with code: {} and message: {}" , sc , msg ) ; final OutputStream emptyStream = new ByteArrayOutputStream ( ) ; printWriter = new PrintWriter ( emptyStream ) ; servletOutputStream = new DelegatingServletOutputStream ( emptyStream ) ; }


Input: By default redirect does not allow writing to output stream its content . In order to support this use - case we need to open a new connection and read the content manually . [CODESPLIT] @ Override public void sendRedirect ( final String location ) throws IOException { try { LOG . debug ( "redirecting to: {}" , location ) ; final InputStream is = externalResourceLocator . locate ( location ) ; IOUtils . copy ( is , servletOutputStream ) ; is . close ( ) ; servletOutputStream . close ( ) ; } catch ( final IOException e ) { LOG . warn ( "{}: Invalid response for location: {}" , e . getClass ( ) . getName ( ) , location ) ; throw e ; } }


Input: { [CODESPLIT] public synchronized WroModel transform ( final WroModel input ) { final WroModel model = input ; for ( final Group group : model . getGroups ( ) ) { final List < Resource > resources = group . getResources ( ) ; for ( final Resource resource : resources ) { processResource ( group , resource ) ; } } LOG . debug ( "Transformed model: {}" , model ) ; return model ; }


Input: Process each resource and replace it with a collection of resources if it contains wildcard . [CODESPLIT] private void processResource ( final Group group , final Resource resource ) { final UriLocator uriLocator = locatorFactory . getInstance ( resource . getUri ( ) ) ; if ( uriLocator instanceof WildcardUriLocatorSupport ) { final WildcardStreamLocator wildcardStreamLocator = ( ( WildcardUriLocatorSupport ) uriLocator ) . getWildcardStreamLocator ( ) ; // TODO should we probably handle the situation when wildcard is present, but the implementation is not // expandedHandledAware? if ( wildcardStreamLocator . hasWildcard ( resource . getUri ( ) ) && wildcardStreamLocator instanceof WildcardExpanderHandlerAware ) { final WildcardExpanderHandlerAware expandedHandler = ( WildcardExpanderHandlerAware ) wildcardStreamLocator ; LOG . debug ( "Expanding resource: {}" , resource . getUri ( ) ) ; final String baseNameFolder = computeBaseNameFolder ( resource , uriLocator , expandedHandler ) ; LOG . debug ( "baseNameFolder: {}" , baseNameFolder ) ; expandedHandler . setWildcardExpanderHandler ( createExpanderHandler ( group , resource , baseNameFolder ) ) ; try { // trigger the wildcard replacement uriLocator . locate ( resource . getUri ( ) ) ; } catch ( final IOException e ) { // log only LOG . debug ( "[FAIL] problem while trying to expand wildcard for the following resource uri: {}" , resource . getUri ( ) ) ; } finally { // remove the handler, it is not needed anymore expandedHandler . setWildcardExpanderHandler ( null ) ; } } } }


Input: Computes the file name of the folder where the resource is located . The implementation uses a trick by invoking the { [CODESPLIT] private String computeBaseNameFolder ( final Resource resource , final UriLocator uriLocator , final WildcardExpanderHandlerAware expandedHandler ) { // Find the baseName // add a recursive wildcard to trigger the wildcard detection. The simple wildcard ('*') is not enough because it // won't work for folders containing only directories with no files. LOG . debug ( "computeBaseNameFolder for resource {}" , resource ) ; final String resourcePath = FilenameUtils . getFullPath ( resource . getUri ( ) ) + DefaultWildcardStreamLocator . RECURSIVE_WILDCARD ; LOG . debug ( "resourcePath: {}" , resourcePath ) ; // use thread local because we need to assign a File inside an anonymous class and it fits perfectly final ThreadLocal < String > baseNameFolderHolder = new ThreadLocal < String > ( ) ; expandedHandler . setWildcardExpanderHandler ( createBaseNameComputerFunction ( baseNameFolderHolder ) ) ; try { uriLocator . locate ( resourcePath ) ; } catch ( final Exception e ) { LOG . debug ( "[FAIL] Exception caught during wildcard expanding for resource: {}\n with exception message {}" , resourcePath , e . getMessage ( ) ) ; } if ( baseNameFolderHolder . get ( ) == null ) { LOG . debug ( "[FAIL] Cannot compute baseName folder for resource: {}" , resource ) ; } return baseNameFolderHolder . get ( ) ; }


Input:
create the handler which expand the resources containing wildcard . [CODESPLIT] public Function < Collection < File > , Void > createExpanderHandler ( final Group group , final Resource resource , final String baseNameFolder ) { LOG . debug ( "createExpanderHandler using baseNameFolder: {}\n for resource {}" , baseNameFolder , resource ) ; return new Function < Collection < File > , Void > ( ) { public Void apply ( final Collection < File > files ) { if ( baseNameFolder == null ) { // replacing group with empty list since the original uri has no associated resources. // No BaseNameFolder found LOG . warn ( "The resource {} is probably invalid, removing it from the group." , resource ) ; group . replace ( resource , new ArrayList < Resource > ( ) ) ; } else { final List < Resource > expandedResources = new ArrayList < Resource > ( ) ; LOG . debug ( "baseNameFolder: {}" , baseNameFolder ) ; for ( final File file : files ) { final String resourcePath = getFullPathNoEndSeparator ( resource ) ; LOG . debug ( "\tresourcePath: {}" , resourcePath ) ; LOG . debug ( "\tfile path: {}" , file . getPath ( ) ) ; final String computedResourceUri = resourcePath + StringUtils . removeStart ( file . getPath ( ) , baseNameFolder ) . replace ( ' ' , ' ' ) ; final Resource expandedResource = Resource . create ( computedResourceUri , resource . getType ( ) ) ; LOG . debug ( "\texpanded resource: {}" , expandedResource ) ; expandedResources . add ( expandedResource ) ; } LOG . debug ( "\treplace resource {}" , resource ) ; group . replace ( resource , expandedResources ) ; } return null ; } /**
       * This method fixes the problem when a resource in a group uses deep wildcard and starts at the root.
       *

       * Find more details here.
       */ private String getFullPathNoEndSeparator ( final Resource resource1 ) { final String result = FilenameUtils . getFullPathNoEndSeparator ( resource1 . getUri ( ) ) ; if ( result != null && 1 == result . length ( ) && 0 == FilenameUtils . indexOfLastSeparator ( result ) ) { return "" ; } return result ; } } ; }


Input: Replace provided url with the new url if needed . [CODESPLIT] @ Override protected final String replaceImageUrl ( final String cssUri , final String imageUrl ) { if ( ! imageUrls . contains ( imageUrl ) ) { imageUrls . add ( imageUrl ) ; return super . replaceImageUrl ( cssUri , imageUrl ) ; } LOG . debug ( "duplicate Image url detected: '{}', skipping dataUri replacement" , imageUrl ) ; return imageUrl ; }


Input: Locates an InputStream for the given uri . [CODESPLIT] public final InputStream locate ( final String uri ) throws IOException { final UriLocator uriLocator = getInstance ( uri ) ; if ( uriLocator == null ) { throw new WroRuntimeException ( "No locator is capable of handling uri: " + uri ) ; } LOG . debug ( "[OK] locating {} using locator: {}" , uri , uriLocator . getClass ( ) . getSimpleName ( ) ) ; return new AutoCloseInputStream ( uriLocator . locate ( uri ) ) ; }


Input: Initialize script builder for evaluation . [CODESPLIT] private RhinoScriptBuilder initScriptBuilder ( ) { try { RhinoScriptBuilder builder = null ; if ( scope == null ) { builder = RhinoScriptBuilder . newChain ( ) . evaluateChain ( getCoffeeScriptAsStream ( ) , DEFAULT_COFFE_SCRIPT ) ; scope = builder . getScope ( ) ; } else { builder = RhinoScriptBuilder . newChain ( scope ) ; } return builder ; } catch ( final IOException ex ) { throw new IllegalStateException ( "Failed reading init script" , ex ) ; } }


Input: Validates a js using jsHint and throws { @link LinterException } if the js is invalid . If no exception is thrown the js is valid . [CODESPLIT] public String compile ( final String data ) { final RhinoScriptBuilder builder = initScriptBuilder ( ) ; final String compileScript = String . format ( "CoffeeScript.compile(%s, %s);" , WroUtil . toJSMultiLineString ( data ) , buildOptions ( ) ) ; return ( String ) builder . evaluate ( compileScript , "CoffeeScript.compile" ) ; }


Input: Creates configuration by looking up in servletContext attributes . If none is found a new one will be created using the configuration factory . [CODESPLIT] private WroConfiguration createConfiguration ( ) { // Extract config from servletContext (if already configured) // TODO use a named helper final WroConfiguration configAttribute = ServletContextAttributeHelper . create ( filterConfig ) . getWroConfiguration ( ) ; if ( configAttribute != null ) { setConfiguration ( configAttribute ) ; } return getWroConfigurationFactory ( ) . create ( ) ; }


Input: Creates { [CODESPLIT] private WroManagerFactory createWroManagerFactory ( ) { if ( wroManagerFactory == null ) { final WroManagerFactory managerFactoryAttribute = ServletContextAttributeHelper . create ( filterConfig ) . getManagerFactory ( ) ; LOG . debug ( "managerFactory attribute: {}" , managerFactoryAttribute ) ; wroManagerFactory = managerFactoryAttribute != null ? managerFactoryAttribute : newWroManagerFactory ( ) ; } LOG . debug ( "created managerFactory: {}" , wroManagerFactory ) ; return wroManagerFactory ; }


Input: Expose MBean to tell JMX infrastructure about our MBean ( only if jmxEnabled is true ) . [CODESPLIT] private void registerMBean ( ) { if ( wroConfiguration . isJmxEnabled ( ) ) { try { mbeanServer = getMBeanServer ( ) ; final ObjectName name = getMBeanObjectName ( ) ; if ( ! mbeanServer . isRegistered ( name ) ) { mbeanServer . registerMBean ( wroConfiguration , name ) ; } } catch ( final JMException e ) { LOG . error ( "Exception occured while registering MBean" , e ) ; } } }


Input: Register property change listeners . [CODESPLIT] private void registerChangeListeners ( ) { wroConfiguration . registerCacheUpdatePeriodChangeListener ( new PropertyChangeListener ( ) { public void propertyChange ( final PropertyChangeEvent event ) { // reset cache headers when any property is changed in order to avoid browser caching headersConfigurer = newResponseHeadersConfigurer ( ) ; wroManagerFactory . onCachePeriodChanged ( valueAsLong ( event . getNewValue ( ) ) ) ; } } ) ; wroConfiguration . registerModelUpdatePeriodChangeListener ( new PropertyChangeListener ( ) { public void propertyChange ( final PropertyChangeEvent event ) { headersConfigurer = newResponseHeadersConfigurer ( ) ; wroManagerFactory . onModelPeriodChanged ( valueAsLong ( event . getNewValue ( ) ) ) ; } } ) ; LOG . debug ( "Cache & Model change listeners were registered" ) ; }


Input: Perform actual processing . [CODESPLIT] private void processRequest ( final HttpServletRequest request , final HttpServletResponse response ) throws ServletException , IOException { setResponseHeaders ( response ) ; // process the uri using manager wroManagerFactory . create ( ) . process ( ) ; }


Input: Invoked when a { @link Exception } is thrown . Allows custom exception handling . The default implementation proceeds with filter chaining when exception is thrown . [CODESPLIT] protected void onException ( final Exception e , final HttpServletResponse response , final FilterChain chain ) { LOG . error ( "Exception occured" , e ) ; try { LOG . warn ( "Cannot process. Proceeding with chain execution." ) ; chain . doFilter ( Context . get ( ) . getRequest ( ) , response ) ; } catch ( final Exception ex ) { // should never happen (use debug level to suppress unuseful logs) LOG . debug ( "Error while chaining the request" , ex ) ; } }


Input: Once set this configuration will be used instead of the one built by the factory . [CODESPLIT] public final void setConfiguration ( final WroConfiguration config ) { notNull ( config ) ; wroConfigurationFactory = new ObjectFactory < WroConfiguration > ( ) { public WroConfiguration create ( ) { return config ; } } ; }


Input: { [CODESPLIT] public void destroy ( ) { //Avoid memory leak by unregistering mBean on destroy unregisterMBean ( ) ; if ( wroManagerFactory != null ) { wroManagerFactory . destroy ( ) ; } if ( wroConfiguration != null ) { wroConfiguration . destroy ( ) ; } Context . destroy ( ) ; }


Input: Identify duplicate group names . [CODESPLIT] private void identifyDuplicateGroupNames ( final Collection < Group > groups ) { LOG . debug ( "identifyDuplicateGroupNames" ) ; final List < String > groupNames = new ArrayList < String > ( ) ; for ( final Group group : groups ) { if ( groupNames . contains ( group . getName ( ) ) ) { throw new WroRuntimeException ( "Duplicate group name detected: " + group . getName ( ) ) ; } groupNames . add ( group . getName ( ) ) ; } }


Input: Merge this model with another model . This is useful for supporting model imports . [CODESPLIT] public void merge ( final WroModel importedModel ) { Validate . notNull ( importedModel , "imported model cannot be null!" ) ; LOG . debug ( "merging importedModel: {}" , importedModel ) ; for ( final String groupName : new WroModelInspector ( importedModel ) . getGroupNames ( ) ) { if ( new WroModelInspector ( this ) . getGroupNames ( ) . contains ( groupName ) ) { throw new WroRuntimeException ( "Duplicate group name detected: " + groupName ) ; } final Group importedGroup = new WroModelInspector ( importedModel ) . getGroupByName ( groupName ) ; addGroup ( importedGroup ) ; } }


Input: { [CODESPLIT] @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { final String content = IOUtils . toString ( reader ) ; final PackerJs packerJs = enginePool . getObject ( ) ; try { writer . write ( packerJs . pack ( content ) ) ; } catch ( final WroRuntimeException e ) { onException ( e ) ; final String resourceUri = resource == null ? StringUtils . EMPTY : "[" + resource . getUri ( ) + "]" ; LOG . warn ( "Exception while applying " + getClass ( ) . getSimpleName ( ) + " processor on the " + resourceUri + " resource, no processing applied..." , e ) ; } finally { reader . close ( ) ; writer . close ( ) ; enginePool . returnObject ( packerJs ) ; } }


Input: This implementation shows the problem with current design of locator implementation . Needs to be changed . [CODESPLIT] public InputStream locate ( final String uri ) throws IOException { final UriLocator locator = getInstance ( uri ) ; if ( locator == null ) { return getDecoratedObject ( ) . locate ( uri ) ; } return locator . locate ( uri ) ; }


Input: { [CODESPLIT] public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { final InputStream is = new ProxyInputStream ( new ReaderInputStream ( reader , getEncoding ( ) ) ) { } ; final OutputStream os = new ProxyOutputStream ( new WriterOutputStream ( writer , getEncoding ( ) ) ) ; try { new JSMin ( is , os ) . jsmin ( ) ; is . close ( ) ; os . close ( ) ; } catch ( final Exception e ) { throw WroRuntimeException . wrap ( e ) ; } finally { IOUtils . closeQuietly ( is ) ; IOUtils . closeQuietly ( os ) ; } }


Input: Apply resourcePostProcessors . [CODESPLIT] private String applyPostProcessors ( final CacheKey cacheKey , final String content ) throws IOException { final Collection < ResourcePostProcessor > processors = processorsFactory . getPostProcessors ( ) ; LOG . debug ( "appying post processors: {}" , processors ) ; if ( processors . isEmpty ( ) ) { return content ; } final Resource resource = Resource . create ( cacheKey . getGroupName ( ) , cacheKey . getType ( ) ) ; Reader reader = new StringReader ( content . toString ( ) ) ; Writer writer = null ; for ( final ResourcePostProcessor processor : processors ) { final ResourcePreProcessor decoratedProcessor = decorateProcessor ( processor , cacheKey . isMinimize ( ) ) ; writer = new StringWriter ( ) ; decoratedProcessor . process ( resource , reader , writer ) ; reader = new StringReader ( writer . toString ( ) ) ; } return writer . toString ( ) ; }


Input: This method is synchronized to ensure that processor is injected before it is being used by other thread . [CODESPLIT] private synchronized ProcessorDecorator decorateProcessor ( final ResourcePostProcessor processor , final boolean minimize ) { final ProcessorDecorator decorated = new DefaultProcessorDecorator ( processor , minimize ) { @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { try { callbackRegistry . onBeforePostProcess ( ) ; super . process ( resource , reader , writer ) ; } finally { callbackRegistry . onAfterPostProcess ( ) ; } } } ; injector . inject ( decorated ) ; return decorated ; }


Input:
{ [CODESPLIT] public final void doFilter ( final ServletRequest req , final ServletResponse res , final FilterChain chain ) throws IOException , ServletException { final HttpServletRequest request = ( HttpServletRequest ) req ; final HttpServletResponse response = ( HttpServletResponse ) res ; //preserve current correlationId to ensure proper clean up during nested requests.
 final String originalCorrelationId = Context . isContextSet ( ) ? Context . getCorrelationId ( ) : null ; Context . set ( Context . webContext ( request , response , this . filterConfig ) , getWroConfiguration ( ) ) ; final String correlationId = Context . getCorrelationId ( ) ; try { chain . doFilter ( request , response ) ; } finally { Context . setCorrelationId ( correlationId ) ; Context . unset ( ) ; if ( originalCorrelationId != null ) { Context . setCorrelationId ( originalCorrelationId ) ; } } }


Input: { [CODESPLIT] public void doFilter ( final ServletRequest req , final ServletResponse res , final FilterChain chain ) throws IOException , ServletException { final HttpServletRequest request = ( HttpServletRequest ) req ; final HttpServletResponse response = ( HttpServletResponse ) res ; try { // add request, response & servletContext to thread local Context . set ( Context . webContext ( request , response , filterConfig ) ) ; final ByteArrayOutputStream os = new ByteArrayOutputStream ( ) ; final HttpServletResponse wrappedResponse = new RedirectedStreamServletResponseWrapper ( os , response ) ; chain . doFilter ( request , wrappedResponse ) ; final Reader reader = new StringReader ( new String ( os . toByteArray ( ) , Context . get ( ) . getConfig ( ) . getEncoding ( ) ) ) ; final StringWriter writer = new StringWriter ( ) ; final String requestUri = request . getRequestURI ( ) . replaceFirst ( request . getContextPath ( ) , "" ) ; doProcess ( requestUri , reader , writer ) ; // it is important to update the contentLength to new value, otherwise the transfer can be closed without all // bytes being read. Some browsers (chrome) complains with the following message: ERR_CONNECTION_CLOSED final int contentLength = writer . getBuffer ( ) . length ( ) ; response . setContentLength ( contentLength ) ; // Content length can be 0 when the 30x (not modified) status code is returned. if ( contentLength > 0 ) { IOUtils . write ( writer . toString ( ) , response . getOutputStream ( ) ) ; } } catch ( final RuntimeException e ) { onRuntimeException ( e , response , chain ) ; } finally { Context . unset ( ) ; } }


Input: Applies configured processor on the intercepted stream . [CODESPLIT] private void doProcess ( final String requestUri , final Reader reader , final Writer writer ) throws IOException { Reader input = reader ; Writer output = null ; LOG . debug ( "processing resource: {}" , requestUri ) ; try { final StopWatch stopWatch = new StopWatch ( ) ; final Injector injector = InjectorBuilder . create ( new BaseWroManagerFactory ( ) ) . build ( ) ; final List < ResourcePreProcessor > processors = getProcessorsList ( ) ; if ( processors == null || processors . isEmpty ( ) ) { IOUtils . copy ( reader , writer ) ; } else { for ( final ResourcePreProcessor processor : processors ) { stopWatch . start ( "Using " + processor . getClass ( ) . getSimpleName ( ) ) ; // inject all required properties injector . inject ( processor ) ; output = new StringWriter ( ) ; LOG . debug ( "Using {} processor" , processor ) ; processor . process ( createResource ( requestUri ) , input , output ) ; input = new StringReader ( output . toString ( ) ) ; stopWatch . stop ( ) ; } LOG . debug ( stopWatch . prettyPrint ( ) ) ; if ( output != null ) { writer . write ( output . toString ( ) ) ; } } } finally { reader . close ( ) ; writer . close ( ) ; } }


Input: Invoked when a { @link RuntimeException } is thrown . Allows custom exception handling . The default implementation redirects to 404 for a specific { @link WroRuntimeException } exception when in DEPLOYMENT mode . [CODESPLIT] protected void onRuntimeException ( final RuntimeException e , final HttpServletResponse response , final FilterChain chain ) { LOG . debug ( "RuntimeException occured" , e ) ; try { LOG . debug ( "Cannot process. Proceeding with chain execution." ) ; chain . doFilter ( Context . get ( ) . getRequest ( ) , response ) ; } catch ( final Exception ex ) { // should never happen LOG . error ( "Error while chaining the request." ) ; } }


Input: Split multiple options into an array of options . [CODESPLIT] public String [ ] splitOptions ( final String optionAsString ) { return optionAsString == null ? ArrayUtils . EMPTY_STRING_ARRAY : optionAsString . split ( "(?ims),(?![^\\[\\]]*\\])" ) ; }


Input: Initialize script builder for evaluation . [CODESPLIT] private RhinoScriptBuilder initScriptBuilder ( ) { try { RhinoScriptBuilder builder = null ; if ( scope == null ) { builder = RhinoScriptBuilder . newClientSideAwareChain ( ) . addJSON ( ) . evaluateChain ( getScriptAsStream ( ) , "cjson.js" ) ; scope = builder . getScope ( ) ; } else { builder = RhinoScriptBuilder . newChain ( scope ) ; } return builder ; } catch ( final Exception e ) { LOG . error ( "Processing error:" + e . getMessage ( ) , e ) ; throw new WroRuntimeException ( "Processing error" , e ) ; } }


Input: Initialize script builder for evaluation . [CODESPLIT] private RhinoScriptBuilder initScriptBuilder ( ) { try { RhinoScriptBuilder builder = null ; if ( scope == null ) { final InputStream initStream = LessCss . class . getResourceAsStream ( SCRIPT_INIT ) ; builder = RhinoScriptBuilder . newClientSideAwareChain ( ) . evaluateChain ( initStream , SCRIPT_INIT ) . evaluateChain ( getScriptAsStream ( ) , DEFAULT_LESS_JS ) ; scope = builder . getScope ( ) ; } else { builder = RhinoScriptBuilder . newChain ( scope ) ; } return builder ; } catch ( final IOException ex ) { throw new IllegalStateException ( "Failed reading javascript less.js" , ex ) ; } catch ( final Exception e ) { LOG . error ( "Processing error:" + e . getMessage ( ) , e ) ; throw new WroRuntimeException ( "Processing error" , e ) ; } }


Input: Load the properties from the stream . The implementation will handle comments properly by removing them before properties are loaded . [CODESPLIT] public Properties load ( final InputStream inputStream ) throws IOException { Validate . notNull ( inputStream ) ; final String rawContent = IOUtils . toString ( inputStream , CharEncoding . UTF_8 ) ; parseProperties ( rawContent . replaceAll ( REGEX_COMMENTS , "" ) ) ; return this . properties ; }


Input: parse the properties from the provided string containing a raw properties [CODESPLIT] private void parseProperties ( final String propertiesAsString ) { //should work also \r?\n final String [ ] propertyEntries = propertiesAsString . split ( "\\r?\\n" ) ; for ( final String entry : propertyEntries ) { readPropertyEntry ( entry ) ; } }


Input: Creates a { [CODESPLIT] private StandaloneContext createStandaloneContext ( ) { final StandaloneContext runContext = new StandaloneContext ( ) ; runContext . setContextFoldersAsCSV ( getContextFoldersAsCSV ( ) ) ; runContext . setMinimize ( isMinimize ( ) ) ; runContext . setWroFile ( getWroFile ( ) ) ; runContext . setIgnoreMissingResourcesAsString ( isIgnoreMissingResources ( ) ) ; return runContext ; }


Input: This method will ensure that you have a right and initialized instance of { @link StandaloneContextAware } . [CODESPLIT] protected final WroManagerFactory getManagerFactory ( ) { if ( managerFactory == null ) { try { managerFactory = wroManagerFactory != null ? createCustomManagerFactory ( ) : newWroManagerFactory ( ) ; onAfterCreate ( managerFactory ) ; } catch ( final MojoExecutionException e ) { throw WroRuntimeException . wrap ( e ) ; } } return managerFactory ; }


Input: Creates a custom instance of Manager factory . The wroManagerFactory parameter value is used to identify the manager class . [CODESPLIT] private WroManagerFactory createCustomManagerFactory ( ) throws MojoExecutionException { WroManagerFactory factory = null ; try { final Class < ? > wroManagerFactoryClass = Thread . currentThread ( ) . getContextClassLoader ( ) . loadClass ( wroManagerFactory . trim ( ) ) ; factory = ( WroManagerFactory ) wroManagerFactoryClass . newInstance ( ) ; } catch ( final Exception e ) { throw new MojoExecutionException ( "Invalid wroManagerFactoryClass, called: " + wroManagerFactory , e ) ; } return factory ; }


Input: Allows explicitly to override the default implementation of the factory assuming { [CODESPLIT] protected WroManagerFactory newWroManagerFactory ( ) throws MojoExecutionException { WroManagerFactory factory = null ; if ( wroManagerFactory == null ) { factory = new ConfigurableWroManagerFactory ( ) ; } getLog ( ) . info ( "wroManagerFactory class: " + factory . getClass ( ) . getName ( ) ) ; return factory ; }


Input: Initialize the created { [CODESPLIT] private void onAfterCreate ( final WroManagerFactory factory ) throws MojoExecutionException { if ( factory instanceof ExtraConfigFileAware ) { if ( extraConfigFile == null ) { throw new MojoExecutionException ( "The " + factory . getClass ( ) + " requires a valid extraConfigFile!" ) ; } getLog ( ) . debug ( "Using extraConfigFile: " + extraConfigFile . getAbsolutePath ( ) ) ; ( ( ExtraConfigFileAware ) factory ) . setExtraConfigFile ( extraConfigFile ) ; } // initialize before process. if ( factory instanceof StandaloneContextAware ) { ( ( StandaloneContextAware ) factory ) . initialize ( createStandaloneContext ( ) ) ; } }


Input: Store digest for all resources contained inside the list of provided groups . [CODESPLIT] private void persistResourceFingerprints ( final List < String > groupNames ) { final WroModelInspector modelInspector = new WroModelInspector ( getModel ( ) ) ; for ( final String groupName : groupNames ) { final Group group = modelInspector . getGroupByName ( groupName ) ; if ( group != null ) { for ( final Resource resource : group . getResources ( ) ) { getResourceChangeHandler ( ) . remember ( resource ) ; } } } }


Input: Check if the provided group is a target group . [CODESPLIT] private boolean isTargetGroup ( final Group group ) { notNull ( group ) ; final String targetGroups = getTargetGroups ( ) ; // null, means all groups are target groups return targetGroups == null || targetGroups . contains ( group . getName ( ) ) ; }


Input: Update the classpath . [CODESPLIT] protected final void extendPluginClasspath ( ) throws MojoExecutionException { // this code is inspired from http://teleal.org/weblog/Extending%20the%20Maven%20plugin%20classpath.html final List < String > classpathElements = new ArrayList < String > ( ) ; try { classpathElements . addAll ( mavenProject . getRuntimeClasspathElements ( ) ) ; } catch ( final DependencyResolutionRequiredException e ) { throw new MojoExecutionException ( "Could not get compile classpath elements" , e ) ; } final ClassLoader classLoader = createClassLoader ( classpathElements ) ; Thread . currentThread ( ) . setContextClassLoader ( classLoader ) ; }


Input: { [CODESPLIT] @ Override protected boolean isEnabled ( final Resource resource ) { // apply processor only when minimize is required or the processor is not minimize aware final boolean applyProcessor = ( resource != null && resource . isMinimize ( ) && minimize ) || ( resource == null && minimize ) || ! isMinimize ( ) ; return super . isEnabled ( resource ) && applyProcessor ; }


Input:
Override this method in order to provide different xml definition file name . [CODESPLIT] protected InputStream getModelResourceAsStream ( ) throws IOException { final ServletContext servletContext = context . getServletContext ( ) ; // Don't allow NPE, throw a more detailed exception
 if ( servletContext == null ) { throw new WroRuntimeException ( "No servletContext is available. Probably you are running this code outside of the request cycle!" ) ; } final String resourceLocation = "/WEB-INF/" + getDefaultModelFilename ( ) ; final InputStream stream = servletContext . getResourceAsStream ( resourceLocation ) ; if ( stream == null ) { throw new IOException ( "Invalid resource requested: " + resourceLocation ) ; } return stream ; }


Input: Creates a resource and set the correct { @link ResourceType } based on uri extension . If resourceType cannot be identified an exception is thrown . [CODESPLIT] public static Resource create ( final String uri ) { final String resourceExtension = FilenameUtils . getExtension ( uri ) ; final ResourceType type = ResourceType . get ( resourceExtension ) ; return new Resource ( uri , type ) ; }


Input:
Perform a cleaning of the uri by trimming it and removing last / character if exists . [CODESPLIT] private static String cleanUri ( final String uri ) { String result = uri . trim ( ) ; //handle empty uri
 if ( ! StringUtils . isEmpty ( uri ) ) { final int endIndex = result . length ( ) - 1 ; if ( result . lastIndexOf ( ' ' ) == endIndex ) { result = result . substring ( 0 , endIndex ) ; } } return result ; }


Input: { [CODESPLIT] public InputStream locate ( final String uri ) throws IOException { notNull ( uri , "uri cannot be NULL!" ) ; if ( getWildcardStreamLocator ( ) . hasWildcard ( uri ) ) { final String fullPath = FilenameUtils . getFullPath ( uri ) ; final URL url = new URL ( fullPath ) ; return getWildcardStreamLocator ( ) . locateStream ( uri , new File ( URLDecoder . decode ( url . getFile ( ) , "UTF-8" ) ) ) ; } final URL url = new URL ( uri ) ; final URLConnection connection = url . openConnection ( ) ; // avoid jar file locking on Windows. connection . setUseCaches ( false ) ; //add explicit user agent header. This is required by some cdn resources which otherwise would return 403 status code. connection . setRequestProperty ( "User-Agent" , "java" ) ; // setting these timeouts ensures the client does not deadlock indefinitely // when the server has problems. connection . setConnectTimeout ( timeout ) ; connection . setReadTimeout ( timeout ) ; return new BufferedInputStream ( connection . getInputStream ( ) ) ; }


Input: { [CODESPLIT] public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { try { final String content = IOUtils . toString ( reader ) ; String result = ConsoleStripperProcessor . PATTERN . matcher ( content ) . replaceAll ( "" ) ; writer . write ( result ) ; } finally { reader . close ( ) ; writer . close ( ) ; } }


Input: A factory method which uses { @link WroConfiguration } to get the configured wroManager className . [CODESPLIT] public static DefaultWroManagerFactory create ( final WroConfiguration configuration ) { return create ( new ObjectFactory < WroConfiguration > ( ) { public WroConfiguration create ( ) { return configuration ; } } ) ; }


Input: Initialized inner factory based on provided configuration . [CODESPLIT] private WroManagerFactory initFactory ( final Properties properties ) { WroManagerFactory factory = null ; final String wroManagerClassName = properties . getProperty ( ConfigConstants . managerFactoryClassName . name ( ) ) ; if ( StringUtils . isEmpty ( wroManagerClassName ) ) { // If no context param was specified we return the default factory factory = newManagerFactory ( ) ; } else { // Try to find the specified factory class Class < ? > factoryClass = null ; try { factoryClass = Thread . currentThread ( ) . getContextClassLoader ( ) . loadClass ( wroManagerClassName ) ; factory = ( WroManagerFactory ) factoryClass . newInstance ( ) ; } catch ( final Exception e ) { throw new WroRuntimeException ( "Exception while loading WroManagerFactory class:" + wroManagerClassName , e ) ; } } // add properties if required if ( factory instanceof ConfigurableWroManagerFactory ) { ( ( ConfigurableWroManagerFactory ) factory ) . addConfigProperties ( properties ) ; } return factory ; }


Input: Initialize script builder for evaluation . [CODESPLIT] private RhinoScriptBuilder initScriptBuilder ( ) { try { return RhinoScriptBuilder . newChain ( ) . evaluateChain ( getStreamForBase2 ( ) , "base2.min.js" ) . evaluateChain ( getStreamForPacker ( ) , "packer.min.js" ) ; } catch ( final IOException ex ) { throw new IllegalStateException ( "Failed reading init script" , ex ) ; } }


Input: Set a list of transformers to apply on decorated model factory . [CODESPLIT] public ModelTransformerFactory setTransformers ( final List < Transformer < WroModel > > modelTransformers ) { Validate . notNull ( modelTransformers ) ; this . modelTransformers = modelTransformers ; return this ; }


Input: { [CODESPLIT] @ Override public WroModel create ( ) { WroModel model = super . create ( ) ; LOG . debug ( "using {} transformers" , modelTransformers ) ; for ( final Transformer < WroModel > transformer : modelTransformers ) { injector . inject ( transformer ) ; LOG . debug ( "using transformer: {}" , transformer . getClass ( ) ) ; try { model = transformer . transform ( model ) ; } catch ( final Exception e ) { throw new WroRuntimeException ( "Exception during model transformation" , e ) ; } } return model ; }


Input: visible for testing the init of a HandlebarsJs template [CODESPLIT] @ Override public String compile ( final String content , final String name ) { final String precompiledFunction = super . compile ( content , "" ) ; return String . format ( "(function() {Ember.TEMPLATES[%s] = Ember.Handlebars.template(%s)})();" , name , precompiledFunction ) ; }


Input: { [CODESPLIT] @ Override protected InputStream getCompilerAsStream ( ) throws IOException { final Vector < InputStream > inputStreams = new Vector < InputStream > ( ) ; inputStreams . add ( getWebjarLocator ( ) . locate ( WebjarUriLocator . createUri ( "jquery.js" ) ) ) ; inputStreams . add ( getWebjarLocator ( ) . locate ( WebjarUriLocator . createUri ( "handlebars.js" ) ) ) ; inputStreams . add ( getWebjarLocator ( ) . locate ( WebjarUriLocator . createUri ( "ember.js" ) ) ) ; inputStreams . add ( EmberJs . class . getResourceAsStream ( DEFAULT_HEADLESS_RHINO_JS ) ) ; return new SequenceInputStream ( inputStreams . elements ( ) ) ; }


Input: Check if url must be replaced or not . The replacement is not needed if the url of the image is absolute ( can be resolved by urlResourceLocator ) or if the url is a data uri ( base64 encoded value ) . [CODESPLIT] protected boolean isReplaceNeeded ( final String url ) { return ! ( UrlUriLocator . isValid ( url ) || DataUriGenerator . isDataUri ( url . trim ( ) ) ) ; }


Input: Apply preProcessors on resources and merge them after all preProcessors are applied . [CODESPLIT] public String processAndMerge ( final List < Resource > resources , final boolean minimize ) throws IOException { return processAndMerge ( resources , ProcessingCriteria . create ( ProcessingType . ALL , minimize ) ) ; }


Input: Apply preProcessors on resources and merge them . [CODESPLIT] public String processAndMerge ( final List < Resource > resources , final ProcessingCriteria criteria ) throws IOException { notNull ( criteria ) ; LOG . debug ( "criteria: {}" , criteria ) ; callbackRegistry . onBeforeMerge ( ) ; try { notNull ( resources ) ; LOG . debug ( "process and merge resources: {}" , resources ) ; final StringBuffer result = new StringBuffer ( ) ; if ( shouldRunInParallel ( resources ) ) { result . append ( runInParallel ( resources , criteria ) ) ; } else { for ( final Resource resource : resources ) { LOG . debug ( "\tmerging resource: {}" , resource ) ; result . append ( applyPreProcessors ( resource , criteria ) ) ; } } return result . toString ( ) ; } finally { callbackRegistry . onAfterMerge ( ) ; } }


Input: runs the pre processors in parallel . [CODESPLIT] private String runInParallel ( final List < Resource > resources , final ProcessingCriteria criteria ) throws IOException { LOG . debug ( "Running preProcessing in Parallel" ) ; final StringBuffer result = new StringBuffer ( ) ; final List < Callable < String > > callables = new ArrayList < Callable < String > > ( ) ; for ( final Resource resource : resources ) { callables . add ( new Callable < String > ( ) { public String call ( ) throws Exception { LOG . debug ( "Callable started for resource: {} ..." , resource ) ; return applyPreProcessors ( resource , criteria ) ; } } ) ; } final ExecutorService exec = getExecutorService ( ) ; final List < Future < String > > futures = new ArrayList < Future < String > > ( ) ; for ( final Callable < String > callable : callables ) { // decorate with ContextPropagatingCallable in order to allow spawn threads to access the Context final Callable < String > decoratedCallable = new ContextPropagatingCallable < String > ( callable ) ; futures . add ( exec . submit ( decoratedCallable ) ) ; } for ( final Future < String > future : futures ) { try { result . append ( future . get ( ) ) ; } catch ( final Exception e ) { // propagate original cause final Throwable cause = e . getCause ( ) ; if ( cause instanceof WroRuntimeException ) { throw ( WroRuntimeException ) cause ; } else if ( cause instanceof IOException ) { throw ( IOException ) cause ; } else { throw new WroRuntimeException ( "Problem during parallel pre processing" , e ) ; } } } return result . toString ( ) ; }


Input: Apply a list of preprocessors on a resource . [CODESPLIT] private String applyPreProcessors ( final Resource resource , final ProcessingCriteria criteria ) throws IOException { final Collection < ResourcePreProcessor > processors = processorsFactory . getPreProcessors ( ) ; LOG . debug ( "applying preProcessors: {}" , processors ) ; String resourceContent = null ; try { resourceContent = getResourceContent ( resource ) ; } catch ( final IOException e ) { LOG . debug ( "Invalid resource found: {}" , resource ) ; if ( Context . get ( ) . getConfig ( ) . isIgnoreMissingResources ( ) ) { return StringUtils . EMPTY ; } else { LOG . error ( "Cannot ignore missing resource:  {}" , resource ) ; throw e ; } } if ( ! processors . isEmpty ( ) ) { Writer writer = null ; for ( final ResourcePreProcessor processor : processors ) { final ResourcePreProcessor decoratedProcessor = decoratePreProcessor ( processor , criteria ) ; writer = new StringWriter ( ) ; final Reader reader = new StringReader ( resourceContent ) ; // decorate and process decoratedProcessor . process ( resource , reader , writer ) ; // use the outcome for next input resourceContent = writer . toString ( ) ; } } // add explicitly new line at the end to avoid unexpected comment issue return String . format ( "%s%n" , resourceContent ) ; }


Input: Decorates preProcessor with mandatory decorators . This method is synchronized to ensure that processor is injected before it is being used by other thread . [CODESPLIT] private synchronized ResourcePreProcessor decoratePreProcessor ( final ResourcePreProcessor processor , final ProcessingCriteria criteria ) { final ResourcePreProcessor decorated = new DefaultProcessorDecorator ( processor , criteria ) { @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { try { callbackRegistry . onBeforePreProcess ( ) ; super . process ( resource , reader , writer ) ; } finally { callbackRegistry . onAfterPreProcess ( ) ; } } } ; injector . inject ( decorated ) ; return decorated ; }


Input: { [CODESPLIT] public void onBeforeModelCreated ( ) { forEachCallbackDo ( new Function < LifecycleCallback , Void > ( ) { public Void apply ( final LifecycleCallback input ) throws Exception { input . onBeforeModelCreated ( ) ; return null ; } } ) ; }


Input: Persist the fallbackStorage to the fallbackStorageFile . This method should be invoked only once during build since it is relatively expensive . Not invoking it would break the incremental build feature . [CODESPLIT] public void persist ( ) { OutputStream os = null ; try { os = new FileOutputStream ( fallbackStorageFile ) ; fallbackStorage . store ( os , "Generated" ) ; LOG . debug ( "fallback storage written to {}" , fallbackStorageFile ) ; } catch ( final IOException e ) { LOG . warn ( "Cannot persist fallback storage: {}." , fallbackStorageFile , e ) ; } finally { IOUtils . closeQuietly ( os ) ; } }


Input:
Scans the object and inject the supported values into the fields having @Inject annotation present . [CODESPLIT] public < T > T inject ( final T object ) { notNull ( object ) ; //    if (!Context.isContextSet()) {
 //      throw new WroRuntimeException("No Context Set");
 //    }
 if ( ! injectedObjects . containsKey ( computeKey ( object ) ) ) { injectedObjects . put ( computeKey ( object ) , true ) ; processInjectAnnotation ( object ) ; } return object ; }


Input:
Check for each field from the passed object if @Inject annotation is present & inject the required field if supported otherwise warns about invalid usage . [CODESPLIT] private void processInjectAnnotation ( final Object object ) { try { final Collection < Field > fields = getAllFields ( object ) ; for ( final Field field : fields ) { if ( field . isAnnotationPresent ( Inject . class ) ) { if ( ! acceptAnnotatedField ( object , field ) ) { final String message = String . format ( "@Inject cannot be applied on object: %s to field of type: %s using injector %s" , object , field . getType ( ) , this ) ; LOG . error ( message + ". Supported types are: {}" , map . keySet ( ) ) ; throw new WroRuntimeException ( message ) ; } } } // handle special cases like decorators. Perform recursive injection
 if ( object instanceof ObjectDecorator ) { processInjectAnnotation ( ( ( ObjectDecorator < ? > ) object ) . getDecoratedObject ( ) ) ; } } catch ( final Exception e ) { LOG . error ( "Error while scanning @Inject annotation" , e ) ; throw WroRuntimeException . wrap ( e , "Exception while trying to process @Inject annotation on object: " + object ) ; } }


Input:
Return all fields for given object also those from the super classes . [CODESPLIT] private Collection < Field > getAllFields ( final Object object ) { final Collection < Field > fields = new ArrayList < Field > ( ) ; fields . addAll ( Arrays . asList ( object . getClass ( ) . getDeclaredFields ( ) ) ) ; // inspect super classes
 Class < ? > superClass = object . getClass ( ) . getSuperclass ( ) ; while ( superClass != null ) { fields . addAll ( Arrays . asList ( superClass . getDeclaredFields ( ) ) ) ; superClass = superClass . getSuperclass ( ) ; } return fields ; }


Input:
Analyze the field containing { @link Inject } annotation and set its value to appropriate value . Override this method if you want to inject something else but uriLocatorFactory . [CODESPLIT] private boolean acceptAnnotatedField ( final Object object , final Field field ) throws IllegalAccessException { boolean accept = false ; // accept private modifiers
 field . setAccessible ( true ) ; for ( final Map . Entry < Class < ? > , Object > entry : map . entrySet ( ) ) { if ( entry . getKey ( ) . isAssignableFrom ( field . getType ( ) ) ) { Object value = entry . getValue ( ) ; // treat factories as a special case for lazy load of the objects.
 if ( value instanceof InjectorObjectFactory ) { value = ( ( InjectorObjectFactory < ? > ) value ) . create ( ) ; inject ( value ) ; } field . set ( object , value ) ; accept = true ; break ; } } return accept ; }


Input: Computes the url of the image to be replaced in a css resource . [CODESPLIT] public String rewrite ( final String cssUri , final String imageUrl ) { notNull ( cssUri ) ; notNull ( imageUrl ) ; if ( StringUtils . isEmpty ( imageUrl ) ) { return imageUrl ; } if ( ServletContextUriLocator . isValid ( cssUri ) ) { if ( ServletContextUriLocator . isValid ( imageUrl ) ) { return prependContextPath ( imageUrl ) ; } // Treat WEB-INF special case if ( ServletContextUriLocator . isProtectedResource ( cssUri ) ) { return context . proxyPrefix + computeNewImageLocation ( cssUri , imageUrl ) ; } // Compute the folder where the final css is located. This is important for computing image location after url // rewriting. // Prefix of the path to the overwritten image url. This will be of the following type: "../" or "../.." depending // on the depth of the aggregatedFolderPath. final String aggregatedPathPrefix = computeAggregationPathPrefix ( context . aggregatedFolderPath ) ; LOG . debug ( "computed aggregatedPathPrefix {}" , aggregatedPathPrefix ) ; String newImageLocation = computeNewImageLocation ( aggregatedPathPrefix + cssUri , imageUrl ) ; if ( newImageLocation . startsWith ( ServletContextUriLocator . PREFIX ) ) { newImageLocation = prependContextPath ( newImageLocation ) ; } LOG . debug ( "newImageLocation: {}" , newImageLocation ) ; return newImageLocation ; } if ( ClasspathUriLocator . isValid ( cssUri ) ) { final String proxyUrl = context . proxyPrefix + computeNewImageLocation ( cssUri , imageUrl ) ; final String contextRelativeUrl = prependContextPath ( imageUrl ) ; //final String contextRelativeUrl = context.contextPath + imageUrl; // leave imageUrl unchanged if it is a servlet context relative resource return ( ServletContextUriLocator . isValid ( imageUrl ) ? contextRelativeUrl : proxyUrl ) ; } if ( UrlUriLocator . isValid ( cssUri ) ) { final String computedCssUri = ServletContextUriLocator . isValid ( imageUrl ) ? computeCssUriForExternalServer ( cssUri ) : cssUri ; return computeNewImageLocation ( computedCssUri , imageUrl ) ; } throw new WroRuntimeException ( "Could not replace imageUrl: " + imageUrl + ", contained at location: " + cssUri ) ; }


Input: Css files hosted on external server should use its host as the root context when rewriting image url s starting with / character . [CODESPLIT] private String computeCssUriForExternalServer ( final String cssUri ) { String exernalServerCssUri = cssUri ; try { // compute the host of the external server (with protocol & port). final String serverHost = cssUri . replace ( new URL ( cssUri ) . getPath ( ) , StringUtils . EMPTY ) ; // the uri should end mandatory with / exernalServerCssUri = serverHost + ServletContextUriLocator . PREFIX ; LOG . debug ( "using {} host as cssUri" , exernalServerCssUri ) ; } catch ( final MalformedURLException e ) { // should never happen } return exernalServerCssUri ; }


Input: Concatenates cssUri and imageUrl after few changes are applied to both input parameters . [CODESPLIT] private String computeNewImageLocation ( final String cssUri , final String imageUrl ) { LOG . debug ( "cssUri: {}, imageUrl {}" , cssUri , imageUrl ) ; final String cleanImageUrl = cleanImageUrl ( imageUrl ) ; // TODO move to ServletContextUriLocator as a helper method? // for the following input: /a/b/c/1.css => /a/b/c/ int idxLastSeparator = cssUri . lastIndexOf ( ServletContextUriLocator . PREFIX ) ; if ( idxLastSeparator == - 1 ) { if ( ClasspathUriLocator . isValid ( cssUri ) ) { idxLastSeparator = cssUri . lastIndexOf ( ClasspathUriLocator . PREFIX ) ; // find the index of ':' character used by classpath prefix if ( idxLastSeparator >= 0 ) { idxLastSeparator += ClasspathUriLocator . PREFIX . length ( ) - 1 ; } } if ( idxLastSeparator < 0 ) { throw new IllegalStateException ( "Invalid cssUri: " + cssUri + ". Should contain at least one '/' character!" ) ; } } final String cssUriFolder = cssUri . substring ( 0 , idxLastSeparator + 1 ) ; // remove '/' from imageUrl if it starts with one. final String processedImageUrl = cleanImageUrl . startsWith ( ServletContextUriLocator . PREFIX ) ? cleanImageUrl . substring ( 1 ) : cleanImageUrl ; final String computedImageLocation = cleanPath ( cssUriFolder + processedImageUrl ) ; LOG . debug ( "computedImageLocation: {}" , computedImageLocation ) ; return computedImageLocation ; }


Input: Add a custom key - value pair attribute . Each pair is added to an internal map . The custom attributes can be used to make the key more fine grained ( Ex : based on browser version or a request parameter ) . Both elements of the attribute ( key & value ) should be not null . If any of these are null the attribute won t be added . [CODESPLIT] public CacheKey addAttribute ( final String key , final String value ) { if ( key != null && value != null ) { map . put ( key , value ) ; } return this ; }


Input: { [CODESPLIT] @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { try { final YuiCssCompressor compressor = new YuiCssCompressor ( reader ) ; compressor . compress ( writer , linebreakpos ) ; } catch ( final Exception e ) { LOG . error ( "Exception occured while processing resource: " + resource + " using processor: " + ALIAS ) ; onException ( e ) ; } finally { reader . close ( ) ; writer . close ( ) ; } }


Input: { [CODESPLIT] public void onCachePeriodChanged ( final long period ) { try { managerInitializer . get ( ) . onCachePeriodChanged ( period ) ; } catch ( final WroRuntimeException e ) { LOG . warn ( "[FAIL] Unable to reload cache, probably because invoked outside of context" ) ; } }


Input: { [CODESPLIT] public void onModelPeriodChanged ( final long period ) { try { managerInitializer . get ( ) . onModelPeriodChanged ( period ) ; } catch ( final WroRuntimeException e ) { LOG . warn ( "[FAIL] Unable to reload model, probably because invoked outside of context" ) ; } }


Input: Add a single model transformer . [CODESPLIT] public BaseWroManagerFactory addModelTransformer ( final Transformer < WroModel > modelTransformer ) { if ( modelTransformers == null ) { modelTransformers = new ArrayList < Transformer < WroModel > > ( ) ; } this . modelTransformers . add ( modelTransformer ) ; return this ; }


Input:
Write to stream the content of the processed resource bundle . [CODESPLIT] public void serveProcessedBundle ( ) throws IOException { final WroConfiguration configuration = context . getConfig ( ) ; final HttpServletRequest request = context . getRequest ( ) ; final HttpServletResponse response = context . getResponse ( ) ; OutputStream os = null ; try { final CacheKey cacheKey = getSafeCacheKey ( request ) ; initAggregatedFolderPath ( request , cacheKey . getType ( ) ) ; final CacheValue cacheValue = cacheStrategy . get ( cacheKey ) ; // TODO move ETag check in wroManagerFactory final String ifNoneMatch = request . getHeader ( HttpHeader . IF_NONE_MATCH . toString ( ) ) ; // enclose etag value in quotes to be compliant with the RFC final String etagValue = String . format ( "\"%s\"" , cacheValue . getHash ( ) ) ; if ( etagValue != null && etagValue . equals ( ifNoneMatch ) ) { LOG . debug ( "ETag hash detected: {}. Sending {} status code" , etagValue , HttpServletResponse . SC_NOT_MODIFIED ) ; response . setStatus ( HttpServletResponse . SC_NOT_MODIFIED ) ; // because we cannot return null, return a stream containing nothing. // TODO close output stream? return ; } /**
       * Set contentType before actual content is written, solves

       * issue341
       */ response . setContentType ( cacheKey . getType ( ) . getContentType ( ) + "; charset=" + configuration . getEncoding ( ) ) ; // set ETag header response . setHeader ( HttpHeader . ETAG . toString ( ) , etagValue ) ; os = response . getOutputStream ( ) ; if ( cacheValue . getRawContent ( ) != null ) { // use gziped response if supported & Set content length based on gzip flag if ( isGzipAllowed ( ) ) { response . setContentLength ( cacheValue . getGzippedContent ( ) . length ) ; // add gzip header and gzip response response . setHeader ( HttpHeader . CONTENT_ENCODING . toString ( ) , "gzip" ) ; response . setHeader ( "Vary" , "Accept-Encoding" ) ; IOUtils . write ( cacheValue . getGzippedContent ( ) , os ) ; } else { //using getRawContent().length() is not the same and can return 2Bytes smaller size. response . setContentLength ( cacheValue . getRawContent ( ) . getBytes ( configuration . getEncoding ( ) ) . length ) ; IOUtils . write ( cacheValue . getRawContent ( ) , os , configuration . getEncoding ( ) ) ; } } } finally { if ( os != null ) { IOUtils . closeQuietly ( os ) ; } } }


Input: Set the aggregatedFolderPath if required . [CODESPLIT] private void initAggregatedFolderPath ( final HttpServletRequest request , final ResourceType type ) { if ( ResourceType . CSS == type && context . getAggregatedFolderPath ( ) == null ) { final String requestUri = request . getRequestURI ( ) ; final String cssFolder = StringUtils . removeEnd ( requestUri , FilenameUtils . getName ( requestUri ) ) ; final String aggregatedFolder = StringUtils . removeStart ( cssFolder , request . getContextPath ( ) ) ; LOG . debug ( "set aggregatedFolderPath: {}" , aggregatedFolder ) ; Context . get ( ) . setAggregatedFolderPath ( aggregatedFolder ) ; } }


Input: Extract variables map from variables body . [CODESPLIT] private Map < String , String > extractVariables ( final String variablesBody ) { final Map < String , String > map = new HashMap < String , String > ( ) ; final Matcher m = PATTERN_VARIABLES_BODY . matcher ( variablesBody ) ; LOG . debug ( "parsing variables body" ) ; while ( m . find ( ) ) { final String key = m . group ( 1 ) ; final String value = m . group ( 2 ) ; if ( map . containsKey ( key ) ) { LOG . warn ( "A duplicate variable name found with name: {} and value: {}." , key , value ) ; } map . put ( key , value ) ; } return map ; }


Input: { [CODESPLIT] public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { try { final String css = IOUtils . toString ( reader ) ; final String result = parseCss ( css ) ; writer . write ( result ) ; } finally { reader . close ( ) ; writer . close ( ) ; } }


Input:
Parse css find all defined variables & replace them . [CODESPLIT] private String parseCss ( final String css ) { // map containing variables & their values
 final Map < String , String > map = new HashMap < String , String > ( ) ; final StringBuffer sb = new StringBuffer ( ) ; final Matcher m = PATTERN_VARIABLES_DEFINITION . matcher ( css ) ; while ( m . find ( ) ) { final String variablesBody = m . group ( 1 ) ; // LOG.debug("variables body: " + variablesBody);
 // extract variables
 map . putAll ( extractVariables ( variablesBody ) ) ; // remove variables definition
 m . appendReplacement ( sb , "" ) ; } m . appendTail ( sb ) ; // LOG.debug("replaced variables: " + result);
 return replaceVariables ( sb . toString ( ) , map ) ; }


Input: Replace variables from css with provided variables map . [CODESPLIT] private String replaceVariables ( final String css , final Map < String , String > variables ) { final StringBuffer sb = new StringBuffer ( ) ; final Matcher m = PATTERN_VARIABLE_HOLDER . matcher ( css ) ; while ( m . find ( ) ) { final String oldMatch = m . group ( ) ; final String variableName = m . group ( 1 ) ; final String variableValue = variables . get ( variableName ) ; if ( variableValue != null ) { final String newReplacement = oldMatch . replace ( oldMatch , variableValue ) ; m . appendReplacement ( sb , newReplacement . trim ( ) ) ; } else { LOG . warn ( "No variable with name " + variableName + " was found!" ) ; } } m . appendTail ( sb ) ; return sb . toString ( ) ; }


Input: { [CODESPLIT] @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { try { super . process ( resource , reader , writer ) ; } finally { IOUtils . closeQuietly ( reader ) ; IOUtils . closeQuietly ( writer ) ; } }


Input: { [CODESPLIT] @ Override protected boolean isEnabled ( final Resource resource ) { final boolean isApplicable = resource != null ? isEligible ( criteria . isMinimize ( ) , resource . getType ( ) ) : true ; return super . isEnabled ( resource ) && isApplicable ; }


Input: { [CODESPLIT] public String rename ( final String originalName , final InputStream inputStream ) { final String baseName = FilenameUtils . getBaseName ( originalName ) ; final String extension = FilenameUtils . getExtension ( originalName ) ; final long timestamp = getTimestamp ( ) ; final StringBuilder sb = new StringBuilder ( baseName ) . append ( "-" ) . append ( timestamp ) ; if ( ! StringUtils . isEmpty ( extension ) ) { sb . append ( "." ) . append ( extension ) ; } return sb . toString ( ) ; }


Input: { [CODESPLIT] @ Override protected Map < String , CacheStrategy < CacheKey , CacheValue > > getStrategies ( final CacheStrategyProvider provider ) { return provider . provideCacheStrategies ( ) ; }


Input: Transforms a post processor into pre processor . [CODESPLIT] private static ResourcePreProcessor toPreProcessor ( final ResourcePostProcessor postProcessor ) { return new AbstractProcessorDecoratorSupport < ResourcePostProcessor > ( postProcessor ) { public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { postProcessor . process ( reader , writer ) ; } @ Override protected boolean isMinimizeInternal ( ) { return isMinimizeForProcessor ( postProcessor ) ; } @ Override protected SupportedResourceType getSupportedResourceTypeInternal ( ) { return getSupportedResourceTypeForProcessor ( postProcessor ) ; } @ Override public String toString ( ) { return postProcessor . toString ( ) ; } } ; }


Input: Indicates if the processor is eligible for usage based on provided criteria . [CODESPLIT] public final boolean isEligible ( final boolean minimize , final ResourceType searchedType ) { Validate . notNull ( searchedType ) ; final SupportedResourceType supportedType = getSupportedResourceType ( ) ; final boolean isTypeSatisfied = supportedType == null || ( supportedType != null && searchedType == supportedType . value ( ) ) ; final boolean isMinimizedSatisfied = minimize == true || ! isMinimize ( ) ; return isTypeSatisfied && isMinimizedSatisfied ; }


Input: Called when { @link LinterException } is thrown . Allows subclasses to re - throw this exception as a { @link RuntimeException } or handle it differently . The default implementation simply logs the errors . [CODESPLIT] protected void onLinterException ( final LinterException e , final Resource resource ) { LOG . error ( "The following resource: " + resource + " has " + e . getErrors ( ) . size ( ) + " errors." , e ) ; }


Input: { [CODESPLIT] public final void contextInitialized ( final ServletContextEvent event ) { this . servletContext = event . getServletContext ( ) ; attributeHelper = new ServletContextAttributeHelper ( this . servletContext , getListenerName ( ) ) ; initListener ( event . getServletContext ( ) ) ; }


Input:
{ [CODESPLIT] public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { final StopWatch watch = new StopWatch ( ) ; watch . start ( "pack" ) ; //initialize rhino context
 Context . enter ( ) ; try { final String script = IOUtils . toString ( reader ) ; final String stripConsole = null ; //normal, warn, all
 LOG . debug ( "compressing script: {}" , StringUtils . abbreviate ( script , 40 ) ) ; final String out = Compressor . compressScript ( script , 0 , 0 , stripConsole ) ; writer . write ( out ) ; } finally { Context . exit ( ) ; reader . close ( ) ; writer . close ( ) ; watch . stop ( ) ; LOG . debug ( watch . prettyPrint ( ) ) ; } }


Input: { [CODESPLIT] @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { StopWatch stopWatch = null ; if ( isDebug ( ) ) { stopWatch = new StopWatch ( ) ; before ( stopWatch ) ; } try { super . process ( resource , reader , writer ) ; } finally { if ( isDebug ( ) ) { after ( stopWatch ) ; } } }


Input: { [CODESPLIT] private UriLocatorFactory newLocatorFactory ( ) { final SimpleUriLocatorFactory factory = new SimpleUriLocatorFactory ( ) ; final List < UriLocator > locators = getConfiguredStrategies ( ) ; for ( final UriLocator locator : locators ) { factory . addLocator ( locator ) ; } // use default when none provided if ( locators . isEmpty ( ) ) { LOG . debug ( "No locators configured. Using Default locator factory." ) ; return new DefaultUriLocatorFactory ( ) ; } return factory ; }


Input: { [CODESPLIT] public boolean accept ( final String url ) { if ( url == null ) return false ; final String extension = FilenameUtils . getExtension ( url ) ; // scss file have either no extension or scss // maybe check for the "_"? if ( "" . equals ( extension ) || "scss" . equals ( extension ) ) { boolean result = getScssFile ( url ) != null ; if ( ! result ) { LOG . debug ( "Possible scss file not found {}" , url ) ; } return result ; } else { return false ; } }


Input: { [CODESPLIT] public InputStream locate ( final String uri ) throws IOException { Validate . notNull ( uri , "URI cannot be NULL!" ) ; LOG . debug ( "loading  scss file: {}" , uri ) ; return new FileInputStream ( getScssFile ( uri ) ) ; }


Input: Destroy the initialized object . This will trigger the re - initialization when { [CODESPLIT] public void destroy ( ) { if ( isInitialized ( ) ) { if ( get ( ) instanceof Destroyable ) { try { ( ( Destroyable ) get ( ) ) . destroy ( ) ; } catch ( final Exception e ) { LOG . error ( "destroy operation failed" , e ) ; } } } object = null ; }


Input: { [CODESPLIT] @ Override protected String replaceDeclaration ( final String originalDeclaration , final String modifiedDeclaration ) { return originalDeclaration . equals ( modifiedDeclaration ) ? modifiedDeclaration : computeNewDeclaration ( originalDeclaration , modifiedDeclaration ) ; }


Input: { [CODESPLIT] public void doFilter ( final ServletRequest req , final ServletResponse res , final FilterChain chain ) throws IOException , ServletException { final HttpServletRequest request = ( HttpServletRequest ) req ; final HttpServletResponse response = ( HttpServletResponse ) res ; if ( isGzipAllowed ( request ) ) { doGzipResponse ( request , response , chain ) ; } else { LOG . debug ( "Gzip not allowed. Proceeding with chain." ) ; chain . doFilter ( request , response ) ; } }


Input: Performs actual gzip of the filtered content . [CODESPLIT] private void doGzipResponse ( final HttpServletRequest req , final HttpServletResponse response , final FilterChain chain ) throws IOException , ServletException { LOG . debug ( "Applying gzip on resource: " + req . getRequestURI ( ) ) ; response . setHeader ( HttpHeader . CONTENT_ENCODING . toString ( ) , "gzip" ) ; final ByteArrayOutputStream baos = new ByteArrayOutputStream ( ) ; final CountingOutputStream countingStream = new CountingOutputStream ( new GZIPOutputStream ( new BufferedOutputStream ( baos ) ) ) ; // final GZIPOutputStream gzout = new GZIPOutputStream(new BufferedOutputStream(baos)); // Perform gzip operation in-memory before sending response final HttpServletResponseWrapper wrappedResponse = new RedirectedStreamServletResponseWrapper ( countingStream , response ) ; chain . doFilter ( req , wrappedResponse ) ; // close underlying stream countingStream . close ( ) ; response . setContentLength ( countingStream . getCount ( ) ) ; // avoid NO CONTENT error thrown by jetty when gzipping empty response if ( countingStream . getCount ( ) > 0 ) { IOUtils . write ( baos . toByteArray ( ) , response . getOutputStream ( ) ) ; } }


Input: Decorates a processor which will be applied on provided patterns . [CODESPLIT] public static PathPatternProcessorDecorator include ( final Object processor , final String ... patterns ) { return new PathPatternProcessorDecorator ( processor , true , patterns ) ; }


Input: Decorates a processor which will not be applied on provided patterns . [CODESPLIT] public static PathPatternProcessorDecorator exclude ( final Object processor , final String ... patterns ) { return new PathPatternProcessorDecorator ( processor , false , patterns ) ; }


Input: { [CODESPLIT] @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { if ( resource != null ) { final String uri = resource . getUri ( ) ; LOG . debug ( "matching uri: {}" , uri ) ; if ( includes ) { // Match (p1 OR p2 OR .. pn) for ( String pattern : patterns ) { if ( matcher . match ( pattern , uri ) ) { LOG . debug ( "Processing resource: {}. Match found: {}" , uri , toString ( ) ) ; getDecoratedObject ( ) . process ( resource , reader , writer ) ; return ; } } } else { boolean process = true ; // Match !(p1 AND p2 AND .. pn) for ( String pattern : patterns ) { if ( matcher . match ( pattern , uri ) ) { process = false ; break ; } } if ( process ) { LOG . debug ( "Processing resource: {}. Match found: {}" , uri , toString ( ) ) ; getDecoratedObject ( ) . process ( resource , reader , writer ) ; return ; } } LOG . debug ( "Skipping {} from {}. No match found: {}" , new Object [ ] { uri , getDecoratedObject ( ) , toString ( ) } ) ; WroUtil . safeCopy ( reader , writer ) ; } else { throw new WroRuntimeException ( "Wrong usage of " + toString ( ) + ". Please use it as a pre-processor." ) ; } }


Input: Factory method which requires all mandatory fields . [CODESPLIT] public static ResourceChangeHandler create ( final WroManagerFactory managerFactory , final Log log ) { notNull ( managerFactory , "WroManagerFactory was not set" ) ; notNull ( log , "Log was not set" ) ; return new ResourceChangeHandler ( ) . setManagerFactory ( managerFactory ) . setLog ( log ) ; }


Input: Will persist the information regarding the provided resource in some internal store . This information will be used later to check if the resource is changed . [CODESPLIT] public void remember ( final Resource resource ) { final WroManager manager = getManagerFactory ( ) . create ( ) ; final HashStrategy hashStrategy = manager . getHashStrategy ( ) ; final UriLocatorFactory locatorFactory = manager . getUriLocatorFactory ( ) ; if ( rememberedSet . contains ( resource . getUri ( ) ) ) { // only calculate fingerprints and check imports if not already done getLog ( ) . debug ( "Resource with uri '" + resource . getUri ( ) + "' has already been updated in this run." ) ; } else { try { final String fingerprint = hashStrategy . getHash ( locatorFactory . locate ( resource . getUri ( ) ) ) ; getBuildContextHolder ( ) . setValue ( resource . getUri ( ) , fingerprint ) ; rememberedSet . add ( resource . getUri ( ) ) ; getLog ( ) . debug ( "Persist fingerprint for resource '" + resource . getUri ( ) + "' : " + fingerprint ) ; if ( resource . getType ( ) == ResourceType . CSS ) { final Reader reader = new InputStreamReader ( locatorFactory . locate ( resource . getUri ( ) ) ) ; getLog ( ) . debug ( "Check @import directive from " + resource ) ; // persist fingerprints in imported resources. persistFingerprintsForCssImports ( resource , reader ) ; } } catch ( final IOException e ) { getLog ( ) . debug ( "could not check fingerprint of resource: " + resource ) ; } } }


Input: Invokes the provided function for each detected css import . [CODESPLIT] private void forEachCssImportApply ( final Function < String , ChangeStatus > func , final Resource resource , final Reader reader ) throws IOException { final ResourcePreProcessor processor = createCssImportProcessor ( func ) ; InjectorBuilder . create ( getManagerFactory ( ) ) . build ( ) . inject ( processor ) ; processor . process ( resource , reader , new StringWriter ( ) ) ; }


Input: After invoking this method on a resource the next invocation of { @link #isResourceChanged ( Resource ) } will return true . [CODESPLIT] public void forget ( final Resource resource ) { if ( resource != null ) { getBuildContextHolder ( ) . setValue ( resource . getUri ( ) , null ) ; rememberedSet . remove ( resource . getUri ( ) ) ; } }


Input: { [CODESPLIT] public String getHash ( final InputStream inputStream ) throws IOException { try { return getConfiguredStrategy ( ) . getHash ( inputStream ) ; } finally { IOUtils . closeQuietly ( inputStream ) ; } }


Input: Factory method for creating a { @link ResourceLintReport } instance . [CODESPLIT] public static < T > ResourceLintReport < T > create ( final String resourcePath , final Collection < T > lints ) { return new ResourceLintReport < T > ( resourcePath , lints ) ; }


Input: This filtering is required in order to ensure that no nulls are passed ( which happens when using gson for deserializing json collection . [CODESPLIT] private List < T > filter ( final Collection < T > collection ) { final List < T > nullFreeList = new ArrayList < T > ( ) ; if ( collection != null ) { for ( final T item : collection ) { if ( item != null ) { nullFreeList . add ( item ) ; } } } return nullFreeList ; }


Input: { [CODESPLIT] public String getGroupName ( final HttpServletRequest request ) { Validate . notNull ( request ) ; String uri = request . getRequestURI ( ) ; // check if include or uri path are present and use one of these as request uri. final String includeUriPath = ( String ) request . getAttribute ( ATTR_INCLUDE_PATH ) ; uri = includeUriPath != null ? includeUriPath : uri ; final String groupName = FilenameUtils . getBaseName ( stripSessionID ( uri ) ) ; return StringUtils . isEmpty ( groupName ) ? null : groupName ; }


Input: Extracts the resource type by parsing the uri & finds the extension . If extension is valid ( css or js ) returns corresponding ResourceType otherwise throws exception . <p > Valid examples of uri are : <code > / context / somePath / test . js< / code > or <code > / context / somePath / test . css< / code > { [CODESPLIT] public ResourceType getResourceType ( final HttpServletRequest request ) { Validate . notNull ( request ) ; final String uri = request . getRequestURI ( ) ; Validate . notNull ( uri ) ; ResourceType type = null ; try { type = ResourceType . get ( FilenameUtils . getExtension ( stripSessionID ( uri ) ) ) ; } catch ( final IllegalArgumentException e ) { LOG . debug ( "[FAIL] Cannot identify resourceType for uri: {}" , uri ) ; } return type ; }


Input: { [CODESPLIT] public String encodeGroupUrl ( final String groupName , final ResourceType resourceType , final boolean minimize ) { return String . format ( "%s.%s?" + PARAM_MINIMIZE + "=%s" , groupName , resourceType . name ( ) . toLowerCase ( ) , minimize ) ; }


Input: The minimization is can be switched off only in debug mode . [CODESPLIT] public boolean isMinimized ( final HttpServletRequest request ) { Validate . notNull ( request ) ; final String minimizeAsString = request . getParameter ( PARAM_MINIMIZE ) ; return ! ( Context . get ( ) . getConfig ( ) . isDebug ( ) && "false" . equalsIgnoreCase ( minimizeAsString ) ) ; }


Input: { [CODESPLIT] public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { try { final String script = IOUtils . toString ( reader ) ; writer . write ( script ) ; if ( isSemicolonNeeded ( script ) ) { writer . write ( ' ' ) ; } } finally { reader . close ( ) ; writer . close ( ) ; } }


Input: { [CODESPLIT] @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { final String content = IOUtils . toString ( reader ) ; try { writer . write ( doProcess ( content ) ) ; } catch ( final WroRuntimeException e ) { onException ( e ) ; final String resourceUri = resource == null ? StringUtils . EMPTY : "[" + resource . getUri ( ) + "]" ; LOG . warn ( "Exception while applying hpack processor on the " + resourceUri + " resource, no processing applied..." , e ) ; } finally { reader . close ( ) ; writer . close ( ) ; } }


Input: { [CODESPLIT] public final void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { LOG . debug ( "Applying {} processor" , toString ( ) ) ; validate ( ) ; try { final String result = parseCss ( resource , IOUtils . toString ( reader ) ) ; writer . write ( result ) ; } finally { //imkportant to avoid memory leak clearProcessedImports ( ) ; reader . close ( ) ; writer . close ( ) ; } }


Input: Find a set of imported resources inside a given resource . [CODESPLIT] private List < Resource > findImportedResources ( final String resourceUri , final String cssContent ) throws IOException { // it should be sorted final List < Resource > imports = new ArrayList < Resource > ( ) ; final String css = cssContent ; final List < String > foundImports = findImports ( css ) ; for ( final String importUrl : foundImports ) { final Resource importedResource = createImportedResource ( resourceUri , importUrl ) ; // check if already exist if ( imports . contains ( importedResource ) ) { LOG . debug ( "[WARN] Duplicate imported resource: {}" , importedResource ) ; } else { imports . add ( importedResource ) ; onImportDetected ( importedResource . getUri ( ) ) ; } } return imports ; }


Input: Build a { [CODESPLIT] private Resource createImportedResource ( final String resourceUri , final String importUrl ) { final String absoluteUrl = uriLocatorFactory . getInstance ( importUrl ) != null ? importUrl : computeAbsoluteUrl ( resourceUri , importUrl ) ; return Resource . create ( absoluteUrl , ResourceType . CSS ) ; }


Input: Computes absolute url of the imported resource . [CODESPLIT] private String computeAbsoluteUrl ( final String relativeResourceUri , final String importUrl ) { final String folder = WroUtil . getFullPath ( relativeResourceUri ) ; // remove '../' & normalize the path. return StringUtils . cleanPath ( folder + importUrl ) ; }


Input: Used to identify whether the { @link HttpServletResponse#SC_NOT_MODIFIED } or { @link HttpServletResponse#SC_OK } should be returned . Currently a single timestamp is used to detect the change for all resources . This might be no accurate but at least it allows sending NOT_MODIFIED header much often resulting in less load on the server . <p / > Override this method if a different way detecting change is required . [CODESPLIT] protected boolean isResourceChanged ( final HttpServletRequest request ) { try { final long ifModifiedSince = request . getDateHeader ( HttpHeader . IF_MODIFIED_SINCE . toString ( ) ) ; return ifModifiedSince < getHeadersConfigurer ( ) . getLastModifiedTimestamp ( ) ; } catch ( final Exception e ) { LOG . warn ( "Could not extract IF_MODIFIED_SINCE header for request: " + request . getRequestURI ( ) + ". Assuming content is changed. " , e ) ; return true ; } }


Input: Builds the request path for this request handler using the assumption that { @link WroFilter } has a mapping ending with a <code > * < / code > character . [CODESPLIT] public static String createProxyPath ( final String requestUri , final String resourceId ) { notNull ( requestUri ) ; notNull ( resourceId ) ; return requestUri + getRequestHandlerPath ( resourceId ) ; }


Input: Creates a comma separated list of items . [CODESPLIT] public static String createItemsAsString ( final String ... items ) { final StringBuffer sb = new StringBuffer ( ) ; for ( int i = 0 ; i < items . length ; i ++ ) { sb . append ( items [ i ] ) ; if ( i < items . length - 1 ) { sb . append ( TOKEN_DELIMITER ) ; } } return sb . toString ( ) ; }


Input: Creates a list of aliases based on provided string containing comma separated values of aliases . [CODESPLIT] private List < String > getAliasList ( final String aliasCsv ) { LOG . debug ( "configured aliases: {}" , aliasCsv ) ; final List < String > list = new ArrayList < String > ( ) ; if ( ! StringUtils . isEmpty ( aliasCsv ) ) { final String [ ] tokens = aliasCsv . split ( TOKEN_DELIMITER ) ; for ( final String token : tokens ) { list . add ( token . trim ( ) ) ; } } return list ; }


Input:
Initialize the context . [CODESPLIT] private ScriptableObject createContext ( final ScriptableObject initialScope ) { final Context context = getContext ( ) ; context . setOptimizationLevel ( - 1 ) ; // TODO redirect errors from System.err to LOG.error()
 context . setErrorReporter ( new ToolErrorReporter ( false ) ) ; context . setLanguageVersion ( Context . VERSION_1_8 ) ; InputStream script = null ; final ScriptableObject scriptCommon = ( ScriptableObject ) context . initStandardObjects ( initialScope ) ; try { script = new AutoCloseInputStream ( getClass ( ) . getResourceAsStream ( "commons.js" ) ) ; context . evaluateReader ( scriptCommon , new InputStreamReader ( script ) , "commons.js" , 1 , null ) ; } catch ( final IOException e ) { throw new RuntimeException ( "Problem while evaluationg commons script." , e ) ; } finally { IOUtils . closeQuietly ( script ) ; } return scriptCommon ; }


Input:
Add a client side environment to the script context ( client - side aware ) . [CODESPLIT] public RhinoScriptBuilder addClientSideEnvironment ( ) { try { //final InputStream scriptEnv = getClass().getResourceAsStream(SCRIPT_ENV);
 final InputStream scriptEnv = new WebjarUriLocator ( ) . locate ( "env.rhino.js" ) ; evaluateChain ( scriptEnv , SCRIPT_ENV ) ; return this ; } catch ( final IOException e ) { throw new RuntimeException ( "Couldn't initialize env.rhino script" , e ) ; } }


Input: This method will load JSON utility and aslo a Douglas Crockford s <a href = https : // github . com / douglascrockford / JSON - js / blob / master / cycle . js > utility< / a > required for decycling objects which would fail otherwise when using JSON . stringify . [CODESPLIT] public RhinoScriptBuilder addJSON ( ) { try { final InputStream script = new AutoCloseInputStream ( new WebjarUriLocator ( ) . locate ( WebjarUriLocator . createUri ( "20110223/json2.js" ) ) ) ; final InputStream scriptCycle = getClass ( ) . getResourceAsStream ( SCRIPT_CYCLE ) ; evaluateChain ( script , SCRIPT_JSON ) ; evaluateChain ( scriptCycle , SCRIPT_CYCLE ) ; return this ; } catch ( final IOException e ) { throw new RuntimeException ( "Couldn't initialize json2.min.js script" , e ) ; } }


Input: Evaluates a script and return { @link RhinoScriptBuilder } for a chained script evaluation . [CODESPLIT] public RhinoScriptBuilder evaluateChain ( final InputStream stream , final String sourceName ) throws IOException { notNull ( stream ) ; try { getContext ( ) . evaluateReader ( scope , new InputStreamReader ( stream ) , sourceName , 1 , null ) ; return this ; } catch ( final RhinoException e ) { if ( e instanceof RhinoException ) { LOG . error ( "RhinoException: {}" , RhinoUtils . createExceptionMessage ( e ) ) ; } throw e ; } catch ( final RuntimeException e ) { LOG . error ( "Exception caught" , e ) ; throw e ; } finally { stream . close ( ) ; } }


Input: Evaluates a script and return { @link RhinoScriptBuilder } for a chained script evaluation . [CODESPLIT] public RhinoScriptBuilder evaluateChain ( final String script , final String sourceName ) { notNull ( script ) ; getContext ( ) . evaluateString ( scope , script , sourceName , 1 , null ) ; return this ; }


Input: Evaluates a script from a reader . [CODESPLIT] public Object evaluate ( final Reader reader , final String sourceName ) throws IOException { notNull ( reader ) ; try { return evaluate ( IOUtils . toString ( reader ) , sourceName ) ; } finally { reader . close ( ) ; } }


Input:
Evaluates a script . [CODESPLIT] public Object evaluate ( final String script , final String sourceName ) { notNull ( script ) ; // make sure we have a context associated with current thread
 try { return getContext ( ) . evaluateString ( scope , script , sourceName , 1 , null ) ; } catch ( final RhinoException e ) { final String message = RhinoUtils . createExceptionMessage ( e ) ; LOG . error ( "JavaScriptException occured: {}" , message ) ; throw new WroRuntimeException ( message ) ; } finally { // Rhino throws an exception when trying to exit twice. Make sure we don't get any exception
 if ( Context . getCurrentContext ( ) != null ) { Context . exit ( ) ; } } }


Input: Perform processing of the uri . [CODESPLIT] public final void process ( ) throws IOException { // reschedule cache & model updates final WroConfiguration config = Context . get ( ) . getConfig ( ) ; cacheSchedulerHelper . scheduleWithPeriod ( config . getCacheUpdatePeriod ( ) ) ; modelSchedulerHelper . scheduleWithPeriod ( config . getModelUpdatePeriod ( ) ) ; resourceBundleProcessor . serveProcessedBundle ( ) ; }


Input: Encodes a fingerprint of the resource into the path . The result may look like this : $ { fingerprint } / myGroup . js [CODESPLIT] public final String encodeVersionIntoGroupPath ( final String groupName , final ResourceType resourceType , final boolean minimize ) { // TODO use CacheKeyFactory final CacheKey key = new CacheKey ( groupName , resourceType , minimize ) ; final CacheValue cacheValue = cacheStrategy . get ( key ) ; final String groupUrl = groupExtractor . encodeGroupUrl ( groupName , resourceType , minimize ) ; // encode the fingerprint of the resource into the resource path return formatVersionedResource ( cacheValue . getHash ( ) , groupUrl ) ; }


Input: Format the version of the resource in the path . Default implementation use hash as a folder : <hash > / groupName . js . The implementation can be changed to follow a different versioning style like version parameter : / groupName . js?version = <hash > [CODESPLIT] protected String formatVersionedResource ( final String hash , final String resourcePath ) { return String . format ( "%s/%s" , hash , resourcePath ) ; }


Input: Called when { [CODESPLIT] public final void destroy ( ) { try { cacheSchedulerHelper . destroy ( ) ; modelSchedulerHelper . destroy ( ) ; cacheStrategy . destroy ( ) ; modelFactory . destroy ( ) ; resourceWatcher . destroy ( ) ; destroyProcessors ( ) ; } catch ( final Exception e ) { LOG . error ( "Exception occured during manager destroy!" , e ) ; } finally { LOG . debug ( "WroManager destroyed" ) ; } }


Input: Invokes destroy method on all { [CODESPLIT] private void destroyProcessors ( ) throws Exception { for ( final ResourcePreProcessor processor : processorsFactory . getPreProcessors ( ) ) { if ( processor instanceof Destroyable ) { ( ( Destroyable ) processor ) . destroy ( ) ; } } for ( final ResourcePostProcessor processor : processorsFactory . getPostProcessors ( ) ) { if ( processor instanceof Destroyable ) { ( ( Destroyable ) processor ) . destroy ( ) ; } } }


Input: { [CODESPLIT] public Map < String , CacheStrategy < CacheKey , CacheValue > > provideCacheStrategies ( ) { return new HashMap < String , CacheStrategy < CacheKey , CacheValue > > ( ) ; }


Input: Checks if the provided url is a resource proxy request . [CODESPLIT] private boolean isHandlerRequest ( final HttpServletRequest request ) { String apiHandlerValue = request . getParameter ( PATH_API ) ; return PATH_HANDLER . equals ( apiHandlerValue ) && retrieveCacheKey ( request ) != null ; }


Input: Computes the servlet context relative url to call this handler using a server - side invocation . Hides the details about creating a valid url and providing the authorization key required to invoke this handler . [CODESPLIT] public static String createHandlerRequestPath ( final CacheKey cacheKey , final HttpServletRequest request ) { final String handlerQueryPath = getRequestHandlerPath ( cacheKey . getGroupName ( ) , cacheKey . getType ( ) ) ; return request . getServletPath ( ) + handlerQueryPath ; }


Input: Encodes a version using some logic . [CODESPLIT] private String rename ( final String group , final InputStream input ) throws Exception { try { final String newName = getManagerFactory ( ) . create ( ) . getNamingStrategy ( ) . rename ( group , input ) ; groupNames . setProperty ( group , newName ) ; return newName ; } catch ( final IOException e ) { throw new MojoExecutionException ( "Error occured during renaming" , e ) ; } }


Input: Computes the destination folder based on resource type . [CODESPLIT] private File computeDestinationFolder ( final ResourceType resourceType ) throws MojoExecutionException { File folder = destinationFolder ; if ( resourceType == ResourceType . JS ) { if ( jsDestinationFolder != null ) { folder = jsDestinationFolder ; } } if ( resourceType == ResourceType . CSS ) { if ( cssDestinationFolder != null ) { folder = cssDestinationFolder ; } } getLog ( ) . info ( "folder: " + folder ) ; if ( folder == null ) { throw new MojoExecutionException ( "Couldn't compute destination folder for resourceType: " + resourceType + ". That means that you didn't define one of the following parameters: " + "destinationFolder, cssDestinationFolder, jsDestinationFolder" ) ; } if ( ! folder . exists ( ) ) { folder . mkdirs ( ) ; } return folder ; }


Input: Process a single group . [CODESPLIT] private void processGroup ( final String group , final File parentFoder ) throws Exception { ByteArrayOutputStream resultOutputStream = null ; InputStream resultInputStream = null ; try { getLog ( ) . info ( "processing group: " + group ) ; // mock request final HttpServletRequest request = Mockito . mock ( HttpServletRequest . class ) ; Mockito . when ( request . getContextPath ( ) ) . thenReturn ( normalizeContextPath ( contextPath ) ) ; Mockito . when ( request . getRequestURI ( ) ) . thenReturn ( group ) ; // mock response final HttpServletResponse response = Mockito . mock ( HttpServletResponse . class ) ; resultOutputStream = new ByteArrayOutputStream ( ) ; Mockito . when ( response . getOutputStream ( ) ) . thenReturn ( new DelegatingServletOutputStream ( resultOutputStream ) ) ; // init context final WroConfiguration config = Context . get ( ) . getConfig ( ) ; // the maven plugin should ignore empty groups, since it will try to process all types of resources. config . setIgnoreEmptyGroup ( true ) ; Context . set ( Context . webContext ( request , response , Mockito . mock ( FilterConfig . class ) ) , config ) ; Context . get ( ) . setAggregatedFolderPath ( getAggregatedPathResolver ( ) . resolve ( ) ) ; // perform processing getManagerFactory ( ) . create ( ) . process ( ) ; // encode version & write result to file resultInputStream = new UnclosableBufferedInputStream ( resultOutputStream . toByteArray ( ) ) ; final File destinationFile = new File ( parentFoder , rename ( group , resultInputStream ) ) ; final File parentFolder = destinationFile . getParentFile ( ) ; if ( ! parentFolder . exists ( ) ) { // make directories if required parentFolder . mkdirs ( ) ; } destinationFile . createNewFile ( ) ; // allow the same stream to be read again resultInputStream . reset ( ) ; getLog ( ) . debug ( "Created file: " + destinationFile . getName ( ) ) ; final OutputStream fos = new FileOutputStream ( destinationFile ) ; // use reader to detect encoding IOUtils . copy ( resultInputStream , fos ) ; fos . close ( ) ; // delete empty files if ( destinationFile . length ( ) == 0 ) { getLog ( ) . debug ( "No content found for group: " + group ) ; destinationFile . delete ( ) ; } else { getLog ( ) . info ( "file size: " + destinationFile . getName ( ) + " -> " + destinationFile . length ( ) + " bytes" ) ; getLog ( ) . info ( destinationFile . getAbsolutePath ( ) + " (" + destinationFile . length ( ) + " bytes" + ")" ) ; } } finally { // instruct the build about the change in context of incremental build if ( getBuildContext ( ) != null ) { getBuildContext ( ) . refresh ( parentFoder ) ; } if ( resultOutputStream != null ) { resultOutputStream . close ( ) ; } if ( resultInputStream != null ) { resultInputStream . close ( ) ; } } }


Input: Wraps original exception into { @link WroRuntimeException } and throw it . [CODESPLIT] public static WroRuntimeException wrap ( final Exception e , final String message ) { if ( e instanceof WroRuntimeException ) { return ( WroRuntimeException ) e ; } return new WroRuntimeException ( message , e ) ; }


Input:
{ [CODESPLIT] @ Override public void process ( final Resource resource , final Reader reader , final Writer writer ) throws IOException { final String content = IOUtils . toString ( reader ) ; final CompilerOptions compilerOptions = optionsPool . getObject ( ) ; final Compiler compiler = newCompiler ( compilerOptions ) ; try { final String fileName = resource == null ? "wro4j-processed-file.js" : resource . getUri ( ) ; final SourceFile [ ] input = new SourceFile [ ] { SourceFile . fromInputStream ( fileName , new ByteArrayInputStream ( content . getBytes ( getEncoding ( ) ) ) ) } ; SourceFile [ ] externs = getExterns ( resource ) ; if ( externs == null ) { // fallback to empty array when null is provided.
 externs = new SourceFile [ ] { } ; } Result result = null ; result = compiler . compile ( Arrays . asList ( externs ) , Arrays . asList ( input ) , compilerOptions ) ; if ( result . success ) { writer . write ( compiler . toSource ( ) ) ; } else { throw new WroRuntimeException ( "Compilation has errors: " + Arrays . asList ( result . errors ) ) ; } } catch ( final Exception e ) { onException ( e ) ; } finally { reader . close ( ) ; writer . close ( ) ; optionsPool . returnObject ( compilerOptions ) ; } }


Input:
Computes { [CODESPLIT] final SupportedResourceType getSupportedResourceTypeForProcessor ( final Object processor ) { SupportedResourceType supportedType = processor . getClass ( ) . getAnnotation ( SupportedResourceType . class ) ; /**
     * This is a special case for processors which implement {@link SupportedResourceTypeProvider} interface. This is
     * useful for decorator processors which needs to "inherit" the {@link SupportedResourceType} of the decorated
     * processor.
     */ if ( processor instanceof SupportedResourceTypeAware ) { supportedType = ( ( SupportedResourceTypeAware ) processor ) . getSupportedResourceType ( ) ; } return supportedType ; }


Input: Check if an uri from a particular group has changed . [CODESPLIT] public boolean checkChangeForGroup ( final String uri , final String groupName ) throws IOException { notNull ( uri ) ; notNull ( groupName ) ; LOG . debug ( "group={}, uri={}" , groupName , uri ) ; final ResourceChangeInfo resourceInfo = changeInfoMap . get ( uri ) ; if ( resourceInfo . isCheckRequiredForGroup ( groupName ) ) { final InputStream inputStream = locatorFactory . locate ( uri ) ; try { final String currentHash = hashStrategy . getHash ( inputStream ) ; resourceInfo . updateHashForGroup ( currentHash , groupName ) ; } finally { IOUtils . closeQuietly ( inputStream ) ; } } return resourceInfo . isChanged ( groupName ) ; }


Input: A getter used for lazy loading overrides RubySassEngine#getEngine () and ensure the bourbon gem is imported ( required ) . [CODESPLIT] @ Override protected RubySassEngine newEngine ( ) { final RubySassEngine engine = super . newEngine ( ) ; engine . addRequire ( BOURBON_GEM_REQUIRE ) ; return engine ; }


Input: { [CODESPLIT] @ Override public String compile ( final String content , final String name ) { return HANDLEBARS_JS_TEMPLATES_INIT + "templates[" + name + "] = template(" + super . compile ( content , "" ) + " ); })();" ; }


Input: Initialize script builder for evaluation . [CODESPLIT] private RhinoScriptBuilder initScriptBuilder ( ) { try { RhinoScriptBuilder builder = null ; if ( scope == null ) { final String scriptInit = "var exports = {};" ; builder = RhinoScriptBuilder . newChain ( ) . evaluateChain ( scriptInit , "initSass" ) . evaluateChain ( getScriptAsStream ( ) , DEFAULT_SASS_JS ) ; scope = builder . getScope ( ) ; } else { builder = RhinoScriptBuilder . newChain ( scope ) ; } return builder ; } catch ( final IOException ex ) { throw new WroRuntimeException ( "Failed reading javascript sass.js" , ex ) ; } }


Input: This implementation will try to locate the provided resource inside contextFolder configured by standaloneContext . If a resource cannot be located the next contextFolder from the list will be tried . The first successful result will be returned . [CODESPLIT] @ Override public InputStream locate ( final String uri ) throws IOException { validState ( standaloneContext != null , "Locator was not initialized properly. StandaloneContext missing." ) ; Exception lastException = null ; final String [ ] contextFolders = standaloneContext . getContextFolders ( ) ; for ( final String contextFolder : contextFolders ) { try { return locateStreamWithContextFolder ( uri , contextFolder ) ; } catch ( final IOException e ) { lastException = e ; LOG . debug ( "Could not locate: {} using contextFolder: {}" , uri , contextFolder ) ; } } final String exceptionMessage = String . format ( "No valid resource '%s' found inside any of contextFolders: %s" , uri , Arrays . toString ( standaloneContext . getContextFolders ( ) ) ) ; throw new IOException ( exceptionMessage , lastException ) ; }


Input: TODO this is duplicated code ( from super ) - > find a way to reuse it . [CODESPLIT] private InputStream locateStreamWithContextFolder ( final String uri , final String contextFolder ) throws IOException , FileNotFoundException { if ( getWildcardStreamLocator ( ) . hasWildcard ( uri ) ) { final String fullPath = WroUtil . getFullPath ( uri ) ; final String realPath = contextFolder + fullPath ; return getWildcardStreamLocator ( ) . locateStream ( uri , new File ( realPath ) ) ; } final String uriWithoutPrefix = uri . replaceFirst ( PREFIX , EMPTY ) ; final File file = new File ( contextFolder , uriWithoutPrefix ) ; LOG . debug ( "Opening file: " + file . getPath ( ) ) ; return new FileInputStream ( file ) ; }


Input: Initialize script builder for evaluation . [CODESPLIT] private RhinoScriptBuilder initScriptBuilder ( ) { try { RhinoScriptBuilder builder = null ; if ( scope == null ) { builder = RhinoScriptBuilder . newChain ( ) . evaluateChain ( getScriptAsStream ( ) , DEFAULT_CSSLINT_JS ) ; scope = builder . getScope ( ) ; } else { builder = RhinoScriptBuilder . newChain ( scope ) ; } return builder ; } catch ( final IOException ex ) { throw new IllegalStateException ( "Failed reading init script" , ex ) ; } }


Input: Validates a css resource using cssLint and throws { @link CssLintException } if the resource is invalid . If no exception is thrown the resource is valid . [CODESPLIT] public void validate ( final String data ) throws CssLintException { final StopWatch watch = new StopWatch ( ) ; watch . start ( "init" ) ; final RhinoScriptBuilder builder = initScriptBuilder ( ) ; watch . stop ( ) ; watch . start ( "cssLint" ) ; LOG . debug ( "options: {}" , this . options ) ; final String script = buildCssLintScript ( WroUtil . toJSMultiLineString ( data ) ) ; LOG . debug ( "script: {}" , script ) ; builder . evaluate ( script , "CSSLint.verify" ) . toString ( ) ; final boolean valid = Boolean . parseBoolean ( builder . evaluate ( "result.length == 0" , "checkNoErrors" ) . toString ( ) ) ; if ( ! valid ) { final String json = builder . addJSON ( ) . evaluate ( "JSON.stringify(result)" , "CssLint messages" ) . toString ( ) ; LOG . debug ( "json {}" , json ) ; final Type type = new TypeToken < List < CssLintError > > ( ) { } . getType ( ) ; final List < CssLintError > errors = new Gson ( ) . fromJson ( json , type ) ; LOG . debug ( "Errors: {}" , errors ) ; throw new CssLintException ( ) . setErrors ( errors ) ; } LOG . debug ( "isValid: {}" , valid ) ; watch . stop ( ) ; LOG . debug ( watch . prettyPrint ( ) ) ; }


Input: Ensure that a not null pool will be created . [CODESPLIT] private GenericObjectPool < T > createObjectPool ( final ObjectFactory < T > objectFactory ) { final GenericObjectPool < T > pool = newObjectPool ( objectFactory ) ; notNull ( pool ) ; return pool ; }


Input:
Creates a { [CODESPLIT] protected GenericObjectPool < T > newObjectPool ( final ObjectFactory < T > objectFactory ) { final int maxActive = Math . max ( 2 , Runtime . getRuntime ( ) . availableProcessors ( ) ) ; final GenericObjectPool < T > pool = new GenericObjectPool < T > ( new BasePoolableObjectFactory < T > ( ) { @ Override public T makeObject ( ) throws Exception { return objectFactory . create ( ) ; } } ) ; pool . setMaxActive ( maxActive ) ; pool . setMaxIdle ( MAX_IDLE ) ; pool . setMaxWait ( MAX_WAIT ) ; /**
     * Use WHEN_EXHAUSTED_GROW strategy, otherwise the pool object retrieval can fail. More details here:
     * http://code.google.com/p/wro4j/issues/detail?id=364
     */ pool . setWhenExhaustedAction ( GenericObjectPool . WHEN_EXHAUSTED_GROW ) ; // make object eligible for eviction after a predefined amount of time.
 pool . setSoftMinEvictableIdleTimeMillis ( EVICTABLE_IDLE_TIME ) ; pool . setTimeBetweenEvictionRunsMillis ( EVICTABLE_IDLE_TIME ) ; return pool ; }