/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.usergrid.chop.plugin;
import java.io.File;
import java.io.FileInputStream;
import java.net.URI;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.usergrid.chop.api.ChopUtils;
import org.apache.usergrid.chop.api.Constants;
import org.apache.usergrid.chop.api.Project;
import org.apache.usergrid.chop.api.ProjectBuilder;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
/**
* This is the parent class for all chop plugin goal classes, takes the configuration parameters from caller
* module's pom and provides extended get methods for several file paths that will be used by extended classes
*/
public class MainMojo extends AbstractMojo implements Constants {
static {
System.setProperty( "javax.net.ssl.trustStore", "jssecacerts" );
}
protected final static Logger LOG = LoggerFactory.getLogger( MainMojo.class );
@Parameter( defaultValue = "${project}", readonly = true )
protected MavenProject project;
@Parameter( defaultValue = "${plugin}", readonly = true )
protected PluginDescriptor plugin;
@Parameter( defaultValue = "${settings.localRepository}" )
protected String localRepository;
/**
* If this parameter is 'true', it causes the plugin goal to fail when there are uncommitted modified
* sources in the local git repository.
*/
@Parameter( property = "failIfCommitNecessary", defaultValue = "false" )
protected boolean failIfCommitNecessary;
/**
* Number of instances that the runner will be running on for tests
*/
@Parameter( property = "runnerCount", defaultValue = "3" )
protected Integer runnerCount;
/**
* Endpoint URL of the coordinator
*/
@Parameter( property = "endpoint", required = true )
protected String endpoint;
/**
* User name that will be used when hitting the coordinator endpoint
*/
@Parameter( property = "username", required = true )
protected String username;
/**
* Password that will be used when hitting the coordinator endpoint
*/
@Parameter( property = "password", required = true )
protected String password;
/**
* This is the package base to use when scanning for chopped tests.
*/
@Parameter( property = "testPackageBase", required = true )
protected String testPackageBase;
/**
* @todo is this still necessary?
*
* Leaving this null will default to the use of "changeit" for the passphrase.
*/
@Parameter( property = "certStorePassphrase" )
protected String certStorePassphrase;
@Parameter( property = "finalName", defaultValue = "${project.artifactId}-${project.version}-chop" )
protected String finalName;
protected static ExecutorService executor;
@Override
public void execute() throws MojoExecutionException {
}
@SuppressWarnings( "UnusedDeclaration" )
protected MainMojo( MainMojo mojo ) {
this.username = mojo.username;
this.password = mojo.password;
this.endpoint = mojo.endpoint;
this.certStorePassphrase = mojo.certStorePassphrase;
this.failIfCommitNecessary = mojo.failIfCommitNecessary;
this.localRepository = mojo.localRepository;
this.plugin = mojo.plugin;
this.project = mojo.project;
this.runnerCount = mojo.runnerCount;
}
protected void initCertStore() {
try {
final URI uri = URI.create( endpoint );
/**
* This is because we are using self-signed uniform certificates for now,
* it should be removed if we switch to a CA signed dynamic certificate scheme!
* */
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier() {
public boolean verify( String hostname, javax.net.ssl.SSLSession sslSession) {
return hostname.equals( uri.getHost() );
}
}
);
if ( certStorePassphrase == null ) {
ChopUtils.installCert( uri.getHost(), uri.getPort(), null );
}
else {
ChopUtils.installCert( uri.getHost(), uri.getPort(), certStorePassphrase.toCharArray() );
}
}
catch ( Exception e ) {
e.printStackTrace();
}
}
protected MainMojo() {
}
public String getProjectOutputJarPath() {
return Utils.forceSlashOnDir( project.getBuild().getDirectory() ) + project.getBuild().getFinalName() +
"." + project.getPackaging();
}
public String getProjectTestOutputJarPath() {
return Utils.forceSlashOnDir( project.getBuild().getDirectory() ) + project.getBuild().getFinalName() +
"-tests.jar";
}
/** @return Returns the project base directory with a '/' at the end */
public String getProjectBaseDirectory() {
return Utils.forceSlashOnDir( project.getBasedir().getAbsolutePath() );
}
/** @return Returns the extracted path of RUNNER_JAR file with a '/' at the end */
public String getExtractedRunnerPath() {
return getProjectBaseDirectory() + "target/runner/";
}
/** @return Returns the full path of created runner.jar file */
public File getRunnerFile() {
return new File( project.getBuild().getDirectory(), finalName + ".jar" );
}
/** @return Returns the full path of created project.json file */
public String getProjectFileToUploadPath() {
return getExtractedRunnerPath() + "WEB-INF/classes/" + PROJECT_FILE;
}
private String getShortUuid() throws MojoExecutionException {
String uuid = Utils.getLastCommitUuid( Utils.getGitConfigFolder( project.getBasedir().getParent() ) );
return uuid.substring( 0, CHARS_OF_UUID/2 ) + uuid.substring( uuid.length() - CHARS_OF_UUID/2 );
}
/** @return Returns the full path of the original chop-runner jar file in the local maven repository */
public String getRunnerInLocalRepo() {
String path = localRepository;
Artifact chopPluginArtifact = plugin.getPluginArtifact();
path += "/" + chopPluginArtifact.getGroupId().replace( '.', '/' ) + "/chop-runner/" +
chopPluginArtifact.getVersion() + "/chop-runner-" + chopPluginArtifact.getVersion() + ".jar";
return path;
}
/**
* Loads the project configuration data if available.
*
* @return the Project for this project or blow chunks
* @throws MojoExecutionException the chunks we blow
*/
public Project loadProjectConfiguration() throws MojoExecutionException {
File projectFile = new File( getProjectFileToUploadPath() );
if ( ! projectFile.exists() ) {
LOG.warn( "It seems as though the project properties file {} does not exist. Creating it and the jar now.",
projectFile );
RunnerMojo runnerMojo = new RunnerMojo( this );
runnerMojo.execute();
if ( projectFile.exists() ) {
LOG.info( "Jar is generated and project file exists." );
}
else {
throw new MojoExecutionException( "Failed to generate the project.properties." );
}
}
// Load the project configuration from the file system
Project project;
try {
Properties props = new Properties();
props.load( new FileInputStream( projectFile ) );
ProjectBuilder builder = new ProjectBuilder( props );
project = builder.getProject();
}
catch ( Exception e ) {
LOG.error( "Error accessing project info from local filesystem: {}", getProjectFileToUploadPath(), e );
throw new MojoExecutionException(
"Cannot access local file system based project information: " + getProjectFileToUploadPath(), e );
}
return project;
}
protected boolean isReadyToDeploy() {
File source = getRunnerFile();
try {
if ( ! source.exists() ) {
return false;
}
File extractedConfigPropFile = new File( getExtractedRunnerPath(), PROJECT_FILE);
if ( extractedConfigPropFile.exists() ) {
Properties props = new Properties();
FileInputStream inputStream = new FileInputStream( extractedConfigPropFile );
props.load( inputStream );
inputStream.close();
String commitId = Utils.getLastCommitUuid( Utils.getGitConfigFolder( getProjectBaseDirectory() ) );
/** If failIfCommitNecessary set to false, no need to force rebuild with different commit id */
return ( ! failIfCommitNecessary ) || commitId.equals( props.getProperty( Project.GIT_UUID_KEY ) );
}
}
catch ( Exception e ) {
LOG.error( "Error while trying to find out if runner file is ready to deploy", e );
}
return false;
}
}