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 org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.plexus.util.FileUtils;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
import org.apache.openjpa.jdbc.meta.MappingTool;
import org.apache.openjpa.lib.conf.Configurations;
import org.apache.openjpa.lib.meta.ClassArgParser;
import org.apache.openjpa.lib.util.Options;
import org.apache.openjpa.meta.MetaDataRepository;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import javax.persistence.Entity;
/**
* Processes Application model classes and generate the DDL by running the
* OpenJPA MappingTool.
*
* We have to split the generation of the SQL files and the mapping info
* into 2 separate mojos, since the MappingTool struggles to generate both
* in one step.
*
* @author <a href='mailto:struberg@yahoo.de'>Mark Struberg</a>
* @version $Id$
* @since 1.0
*/
public abstract class AbstractOpenJpaMappingToolMojo
extends AbstractOpenJpaMojo
{
/**
* Argument to specify the action to take on each class. The available actions are:
* buildSchema, validate
* @parameter
*/
protected String action;
/** used for passing the action parameter to the mapping tool */
protected static final String OPTION_ACTION = "action";
/**
* {@inheritDoc}
*
* @see org.apache.maven.plugin.Mojo#execute()
*/
public void execute()
throws MojoExecutionException, MojoFailureException
{
if ( skipMojo() )
{
return;
}
if ( !getEntityClasses().exists() )
{
FileUtils.mkdir( getEntityClasses().getAbsolutePath() );
}
List entities = findEntityClassFiles();
mappingTool( entities );
}
/**
* Processes a list of class file resources and perform the proper
* mapping action.
*
* @param files class file resources to map.
* @throws MojoExecutionException if the MappingTool detected an error
*/
private void mappingTool( List files )
throws MojoExecutionException
{
extendRealmClasspath();
Options opts = getOptions();
filterPersistenceCapable( files, opts );
// list of input files
final String[] args = getFilePaths( files );
boolean ok = Configurations.runAgainstAllAnchors( opts,
new Configurations.Runnable() {
public boolean run( Options opts ) throws IOException, SQLException
{
JDBCConfiguration conf = new JDBCConfigurationImpl();
try
{
return MappingTool.run( conf, args, opts );
}
finally
{
conf.close();
}
}
}
);
if ( !ok )
{
throw new MojoExecutionException( "The OpenJPA MappingTool detected an error!" );
}
}
/**
* Filter out all classes which are not PersistenceCapable.
* This is needed since the MappingTool fails if it gets non-persistent capable classes.
* @param files List with classPath Files; non persistence classes will be removed
* @param opts filled configuration Options
*/
private void filterPersistenceCapable( List files, Options opts )
{
JDBCConfiguration conf = new JDBCConfigurationImpl();
Configurations.populateConfiguration( conf, opts );
MetaDataRepository repo = conf.newMetaDataRepositoryInstance();
ClassArgParser cap = repo.getMetaDataFactory().newClassArgParser();
Iterator fileIt = files.iterator();
while ( fileIt.hasNext() )
{
File classPath = (File) fileIt.next();
Class[] classes = cap.parseTypes( classPath.getAbsolutePath() );
if ( classes == null )
{
getLog().info( "Found no classes for " + classPath.getAbsolutePath() );
}
else
{
for ( int i = 0; i < classes.length; i++ )
{
Class cls = classes[i];
if ( cls.getAnnotation( Entity.class ) != null )
{
getLog().debug( "Found @Entity in class " + classPath );
}
else if ( implementsPersistenceCapable( cls ) )
{
getLog().debug( "Found class " + classPath + " that implements interface "
+ PersistenceCapable.class.getName() );
}
else
{
getLog().debug( "Removing non-entity class " + classPath );
fileIt.remove();
}
}
}
}
}
/**
* @param cls the Class to check
* @return <code>true</code> if the given Class cls implements the interface {@link PersistenceCapable}
*/
private boolean implementsPersistenceCapable( Class cls )
{
boolean isPersistenceCapable = false;
Class[] interfaces = cls.getInterfaces();
for ( int i = 0; i < interfaces.length; i++ )
{
if ( interfaces[ i ].getName().equals( PersistenceCapable.class.getName() ) )
{
isPersistenceCapable = true;
break;
}
}
return isPersistenceCapable;
}
}