001    /**************************************************************************************
002     * Copyright (C) 2009 Progress Software, Inc. All rights reserved.                    *
003     * http://fusesource.com                                                              *
004     * ---------------------------------------------------------------------------------- *
005     * The software in this package is published under the terms of the AGPL license      *
006     * a copy of which has been included with this distribution in the license.txt file.  *
007     **************************************************************************************/
008    package org.fusesource.mvnplugins.avro;
009    
010    import java.io.File;
011    import java.io.FileFilter;
012    import java.io.FileWriter;
013    import java.io.IOException;
014    import java.io.Writer;
015    
016    import org.apache.avro.specific.SpecificCompiler;
017    import org.apache.maven.plugin.AbstractMojo;
018    import org.apache.maven.plugin.MojoExecutionException;
019    import org.apache.maven.project.MavenProject;
020    
021    /**
022     * A Maven Mojo so that the Avro compiler can be used with maven.
023     * 
024     * @goal compile
025     * @phase process-sources
026     
027     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
028     */
029    public class AvroMojo extends AbstractMojo {
030    
031        /**
032         * The maven project.
033         * 
034         * @parameter expression="${project}"
035         * @required
036         * @readonly
037         */
038        protected MavenProject project;
039    
040        /**
041         * The directory where the Avro files (<code>*.avpr</code> or <code>*.avsc</code>) are
042         * located.
043         * 
044         * @parameter default-value="${basedir}/src/main/avro"
045         */
046        private File mainSourceDirectory;
047    
048        /**
049         * The directory where the output files will be located.
050         * 
051         * @parameter default-value="${project.build.directory}/generated-sources/avro"
052         */
053        private File mainOutputDirectory;
054        
055        /**
056         * The directory where the Avro files (<code>*.avpr</code> or <code>*.avsc</code>) are
057         * located.
058         * 
059         * @parameter default-value="${basedir}/src/test/avro"
060         */
061        private File testSourceDirectory;
062    
063        /**
064         * The directory where the output files will be located.
065         * 
066         * @parameter default-value="${project.build.directory}/test-generated-sources/avro"
067         */
068        private File testOutputDirectory;
069    
070        public void execute() throws MojoExecutionException {
071    
072            File[] mainFiles = null;
073            if ( mainSourceDirectory.exists() ) {
074                mainFiles = mainSourceDirectory.listFiles(new FileFilter() {
075                    public boolean accept(File pathname) {
076                        String name = pathname.getName();
077                        return name.endsWith(".avsc") || name.endsWith(".avpr");
078                    }
079                });
080                if (mainFiles==null || mainFiles.length==0) {
081                    getLog().warn("No avro files found in directory: " + mainSourceDirectory.getPath());
082                } else {
083                    processFiles(mainFiles, mainOutputDirectory);
084                    this.project.addCompileSourceRoot(mainOutputDirectory.getAbsolutePath());
085                }
086            }
087            
088            File[] testFiles = null;
089            if ( testSourceDirectory.exists() ) {
090                testFiles = testSourceDirectory.listFiles(new FileFilter() {
091                    public boolean accept(File pathname) {
092                        String name = pathname.getName();
093                        return name.endsWith(".avsc") || name.endsWith(".avpr");
094                    }
095                });
096                if (testFiles==null || testFiles.length==0) {
097                    getLog().warn("No avro files found in directory: " + testSourceDirectory.getPath());
098                } else {
099                    processFiles(testFiles, testOutputDirectory);
100                    this.project.addTestCompileSourceRoot(testOutputDirectory.getAbsolutePath());
101                }
102            }
103        }
104    
105    
106        static private String uCamel(String name) {
107            boolean upNext=true;
108            StringBuilder sb = new StringBuilder();
109            for (int i = 0; i < name.length(); i++) {
110                char c = name.charAt(i);
111                if( Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) {
112                    if( upNext ) {
113                        c = Character.toUpperCase(c);
114                        upNext=false;
115                    }
116                    sb.append(c);
117                } else {
118                    upNext=true;
119                }
120            }
121            return sb.toString();
122        }
123        
124        private void processFiles(File[] mainFiles, File outputDir) throws MojoExecutionException {
125            for (File file : mainFiles) {
126                try {
127                    
128                    getLog().info("Compiling: "+file.getPath());
129                    SpecificCompiler compiler;
130                    if( file.getName().endsWith(".avpr") ) {
131                        compiler = SpecificCompiler.compileProtocol(file);
132                    } else if( file.getName().endsWith(".avsc") ) {
133                        compiler = SpecificCompiler.compileSchema(file);
134                    } else {
135                        throw new RuntimeException("Unhandled file type: "+file.getName());
136                    }
137                    
138                    String targetName = file.getName();
139                    targetName = targetName.substring(0, targetName.indexOf('.'));
140                    targetName = uCamel(targetName)+ ".java";
141                    
142                    File target;
143                    
144                    String namespace = compiler.getNamespace();
145                    if (namespace == null || namespace.length() == 0) {
146                        target = new File(outputDir, targetName);
147                    } else {
148                        target = new File(new File(outputDir, namespace.replace('.', File.separatorChar)), targetName);
149                    }
150                    target.getParentFile().mkdirs();
151                    
152                    getLog().info("  writting: "+target.getPath());
153                    
154                    Writer out = new FileWriter(target);
155                    try {
156                        out.write(compiler.getCode());
157                    } finally {
158                        out.close();
159                    }   
160                   
161                } catch (IOException e) {
162                    throw new MojoExecutionException("Avro compile failed.", e);
163                }
164            }
165        }
166    
167    }