001package org.apache.maven.doxia.macro.snippet; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.BufferedReader; 023import java.io.IOException; 024import java.io.InputStreamReader; 025import java.net.URL; 026import java.util.ArrayList; 027import java.util.List; 028import java.util.Locale; 029 030import org.codehaus.plexus.util.IOUtil; 031 032/** 033 * Utility class for reading snippets. 034 * 035 * @version $Id$ 036 */ 037public class SnippetReader 038{ 039 /** System-dependent EOL. */ 040 private static final String EOL = System.getProperty( "line.separator" ); 041 042 /** The source. */ 043 private URL source; 044 045 /** The encoding of the source. */ 046 private String encoding; 047 048 /** 049 * Constructor. 050 * 051 * @param src The source 052 * @param encoding The file encoding 053 */ 054 public SnippetReader( URL src, String encoding ) 055 { 056 this.source = src; 057 this.encoding = encoding; 058 } 059 060 /** 061 * Constructor. 062 * 063 * @param src The source 064 */ 065 public SnippetReader( URL src ) 066 { 067 this( src, null ) ; 068 } 069 070 /** 071 * Reads the snippet with given id. 072 * 073 * @param snippetId The id of the snippet. 074 * @return The snippet. 075 * @throws java.io.IOException if something goes wrong. 076 */ 077 public StringBuffer readSnippet( String snippetId ) 078 throws IOException 079 { 080 List<String> lines = readLines( snippetId ); 081 int minIndent = minIndent( lines ); 082 StringBuffer result = new StringBuffer(); 083 for ( String line : lines ) 084 { 085 result.append( line.substring( minIndent ) ); 086 result.append( EOL ); 087 } 088 return result; 089 } 090 091 /** 092 * Returns the minimal indent of all the lines in the given List. 093 * 094 * @param lines A List of lines. 095 * @return the minimal indent. 096 */ 097 int minIndent( List<String> lines ) 098 { 099 int minIndent = Integer.MAX_VALUE; 100 for ( String line : lines ) 101 { 102 minIndent = Math.min( minIndent, indent( line ) ); 103 } 104 return minIndent; 105 } 106 107 /** 108 * Returns the indent of the given line. 109 * 110 * @param line A line. 111 * @return the indent. 112 */ 113 int indent( String line ) 114 { 115 char[] chars = line.toCharArray(); 116 int indent = 0; 117 for ( ; indent < chars.length; indent++ ) 118 { 119 if ( chars[indent] != ' ' ) 120 { 121 break; 122 } 123 } 124 return indent; 125 } 126 127 /** 128 * Reads the snippet and returns the lines in a List. 129 * 130 * @param snippetId The id of the snippet. 131 * @return A List of lines. 132 * @throws IOException if something goes wrong. 133 */ 134 private List<String> readLines( String snippetId ) 135 throws IOException 136 { 137 BufferedReader reader; 138 if ( encoding == null || "".equals( encoding ) ) 139 { 140 reader = new BufferedReader( new InputStreamReader( source.openStream() ) ); 141 } 142 else 143 { 144 reader = new BufferedReader( new InputStreamReader( source.openStream(), encoding ) ); 145 } 146 147 List<String> lines = new ArrayList<String>(); 148 try 149 { 150 boolean capture = false; 151 String line; 152 while ( ( line = reader.readLine() ) != null ) 153 { 154 if ( snippetId == null || "".equals( snippetId.trim() ) ) 155 { 156 lines.add( line ); 157 } 158 else 159 { 160 if ( isStart( snippetId, line ) ) 161 { 162 capture = true; 163 } 164 else if ( isEnd( snippetId, line ) ) 165 { 166 break; 167 } 168 else if ( capture ) 169 { 170 lines.add( line ); 171 } 172 } 173 } 174 } 175 finally 176 { 177 IOUtil.close( reader ); 178 } 179 return lines; 180 } 181 182 /** 183 * Determines if the given line is a start demarcator. 184 * 185 * @param snippetId the id of the snippet. 186 * @param line the line. 187 * @return True, if the line is a start demarcator. 188 */ 189 protected boolean isStart( String snippetId, String line ) 190 { 191 return isDemarcator( snippetId, "START", line ); 192 } 193 194 /** 195 * Determines if the given line is a demarcator. 196 * 197 * @param snippetId the id of the snippet. 198 * @param what Identifier for the demarcator. 199 * @param line the line. 200 * @return True, if the line is a start demarcator. 201 */ 202 protected boolean isDemarcator( String snippetId, String what, String line ) 203 { 204 String upper = line.toUpperCase( Locale.ENGLISH ); 205 return upper.contains( what.toUpperCase( Locale.ENGLISH ) ) 206 && upper.contains( "SNIPPET" ) 207 && line.contains( snippetId ); 208 } 209 210 /** 211 * Determines if the given line is an end demarcator. 212 * 213 * @param snippetId the id of the snippet. 214 * @param line the line. 215 * @return True, if the line is an end demarcator. 216 */ 217 protected boolean isEnd( String snippetId, String line ) 218 { 219 return isDemarcator( snippetId, "END", line ); 220 } 221}