| /******************************************************************************* |
| * Copyright (c) 2010, 2011 EclipseSource and others. 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: |
| * Holger Staudacher - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.libra.warproducts.core; |
| |
| import java.io.*; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.*; |
| |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.service.resolver.BundleDescription; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.pde.core.plugin.*; |
| import org.eclipse.pde.internal.build.*; |
| import org.eclipse.pde.internal.core.ICoreConstants; |
| import org.eclipse.pde.internal.core.PDECore; |
| import org.eclipse.pde.internal.core.exports.FeatureExportInfo; |
| import org.eclipse.pde.internal.core.exports.FeatureExportOperation; |
| import org.eclipse.pde.internal.core.ifeature.IFeature; |
| import org.eclipse.pde.internal.core.ifeature.IFeatureModel; |
| import org.eclipse.pde.internal.core.iproduct.IJREInfo; |
| import org.eclipse.pde.internal.core.iproduct.IProduct; |
| import org.eclipse.pde.internal.core.util.CoreUtility; |
| import org.w3c.dom.Element; |
| |
| public class WARProductExportOperation extends FeatureExportOperation { |
| |
| private static final String STATUS_MESSAGE = "!MESSAGE"; //$NON-NLS-1$ |
| private static final String STATUS_ENTRY = "!ENTRY"; //$NON-NLS-1$ |
| private static final String STATUS_SUBENTRY = "!SUBENTRY"; //$NON-NLS-1$ |
| private static final String MAC_JAVA_FRAMEWORK |
| = "/System/Library/Frameworks/JavaVM.framework"; //$NON-NLS-1$ |
| private String featureLocation; |
| private String root; |
| private IProduct product; |
| private static String errorMessage; |
| |
| public static void setErrorMessage( final String message ) { |
| errorMessage = message; |
| } |
| |
| public static String getErrorMessage() { |
| return errorMessage; |
| } |
| |
| public static IStatus parseErrorMessage( final CoreException e ) { |
| IStatus result = null; |
| if( errorMessage != null ) { |
| MultiStatus status = null; |
| StringTokenizer tokenizer = new StringTokenizer( errorMessage, "\n" ); //$NON-NLS-1$ |
| while( tokenizer.hasMoreTokens() ) { |
| String line = tokenizer.nextToken().trim(); |
| if( line.startsWith( STATUS_ENTRY ) && tokenizer.hasMoreElements() ) { |
| String next = tokenizer.nextToken(); |
| if( next.startsWith( STATUS_MESSAGE ) ) { |
| status = new MultiStatus( PDECore.PLUGIN_ID, |
| 0, |
| next.substring( 8 ), |
| null ); |
| } |
| } else if( line.startsWith( STATUS_SUBENTRY ) |
| && tokenizer.hasMoreElements() |
| && status != null ) |
| { |
| String next = tokenizer.nextToken(); |
| if( next.startsWith( STATUS_MESSAGE ) ) { |
| status.add( new Status( IStatus.ERROR, |
| PDECore.PLUGIN_ID, |
| next.substring( 8 ) ) ); |
| } |
| } |
| } |
| if( status != null ) { |
| result = status; |
| } else { |
| // parsing didn't work, just set the message |
| result = new MultiStatus( PDECore.PLUGIN_ID, 0, new IStatus[]{ |
| e.getStatus() |
| }, errorMessage, null ); |
| } |
| } |
| return result; |
| } |
| |
| public WARProductExportOperation( final FeatureExportInfo info, |
| final String name, |
| final IProduct product, |
| final String root ) |
| { |
| super( info, name ); |
| this.product = product; |
| this.root = root; |
| } |
| |
| protected IStatus run( final IProgressMonitor monitor ) { |
| IStatus result = null; |
| String[][] configurations = fInfo.targets; |
| if( configurations == null ) { |
| configurations = new String[][] { |
| { |
| TargetPlatform.getOS(), |
| TargetPlatform.getWS(), |
| TargetPlatform.getOSArch(), |
| TargetPlatform.getNL() |
| } |
| }; |
| } |
| cleanupBuildRepo(); |
| errorMessage = null; |
| try { |
| monitor.beginTask( "", 10 ); //$NON-NLS-1$ |
| try { |
| // create a feature to wrap all plug-ins and features |
| String featureID = "org.eclipse.pde.container.feature"; //$NON-NLS-1$ |
| featureLocation = fBuildTempLocation + File.separator + featureID; |
| createFeature( featureID, |
| featureLocation, |
| configurations, |
| product.includeLaunchers() ); |
| createBuildPropertiesFile( featureLocation, configurations ); |
| doExport( featureID, |
| null, |
| featureLocation, |
| configurations, |
| new SubProgressMonitor( monitor, 8 ) ); |
| } catch( final IOException e ) { |
| PDECore.log( e ); |
| } catch( final InvocationTargetException e ) { |
| String problemMessage |
| = Messages.FeatureBasedExportOperation_ProblemDuringExport; |
| result = new Status( IStatus.ERROR, |
| PDECore.PLUGIN_ID, |
| problemMessage, |
| e.getTargetException() ); |
| } catch( final CoreException e ) { |
| if( errorMessage != null ) { |
| result = parseErrorMessage( e ); |
| } else { |
| result = e.getStatus(); |
| } |
| } finally { |
| // Clean up generated files |
| for( int j = 0; j < fInfo.items.length; j++ ) { |
| try { |
| deleteBuildFiles( fInfo.items[ j ] ); |
| } catch( CoreException e ) { |
| PDECore.log( e ); |
| } |
| } |
| cleanup( null, new SubProgressMonitor( monitor, 1 ) ); |
| } |
| if( hasAntErrors() ) { |
| String compilationErrors |
| = Messages.FeatureExportOperation_CompilationErrors; |
| String bind = NLS.bind( compilationErrors, |
| fInfo.destinationDirectory ); |
| result = new Status( IStatus.WARNING, |
| PDECore.PLUGIN_ID, |
| bind ); |
| } |
| } finally { |
| monitor.done(); |
| errorMessage = null; |
| } |
| if( result == null ) { |
| result = Status.OK_STATUS; |
| } |
| return result; |
| } |
| |
| protected boolean groupedConfigurations() { |
| // we never group product exports |
| return false; |
| } |
| |
| private void cleanupBuildRepo() { |
| File metadataTemp = new File( fBuildTempMetadataLocation ); |
| if( metadataTemp.exists() ) { |
| // make sure our build metadata repo is clean |
| deleteDir( metadataTemp ); |
| } |
| } |
| |
| protected String[] getPaths() { |
| String[] paths = super.getPaths(); |
| String[] all = new String[ paths.length + 1 ]; |
| all[ 0 ] = featureLocation |
| + File.separator |
| + ICoreConstants.FEATURE_FILENAME_DESCRIPTOR; |
| System.arraycopy( paths, 0, all, 1, paths.length ); |
| return all; |
| } |
| |
| private void createBuildPropertiesFile( final String featureLocation, |
| final String[][] configurations ) |
| throws IOException |
| { |
| File file = new File( featureLocation ); |
| if( !file.exists() || !file.isDirectory() ) { |
| if (! file.mkdirs()){ |
| throw new IOException( Messages.creatorCouldntCopy+"\n"+file ); |
| } |
| } |
| Properties properties = new Properties(); |
| handleRootFiles( configurations, properties ); |
| handleJREInfo( configurations, properties ); |
| handleExportSource( properties ); |
| File fileToSave |
| = new File( file, ICoreConstants.BUILD_FILENAME_DESCRIPTOR ); |
| save( fileToSave, properties, "Build Configuration" ); //$NON-NLS-1$ |
| } |
| |
| private void handleRootFiles( final String[][] configurations, |
| final Properties properties ) |
| throws IOException |
| { |
| if( configurations.length > 0 ) { |
| String rootPrefix = IBuildPropertiesConstants.ROOT_PREFIX |
| + configurations[ 0 ][ 0 ] |
| + "." + configurations[ 0 ][ 1 ] //$NON-NLS-1$ |
| + "." + configurations[ 0 ][ 2 ]; //$NON-NLS-1$ |
| properties.put( rootPrefix, getRootFileLocations( false ) ); |
| prepareWARFile( properties, rootPrefix ); |
| } |
| } |
| |
| private void prepareWARFile( final Properties properties, |
| final String rootPrefix ) |
| throws IOException |
| { |
| if( product instanceof IWARProduct ) { |
| IWARProduct warProduct = ( IWARProduct )product; |
| IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); |
| IFile launchIni = wsRoot.getFile( warProduct.getLaunchIni() ); |
| String launchIniPath |
| = createWarContent( launchIni.getLocation(), "launch.ini" ); //$NON-NLS-1$ |
| IFile webXml = wsRoot.getFile( warProduct.getWebXml() ); |
| String webXmlPath = createWarContent( webXml.getLocation(), "web.xml" ); //$NON-NLS-1$ |
| properties.put( rootPrefix, "absolute:file:" + webXmlPath //$NON-NLS-1$ |
| + ",absolute:file:" + launchIniPath ); //$NON-NLS-1$ |
| String libDir = createLibDir(); |
| copyLibraries( libDir ); |
| properties.put( rootPrefix + ".folder." + "lib", "absolute:" + libDir ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| } |
| |
| private String createLibDir() throws IOException { |
| String location = featureLocation; |
| File dir = new File( location, "lib" ); //$NON-NLS-1$ |
| if (! dir.mkdirs()){ |
| throw new IOException( Messages.creatorCouldntCopy+": "+dir ); |
| } |
| return dir.getAbsolutePath(); |
| } |
| |
| private void copyLibraries( final String libDir ) throws IOException { |
| IWARProduct warProduct = ( IWARProduct)product; |
| IPath[] libraries = warProduct.getLibraries(); |
| for( int i = 0; i < libraries.length; i++ ) { |
| IPath lib |
| = WARProductUtil.getAbsolutLibraryPath( libraries[ i ], warProduct ); |
| copyLibrary( libDir, lib ); |
| } |
| } |
| |
| private static void copyLibrary( final String libDir, final IPath filePath ) |
| throws IOException |
| { |
| String fileName = filePath.segment( filePath.segmentCount() - 1 ); |
| File template = new File( filePath.toOSString() ); |
| File destinationFile = new File( libDir + File.separator + fileName ); |
| CoreUtility.readFile( new FileInputStream( template ), destinationFile ); |
| } |
| |
| private String createWarContent( final IPath pathToContent, |
| final String fileName ) |
| throws IOException |
| { |
| File destinationFile = new File( featureLocation, fileName ); |
| File template = new File( pathToContent.toOSString() ); |
| CoreUtility.readFile( new FileInputStream( template ), destinationFile ); |
| return destinationFile.getAbsolutePath(); |
| } |
| |
| private void handleJREInfo( final String[][] configurations, |
| final Properties properties ) |
| { |
| IJREInfo jreInfo = product.getJREInfo(); |
| for( int i = 0; i < configurations.length; i++ ) { |
| String[] config = configurations[ i ]; |
| File vm = jreInfo != null ? jreInfo.getJVMLocation( config[ 0 ] ) : null; |
| if( vm != null ) { |
| if( config[ 0 ].equals( "macosx" ) //$NON-NLS-1$ |
| && vm.getPath().startsWith( MAC_JAVA_FRAMEWORK ) ) |
| { |
| continue; |
| } |
| String rootPrefix = IBuildPropertiesConstants.ROOT_PREFIX |
| + config[ 0 ] |
| + "." + config[ 1 ] + //$NON-NLS-1$ |
| "." //$NON-NLS-1$ |
| + config[ 2 ]; |
| properties.put( rootPrefix + ".folder.jre", "absolute:" //$NON-NLS-1$ //$NON-NLS-2$ |
| + vm.getAbsolutePath() ); |
| String perms = ( String )properties.get( rootPrefix |
| + ".permissions.755" ); //$NON-NLS-1$ |
| if( perms != null ) { |
| StringBuffer buffer = new StringBuffer( perms ); |
| buffer.append( "," ); //$NON-NLS-1$ |
| buffer.append( "jre/bin/java" ); //$NON-NLS-1$ |
| properties.put( rootPrefix + ".permissions.755", buffer.toString() ); //$NON-NLS-1$ |
| } |
| } |
| } |
| } |
| |
| private void handleExportSource( final Properties properties ) { |
| if( fInfo.exportSource && fInfo.exportSourceBundle ) { |
| properties.put( IBuildPropertiesConstants.PROPERTY_INDIVIDUAL_SOURCE, |
| "true" ); //$NON-NLS-1$ |
| List<IPluginModelBase> workspacePlugins = Arrays.asList( PluginRegistry.getWorkspaceModels() ); |
| for( int i = 0; i < fInfo.items.length; i++ ) { |
| if( fInfo.items[ i ] instanceof IFeatureModel ) { |
| IFeature feature = ( ( IFeatureModel )fInfo.items[ i ] ).getFeature(); |
| properties.put( "generate.feature@" + feature.getId().trim() //$NON-NLS-1$ |
| + ".source", feature.getId() ); //$NON-NLS-1$ //$NON-NLS-2$ |
| } else { |
| BundleDescription bundle = null; |
| if( fInfo.items[ i ] instanceof IPluginModelBase ) { |
| IPluginModelBase baseItem = ( IPluginModelBase )fInfo.items[ i ]; |
| bundle = baseItem.getBundleDescription(); |
| } |
| if( bundle == null ) { |
| if( fInfo.items[ i ] instanceof BundleDescription ) |
| bundle = ( BundleDescription )fInfo.items[ i ]; |
| } |
| if( bundle == null ) { |
| continue; |
| } |
| // it doesn't matter if we generate extra properties for platforms we |
| // aren't exporting for |
| if( workspacePlugins.contains( PluginRegistry.findModel( bundle ) ) ) |
| { |
| properties.put( "generate.plugin@" + bundle.getSymbolicName().trim() //$NON-NLS-1$ |
| + ".source", bundle.getSymbolicName() ); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } |
| } |
| } |
| |
| protected boolean publishingP2Metadata() { |
| return fInfo.exportMetadata; |
| } |
| |
| private static String getRootFileLocations( final boolean hasLaunchers ) { |
| // Get the files that go in the root of the eclipse install, excluding the |
| // launcher |
| StringBuffer buffer = new StringBuffer(); |
| if( !hasLaunchers ) { |
| File homeDir = new File( TargetPlatform.getLocation() ); |
| if( homeDir.exists() && homeDir.isDirectory() ) { |
| File file = new File( homeDir, "startup.jar" ); //$NON-NLS-1$ |
| if( file.exists() ) |
| appendAbsolutePath( buffer, file ); |
| file = new File( homeDir, "libXm.so.2" ); //$NON-NLS-1$ |
| if( file.exists() ) { |
| appendAbsolutePath( buffer, file ); |
| } |
| } |
| } |
| return buffer.toString(); |
| } |
| |
| private static void appendAbsolutePath( final StringBuffer buffer, |
| final File file ) |
| { |
| if( buffer.length() > 0 ) |
| buffer.append( "," ); //$NON-NLS-1$ |
| buffer.append( "absolute:file:" ); //$NON-NLS-1$ |
| buffer.append( file.getAbsolutePath() ); |
| } |
| |
| protected HashMap<String,String> createAntBuildProperties( final String[][] configs ) { |
| HashMap<String,String> properties = super.createAntBuildProperties( configs ); |
| fAntBuildProperties.put( IXMLConstants.PROPERTY_COLLECTING_FOLDER, root ); |
| fAntBuildProperties.put( IXMLConstants.PROPERTY_ARCHIVE_PREFIX, root ); |
| return properties; |
| } |
| |
| protected void setupGenerator( final BuildScriptGenerator generator, |
| final String featureID, |
| final String versionId, |
| final String[][] configs, |
| final String featureLocation ) |
| throws CoreException |
| { |
| super.setupGenerator( generator, |
| featureID, |
| versionId, |
| configs, |
| featureLocation ); |
| generator.setGenerateVersionsList( true ); |
| if( product != null ) { |
| generator.setProduct( product.getModel().getInstallLocation() ); |
| } |
| } |
| |
| protected void setAdditionalAttributes( final Element plugin, |
| final BundleDescription bundle ) |
| { |
| String unpack = Boolean.toString( CoreUtility.guessUnpack( bundle ) ); |
| plugin.setAttribute( "unpack", unpack ); //$NON-NLS-1$ |
| } |
| |
| protected String getAssemblyScriptName( String featureID, |
| String os, |
| String ws, |
| String arch, |
| String featureLocation ) |
| { |
| String configIni = featureLocation + IPath.SEPARATOR + "productRootFiles" + IPath.SEPARATOR + |
| os + "." + ws + "." + arch + IPath.SEPARATOR + "configuration" + IPath.SEPARATOR + "config.ini"; |
| addExtensionbundleToConfigIni( configIni ); |
| return super.getAssemblyScriptName( featureID, os, ws, arch, featureLocation ); |
| } |
| |
| private static void addExtensionbundleToConfigIni( String configIni ) { |
| try { |
| File file = new File( configIni ); |
| if( file.exists() ) { |
| BufferedReader reader = new BufferedReader(new FileReader(file)); |
| String line = ""; |
| StringBuilder oldtext = new StringBuilder(); |
| while( ( line = reader.readLine() ) != null ) { |
| oldtext.append( line ); |
| oldtext.append( "\n" ); |
| } |
| reader.close(); |
| String newtext = oldtext.toString().replaceAll( "org.eclipse.equinox.http.servlet@start", |
| "org.eclipse.equinox.servletbridge.extensionbundle,\\\\\n " + |
| "org.eclipse.equinox.http.servlet@start"); |
| FileWriter writer = new FileWriter( configIni ); |
| writer.write(newtext); |
| writer.close(); |
| } |
| } catch( IOException e ) { |
| throw new IllegalStateException( e ); |
| } |
| } |
| |
| } |