/** * 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. */ package org.jboss.loom.actions; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jboss.loom.conf.Configuration; import org.jboss.loom.ex.ActionException; import org.jboss.loom.ex.MigrationException; import org.jboss.loom.spi.IMigrator; import org.jboss.loom.spi.ann.ActionDescriptor; import org.jboss.loom.spi.ann.Property; import org.jboss.loom.utils.as7.AS7ModuleUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Ondrej Zizka, ozizka at redhat.com */ @ActionDescriptor( header = "EAP 6 module creation") public class ModuleCreationAction extends AbstractStatefulAction implements Serializable { private static final Logger log = LoggerFactory.getLogger(ModuleCreationAction.class); private static final String MODULE_XML_FNAME = "module.xml"; // Action data File jarFile; String moduleName; String[] deps; Configuration.IfExists ifExists; // Backup private File moduleDir; private File backupDir; public ModuleCreationAction( Class<? extends IMigrator> fromMigrator, String moduleName, String[] deps, File jar, Configuration.IfExists ifExists) { super(fromMigrator); this.jarFile = jar; this.moduleName = moduleName; this.deps = deps; this.ifExists = ifExists; } @Override public String toDescription() { return "Create an AS 7 module '"+moduleName+"' from .jar " + this.jarFile.getPath() + ", deps: " + StringUtils.join(deps, " "); } @Override public void preValidate() throws MigrationException { if( ! jarFile.exists() ) throw new ActionException(this, "Module source jar doesn't exist: " + jarFile.getPath()); File dir = getModuleDir(); // Stored in perform. if( dir.exists() ){ switch( this.ifExists ){ case FAIL: throw new ActionException(this, "Module dir already exists in AS 7, overwrite not allowed: " + dir.getAbsolutePath()); case ASK: case MERGE: throw new UnsupportedOperationException("ASK and MERGE are not supported for " + getClass().getSimpleName()); case WARN: log.warn("Module directory for "+this.moduleName+" already exists: " + dir); break; case SKIP: log.debug("Module directory for "+this.moduleName+" already exists, skipping: " + dir); break; case GUI: log.warn("GUI not supported yet to decide IfExists for "+this.moduleName+" dir: " + dir); case OVERWRITE: break; } } }// preValidate() @Override public void perform() throws MigrationException { // Create a module. try { // Copy jar file File dir = getModuleDir(); FileUtils.copyFileToDirectory(this.jarFile, dir); //File dest = new File(dir, this.jarFile.getName()); //FileUtils.copyFile( jarFile, dest ); // XML doc File moduleXmlFile = new File(dir, MODULE_XML_FNAME); if( moduleXmlFile.exists() && this.ifExists != Configuration.IfExists.OVERWRITE ) throw new ActionException(this, MODULE_XML_FNAME + " already exists: " + moduleXmlFile.getPath() ); //Document doc = AS7ModuleUtils.createModuleXML( moduleName, jarFile.getName(), deps ); //XmlUtils.transformDocToFile( doc, moduleXmlFile ); AS7ModuleUtils.createModuleXML_FreeMarker( new ModuleXmlInfo( moduleName, jarFile.getName(), deps ), moduleXmlFile ); // Backup this.moduleDir = dir; } catch( IOException ex ) { throw new ActionException(this, "Copying failed: " + ex.getMessage(), ex); } catch( Exception ex ) { throw new ActionException(this, "Creation of " + MODULE_XML_FNAME + " failed: " + ex.getMessage(), ex); } setState(State.DONE); } @Override public void rollback() throws MigrationException { //if( this.isAfterPerform() ) FileUtils.deleteQuietly( this.moduleDir ); if( this.backupDir != null ){ try { FileUtils.moveDirectory( this.backupDir, this.moduleDir ); } catch( Exception ex ) { throw new ActionException( this, "Can't move " + backupDir + " to " + moduleDir + ": " + ex ); } } setState(State.ROLLED_BACK); } @Override public void backup() throws MigrationException { if( getModuleDir().exists() ){ Path tmpDir; this.moduleDir = getModuleDir(); try { tmpDir = Files.createTempDirectory( "JBossAS-migr-backup-"+moduleName ); this.backupDir = tmpDir.toFile(); } catch( IOException ex ) { throw new ActionException( this, "Failed creating a backup dir. " + ex.getMessage(), ex); } try { FileUtils.copyDirectory(getModuleDir(), tmpDir.toFile() ); // Writes into. } catch( IOException ex ) { throw new ActionException( this, "Failed copying to the backup dir " + tmpDir + " : " + ex.getMessage(), ex); } } setState(State.BACKED_UP); } @Override public void cleanBackup() { if( this.getMigrationContext().getConf().getGlobal().isDryRun() ) checkState( State.BACKED_UP ); else checkState( State.DONE, State.ROLLED_BACK ); if( this.backupDir != null ){ try { FileUtils.deleteDirectory( this.backupDir ); } catch( IOException ex ) { //throw new ActionException( this, "Failed deleting the backup dir " + backupDir + " : " + ex.getMessage(), ex); String msg = "Failed deleting the backup dir " + backupDir + " : " + ex.getMessage(); log.error( msg ); this.addWarning( msg ); } } setState(State.FINISHED); } @Override public void postValidate() throws MigrationException { } private File getModuleDir() { return new File( getMigrationContext().getAs7Config().getModulesDir(), this.moduleName.replace('.', '/') + "/main" ); } @Override public String toString() { return "ModuleCreationAction{ " + moduleName + " ifEx=" + ifExists + ", jar=" + jarFile + ", modDir=" + moduleDir + ", backup=" + backupDir + '}'; } // Getters / properties @Property(name = "jarFile", label = "JAR file to copy", style = "code") public File getJarFile() { return jarFile; } @Property(name = "moduleName", label = "Module name", style = "code") public String getModuleName() { return moduleName; } public String[] getDeps() { return deps; } // == Structures == // public static class ModuleXmlInfo { public String moduleName; public String jarFile; public List<Dep> deps; public ModuleXmlInfo( String moduleName, String jarFile, String[] deps ) { this.moduleName = moduleName; this.jarFile = jarFile; this.deps = Dep.listFrom( deps ); } public List<String> getResourceRoots() { return new LinkedList(){{ add(getJarFile()); }}; } // for FreeMarker template. public String getModuleName() { return moduleName; } public String getJarFile() { return jarFile; } public List<Dep> getDeps() { return deps; } }// ModuleXmlInfo public static class Dep { public String name; public boolean optional; public Dep( String name, boolean optional ) { this.name = name; this.optional = optional; } public String getName() { return name; } public boolean isOptional() { return optional; } private static List<Dep> listFrom( String[] depsDef ){ List<Dep> deps = new ArrayList(depsDef.length); boolean isNextOpt = false; for( String dep : depsDef ) { if( dep == null ){ isNextOpt = true; continue; } deps.add( new Dep( dep, isNextOpt ) ); isNextOpt = false; } return deps; } }// class Dep }// class