001/*
002 * The Kuali Financial System, a comprehensive financial management system for higher education.
003 *
004 * Copyright 2005-2014 The Kuali Foundation
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU Affero General Public License as
008 * published by the Free Software Foundation, either version 3 of the
009 * License, or (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU Affero General Public License for more details.
015 *
016 * You should have received a copy of the GNU Affero General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019import java.io.BufferedReader;
020import java.io.BufferedWriter;
021import java.io.File;
022import java.io.FileReader;
023import java.io.FileWriter;
024import java.io.IOException;
025import java.io.StringReader;
026import java.util.ArrayList;
027import java.util.Collection;
028import java.util.List;
029
030import org.apache.commons.io.DirectoryWalker;
031import org.apache.commons.io.FileUtils;
032import org.apache.commons.io.filefilter.FileFilterUtils;
033import org.apache.commons.io.filefilter.HiddenFileFilter;
034import org.apache.commons.io.filefilter.IOFileFilter;
035
036public class LicenseHeaderUpdate {
037
038    public static final String AGPL_LICENSE_TEXT = "The Kuali Financial System, a comprehensive financial management system for higher education.\n" +
039            "\n" +
040            "Copyright 2005-2014 The Kuali Foundation\n" +
041            "\n" +
042            "This program is free software: you can redistribute it and/or modify\n" +
043            "it under the terms of the GNU Affero General Public License as\n" +
044            "published by the Free Software Foundation, either version 3 of the\n" +
045            "License, or (at your option) any later version.\n" +
046            "\n" +
047            "This program is distributed in the hope that it will be useful,\n" +
048            "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +
049            "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" +
050            "GNU Affero General Public License for more details.\n" +
051            "\n" +
052            "You should have received a copy of the GNU Affero General Public License\n" +
053            "along with this program.  If not, see <http://www.gnu.org/licenses/>.";
054
055    static final String LINE_SEPARATOR = System.getProperty("line.separator");
056
057    private static final List<String> blacklistedFiles = new ArrayList<String>();
058
059    /**
060     *
061     * @param args
062     */
063    public static void main(String[] args) throws Exception {
064        setupBlackList();
065        handleJavaStyleComments( args[0] );
066        handleJSPStyleComments( args[0] );
067        handleXMLStyleComments( args[0] );
068        handlePropertyStyleComments( args[0] );
069        handleSQLStyleComments( args[0] );
070    }
071
072    public static void setupBlackList() {
073        blacklistedFiles.add("build"+File.separator+"project"+File.separator+"OJB-logging.properties");
074        blacklistedFiles.add("build"+File.separator+"project"+File.separator+"OJB.properties");
075        blacklistedFiles.add("work"+File.separator+"db"+File.separator+"kfs-db"+File.separator+"db-impex"+File.separator+"impex"+File.separator+"src"+File.separator+"org"+File.separator+"kuali"+File.separator+"core"+File.separator+"db"+File.separator+"torque"+File.separator+"KualiDatabase.java");
076        blacklistedFiles.add("work"+File.separator+"src"+File.separator+"org"+File.separator+"springframework"+File.separator+"beans"+File.separator+"factory"+File.separator+"support"+File.separator+"DefaultListableBeanFactory.java");
077    }
078
079    public static void handleJavaStyleComments( String baseDir ) throws Exception {
080        IOFileFilter sourceFileFilter = FileFilterUtils.orFileFilter(
081                FileFilterUtils.suffixFileFilter("java"),
082                FileFilterUtils.suffixFileFilter("js") );
083        sourceFileFilter = FileFilterUtils.orFileFilter(
084                sourceFileFilter,
085                FileFilterUtils.suffixFileFilter("css") );
086        sourceFileFilter = FileFilterUtils.orFileFilter(
087                sourceFileFilter,
088                FileFilterUtils.suffixFileFilter("groovy") );
089        sourceFileFilter = FileFilterUtils.makeSVNAware(sourceFileFilter);
090        sourceFileFilter = FileFilterUtils.makeFileOnly(sourceFileFilter);
091
092        LicensableFileDirectoryWalker dw = new LicensableFileDirectoryWalker(sourceFileFilter, "/*", " * ", " */");
093        Collection<String> results = dw.run( baseDir );
094        System.out.println( results );
095    }
096
097    public static void handleJSPStyleComments( String baseDir ) throws Exception {
098        IOFileFilter sourceFileFilter = FileFilterUtils.orFileFilter(
099                FileFilterUtils.suffixFileFilter("jsp"),
100                FileFilterUtils.suffixFileFilter("tag") );
101        sourceFileFilter = FileFilterUtils.orFileFilter(
102                sourceFileFilter,
103                FileFilterUtils.suffixFileFilter("inc") );
104        sourceFileFilter = FileFilterUtils.makeSVNAware(sourceFileFilter);
105        sourceFileFilter = FileFilterUtils.makeFileOnly(sourceFileFilter);
106
107        LicensableFileDirectoryWalker dw = new LicensableFileDirectoryWalker(sourceFileFilter, "<%--", "   - ", "--%>");
108        Collection<String> results = dw.run( baseDir );
109        System.out.println( results );
110    }
111
112    public static void handlePropertyStyleComments( String baseDir ) throws Exception {
113        IOFileFilter sourceFileFilter = FileFilterUtils.orFileFilter(
114                FileFilterUtils.suffixFileFilter("properties"),
115                FileFilterUtils.suffixFileFilter("cmd") );
116        sourceFileFilter = FileFilterUtils.orFileFilter(
117                sourceFileFilter,
118                FileFilterUtils.suffixFileFilter("sh") );
119        sourceFileFilter = FileFilterUtils.makeSVNAware(sourceFileFilter);
120        sourceFileFilter = FileFilterUtils.makeFileOnly(sourceFileFilter);
121
122        LicensableFileDirectoryWalker dw = new LicensableFileDirectoryWalker(sourceFileFilter, "########################################", "# ", "########################################");
123        Collection<String> results = dw.run( baseDir );
124        System.out.println( results );
125    }
126
127    public static void handleSQLStyleComments( String baseDir ) throws Exception {
128        IOFileFilter sourceFileFilter = FileFilterUtils.suffixFileFilter("sql");
129        sourceFileFilter = FileFilterUtils.makeSVNAware(sourceFileFilter);
130        sourceFileFilter = FileFilterUtils.makeFileOnly(sourceFileFilter);
131
132        LicensableFileDirectoryWalker dw = new LicensableFileDirectoryWalker(sourceFileFilter, "--", "-- ", LINE_SEPARATOR);
133        Collection<String> results = dw.run( baseDir );
134        System.out.println( results );
135    }
136
137    public static void handleXMLStyleComments( String baseDir ) throws Exception {
138        IOFileFilter sourceFileFilter = FileFilterUtils.orFileFilter(
139                FileFilterUtils.suffixFileFilter("xml"),
140                FileFilterUtils.suffixFileFilter("jrxml") );
141        sourceFileFilter = FileFilterUtils.orFileFilter(
142                sourceFileFilter,
143                FileFilterUtils.suffixFileFilter("html") );
144        sourceFileFilter = FileFilterUtils.orFileFilter(
145                sourceFileFilter,
146                FileFilterUtils.suffixFileFilter("htm") );
147        sourceFileFilter = FileFilterUtils.orFileFilter(
148                sourceFileFilter,
149                FileFilterUtils.suffixFileFilter("xsd") );
150        sourceFileFilter = FileFilterUtils.orFileFilter(
151                sourceFileFilter,
152                FileFilterUtils.suffixFileFilter("tld") );
153        sourceFileFilter = FileFilterUtils.makeSVNAware(sourceFileFilter);
154        sourceFileFilter = FileFilterUtils.makeFileOnly(sourceFileFilter);
155
156        LicensableFileDirectoryWalker dw = new LicensableFileDirectoryWalker(sourceFileFilter, "<!--", "   - ", " -->");
157        Collection<String> results = dw.run( baseDir );
158        System.out.println( results );
159    }
160
161    public static class LicensableFileDirectoryWalker extends DirectoryWalker {
162
163        String firstLine;
164        String lastLine;
165        String linePrefix;
166
167        public LicensableFileDirectoryWalker( IOFileFilter fileFilter, String firstLine, String linePrefix, String lastLine ) {
168            super(HiddenFileFilter.VISIBLE,fileFilter,100);
169            this.firstLine = firstLine;
170            this.linePrefix = linePrefix;
171            this.lastLine = lastLine;
172        }
173        @Override
174        protected void handleDirectoryStart(File directory, int depth, @SuppressWarnings("rawtypes") Collection results) throws IOException {
175            System.out.println( "Directory: " + directory.getAbsolutePath() );
176        }
177        @Override
178        protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
179            if ( directory.getAbsolutePath().endsWith("WEB-INF"+File.separator+"classes") ) {
180                return false;
181            }
182            if ( directory.getAbsolutePath().endsWith("test"+File.separator+"classes") ) {
183                return false;
184            }
185            if ( directory.getAbsolutePath().endsWith("build"+File.separator+"tomcat") ) {
186                return false;
187            }
188            if ( directory.getAbsolutePath().endsWith("build"+File.separator+"rice-datadictionary") ) {
189                return false;
190            }
191            if ( directory.getAbsolutePath().endsWith("kr"+File.separator+"static"+File.separator+"help") ) {
192                return false;
193            }
194            if ( directory.getName().equals("META-INF") ) {
195                return false;
196            }
197            return true;
198        }
199        @Override
200        protected void handleFile(File file, int depth, @SuppressWarnings("rawtypes") Collection results) throws IOException {
201            if (isBlacklisted(file.getAbsolutePath())) {
202                System.err.println( "Found blacklisted file, skipping file: " + file.getAbsolutePath() );
203                results.add("FILE SKIPPED - BLACKLISTED: " + file.getAbsolutePath() );
204                return;
205            }
206            System.out.println( "Handing File: " + file.getAbsolutePath() );
207            BufferedReader r = new BufferedReader(new FileReader( file ) );
208            String currentLine = null;
209            String savedFirstLine = null;
210            // check the initial line of the file
211            String line1 = r.readLine();
212            // if the file is empty, just skip
213            if ( line1 == null ) {
214                results.add("FILE SKIPPED - EMPTY: " + file.getAbsolutePath() );
215                return;
216            }
217            if ( line1.startsWith("<?") ) { // special hack for XML files
218                savedFirstLine = line1;
219                line1 = r.readLine();
220            }
221            if ( line1.trim().equals(firstLine.trim()) ) {
222                // if found, skip until find a line containing the lastLine
223                while ( (currentLine = r.readLine()) != null ) {
224                    // throw away the lines
225                    if ( currentLine.trim().equals(lastLine.trim()) ) {
226                        break;
227                    }
228                }
229                if ( currentLine == null ) {
230                    // we reached the end of the file before finding the end of the comment, ABORT!
231                    System.err.println( "Unable to find end of existing header section, skipping file: " + file.getAbsolutePath() );
232                    results.add("FILE SKIPPED - UNABLE TO FIND END OF HEADER: " + file.getAbsolutePath() );
233                    return;
234                }
235            }
236            File outputFile = new File( file.getAbsolutePath() + "-out" );
237            BufferedWriter w = new BufferedWriter( new FileWriter( outputFile ) );
238            if ( savedFirstLine != null ) {
239                w.write( savedFirstLine );
240                w.write( LINE_SEPARATOR );
241            }
242            // now, write the new header file
243            w.write( firstLine );
244            w.write( LINE_SEPARATOR );
245            BufferedReader headerReader = new BufferedReader( new StringReader( AGPL_LICENSE_TEXT ) );
246            while ( (currentLine = headerReader.readLine()) != null ) {
247                w.write( linePrefix );
248                w.write( currentLine );
249                w.write( LINE_SEPARATOR );
250            }
251            if ( lastLine.equals(LINE_SEPARATOR) ) { // special hack for SQL files
252                w.write("--" + LINE_SEPARATOR);
253                w.write( LINE_SEPARATOR );
254            } else {
255                w.write( lastLine );
256                w.write( LINE_SEPARATOR );
257            }
258            headerReader.close();
259            if ( !line1.trim().equals(firstLine.trim()) ) {
260                w.write( line1 );
261                w.write( LINE_SEPARATOR );
262            }
263
264            while ( (currentLine = r.readLine()) != null ) {
265                w.write(currentLine);
266                w.write(LINE_SEPARATOR);
267            }
268            // delete the original file and replace with the completed output file
269            w.close();
270            r.close();
271            FileUtils.deleteQuietly(file);
272            FileUtils.moveFile(outputFile, file);
273        }
274        public Collection<String> run( String projectDir ) throws IOException {
275            Collection<String> results = new ArrayList<String>();
276            walk( new File( projectDir ), results );
277            return results;
278        }
279        protected boolean isBlacklisted(String file) {
280            for (String str : blacklistedFiles) {
281                if (file.endsWith(str)) {
282                    return true;
283                }
284            }
285            return false;
286        }
287    }
288}