001    /**
002     * Copyright 2010-2012 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.codehaus.mojo.license.header.transformer;
017    
018    
019    import org.apache.commons.lang.StringUtils;
020    import org.codehaus.mojo.license.header.FileHeader;
021    
022    import java.util.regex.Matcher;
023    import java.util.regex.Pattern;
024    
025    /**
026     * Abstract implementation of {@link FileHeaderTransformer}.
027     * <p/>
028     * Concrete implementation should only have to give comment configuration.
029     *
030     * @author tchemit <chemit@codelutin.com>
031     * @since 1.0
032     */
033    public abstract class AbstractFileHeaderTransformer
034        implements FileHeaderTransformer
035    {
036    
037        /**
038         * pattern of the copyright string representation :
039         * <ul>
040         * <li>group(1) is Copyright prefix</li>
041         * <li>group(2) is Copyright first year</li>
042         * <li>group(3) is Copyright last year with prefix (can be null)</li>
043         * <li>group(4) is Copyright last year (can be null)</li>
044         * <li>group(5) is Copyright holder</li>
045         * </ul>
046         */
047        protected static final Pattern COPYRIGHT_PATTERN =
048            Pattern.compile( "(.[^\\d]+)?\\s(\\d{4})?(\\s+-\\s+(\\d{4})?){0,1}\\s+(.+)?" );
049    
050        /**
051         * name of transformer
052         */
053        protected String name;
054    
055        /**
056         * description of transfomer
057         */
058        protected String description;
059    
060        /**
061         * section delimiter
062         */
063        protected String sectionDelimiter = DEFAULT_SECTION_DELIMITER;
064    
065        /**
066         * start process tag
067         */
068        protected String processStartTag = DEFAULT_PROCESS_START_TAG;
069    
070        /**
071         * end process tag
072         */
073        protected String processEndTag = DEFAULT_PROCESS_END_TAG;
074    
075        /**
076         * comment start tag
077         */
078        protected String commentStartTag;
079    
080        /**
081         * comment end tag
082         */
083        protected String commentEndTag;
084    
085        /**
086         * comment line prefix (to add for header content)
087         */
088        protected String commentLinePrefix;
089    
090        protected AbstractFileHeaderTransformer( String name, String description, String commentStartTag,
091                                                 String commentEndTag, String commentLinePrefix )
092        {
093            this.name = name;
094            this.description = description;
095    
096            // checks comment start tag is different from comment prefix
097            if ( commentStartTag.equals( commentLinePrefix ) )
098            {
099                throw new IllegalStateException(
100                    "commentStartTag can not be equals to commentPrefixLine, " + "but was [" + commentStartTag + "]" );
101            }
102    
103            // checks comment end tag is different from comment prefix
104            if ( commentEndTag.equals( commentLinePrefix ) )
105            {
106                throw new IllegalStateException(
107                    "commentEndTag can not be equals to commentPrefixLine, " + "but was [" + commentEndTag + "]" );
108            }
109    
110            this.commentStartTag = commentStartTag;
111            this.commentEndTag = commentEndTag;
112            this.commentLinePrefix = commentLinePrefix;
113        }
114    
115        public String getName()
116        {
117            return name;
118        }
119    
120        public void setName( String name )
121        {
122            this.name = name;
123        }
124    
125        public String getDescription()
126        {
127            return description;
128        }
129    
130        public void setDescription( String description )
131        {
132            this.description = description;
133        }
134    
135        public String getSectionDelimiter()
136        {
137            return sectionDelimiter;
138        }
139    
140        public void setSectionDelimiter( String sectionDelimiter )
141        {
142            this.sectionDelimiter = sectionDelimiter;
143        }
144    
145        public String getProcessStartTag()
146        {
147            return processStartTag;
148        }
149    
150        public void setProcessStartTag( String processStartTag )
151        {
152            this.processStartTag = processStartTag;
153        }
154    
155        public String getProcessEndTag()
156        {
157            return processEndTag;
158        }
159    
160        public void setProcessEndTag( String processEndTag )
161        {
162            this.processEndTag = processEndTag;
163        }
164    
165        public String getCommentStartTag()
166        {
167            return commentStartTag;
168        }
169    
170        public void setCommentStartTag( String commentStartTag )
171        {
172            this.commentStartTag = commentStartTag;
173        }
174    
175        public String getCommentEndTag()
176        {
177            return commentEndTag;
178        }
179    
180        public void setCommentEndTag( String commentEndTag )
181        {
182            this.commentEndTag = commentEndTag;
183        }
184    
185        public String getCommentLinePrefix()
186        {
187            return commentLinePrefix;
188        }
189    
190        public String addHeader( String header, String content )
191        {
192            return header + content;
193        }
194    
195        public void setCommentLinePrefix( String commentLinePrefix )
196        {
197            this.commentLinePrefix = commentLinePrefix;
198        }
199    
200        public FileHeader toFileHeader( String header )
201        {
202            FileHeader model = new FileHeader();
203    
204            String[] sections = header.split( getSectionDelimiter() );
205            if ( sections.length != 3 )
206            {
207                throw new IllegalStateException( "could not find 3 sections in\n" + header );
208            }
209    
210            // first section is the description
211            String description = sections[0].trim();
212            model.setDescription( description );
213    
214            // second section is the copyright
215            String copyright = sections[1].trim();
216            Matcher matcher = COPYRIGHT_PATTERN.matcher( copyright );
217            if ( !matcher.matches() )
218            {
219                throw new IllegalStateException( "copyright [" + copyright + "] is not valid" );
220            }
221            String firstYear = matcher.group( 2 );
222            String lastYear = matcher.group( 4 );
223            String holder = matcher.group( 5 );
224            model.setCopyrightFirstYear( Integer.valueOf( firstYear.trim() ) );
225            if ( lastYear != null )
226            {
227                model.setCopyrightLastYear( Integer.valueOf( lastYear.trim() ) );
228            }
229            model.setCopyrightHolder( holder.trim() );
230    
231            // third section is the license
232            String license = sections[2].trim();
233            model.setLicense( license );
234            return model;
235        }
236    
237        public String toString( FileHeader model )
238            throws NullPointerException
239        {
240            if ( model == null )
241            {
242                throw new NullPointerException( "model can not be null!" );
243            }
244            StringBuilder buffer = new StringBuilder();
245    
246            String sectionDelimiter = LINE_SEPARATOR + getSectionDelimiter() + LINE_SEPARATOR;
247    
248            // add description section
249            buffer.append( model.getDescription().trim() );
250            buffer.append( sectionDelimiter );
251    
252            // add copyright section
253            buffer.append( model.getCopyright().trim() );
254            buffer.append( sectionDelimiter );
255    
256            // add license section
257            buffer.append( model.getLicense().trim() ).append( LINE_SEPARATOR );
258            return buffer.toString();
259        }
260    
261        public String toHeaderContent( FileHeader model )
262            throws NullPointerException
263        {
264    
265            String result;
266    
267            // model to text
268            result = toString( model );
269    
270            // box with process tag
271            result = boxProcessTag( result );
272    
273            // box header with comment prefix
274            result = boxComment( result, false );
275    
276            // remove all before process start tag
277            // remove all after process end tag
278            // this is a requirement for processor to respect involution.
279            int index = result.indexOf( getProcessStartTag() );
280            int lastIndex = result.lastIndexOf( getProcessEndTag() ) + getProcessEndTag().length();
281    
282            result = result.substring( index, lastIndex );
283            return result;
284        }
285    
286        public String boxComment( String header, boolean withTags )
287        {
288            StringBuilder buffer = new StringBuilder();
289            if ( withTags )
290            {
291                buffer.append( getCommentStartTag() ).append( LINE_SEPARATOR );
292            }
293            for ( String line : header.split( LINE_SEPARATOR + "" ) )
294            {
295                buffer.append( getCommentLinePrefix() );
296                buffer.append( line );
297                buffer.append( LINE_SEPARATOR );
298            }
299            if ( withTags )
300            {
301                buffer.append( getCommentEndTag() ).append( LINE_SEPARATOR );
302            }
303            return buffer.toString();
304        }
305    
306        public String unboxComent( String header )
307        {
308            StringBuilder buffer = new StringBuilder();
309            int prefixLength = getCommentLinePrefix().length();
310            for ( String line : header.split( LINE_SEPARATOR + "" ) )
311            {
312                if ( StringUtils.isEmpty( line ) || line.contains( getCommentStartTag() ) ||
313                    line.contains( getCommentEndTag() ) )
314                {
315    
316                    // not be unboxed, but just skipped
317                    continue;
318                }
319                int index = line.indexOf( getCommentLinePrefix() );
320                if ( index > -1 )
321                {
322    
323                    // remove comment prefix
324                    line = line.substring( index + prefixLength );
325                }
326                else
327                {
328                    String s = getCommentLinePrefix().trim();
329                    if ( line.startsWith( s ) )
330                    {
331                        if ( line.length() <= s.length() )
332                        {
333                            line = "";
334                        }
335                    }
336                    else
337                    {
338                        line = line.substring( s.length() );
339                    }
340                }
341                buffer.append( line ).append( LINE_SEPARATOR );
342            }
343            return buffer.toString();
344        }
345    
346        public String boxProcessTag( String header )
347        {
348            StringBuilder buffer = new StringBuilder();
349            buffer.append( getProcessStartTag() ).append( LINE_SEPARATOR );
350            buffer.append( header.trim() ).append( LINE_SEPARATOR );
351            buffer.append( getProcessEndTag() ).append( LINE_SEPARATOR );
352            return buffer.toString();
353        }
354    
355        public String unboxProcessTag( String boxedHeader )
356        {
357            StringBuilder buffer = new StringBuilder();
358            for ( String line : boxedHeader.split( LINE_SEPARATOR + "" ) )
359            {
360                if ( StringUtils.isEmpty( line ) || line.contains( getProcessStartTag() ) ||
361                    line.contains( getProcessEndTag() ) )
362                {
363    
364                    // not be unboxed, but just skipped
365                    continue;
366                }
367                buffer.append( line ).append( LINE_SEPARATOR );
368            }
369            return buffer.toString();
370        }
371    
372        public boolean isDescriptionEquals( FileHeader header1, FileHeader header2 )
373        {
374            return header1.getDescription().equals( header2.getDescription() );
375        }
376    
377        public boolean isCopyrightEquals( FileHeader header1, FileHeader header2 )
378        {
379            return header1.getCopyright().equals( header2.getCopyright() );
380        }
381    
382        public boolean isLicenseEquals( FileHeader header1, FileHeader header2 )
383        {
384            String license1 = removeSpaces( header1.getLicense() );
385            String license2 = removeSpaces( header2.getLicense() );
386            return license1.equals( license2 );
387        }
388    
389        protected static final Pattern REMOVE_SPACE_PATTERN = Pattern.compile( "(\\s+)" );
390    
391        protected String removeSpaces( String str )
392        {
393            Matcher matcher = REMOVE_SPACE_PATTERN.matcher( str );
394            String result;
395            if ( matcher.find() )
396            {
397                result = matcher.replaceAll( "" );
398            }
399            else
400            {
401                result = str;
402            }
403            return result;
404        }
405    }