/******************************************************************************
* Copyright (c) 2010-2013, Linagora
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Linagora - initial API and implementation
*******************************************************************************/
package com.ebmwebsourcing.petals.services.utils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import com.ebmwebsourcing.petals.common.generation.JbiUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.maven.MavenUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.IoUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.JavaUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.JavaUtils.ExportableClassPath;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.PetalsConstants;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.StatusUtils;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.StringUtils;
import com.ebmwebsourcing.petals.services.PetalsServicesPlugin;
import com.ebmwebsourcing.petals.services.su.jbiproperties.PetalsSPPropertiesManager;
/**
* @author Vincent Zurczak - EBM WebSourcing
*/
public final class ExportUtils {
/**
* Private constructor for utility class.
*/
private ExportUtils() {
// nothing
}
/**
* Exports one or several SU projects into a service assembly.
*
* @param saName the SA name (SA file name = SA name + ".zip")
* @param targetSaPath the absolute file path to the SA file
* @param projects the projects to package
* @param monitor the progress monitor
* @return a status indicating the result of the package operation
*/
public static IStatus exportSuProject(
String saName,
String targetSaPath,
Collection<IProject> projects,
IProgressMonitor monitor ) {
IStatus result = Status.OK_STATUS;
Map<String,File> suEntryNameToSuFile = new HashMap<String,File>( projects.size());
Map<String,String> suNameToComponentName = new HashMap<String,String>( projects.size());
// Package the SU(s)
for( IProject p : projects ) {
if( ! p.isAccessible())
continue;
String errorMsgPrefix = p.getName() + ": ";
File suFile = null;
try {
// Check the component name
Properties pProperties = PetalsSPPropertiesManager.getProperties( p );
String componentName= pProperties.getProperty( PetalsSPPropertiesManager.COMPONENT_DEPLOYMENT_ID, "" );
if( StringUtils.isEmpty( componentName ))
throw new NullPointerException( "The component name is not defined." );
// Package the project
String suName = p.getName();
suFile = packageSuProject( p, suName, monitor );
suEntryNameToSuFile.put( suName + ".zip", suFile );
suNameToComponentName.put( suName, componentName );
} catch( FileNotFoundException e ) {
result = StatusUtils.createStatus( e, errorMsgPrefix );
break;
} catch( IOException e ) {
result = StatusUtils.createStatus( e, errorMsgPrefix );
break;
} catch( NullPointerException e ) {
result = StatusUtils.createStatus( e, errorMsgPrefix );
break;
} catch( CoreException e ) {
result = StatusUtils.createStatus( e, errorMsgPrefix );
break;
}
}
// Package the SA
try {
if( result.isOK()) {
String saJbiXml = JbiUtils.generateJbiXmlForSA( saName, suNameToComponentName );
File saFile = JbiUtils.createJbiArchive( targetSaPath, saJbiXml, suEntryNameToSuFile );
assert saFile != null && saFile.exists();
}
} catch( IOException e ) {
result = StatusUtils.createStatus( e, "SA creation: " );
} finally {
// Delete the temporary SU files
for( File suFile : suEntryNameToSuFile.values()) {
if( suFile != null
&& suFile.exists()
&& ! suFile.delete())
suFile.deleteOnExit();
}
}
return result;
}
/**
* Exports one or several SU projects into a service assembly.
*
* @param outputDirectory the output directory
* @param saProject the SA project to package
* @param monitor the progress monitor
* @return a status indicating the result of the package operation
*/
public static IStatus exportSaProject( String outputDirectory, IProject saProject, IProgressMonitor monitor ) {
// Get the SU projects
List<IProject> projects = new ArrayList<IProject>();
try {
for( IProject refP : saProject.getReferencedProjects()) {
if( refP.isAccessible() && ServiceProjectRelationUtils.isSuProject( refP ))
projects.add( refP );
}
} catch( CoreException e1 ) {
PetalsServicesPlugin.log( e1, IStatus.ERROR );
}
IStatus result = Status.OK_STATUS;
Map<String,File> suEntryNameToSuFile = new HashMap<String,File>( projects.size());
// Package the SU(s)
for( IProject p : projects ) {
String errorMsgPrefix = p.getName() + ": ";
File suFile = null;
try {
String suName = p.getName();
suFile = packageSuProject( p, suName, monitor );
suEntryNameToSuFile.put( suName + ".zip", suFile );
} catch( Exception e ) {
result = StatusUtils.createStatus( e, errorMsgPrefix );
break;
}
}
// Package the SA
try {
if( result.isOK()) {
IFile jbiXmlFile = saProject.getFile( PetalsConstants.LOC_JBI_FILE );
InputStream is = jbiXmlFile.getContents();
ByteArrayOutputStream os = new ByteArrayOutputStream();
IoUtils.copyStream( is, os );
is.close();
String saJbiXml = os.toString( "UTF-8" );
String targetSaPath = new File( outputDirectory, saProject.getName() + ".zip" ).getAbsolutePath();
File saFile = JbiUtils.createJbiArchive( targetSaPath, saJbiXml, suEntryNameToSuFile );
assert saFile != null && saFile.exists();
}
} catch( Exception e ) {
result = StatusUtils.createStatus( e, "SA creation: " );
} finally {
// Delete the temporary SU files
for( File suFile : suEntryNameToSuFile.values()) {
if( suFile != null
&& suFile.exists()
&& ! suFile.delete())
suFile.deleteOnExit();
}
}
return result;
}
/**
* Exports one bulk SU into a service assembly.
*
* @param suName the SU name (SU file name = SU name + ".zip")
* @param saName
* @param targetSaPath the absolute file path to the SA file
* @param componentName the component name
* @param tempDir the project root file
* @return a status indicating the result of the package operation
*
* FIXME: do we need to return a status? The result is not used.
*/
public static IStatus exportSuBulkProject(
String suName,
String saName,
String targetSaPath,
String componentName,
File tempDir ) {
IStatus result = Status.OK_STATUS;
Map<String,File> suEntryNameToSuFile = new HashMap<String,File>( 1 );
// Package the SU(s)
String errorMsgPrefix = suName + ": ";
File suFile = null;
try {
// Create the SU
suFile = new File( System.getProperty( "java.io.tmpdir" ), suName + ".zip" );
suFile = JbiUtils.createJbiArchive( suFile.getAbsolutePath(), new File( tempDir, PetalsConstants.LOC_RES_FOLDER ));
suEntryNameToSuFile.put( suName + ".zip", suFile );
} catch( Exception e ) {
result = StatusUtils.createStatus( e, errorMsgPrefix );
}
// Package the SA
try {
if( result.isOK()) {
String saJbiXml = JbiUtils.generateJbiXmlForSA( componentName, saName, suName );
File saFile = JbiUtils.createJbiArchive( targetSaPath, saJbiXml, suEntryNameToSuFile );
assert saFile != null && saFile.exists();
}
} catch( IOException e ) {
result = StatusUtils.createStatus( e, "SA creation: " );
} finally {
// Delete the temporary SU files
if( suFile != null
&& suFile.exists()
&& ! suFile.delete())
suFile.deleteOnExit();
}
return result;
}
/**
* Packages a SU project.
* <p>
* If the project is a Java project, a JAR is created for the Java resources, and the
* dependencies are added in the generated SU.
* </p>
*
* @param suProject the SU project
* @param suName the SU name
* @param monitor the progress monitor
* @return the created SU file (in a temporary directory)
* @throws CoreException if something went wrong
* @throws IOException if something went wrong
*/
private static File packageSuProject( IProject suProject, String suName, IProgressMonitor monitor )
throws CoreException, IOException {
File suFile = null;
ExportableClassPath classpath = null;
try {
// Package the project
// Java project
if( suProject.hasNature( JavaCore.NATURE_ID )) {
IJavaProject jp = JavaCore.create( suProject );
classpath = JavaUtils.getExportableClasspath( jp, monitor );
}
// Build the entries to package
IFolder resourcesFolder = suProject.getFolder( PetalsConstants.LOC_RES_FOLDER );
Map<String,File> zipEntryToFile = JbiUtils.buildPackagingMap( resourcesFolder.getLocation().toFile());
if( classpath != null ) {
// Do not embed the libraries whose scope is "provided" in the POM
File pomFile = suProject.getFile( PetalsConstants.LOC_POM_FILE ).getLocation().toFile();
Set<String> exclusionPatterns = new HashSet<String> ();
for( String s : MavenUtils.extractDependenciesWithProvidedScope( pomFile )) {
String pattern = Pattern.quote( s ) + "(-\\d+(.\\d+)+)?(-snapshot|-SNAPSHOT)?\\.(jar|zip)";
exclusionPatterns.add( pattern );
}
// Iterate over the files and check they have to be packaged
jarLoop: for( File jarFile : classpath.getExportableClassPath()) {
String entry = jarFile.getName();
for( String pattern : exclusionPatterns ) {
if( entry.matches( pattern ))
continue jarLoop;
}
String suffix = "";
int id = 1;
while( zipEntryToFile.containsKey( entry + suffix ))
suffix = "-" + id;
zipEntryToFile.put( entry + suffix, jarFile );
}
}
// Replace the entry for the jbi.xml file
File jbiXmlFile = zipEntryToFile.remove( "jbi.xml" );
if( jbiXmlFile != null )
zipEntryToFile.put( "META-INF/jbi.xml", jbiXmlFile );
// Package the entries
suFile = new File( System.getProperty( "java.io.tmpdir" ), suName + ".zip" );
suFile = JbiUtils.createJbiArchive( suFile.getAbsolutePath(), zipEntryToFile );
} finally {
// Delete the temporary files
if( classpath != null )
classpath.deleteImplementationJars();
}
return suFile;
}
}