/******************************************************************************* * 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.IWebProject; import com.liferay.ide.core.LiferayCore; import com.liferay.ide.core.LiferayNature; import com.liferay.ide.core.util.CoreUtil; import com.liferay.ide.hook.core.dd.HookDescriptorHelper; import com.liferay.ide.hook.core.util.HookUtil; import com.liferay.ide.project.core.facet.IPluginFacetConstants; import com.liferay.ide.project.core.util.ProjectUtil; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.maven.model.Plugin; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.DirectoryScanner; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.internal.MavenPluginActivator; import org.eclipse.m2e.core.internal.markers.IMavenMarkerManager; import org.eclipse.m2e.core.internal.markers.MavenProblemInfo; import org.eclipse.m2e.core.internal.markers.SourceLocation; import org.eclipse.m2e.core.internal.markers.SourceLocationHelper; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.project.configurator.AbstractProjectConfigurator; import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest; import org.eclipse.m2e.jdt.IClasspathDescriptor; import org.eclipse.m2e.jdt.IJavaProjectConfigurator; import org.eclipse.m2e.wtp.WTPProjectsUtil; import org.eclipse.m2e.wtp.WarPluginConfiguration; import org.eclipse.osgi.util.NLS; import org.eclipse.wst.common.componentcore.ComponentCore; import org.eclipse.wst.common.componentcore.internal.StructureEdit; import org.eclipse.wst.common.componentcore.internal.WorkbenchComponent; import org.eclipse.wst.common.componentcore.internal.util.ComponentUtilities; import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; import org.eclipse.wst.common.frameworks.datamodel.DataModelFactory; import org.eclipse.wst.common.frameworks.datamodel.IDataModel; import org.eclipse.wst.common.frameworks.datamodel.IDataModelProvider; import org.eclipse.wst.common.project.facet.core.IFacetedProject; import org.eclipse.wst.common.project.facet.core.IFacetedProject.Action; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; import org.osgi.framework.Version; /** * @author Gregory Amerson * @author Simon Jiang * @author Kuo Zhang * @author Kamesh Sampath */ @SuppressWarnings( "restriction" ) public class LiferayMavenProjectConfigurator extends AbstractProjectConfigurator implements IJavaProjectConfigurator { private static final IPath ROOT_PATH = new Path("/"); //$NON-NLS-1$ private static final String MAVEN_WAR_PLUGIN_KEY = "org.apache.maven.plugins:maven-war-plugin"; private static final String WAR_SOURCE_FOLDER = "/src/main/webapp"; //$NON-NLS-1$ private IMavenMarkerManager mavenMarkerManager; public LiferayMavenProjectConfigurator() { super(); this.mavenMarkerManager = MavenPluginActivator.getDefault().getMavenMarkerManager(); } private MavenProblemInfo checkValidConfigDir( Plugin liferayMavenPlugin, Xpp3Dom config, String configParam ) { MavenProblemInfo retval = null; String message = null; String value = null; if( configParam != null ) { if( config == null ) { message = NLS.bind( Msgs.missingConfigValue, configParam ); } else { final Xpp3Dom dirNode = config.getChild( configParam ); if( dirNode == null ) { message = NLS.bind( Msgs.missingConfigValue, configParam ); } else { value = dirNode.getValue(); if( CoreUtil.isNullOrEmpty( value ) ) { message = NLS.bind( Msgs.emptyConfigValue, configParam ); } else { final File configDir = new File( value ); if( ( ! configDir.exists() ) || ( ! configDir.isDirectory() ) ) { message = NLS.bind( Msgs.unusableConfigValue, configParam, value ); } } } } } if( message != null ) { final SourceLocation location = SourceLocationHelper.findLocation( liferayMavenPlugin, SourceLocationHelper.CONFIGURATION ); retval = new MavenProblemInfo( message, IMarker.SEVERITY_WARNING, location ); } return retval; } private MavenProblemInfo checkValidVersion( Plugin plugin, Xpp3Dom config, String versionNodeName ) { MavenProblemInfo retval = null; Version liferayVersion = null; String version = null; if( config != null ) { // check for version config node final Xpp3Dom versionNode = config.getChild( versionNodeName ); if( versionNode != null ) { version = versionNode.getValue(); try { liferayVersion = new Version( MavenUtil.getVersion( version ) ); } catch( IllegalArgumentException e ) { // bad version } } } if( liferayVersion == null || liferayVersion.equals( ILiferayConstants.EMPTY_VERSION ) ) { // could not get valid liferayVersion final SourceLocation location = SourceLocationHelper.findLocation( plugin, SourceLocationHelper.CONFIGURATION ); final String problemMsg = NLS.bind( Msgs.unusableConfigValue, versionNodeName, version ); retval = new MavenProblemInfo( problemMsg, IMarker.SEVERITY_WARNING, location ); } return retval; } @Override public void configure( ProjectConfigurationRequest request, IProgressMonitor monitor ) throws CoreException { if( monitor == null ) { monitor = new NullProgressMonitor(); } monitor.beginTask( NLS.bind( Msgs.configuringLiferayProject, request.getProject() ), 100 ); final Plugin liferayMavenPlugin = MavenUtil.getPlugin( request.getMavenProjectFacade(), ILiferayMavenConstants.LIFERAY_MAVEN_PLUGIN_KEY, monitor ); if( ! shouldConfigure( liferayMavenPlugin, request ) ) { monitor.done(); return; } final IProject project = request.getProject(); final IFile pomFile = project.getFile( IMavenConstants.POM_FILE_NAME ); final IFacetedProject facetedProject = ProjectFacetsManager.create( project, false, monitor ); removeLiferayMavenMarkers( project ); monitor.worked( 25 ); final MavenProject mavenProject = request.getMavenProject(); final List<MavenProblemInfo> errors = findLiferayMavenPluginProblems( project, request, monitor ); if( errors.size() > 0 ) { try { this.markerManager.addErrorMarkers( pomFile, ILiferayMavenConstants.LIFERAY_MAVEN_MARKER_CONFIGURATION_WARNING_ID, errors ); } catch( CoreException e ) { // no need to log this error its just best effort } } monitor.worked( 25 ); MavenProblemInfo installProblem = null; if( shouldInstallNewLiferayFacet( mavenProject, facetedProject ) ) { installProblem = installNewLiferayFacet( facetedProject, request, monitor ); } if( shouldAddLiferayNature( mavenProject, facetedProject ) ) { LiferayNature.addLiferayNature( project, monitor ); } monitor.worked( 25 ); if( installProblem != null ) { this.markerManager.addMarker( pomFile, ILiferayMavenConstants.LIFERAY_MAVEN_MARKER_CONFIGURATION_WARNING_ID, installProblem.getMessage(), installProblem.getLocation().getLineNumber(), IMarker.SEVERITY_WARNING ); } else { String pluginType = MavenUtil.getLiferayMavenPluginType( mavenProject ); // IDE-817 we need to mak sure that on deployment it will have the correct suffix for project name final IVirtualComponent projectComponent = ComponentCore.createComponent( project ); try { if( pluginType != null && projectComponent != null ) { final String deployedName = projectComponent.getDeployedName(); final String pluginTypeSuffix = "-" + pluginType; final String deployedFileName = project.getName() + pluginTypeSuffix; if( deployedName == null || ( deployedName != null && ! deployedName.endsWith( pluginTypeSuffix ) ) ) { configureDeployedName( project, deployedFileName ); } final String oldContextRoot = ComponentUtilities.getServerContextRoot( project ); if( oldContextRoot == null || ( oldContextRoot != null && ! oldContextRoot.endsWith( pluginTypeSuffix ) ) ) { final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode( LiferayMavenCore.PLUGIN_ID ); boolean setMavenPluginSuffix = prefs.getBoolean( LiferayMavenCore.PREF_ADD_MAVEN_PLUGIN_SUFFIX, false ); if( setMavenPluginSuffix ) { ComponentUtilities.setServerContextRoot( project, deployedFileName ); } } } } catch( Exception e ) { LiferayMavenCore.logError( "Unable to configure deployed name for project " + project.getName(), e ); } if( ILiferayMavenConstants.THEME_PLUGIN_TYPE.equals( pluginType ) ) { final IVirtualComponent component = ComponentCore.createComponent( project, true ); if( component != null ) { // make sure to update the main deployment folder WarPluginConfiguration config = new WarPluginConfiguration( mavenProject, project ); String warSourceDirectory = config.getWarSourceDirectory(); IFolder contentFolder = project.getFolder( warSourceDirectory ); IPath warPath = ROOT_PATH.append( contentFolder.getProjectRelativePath() ); IPath themeFolder = ROOT_PATH.append( getThemeTargetFolder( mavenProject, project ) ); // add a link to our m2e-liferay/theme-resources folder into deployment assembly WTPProjectsUtil.insertLinkBefore(project, themeFolder, warPath, ROOT_PATH, monitor); } } } if ( project != null && ProjectUtil.isHookProject( project ) ) { final HookDescriptorHelper hookDescriptor = new HookDescriptorHelper( project ); final String customJSPFolder = hookDescriptor.getCustomJSPFolder( null ); if ( customJSPFolder != null ) { final IWebProject webproject = LiferayCore.create( IWebProject.class, project ); if ( webproject != null && webproject.getDefaultDocrootFolder() != null) { final IFolder docFolder = webproject.getDefaultDocrootFolder(); final IPath newPath = Path.fromOSString( customJSPFolder ); final IPath pathValue = docFolder.getFullPath().append( newPath ); final boolean disableCustomJspValidation = LiferayMavenCore.getPreferenceBoolean( LiferayMavenCore.PREF_DISABLE_CUSTOM_JSP_VALIDATION ); if( disableCustomJspValidation ) { HookUtil.configureJSPSyntaxValidationExclude( project, project.getFolder( pathValue.makeRelativeTo( project.getFullPath() ) ), true ); } } } } monitor.worked( 25 ); monitor.done(); } private boolean shouldAddLiferayNature( MavenProject mavenProject, IFacetedProject facetedProject ) { return mavenProject.getPlugin( ILiferayMavenConstants.BND_MAVEN_PLUGIN_KEY ) != null || mavenProject.getPlugin( ILiferayMavenConstants.MAVEN_BUNDLE_PLUGIN_KEY ) != null || getLiferayProjectFacet( facetedProject ) != null; } public static IPath getThemeTargetFolder( MavenProject mavenProject, IProject project ) { return MavenUtil.getM2eLiferayFolder( mavenProject, project ).append( ILiferayMavenConstants.THEME_RESOURCES_FOLDER ); } public void configureClasspath( IMavenProjectFacade facade, IClasspathDescriptor classpath, IProgressMonitor monitor ) throws CoreException { } // Copied from org.eclipse.m2e.wtp.AbstractProjectConfiguratorDelegate#configureDeployedName() protected void configureDeployedName(IProject project, String deployedFileName) { //We need to remove the file extension from deployedFileName int extSeparatorPos = deployedFileName.lastIndexOf('.'); String deployedName = extSeparatorPos > -1? deployedFileName.substring(0, extSeparatorPos): deployedFileName; //From jerr's patch in MNGECLIPSE-965 IVirtualComponent projectComponent = ComponentCore.createComponent(project); if(projectComponent != null && !deployedName.equals(projectComponent.getDeployedName())){//MNGECLIPSE-2331 : Seems projectComponent.getDeployedName() can be null StructureEdit moduleCore = null; try { moduleCore = StructureEdit.getStructureEditForWrite(project); if (moduleCore != null){ WorkbenchComponent component = moduleCore.getComponent(); if (component != null) { component.setName(deployedName); moduleCore.saveIfNecessary(null); } } } finally { if (moduleCore != null) { moduleCore.dispose(); } } } } public void configureRawClasspath( ProjectConfigurationRequest request, IClasspathDescriptor classpath, IProgressMonitor monitor ) throws CoreException { } private List<MavenProblemInfo> findLiferayMavenPluginProblems( IProject project, ProjectConfigurationRequest request, IProgressMonitor monitor ) throws CoreException { final List<MavenProblemInfo> warnings = new ArrayList<MavenProblemInfo>(); // first check to make sure that the AppServer* properties are available and pointed to valid location final Plugin liferayMavenPlugin = MavenUtil.getPlugin( request.getMavenProjectFacade(), ILiferayMavenConstants.LIFERAY_MAVEN_PLUGIN_KEY, monitor ); if( liferayMavenPlugin != null ) { final Xpp3Dom config = (Xpp3Dom) liferayMavenPlugin.getConfiguration(); final MavenProblemInfo validLiferayProblemInfo = checkValidVersion( liferayMavenPlugin, config, ILiferayMavenConstants.PLUGIN_CONFIG_LIFERAY_VERSION ); if( validLiferayProblemInfo != null ) { warnings.add( validLiferayProblemInfo ); } final Version mavenPluginVersion = new Version( MavenUtil.getVersion( liferayMavenPlugin.getVersion() ) ); if( mavenPluginVersion == null || mavenPluginVersion.equals( ILiferayConstants.EMPTY_VERSION ) ) { // could not get valid version for liferaymavenPlugin final SourceLocation location = SourceLocationHelper.findLocation( liferayMavenPlugin, "version" ); final String problemMsg = NLS.bind( Msgs.invalidVersion, "liferay-maven-plugin", liferayMavenPlugin.getVersion() ); final MavenProblemInfo versionProblem = new MavenProblemInfo( problemMsg, IMarker.SEVERITY_WARNING, location ); warnings.add( versionProblem ); } final String[] configDirParams = new String[] { ILiferayMavenConstants.PLUGIN_CONFIG_APP_SERVER_PORTAL_DIR, }; for( final String configParam : configDirParams ) { final MavenProblemInfo configProblemInfo = checkValidConfigDir( liferayMavenPlugin, config, configParam ); if( configProblemInfo != null ) { warnings.add( configProblemInfo ); } } } return warnings; } private IProjectFacetVersion getLiferayProjectFacet( IFacetedProject facetedProject ) { IProjectFacetVersion retval = null; if( facetedProject != null ) { for( IProjectFacetVersion fv : facetedProject.getProjectFacets() ) { if( fv.getProjectFacet().getId().contains( "liferay." ) ) //$NON-NLS-1$ { retval = fv; break; } } } return retval; } private Action getNewLiferayFacetInstallAction( String pluginType ) { Action retval = null; IProjectFacetVersion newFacet = null; IDataModelProvider dataModel = null; if( ILiferayMavenConstants.PORTLET_PLUGIN_TYPE.equals( pluginType ) ) { newFacet = IPluginFacetConstants.LIFERAY_PORTLET_PROJECT_FACET.getDefaultVersion(); dataModel = new MavenPortletPluginFacetInstallProvider(); } else if( ILiferayMavenConstants.HOOK_PLUGIN_TYPE.equals( pluginType ) ) { newFacet = IPluginFacetConstants.LIFERAY_HOOK_PROJECT_FACET.getDefaultVersion(); dataModel = new MavenHookPluginFacetInstallProvider(); } else if( ILiferayMavenConstants.EXT_PLUGIN_TYPE.equals( pluginType ) ) { newFacet = IPluginFacetConstants.LIFERAY_EXT_PROJECT_FACET.getDefaultVersion(); dataModel = new MavenExtPluginFacetInstallProvider(); } else if( ILiferayMavenConstants.LAYOUTTPL_PLUGIN_TYPE.equals( pluginType ) ) { newFacet = IPluginFacetConstants.LIFERAY_LAYOUTTPL_PROJECT_FACET.getDefaultVersion(); dataModel = new MavenLayoutTplPluginFacetInstallProvider(); } else if( ILiferayMavenConstants.THEME_PLUGIN_TYPE.equals( pluginType ) ) { newFacet = IPluginFacetConstants.LIFERAY_THEME_PROJECT_FACET.getDefaultVersion(); dataModel = new MavenThemePluginFacetInstallProvider(); } else if( ILiferayMavenConstants.WEB_PLUGIN_TYPE.equals( pluginType ) ) { newFacet = IPluginFacetConstants.LIFERAY_WEB_PROJECT_FACET.getDefaultVersion(); dataModel = new MavenWebPluginFacetInstallProvider(); } if( newFacet != null ) { final IDataModel config = DataModelFactory.createDataModel( dataModel ); retval = new Action( Action.Type.INSTALL, newFacet, config ); } return retval; } private MavenProblemInfo installNewLiferayFacet( IFacetedProject facetedProject, ProjectConfigurationRequest request, IProgressMonitor monitor ) throws CoreException { MavenProblemInfo retval = null; String pluginType = MavenUtil.getLiferayMavenPluginType( request.getMavenProject() ); if( pluginType == null ) { pluginType = ILiferayMavenConstants.DEFAULT_PLUGIN_TYPE; } final Plugin liferayMavenPlugin = MavenUtil.getPlugin( request.getMavenProjectFacade(), ILiferayMavenConstants.LIFERAY_MAVEN_PLUGIN_KEY, monitor ); final Action action = getNewLiferayFacetInstallAction( pluginType ); if( action != null ) { try { facetedProject.modify( Collections.singleton( action ), monitor ); } catch( Exception e ) { try { final SourceLocation location = SourceLocationHelper.findLocation( liferayMavenPlugin, SourceLocationHelper.CONFIGURATION ); final String problemMsg = NLS.bind( Msgs.facetInstallError, pluginType, e.getCause() != null ? e.getCause().getMessage() : e.getMessage() ); retval = new MavenProblemInfo( location, e ); retval.setMessage( problemMsg ); } catch( Exception e1 ) { } LiferayMavenCore.logError( "Unable to install liferay facet " + action.getProjectFacetVersion(), e.getCause() ); //$NON-NLS-1$ } } return retval; } private void removeLiferayMavenMarkers( IProject project ) throws CoreException { this.mavenMarkerManager.deleteMarkers( project, ILiferayMavenConstants.LIFERAY_MAVEN_MARKER_CONFIGURATION_WARNING_ID ); } /* * IDE-1489 when no liferay maven plugin is found the project will be scanned for liferay specific files */ private boolean shouldConfigure( Plugin liferayMavenPlugin, ProjectConfigurationRequest request ) { final IProject project = request.getProject(); final MavenProject mavenProject = request.getMavenProject(); boolean configureAsLiferayPlugin = liferayMavenPlugin != null; final IFolder warSourceDir = warSourceDirectory( project, mavenProject ); if( !configureAsLiferayPlugin && warSourceDir != null ) { final IPath baseDir = warSourceDir.getRawLocation(); final String[] includes = { "**/liferay*.xml", "**/liferay*.properties" }; final DirectoryScanner dirScanner = new DirectoryScanner(); dirScanner.setBasedir( baseDir.toFile() ); dirScanner.setIncludes( includes ); dirScanner.scan(); final String[] liferayProjectFiles = dirScanner.getIncludedFiles(); configureAsLiferayPlugin = liferayProjectFiles != null && liferayProjectFiles.length > 0; } return configureAsLiferayPlugin; } private boolean shouldInstallNewLiferayFacet( MavenProject mavenProject, IFacetedProject facetedProject ) { return getLiferayProjectFacet( facetedProject ) == null; } private IFolder warSourceDirectory( final IProject project, final MavenProject mavenProject ) { IFolder retval = null; final Xpp3Dom warPluginConfiguration = (Xpp3Dom) mavenProject.getPlugin( MAVEN_WAR_PLUGIN_KEY ).getConfiguration(); if( warPluginConfiguration != null ) { final Xpp3Dom[] warSourceDirs = warPluginConfiguration.getChildren( "warSourceDirectory" ); if( warSourceDirs != null && warSourceDirs.length > 0 ) { final String resourceLocation = warSourceDirs[0].getValue(); retval = project.getFolder( resourceLocation ); } } if( retval == null ) { /* * if no explicit warSourceDirectory set we assume the default warSource directory * ${basedir}/src/main/webapp refer to http://maven.apache.org/plugins/maven-war-plugin/war-mojo.html * for more information */ retval = project.getFolder( WAR_SOURCE_FOLDER ); } return retval; } private static class Msgs extends NLS { public static String configuringLiferayProject; public static String emptyConfigValue; public static String facetInstallError; public static String invalidVersion; public static String missingConfigValue; public static String unusableConfigValue; static { initializeMessages( LiferayMavenProjectConfigurator.class.getName(), Msgs.class ); } } }