/* * 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.openjpa.tools.maven; import java.io.File; import java.io.IOException; import java.sql.SQLException; import java.util.Iterator; import java.util.List; import javax.persistence.Entity; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Parameter; 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 org.codehaus.plexus.util.FileUtils; /** * 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. * * @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<File> 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<File> 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, Thread.currentThread().getContextClassLoader()); } 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<File> files, Options opts) { JDBCConfiguration conf = new JDBCConfigurationImpl(); Configurations.populateConfiguration(conf, opts); MetaDataRepository repo = conf.newMetaDataRepositoryInstance(); ClassArgParser cap = repo.getMetaDataFactory().newClassArgParser(); Iterator<File> fileIt = files.iterator(); while (fileIt.hasNext()) { File classPath = 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; } }