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 java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.InputStreamReader;
25 import java.net.URL;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Locale;
29
30 import org.codehaus.plexus.util.IOUtil;
31
32 /**
33 * Utility class for reading snippets.
34 *
35 * @version $Id: SnippetReader.java 1172204 2011-09-18 06:46:17Z hboutemy $
36 */
37 public class SnippetReader
38 {
39 /** System-dependent EOL. */
40 private static final String EOL = System.getProperty( "line.separator" );
41
42 /** The source. */
43 private URL source;
44
45 /**
46 * Constructor.
47 *
48 * @param src The source.
49 */
50 public SnippetReader( URL src )
51 {
52 this.source = src;
53 }
54
55 /**
56 * Reads the snippet with given id.
57 *
58 * @param snippetId The id of the snippet.
59 * @return The snippet.
60 * @throws java.io.IOException if something goes wrong.
61 */
62 public StringBuffer readSnippet( String snippetId )
63 throws IOException
64 {
65 List<String> lines = readLines( snippetId );
66 int minIndent = minIndent( lines );
67 StringBuffer result = new StringBuffer();
68 for ( String line : lines )
69 {
70 result.append( line.substring( minIndent ) );
71 result.append( EOL );
72 }
73 return result;
74 }
75
76 /**
77 * Returns the minimal indent of all the lines in the given List.
78 *
79 * @param lines A List of lines.
80 * @return the minimal indent.
81 */
82 int minIndent( List<String> lines )
83 {
84 int minIndent = Integer.MAX_VALUE;
85 for ( String line : lines )
86 {
87 minIndent = Math.min( minIndent, indent( line ) );
88 }
89 return minIndent;
90 }
91
92 /**
93 * Returns the indent of the given line.
94 *
95 * @param line A line.
96 * @return the indent.
97 */
98 int indent( String line )
99 {
100 char[] chars = line.toCharArray();
101 int indent = 0;
102 for ( ; indent < chars.length; indent++ )
103 {
104 if ( chars[indent] != ' ' )
105 {
106 break;
107 }
108 }
109 return indent;
110 }
111
112 /**
113 * Reads the snippet and returns the lines in a List.
114 *
115 * @param snippetId The id of the snippet.
116 * @return A List of lines.
117 * @throws IOException if something goes wrong.
118 */
119 private List<String> readLines( String snippetId )
120 throws IOException
121 {
122 // TODO: DOXIA-386, use InputStreamReader(InputStream in, Charset cs)
123 BufferedReader reader = new BufferedReader( new InputStreamReader( source.openStream() ) );
124 List<String> lines = new ArrayList<String>();
125 try
126 {
127 boolean capture = false;
128 String line;
129 while ( ( line = reader.readLine() ) != null )
130 {
131 if ( snippetId == null || "".equals( snippetId.trim() ) )
132 {
133 lines.add( line );
134 }
135 else
136 {
137 if ( isStart( snippetId, line ) )
138 {
139 capture = true;
140 }
141 else if ( isEnd( snippetId, line ) )
142 {
143 break;
144 }
145 else if ( capture )
146 {
147 lines.add( line );
148 }
149 }
150 }
151 }
152 finally
153 {
154 IOUtil.close( reader );
155 }
156 return lines;
157 }
158
159 /**
160 * Determines if the given line is a start demarcator.
161 *
162 * @param snippetId the id of the snippet.
163 * @param line the line.
164 * @return True, if the line is a start demarcator.
165 */
166 protected boolean isStart( String snippetId, String line )
167 {
168 return isDemarcator( snippetId, "START", line );
169 }
170
171 /**
172 * Determines if the given line is a demarcator.
173 *
174 * @param snippetId the id of the snippet.
175 * @param what Identifier for the demarcator.
176 * @param line the line.
177 * @return True, if the line is a start demarcator.
178 */
179 protected boolean isDemarcator( String snippetId, String what, String line )
180 {
181 String upper = line.toUpperCase( Locale.ENGLISH );
182 return upper.contains( what.toUpperCase( Locale.ENGLISH ) )
183 && upper.contains( "SNIPPET" )
184 && line.contains( snippetId );
185 }
186
187 /**
188 * Determines if the given line is an end demarcator.
189 *
190 * @param snippetId the id of the snippet.
191 * @param line the line.
192 * @return True, if the line is an end demarcator.
193 */
194 protected boolean isEnd( String snippetId, String line )
195 {
196 return isDemarcator( snippetId, "END", line );
197 }
198 }