/******************************************************************************* * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * *******************************************************************************/ package com.liferay.ide.maven.core; import com.liferay.ide.core.ILiferayConstants; import com.liferay.ide.core.util.CoreUtil; import com.liferay.ide.core.util.LaunchHelper; import com.liferay.ide.project.core.AbstractProjectBuilder; import java.io.File; import java.io.FileOutputStream; import java.lang.reflect.InvocationTargetException; import java.util.List; import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.m2e.core.MavenPlugin; import org.eclipse.m2e.core.embedder.ICallable; import org.eclipse.m2e.core.embedder.IMaven; import org.eclipse.m2e.core.embedder.IMavenExecutionContext; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.IMavenProjectRegistry; import org.eclipse.m2e.core.project.ResolverConfiguration; import org.eclipse.osgi.util.NLS; /** * @author Gregory Amerson */ @SuppressWarnings( "restriction" ) public class MavenProjectBuilder extends AbstractProjectBuilder { private final String ATTR_GOALS = "M2_GOALS"; private final String ATTR_POM_DIR = IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY; private final String ATTR_PROFILES = "M2_PROFILES"; private final String ATTR_SKIP_TESTS = "M2_SKIP_TESTS"; private final String ATTR_WORKSPACE_RESOLUTION = "M2_WORKSPACE_RESOLUTION"; private final String LAUNCH_CONFIGURATION_TYPE_ID = "org.eclipse.m2e.Maven2LaunchConfigurationType"; protected final IMaven maven = MavenPlugin.getMaven(); protected final IMavenProjectRegistry projectManager = MavenPlugin.getMavenProjectRegistry(); public MavenProjectBuilder( IProject project ) { super( project ); } public IStatus buildLang( IFile langFile, IProgressMonitor monitor ) throws CoreException { final IProgressMonitor sub = new SubProgressMonitor( monitor, 100 ); sub.beginTask( Msgs.buildingLanguages, 100 ); final IMavenProjectFacade facade = MavenUtil.getProjectFacade( getProject(), sub ); sub.worked( 10 ); final ICallable<IStatus> callable = new ICallable<IStatus>() { public IStatus call( IMavenExecutionContext context, IProgressMonitor monitor ) throws CoreException { return MavenUtil.executeMojoGoal( facade, context, ILiferayMavenConstants.PLUGIN_GOAL_BUILD_LANG, monitor ); } }; final IStatus retval = executeMaven( facade, callable, sub ); sub.worked( 80 ); getProject().refreshLocal( IResource.DEPTH_INFINITE, sub ); sub.worked( 10 ); sub.done(); return retval; } public IStatus buildSB( final IFile serviceXmlFile, final String goal, final IProgressMonitor monitor ) throws CoreException { final IProject serviceProject = serviceXmlFile.getProject(); final IMavenProjectFacade facade = MavenUtil.getProjectFacade( serviceProject , monitor ); monitor.worked( 10 ); final ICallable<IStatus> callable = new ICallable<IStatus>() { public IStatus call( IMavenExecutionContext context, IProgressMonitor monitor ) throws CoreException { return MavenUtil.executeMojoGoal( facade, context, goal, monitor ); } }; IStatus retval = null; final IStatus executeStatus = executeMaven( facade, callable, monitor ); if( !executeStatus.isOK() && executeStatus.getException() instanceof MojoExecutionException ) { MojoExecutionException mojoException = (MojoExecutionException) executeStatus.getException(); if( mojoException.getCause() instanceof InvocationTargetException ) { InvocationTargetException ex = (InvocationTargetException) mojoException.getCause(); retval = LiferayMavenCore.createErrorStatus( ex.getTargetException() ); } else { retval = LiferayMavenCore.createErrorStatus( mojoException ); } } else { retval = Status.OK_STATUS; } monitor.worked( 70 ); refreshSiblingProject( facade, monitor ); monitor.worked( 10 ); serviceProject.refreshLocal( IResource.DEPTH_INFINITE, monitor ); monitor.worked( 10 ); monitor.done(); return retval; } @Override public IStatus buildService( IProgressMonitor monitor ) throws CoreException { final IFile serviceFile = preBuildService( monitor ); final IProgressMonitor sub = new SubProgressMonitor( monitor, 100 ); sub.beginTask( Msgs.buildingServices, 100 ); return buildSB( serviceFile, ILiferayMavenConstants.PLUGIN_GOAL_BUILD_SERVICE, sub ); } @Override public IStatus buildWSDD( IProgressMonitor monitor ) throws CoreException { final IFile serviceFile = preBuildService( monitor ); final IProgressMonitor sub = new SubProgressMonitor( monitor, 100 ); sub.beginTask( Msgs.buildingServices, 100 ); return buildSB( serviceFile, ILiferayMavenConstants.PLUGIN_GOAL_BUILD_WSDD, sub ); } public IStatus execGoals( final List<String> goals, final IProgressMonitor monitor ) throws CoreException { IStatus retval = null; final IMavenProjectFacade facade = MavenUtil.getProjectFacade( getProject(), monitor ); final ICallable<IStatus> callable = new ICallable<IStatus>() { public IStatus call( IMavenExecutionContext context, IProgressMonitor monitor ) throws CoreException { final IStatus execStatus = MavenUtil.executeGoals( facade, context, goals, monitor ); final List<Throwable> exceptions = context.getSession().getResult().getExceptions(); return LiferayMavenCore.newMultiStatus().add( execStatus ).addAll( exceptions ).retval(); } }; retval = executeMaven( facade, callable, monitor ); return retval; } private boolean execMavenLaunch( final IProject project, final String goal, final IMavenProjectFacade facade, IProgressMonitor monitor ) throws CoreException { final ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager(); final ILaunchConfigurationType launchConfigurationType = launchManager.getLaunchConfigurationType( LAUNCH_CONFIGURATION_TYPE_ID ); final IPath basedirLocation = project.getLocation(); final String newName = launchManager.generateLaunchConfigurationName( basedirLocation.lastSegment() ); final ILaunchConfigurationWorkingCopy workingCopy = launchConfigurationType.newInstance( null, newName ); workingCopy.setAttribute( IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, "-Dmaven.multiModuleProjectDirectory" ); workingCopy.setAttribute( ATTR_POM_DIR, basedirLocation.toString() ); workingCopy.setAttribute( ATTR_GOALS, goal ); // workingCopy.setAttribute( ATTR_UPDATE_SNAPSHOTS, true ); workingCopy.setAttribute( ATTR_WORKSPACE_RESOLUTION, true ); workingCopy.setAttribute( ATTR_SKIP_TESTS, true ); if( facade != null ) { final ResolverConfiguration configuration = facade.getResolverConfiguration(); final String selectedProfiles = configuration.getSelectedProfiles(); if( selectedProfiles != null && selectedProfiles.length() > 0 ) { workingCopy.setAttribute( ATTR_PROFILES, selectedProfiles ); } new LaunchHelper().launch( workingCopy, "run", monitor ); return true; } else { return false; } } protected IStatus executeMaven( final IMavenProjectFacade projectFacade, final ICallable<IStatus> callable, IProgressMonitor monitor ) throws CoreException { return this.maven.execute( callable, monitor ); } public IProject getPortletProject( IMavenProjectFacade projectFacade, IProgressMonitor monitor ) throws CoreException { IProject retVal = null; try { final Xpp3Dom config = (Xpp3Dom) MavenUtil.getLiferayMavenPluginConfig( projectFacade.getMavenProject() ); final Xpp3Dom webAppDir = config.getChild( ILiferayMavenConstants.PLUGIN_CONFIG_WEBAPPBASE_DIR ); final Xpp3Dom pluginName = config.getChild( ILiferayMavenConstants.PLUGIN_CONFIG_PLUGIN_NAME ); // this should be the name path of a project that should be in user's workspace that we can refresh if( webAppDir != null ) { final String webAppDirValue = webAppDir.getValue(); String projectPath = Path.fromOSString( webAppDirValue ).lastSegment(); retVal = ResourcesPlugin.getWorkspace().getRoot().getProject( projectPath ); } else if( pluginName != null ) { final String pluginNameValue = pluginName.getValue(); retVal = CoreUtil.getProject( pluginNameValue ); } } catch( Exception e ) { LiferayMavenCore.logError( "Could not refresh sibling service project.", e ); //$NON-NLS-1$ } return retVal; } public IFile preBuildService( IProgressMonitor monitor ) throws CoreException { IProject project = getProject(); IFile retval = getDocrootFile( "WEB-INF/" + ILiferayConstants.SERVICE_XML_FILE ); if( retval == null ) { final IMavenProjectFacade projectFacade = MavenUtil.getProjectFacade( project ); if( projectFacade != null ) { final IProject portletProject = getPortletProject( projectFacade, monitor ); if( portletProject != null ) { retval = new MavenProjectBuilder( portletProject ).getDocrootFile( "WEB-INF/" + ILiferayConstants.SERVICE_XML_FILE ); } } } // add support for 7.0 service builder templates if( retval == null ) { retval = project.getFile( "service.xml" ); } return retval; } public void refreshSiblingProject( IMavenProjectFacade projectFacade, IProgressMonitor monitor ) throws CoreException { // need to look up project configuration and refresh the *-service project associated with this project try { // not doing any null checks since this is in large try/catch final Plugin liferayMavenPlugin = MavenUtil.getPlugin( projectFacade, ILiferayMavenConstants.LIFERAY_MAVEN_PLUGIN_KEY, monitor ); final Xpp3Dom config = (Xpp3Dom) liferayMavenPlugin.getConfiguration(); final Xpp3Dom apiBaseDir = config.getChild( ILiferayMavenConstants.PLUGIN_CONFIG_API_BASE_DIR ); // this should be the name path of a project that should be in user's workspace that we can refresh final String apiBaseDirValue = apiBaseDir.getValue(); final IFile apiBasePomFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation( new Path( apiBaseDirValue ).append( IMavenConstants.POM_FILE_NAME ) ); final IMavenProjectFacade apiBaseFacade = this.projectManager.create( apiBasePomFile, true, monitor ); apiBaseFacade.getProject().refreshLocal( IResource.DEPTH_INFINITE, monitor ); } catch( Exception e ) { LiferayMavenCore.logError( "Could not refresh sibling service project.", e ); //$NON-NLS-1$ } } public boolean runMavenGoal( final IProject project, final String goal, final IProgressMonitor monitor ) throws CoreException { final IMavenProjectFacade facade = MavenUtil.getProjectFacade( project, monitor ); return execMavenLaunch( project, goal, facade, monitor ); } protected static class Msgs extends NLS { public static String buildingLanguages; public static String buildingServices; public static String buildingWSDD; static { initializeMessages( MavenProjectBuilder.class.getName(), Msgs.class ); } } @Override public IStatus execInitBundle( IProject project, String taskName, String bundleUrl, IProgressMonitor monitor ) throws CoreException { return Status.OK_STATUS; } @Override public IStatus updateProjectDependency( IProject project, List<String[]> dependencies ) throws CoreException { IMavenProjectFacade projectFacade = MavenUtil.getProjectFacade( project, new NullProgressMonitor() ); if( projectFacade != null ) { MavenProject mavenProject = projectFacade.getMavenProject( new NullProgressMonitor() ); List<Dependency> existedDependencies = mavenProject.getDependencies(); final IMaven maven = MavenPlugin.getMaven(); File pomFile = new File( project.getLocation().toOSString(), IMavenConstants.POM_FILE_NAME ); Model model = maven.readModel( pomFile ); for( String[] dependency : dependencies ) { Dependency de = new Dependency(); de.setGroupId( dependency[0] ); de.setArtifactId( dependency[1] ); de.setVersion( dependency[2] ); String newKey = de.getManagementKey(); boolean existed = false; for( Dependency existedDependency : existedDependencies ) { String existedKey = existedDependency.getManagementKey(); if( existedKey.equals( newKey ) ) { existed = true; break; } } if( existed == false && model != null ) { model.addDependency( de ); } } try(FileOutputStream out = new FileOutputStream( pomFile )) { maven.writeModel( model, out ); out.flush(); out.close(); final WorkspaceJob job = new WorkspaceJob( "Updating project " + project.getName()) { public IStatus runInWorkspace( IProgressMonitor monitor ) { try { project.refreshLocal( IResource.DEPTH_INFINITE, new NullProgressMonitor() ); MavenPlugin.getProjectConfigurationManager().updateProjectConfiguration( project, monitor ); } catch( CoreException ex ) { return ex.getStatus( ); } return Status.OK_STATUS; } }; job.schedule(); } catch( Exception e ) { return LiferayMavenCore.createErrorStatus( "Error updating maven project dependency", e ); } } return Status.OK_STATUS; } }