/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2015 Wisdom Framework
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.wisdom.source.mojo;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseException;
import com.github.javaparser.ast.CompilationUnit;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.wisdom.maven.Constants;
import org.wisdom.maven.WatchingException;
import org.wisdom.maven.mojos.AbstractWisdomWatcherMojo;
import org.wisdom.maven.utils.WatcherUtils;
import org.wisdom.source.ast.model.ControllerModel;
import org.wisdom.source.ast.visitor.ClassSourceVisitor;
import org.wisdom.source.ast.visitor.ControllerSourceVisitor;
import java.io.File;
import java.io.IOException;
/**
* <p>
* Abstract Mojo that extends {@link AbstractWisdomWatcherMojo}. It watch the wisdom source file and create a Java model
* from them thanks to the {@link JavaParser}.
*
* It call the method {@link #controllerParsed(File, ControllerModel)} each time a controller
* has been modified and its model made.
* </p>
*
* @param <T> The type of the object that will be passed to the visitor along the visit of the ControllerModel.
*/
public abstract class AbstractWisdomSourceWatcherMojo<T> extends AbstractWisdomWatcherMojo implements Constants{
/**
* Location of the project Java sources.
*/
protected File javaSourceDir;
/**
* Visit the Controller java source in order to create the Controller model.
*/
private static final ControllerSourceVisitor CONTROLLER_VISITOR = new ControllerSourceVisitor();
private static final ClassSourceVisitor CLASS_VISITOR = new ClassSourceVisitor();
/**
* Create a model for each wisdom controller available in the java source directory and call
* {@link #controllerParsed(File, ControllerModel)} for each of them.
*
* @throws MojoExecutionException when an exception occurred while creating the raml file.
* @throws MojoFailureException {@inheritDoc}
*/
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
javaSourceDir = WatcherUtils.getJavaSource(basedir);
try {
for (File file : FileUtils.listFiles(javaSourceDir, new String[]{"java"}, true)) {
if (accept(file)) {
parseController(file);
}
}
}catch (Exception we){
throw new MojoExecutionException("An exception occurred while created raml file",we);
}
}
/**
* Parse the source file of a wisdom Controller and create a model from it.
* Call {@link #controllerParsed(File, ControllerModel)}.
*
* @param file the controller source file.
* @throws WatchingException
*/
public void parseController(File file) throws WatchingException{
ControllerModel<T> controllerModel = new ControllerModel<>();
//Populate the controller model by visiting the File
try {
JavaParser.parse(file).accept(CONTROLLER_VISITOR,controllerModel);
} catch (ParseException |IOException e) {
throw new WatchingException("Cannot parse "+file.getName(), e);
}
//Call children once the controller has been parsed
controllerParsed(file, controllerModel);
}
/**
* Check if we can create a model from the given source.
*
* @param file {@link File} required to be processed by this plugin.
* @return <code>true</code> if the <code>file</code> implements
* {@link org.wisdom.api.Controller}, <code>false</code> otherwise.
*/
public boolean accept(File file) {
if( !WatcherUtils.isInDirectory(file, javaSourceDir) || !WatcherUtils.hasExtension(file,"java")){
return false;
}
// If the file has been deleted by may have been a controller, return true.
// The cleanup will be applied.
if (! file.isFile()) {
return true;
}
//Parse the Java File and check if it's a wisdom Controller
try {
final CompilationUnit parse = JavaParser.parse(file);
// The visitor return a Boolean object, potentially null.
final Boolean accept = parse.accept(CLASS_VISITOR, null);
return accept != null && accept;
} catch (Exception e) {
getLog().error("Cannot parse " + file.getAbsolutePath(), e);
return false;
}
}
/**
* Create a model for the new controller and call {@link #controllerParsed(File, ControllerModel)}.
*
* @param file The source file that has created.
* @return {@inheritDoc}
* @throws WatchingException {@inheritDoc}
*/
@Override
public boolean fileCreated(File file) throws WatchingException {
parseController(file);
return true;
}
/**
* Create a new model for the controller that has been modified and
* call {@link #controllerParsed(File, ControllerModel)}.
*
* @param file the controller that has been updated.
* @return {@inheritDoc}
* @throws WatchingException {@inheritDoc}
*/
@Override
public boolean fileUpdated(File file) throws WatchingException {
parseController(file);
return true;
}
/**
* Is called when the controller source has been properly visited and its model created.
*
* @param source The file source
* @param model The model of the source
* @throws WatchingException
*/
public abstract void controllerParsed(File source, ControllerModel<T> model) throws WatchingException;
}