package org.codehaus.mojo.openjpa; /* * 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. */ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.FileUtils; import org.apache.openjpa.lib.util.Options; /** * Base class for OpenJPA maven tasks. * * @author <a href='mailto:struberg@yahoo.de'>Mark Struberg</a> * @version $Id$ */ public abstract class AbstractOpenJpaMojo extends AbstractMojo { /** * Location where <code>persistence-enabled</code> classes are located. * * @parameter expression="${openjpa.classes}" * default-value="${project.build.outputDirectory}" * @required */ protected File classes; /** * Comma separated list of includes to scan searchDir to pass to the jobs. * This may be used to restrict the OpenJPA tasks to e.g. a single package which * contains all the entities. * * @parameter default-value="**\/*.class" */ private String includes; /** * Comma separated list of excludes to scan searchDir to pass to the jobs. * This option may be used to stop OpenJPA tasks from scanning non-JPA classes * (which usually leads to warnings such as "Type xxx has no metadata") * * @parameter default-value=""; */ private String excludes; /** * Additional properties passed to the OpenJPA tools. * * @parameter */ private Properties toolProperties; /** * Used if a non-default file location for the persistence.xml should be used * If not specified, the default one in META-INF/persistence.xml will be used. * Please note that this is not a resource location but a file path! * * @parameter */ private String persistenceXmlFile; /** * <p>This setting can be used to override any openjpa.ConnectionDriverName set in the * persistence.xml. It can also be used if the persistence.xml contains no connection * information at all.<P> * * Sample: * <pre> * <connectionDriverName>com.mchange.v2.c3p0.ComboPooledDataSource</connectionDriverName> * </pre> * * This is most times used in conjunction with {@link #connectionProperties}. * * @parameter */ private String connectionDriverName; /** the string used for passing information about the connectionDriverName */ protected static final String OPTION_CONNECTION_DRIVER_NAME = "ConnectionDriverName"; /** * <p>Used to define the credentials or any other connection properties.</p> * * Sample: * <pre> * <connectionProperties> * driverClass=com.mysql.jdbc.Driver, * jdbcUrl=jdbc:mysql://localhost/mydatabase, * user=root, * password=, * minPoolSize=5, * acquireRetryAttempts=3, * maxPoolSize=20 * </connectionProperties> * </pre> * * This is most times used in conjunction with {@link #connectionDriverName}. * * @parameter */ private String connectionProperties; /** the string used for passing information about the connectionProperties */ protected static final String OPTION_CONNECTION_PROPERTIES = "ConnectionProperties"; /** * List of all class path elements that will be searched for the * <code>persistence-enabled</code> classes and resources expected by * PCEnhancer. * * @parameter default-value="${project.compileClasspathElements}" * @required * @readonly */ protected List compileClasspathElements; /** * Setting this parameter to <code>true</code> will force * the execution of this mojo, even if it would get skipped usually. * * @parameter expression="${forceOpenJpaExecution}" * default-value=false * @required */ private boolean forceMojoExecution; /** * The Maven Project Object * * @parameter default-value="${project}" * @required * @readonly */ protected MavenProject project; /** the properties option is used for passing information about the persistence.xml file location */ protected static final String OPTION_PROPERTIES_FILE = "propertiesFile"; /** * The properties option is used for passing information about the persistence.xml * classpath resource and the default unit */ protected static final String OPTION_PROPERTIES = "properties"; /** * When <code>true</code>, skip the execution. * @since 1.0 * @parameter default-value="false" */ private boolean skip; /** * default ct */ public AbstractOpenJpaMojo() { super(); } /** * The File where the class files of the entities to enhance reside * @return normaly the entity classes are located in target/classes */ protected File getEntityClasses() { return classes; } /** * This function retrieves the injected classpath elements for the current mojo. * @return List of classpath elements for the compile phase */ protected List getClasspathElements() { return compileClasspathElements; } /** * Get the options for the various OpenJPA tools. * @return populated Options */ protected abstract Options getOptions(); /** * <p>Determine if the mojo execution should get skipped.</p> * This is the case if: * <ul> * <li>{@link #skip} is <code>true</code></li> * <li>if the mojo gets executed on a project with packaging type 'pom' and * {@link #forceMojoExecution} is <code>false</code></li> * </ul> * * @return <code>true</code> if the mojo execution should be skipped. */ protected boolean skipMojo() { if ( skip ) { getLog().info( "Skip sql execution" ); return true; } if ( !forceMojoExecution && project != null && "pom".equals( project.getPackaging() ) ) { getLog().info( "Skipping sql execution for project with packaging type 'pom'" ); return true; } return false; } /** * This function will usually get called by {@link #getOptions()} * @return the Options filled with the initial values */ protected Options createOptions() { Options opts = new Options(); if ( toolProperties != null ) { opts.putAll( toolProperties ); } if ( persistenceXmlFile != null ) { opts.put( OPTION_PROPERTIES_FILE, persistenceXmlFile ); getLog().debug( "using special persistence XML file: " + persistenceXmlFile ); } if ( connectionDriverName != null ) { opts.put( OPTION_CONNECTION_DRIVER_NAME, connectionDriverName ); } if ( connectionProperties != null ) { opts.put( OPTION_CONNECTION_PROPERTIES, connectionProperties ); } return opts; } /** * This will prepare the current ClassLoader and add all jars and local * classpaths (e.g. target/classes) needed by the OpenJPA task. * * @throws MojoExecutionException on any error inside the mojo */ protected void extendRealmClasspath() throws MojoExecutionException { List urls = new ArrayList(); for ( Iterator itor = getClasspathElements().iterator(); itor.hasNext(); ) { File pathElem = new File( (String) itor.next() ); try { URL url = pathElem.toURI().toURL(); urls.add( url ); getLog().debug( "Added classpathElement URL " + url ); } catch ( MalformedURLException e ) { throw new MojoExecutionException( "Error in adding the classpath " + pathElem, e ); } } ClassLoader jpaRealm = new URLClassLoader( (URL[]) urls.toArray( new URL[urls.size()] ), getClass().getClassLoader() ); // set the new ClassLoader as default for this Thread Thread.currentThread().setContextClassLoader( jpaRealm ); } /** * Locates and returns a list of class files found under specified class * directory. * * @return list of class files. * @throws MojoExecutionException if there was an error scanning class file * resources. */ protected List findEntityClassFiles() throws MojoExecutionException { List files = new ArrayList(); try { files = FileUtils.getFiles( getEntityClasses(), includes, excludes ); } catch ( IOException e ) { throw new MojoExecutionException( "Error while scanning for '" + includes + "' in " + "'" + getEntityClasses().getAbsolutePath() + "'.", e ); } return files; } /** * @param files List of files * @return the paths of the given files as String[] */ protected String[] getFilePaths( List files ) { String[] args = new String[ files.size() ]; for ( int i = 0; i < files.size(); i++ ) { File file = (File) files.get( i ); args[ i ] = file.getAbsolutePath(); } return args; } }