001    // Copyright 2007 by Basil Vandegriend.  All rights reserved.
002    package com.basilv.envgen;
003    
004    import java.io.BufferedReader;
005    import java.io.IOException;
006    import java.io.StringReader;
007    import java.io.Writer;
008    import java.util.Map;
009    
010    import freemarker.template.TemplateModelException;
011    import freemarker.template.TemplateTransformModel;
012    
013    /**
014     * Template to format input into a form acceptable for mainframes.
015     * The formatting changes that are made are:
016     * <ul>
017     * <li>Convert tabs to spaces (4 spaces per tab)</li>
018     * <li>Trim whitespace from end of line</li>
019     * <li>Fail with error message if a line is longer than 75 characters</li>
020     * </ul>
021     */
022    public class MainframeFileFormatTransform implements TemplateTransformModel {
023    
024            static final int MAX_LINE_LENGTH = 75;
025    
026            /**
027             * Must have a default no-arg constructor.
028             */
029        public MainframeFileFormatTransform() {
030        }
031    
032    
033        public Writer getWriter(final Writer out, Map args) throws TemplateModelException {
034    
035            // If you want to handle arguments to the transform, this is where it is done.
036            // Any variables must be stored in the writer instance below and not in the main transform class.
037            
038            final StringBuffer buffer = new StringBuffer();
039                    return new Writer() {
040                            public void write(char cbuf[], int off, int len) {
041                                    buffer.append(cbuf, off, len);
042                            }
043    
044                            public void flush() throws IOException {
045                                    out.flush();
046                            }
047                            
048                            public void close() throws IOException {
049                                    StringBuffer transformedBuffer = transform(buffer);
050                                    out.write(transformedBuffer.toString());
051                                    out.flush();
052                            }
053    
054                    };      
055        }
056        
057        // Non-private for testing
058            static StringBuffer transform(StringBuffer inputBuffer) throws IOException {
059                    BufferedReader reader = new BufferedReader(new StringReader(inputBuffer.toString()));
060                    StringBuffer outputBuffer = new StringBuffer(inputBuffer.length());
061                    try {
062                            int lineNumber = 0;
063                            String line = reader.readLine();
064                            while (line != null) {
065                                    lineNumber++;
066    
067                                    String transformedLine = transformLine(line, lineNumber);
068                                    outputBuffer.append(transformedLine);
069                                    outputBuffer.append("\n"); // since removed by readLine().
070    
071                                    line = reader.readLine();                               
072                            }
073                            
074                    } finally {
075                            reader.close();
076                    }
077                    
078                    return outputBuffer;
079            }
080    
081    
082            // Non-private for testing.
083        static String transformLine(String line, int lineNumber) {
084    
085                    if (line.length() == 0) {
086                            return line;
087                    }
088    
089                    // Convert tabs to spaces
090                    String newLine = line.replaceAll("\t", "    ");
091    
092            // Trim ending whitespace
093            int lastNonWhitespaceIndex = newLine.length() - 1;
094            while (Character.isWhitespace(newLine.charAt(lastNonWhitespaceIndex))) {
095                    lastNonWhitespaceIndex --;
096                    if (lastNonWhitespaceIndex < 0) {
097                            // Line is nothing but whitespace
098                            return "";
099                    }
100            }
101            newLine = newLine.substring(0, lastNonWhitespaceIndex+1);
102            
103            if (newLine.length() > MAX_LINE_LENGTH) {
104                    throw new RuntimeException("Line #" + lineNumber + 
105                                    " is longer than the maximum of " + MAX_LINE_LENGTH + 
106                                    " characters. Line content = [" + line + "].");
107            }
108    
109            return newLine;
110        }
111        
112    }