Coverage Report - org.apache.maven.doxia.macro.snippet.SnippetMacro
 
Classes in this File Line Coverage Branch Coverage Complexity
SnippetMacro
77%
51/66
61%
16/26
3
 
 1  
 package org.apache.maven.doxia.macro.snippet;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.doxia.macro.AbstractMacro;
 23  
 import org.apache.maven.doxia.macro.MacroExecutionException;
 24  
 import org.apache.maven.doxia.macro.MacroRequest;
 25  
 import org.apache.maven.doxia.sink.Sink;
 26  
 import org.codehaus.plexus.util.StringUtils;
 27  
 
 28  
 import java.io.IOException;
 29  
 import java.io.File;
 30  
 import java.net.MalformedURLException;
 31  
 import java.net.URL;
 32  
 import java.util.HashMap;
 33  
 import java.util.Map;
 34  
 import org.apache.maven.doxia.sink.SinkEventAttributeSet;
 35  
 
 36  
 /**
 37  
  * A macro that prints out the content of a file or a URL.
 38  
  *
 39  
  * @plexus.component role-hint="snippet"
 40  
  * @version $Id: SnippetMacro.java 1090706 2011-04-09 23:15:28Z hboutemy $
 41  
  */
 42  4
 public class SnippetMacro
 43  
     extends AbstractMacro
 44  
 {
 45  
     /** Holds the cache. */
 46  2
     private static Map<String, String> cache = new HashMap<String, String>();
 47  
 
 48  
     private static final int HOUR = 60;
 49  
 
 50  
     /** One hour default cache. */
 51  4
     private long timeout = HOUR * HOUR * 1000;
 52  
 
 53  
     /** Holds the time cache. */
 54  2
     private static Map<String, Long> timeCached = new HashMap<String, Long>();
 55  
 
 56  
     /** Debug. */
 57  4
     private boolean debug = false;
 58  
 
 59  
     /** {@inheritDoc} */
 60  
     public void execute( Sink sink, MacroRequest request )
 61  
         throws MacroExecutionException
 62  
     {
 63  6
         String id = (String) request.getParameter( "id" );
 64  
 
 65  6
         String urlParam = (String) request.getParameter( "url" );
 66  
 
 67  6
         String fileParam = (String) request.getParameter( "file" );
 68  
 
 69  6
         boolean verbatim = true;
 70  
 
 71  6
         String verbatimParam = (String) request.getParameter( "verbatim" );
 72  
 
 73  6
         if ( verbatimParam != null && !"".equals( verbatimParam ) )
 74  
         {
 75  2
             verbatim = Boolean.valueOf( verbatimParam ).booleanValue();
 76  
         }
 77  
 
 78  
         URL url;
 79  
 
 80  6
         if ( !StringUtils.isEmpty( urlParam ) )
 81  
         {
 82  
             try
 83  
             {
 84  0
                 url = new URL( urlParam );
 85  
             }
 86  0
             catch ( MalformedURLException e )
 87  
             {
 88  0
                 throw new IllegalArgumentException( urlParam + " is a malformed URL" );
 89  0
             }
 90  
         }
 91  6
         else if ( !StringUtils.isEmpty( fileParam ) )
 92  
         {
 93  6
             File f = new File( fileParam );
 94  
 
 95  6
             if ( !f.isAbsolute() )
 96  
             {
 97  6
                 f = new File( request.getBasedir(), fileParam );
 98  
             }
 99  
 
 100  
             try
 101  
             {
 102  6
                 url = f.toURI().toURL();
 103  
             }
 104  0
             catch ( MalformedURLException e )
 105  
             {
 106  0
                 throw new IllegalArgumentException( fileParam + " is a malformed URL" );
 107  6
             }
 108  6
         }
 109  
         else
 110  
         {
 111  0
             throw new IllegalArgumentException( "Either the 'url' or the 'file' param has to be given." );
 112  
         }
 113  
 
 114  
         StringBuffer snippet;
 115  
 
 116  
         try
 117  
         {
 118  6
             snippet = getSnippet( url, id );
 119  
         }
 120  0
         catch ( IOException e )
 121  
         {
 122  0
             throw new MacroExecutionException( "Error reading snippet", e );
 123  6
         }
 124  
 
 125  6
         if ( verbatim )
 126  
         {
 127  4
             sink.verbatim( SinkEventAttributeSet.BOXED );
 128  
 
 129  4
             sink.text( snippet.toString() );
 130  
 
 131  4
             sink.verbatim_();
 132  
         }
 133  
         else
 134  
         {
 135  2
             sink.rawText( snippet.toString() );
 136  
         }
 137  6
     }
 138  
 
 139  
     /**
 140  
      * Return a snippet of the given url.
 141  
      *
 142  
      * @param url The URL to parse.
 143  
      * @param id The id of the snippet.
 144  
      * @return The snippet.
 145  
      * @throws IOException if something goes wrong.
 146  
      */
 147  
     private StringBuffer getSnippet( URL url, String id )
 148  
         throws IOException
 149  
     {
 150  
         StringBuffer result;
 151  
 
 152  6
         String cachedSnippet = getCachedSnippet( url, id );
 153  
 
 154  6
         if ( cachedSnippet != null )
 155  
         {
 156  0
             result = new StringBuffer( cachedSnippet );
 157  
 
 158  0
             if ( debug )
 159  
             {
 160  0
                 result.append( "(Served from cache)" );
 161  
             }
 162  
         }
 163  
         else
 164  
         {
 165  6
             result = new SnippetReader( url ).readSnippet( id );
 166  
 
 167  6
             cacheSnippet( url, id, result.toString() );
 168  
 
 169  6
             if ( debug )
 170  
             {
 171  0
                 result.append( "(Fetched from url, cache content " ).append( cache ).append( ")" );
 172  
             }
 173  
         }
 174  
 
 175  6
         return result;
 176  
     }
 177  
 
 178  
     /**
 179  
      * Return a snippet from the cache.
 180  
      *
 181  
      * @param url The URL to parse.
 182  
      * @param id The id of the snippet.
 183  
      * @return The snippet.
 184  
      */
 185  
     private String getCachedSnippet( URL url, String id )
 186  
     {
 187  6
         if ( isCacheTimedout( url, id ) )
 188  
         {
 189  6
             removeFromCache( url, id );
 190  
         }
 191  6
         return cache.get( globalSnippetId( url, id ) );
 192  
     }
 193  
 
 194  
     /**
 195  
      * Return true if the snippet has been cached longer than
 196  
      * the current timeout.
 197  
      *
 198  
      * @param url The URL to parse.
 199  
      * @param id The id of the snippet.
 200  
      * @return True if timeout exceeded.
 201  
      */
 202  
     boolean isCacheTimedout( URL url, String id )
 203  
     {
 204  6
         return timeInCache( url, id ) >= timeout;
 205  
     }
 206  
 
 207  
     /**
 208  
      * Return the time the snippet has been cached.
 209  
      *
 210  
      * @param url The URL to parse.
 211  
      * @param id The id of the snippet.
 212  
      * @return The cache time.
 213  
      */
 214  
     long timeInCache( URL url, String id )
 215  
     {
 216  6
         return System.currentTimeMillis() - getTimeCached( url, id );
 217  
     }
 218  
 
 219  
     /**
 220  
      * Return the absolute value of when the snippet has been cached.
 221  
      *
 222  
      * @param url The URL to parse.
 223  
      * @param id The id of the snippet.
 224  
      * @return The cache time.
 225  
      */
 226  
     long getTimeCached( URL url, String id )
 227  
     {
 228  6
         String globalId = globalSnippetId( url, id );
 229  
 
 230  6
         return timeCached.containsKey( globalId ) ? timeCached.get( globalId ).longValue() : 0;
 231  
     }
 232  
 
 233  
     /**
 234  
      * Removes the snippet from the cache.
 235  
      *
 236  
      * @param url The URL to parse.
 237  
      * @param id The id of the snippet.
 238  
      */
 239  
     private void removeFromCache( URL url, String id )
 240  
     {
 241  6
         String globalId = globalSnippetId( url, id );
 242  
 
 243  6
         timeCached.remove( globalId );
 244  
 
 245  6
         cache.remove( globalId );
 246  6
     }
 247  
 
 248  
     /**
 249  
      * Return a global identifier for the snippet.
 250  
      *
 251  
      * @param url The URL to parse.
 252  
      * @param id The id of the snippet.
 253  
      * @return An identifier, concatenated url and id,
 254  
      *  or just url.toString() if id is empty or null.
 255  
      */
 256  
     private String globalSnippetId( URL url, String id )
 257  
     {
 258  30
         if ( StringUtils.isEmpty( id ) )
 259  
         {
 260  10
             return url.toString();
 261  
         }
 262  
 
 263  20
         return url + " " + id;
 264  
     }
 265  
 
 266  
     /**
 267  
      * Puts the given snippet into the cache.
 268  
      *
 269  
      * @param url The URL to parse.
 270  
      * @param id The id of the snippet.
 271  
      * @param content The content of the snippet.
 272  
      */
 273  
     public void cacheSnippet( URL url, String id, String content )
 274  
     {
 275  6
         cache.put( globalSnippetId( url, id ), content );
 276  
 
 277  6
         timeCached.put( globalSnippetId( url, id ), new Long( System.currentTimeMillis() ) );
 278  6
     }
 279  
 
 280  
     /**
 281  
      * Set the cache timeout.
 282  
      *
 283  
      * @param time The timeout to set.
 284  
      */
 285  
     public void setCacheTimeout( int time )
 286  
     {
 287  0
         this.timeout = time;
 288  0
     }
 289  
 }