/*******************************************************************************
* 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.project.ui.migration;
import com.liferay.blade.api.Migration;
import com.liferay.blade.api.MigrationConstants;
import com.liferay.blade.api.Problem;
import com.liferay.blade.api.ProgressMonitor;
import com.liferay.ide.core.util.FileUtil;
import com.liferay.ide.core.util.MarkerUtil;
import com.liferay.ide.project.core.upgrade.FileProblems;
import com.liferay.ide.project.core.upgrade.FileProblemsUtil;
import com.liferay.ide.project.core.upgrade.IgnoredProblemsContainer;
import com.liferay.ide.project.core.upgrade.MigrationProblems;
import com.liferay.ide.project.core.upgrade.UpgradeAssistantSettingsUtil;
import com.liferay.ide.project.core.upgrade.UpgradeProblems;
import com.liferay.ide.project.core.util.ProjectUtil;
import com.liferay.ide.project.ui.ProjectUI;
import com.liferay.ide.project.ui.upgrade.animated.FindBreakingChangesPage;
import com.liferay.ide.project.ui.upgrade.animated.Page;
import com.liferay.ide.project.ui.upgrade.animated.UpgradeView;
import com.liferay.ide.ui.util.UIUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
/**
* @author Gregory Amerson
* @author Andy Wu
* @author Lovett Li
* @author Terry Jia
*/
@SuppressWarnings( "unchecked" )
public class MigrateProjectHandler extends AbstractHandler
{
private String[] ignoreSuperClasses =
{ "com.liferay.portal.service.BaseLocalServiceImpl", "com.liferay.portal.model.CacheModel",
"com.liferay.portal.model.impl.BaseModelImpl", "com.liferay.portal.service.BaseServiceImpl",
"com.liferay.portal.service.persistence.impl.BasePersistenceImpl" };
@Override
public Object execute( ExecutionEvent event ) throws ExecutionException
{
ISelection selection = HandlerUtil.getCurrentSelection( event );
if( selection instanceof IStructuredSelection )
{
Object element = null;
if( ( (IStructuredSelection) selection ).size() > 1 )
{
element = ( (IStructuredSelection) selection ).toArray();
}
else
{
element = ( (IStructuredSelection) selection ).getFirstElement();
}
IProject project = null;
IProject[] projects = null;
if( element instanceof IProject )
{
project = (IProject) element;
}
else if( element instanceof IAdaptable )
{
IAdaptable adaptable = (IAdaptable) element;
project = (IProject) adaptable.getAdapter( IProject.class );
}
else if( element instanceof Object[] )
{
projects = Arrays.copyOf( (Object[]) element, ( (Object[]) element ).length, IProject[].class );
}
if( project != null )
{
if( shouldShowMessageDialog( project ) )
{
final boolean shouldContinue = showMessageDialog( project );
if( !shouldContinue )
{
return null;
}
MarkerUtil.clearMarkers( project, MigrationConstants.MARKER_TYPE, null );
}
final IPath location = project.getLocation();
findMigrationProblems( new IPath[] { location }, new String[] { project.getName() } );
}
else if( projects != null )
{
final List<IPath> locations = new ArrayList<>();
final List<String> projectNames = new ArrayList<>();
boolean shouldContinue = false;
for( IProject iProject : projects )
{
if( shouldContinue == false && shouldShowMessageDialog( iProject ) )
{
shouldContinue = showMessageDialog( project );
if( !shouldContinue )
{
return null;
}
}
if( shouldContinue && shouldShowMessageDialog( iProject ) )
{
MarkerUtil.clearMarkers( iProject, MigrationConstants.MARKER_TYPE, null );
}
locations.add( iProject.getLocation() );
projectNames.add( iProject.getName() );
}
findMigrationProblems( locations.toArray( new IPath[0] ), projectNames.toArray( new String[0] ) );
}
}
return null;
}
public void findMigrationProblems( final IPath[] locations )
{
findMigrationProblems( locations, new String[] { "" } );
}
public void findMigrationProblems( final IPath[] locations, final String[] projectName )
{
Job job = new WorkspaceJob( "Finding migration problems..." )
{
@Override
public IStatus runInWorkspace( final IProgressMonitor monitor ) throws CoreException
{
IStatus retval = Status.OK_STATUS;
final BundleContext context = FrameworkUtil.getBundle( this.getClass() ).getBundleContext();
ProgressMonitor override = new ProgressMonitor()
{
@Override
public void worked( int work )
{
monitor.worked( work );
}
@Override
public void setTaskName( String taskName )
{
monitor.setTaskName( taskName );
}
@Override
public boolean isCanceled()
{
return monitor.isCanceled();
}
@Override
public void done()
{
monitor.done();
}
@Override
public void beginTask( String taskName, int totalWork )
{
monitor.beginTask( taskName, totalWork );
}
};
try
{
final ServiceReference<Migration> sr = context.getServiceReference( Migration.class );
final Migration m = context.getService( sr );
List<Problem> allProblems = null;
boolean isSingleFile =
locations.length == 1 && locations[0].toFile().exists() && locations[0].toFile().isFile();
for( int j = 0; j < locations.length; j++ )
{
allProblems = new ArrayList<>();
if( !override.isCanceled() )
{
List<Problem> problems = null;
if( isSingleFile )
{
clearFileMarkers( locations[j].toFile() );
Set<File> files = new HashSet<>();
files.add( locations[j].toFile() );
problems = m.findProblems( files, override );
}
else
{
problems = m.findProblems( locations[j].toFile(), override );
}
for( Problem problem : problems )
{
if( shouldAdd( problem ) )
{
allProblems.add( problem );
}
}
}
MigrationProblemsContainer container = null;
container = UpgradeAssistantSettingsUtil.getObjectFromStore( MigrationProblemsContainer.class );
MigrationProblems[] migrationProblemsArray = null;
List<MigrationProblems> migrationProblemsList = new ArrayList<MigrationProblems>();
if( container == null )
{
container = new MigrationProblemsContainer();
}
if( container.getProblemsArray() != null )
{
migrationProblemsArray = container.getProblemsArray();
}
if( migrationProblemsArray != null )
{
List<MigrationProblems> mpList = Arrays.asList( migrationProblemsArray );
for( MigrationProblems mp : mpList )
{
migrationProblemsList.add( mp );
}
}
if( allProblems.size() > 0 )
{
MigrationProblems migrationProblems = new MigrationProblems();
List<FileProblems> fileProblemsList =
FileProblemsUtil.newFileProblemsListFrom( allProblems.toArray( new Problem[0] ) );
migrationProblems.setProblems( fileProblemsList.toArray( new FileProblems[0] ) );
migrationProblems.setType( "Code Problems" );
migrationProblems.setSuffix( projectName[j] );
int index = isAlreadyExist( migrationProblemsList, projectName, j );
if( index != -1 )
{
if( isSingleFile )
{
UpgradeProblems up = migrationProblemsList.get( index );
FileProblems[] problems = up.getProblems();
for( int n = 0; n < problems.length; n++ )
{
FileProblems fp = problems[n];
if( fp.getFile().getPath().equals( locations[0].toFile().getPath() ) )
{
problems[n] = fileProblemsList.get( 0 );
break;
}
}
migrationProblems.setProblems( problems );
}
migrationProblemsList.set( index, migrationProblems );
}
else
{
migrationProblemsList.add( migrationProblems );
}
}
else
{
int index = isAlreadyExist( migrationProblemsList, projectName, j );
if( index != -1 )
{
if( isSingleFile )
{
MigrationProblems mp = migrationProblemsList.get( index );
FileProblems[] fps = mp.getProblems();
List<FileProblems> fpList = Arrays.asList( fps );
List<FileProblems> newFPList = new ArrayList<>();
for( FileProblems fp : fpList )
{
if( !fp.getFile().getPath().equals( locations[0].toFile().getPath() ) )
{
newFPList.add( fp );
}
}
mp.setProblems( newFPList.toArray( new FileProblems[0] ) );
migrationProblemsList.set( index, mp );
}
else
{
migrationProblemsList.remove( index );
}
}
}
if( migrationProblemsList.size() > 0 )
{
container.setProblemsArray( migrationProblemsList.toArray( new MigrationProblems[0] ) );
UpgradeAssistantSettingsUtil.setObjectToStore( MigrationProblemsContainer.class, container );
}
else
{
UpgradeAssistantSettingsUtil.setObjectToStore( MigrationProblemsContainer.class, null );
}
}
if( isSingleFile )
{
refreshViewer(allProblems);
}
else
{
allProblems.add( new Problem() );
m.reportProblems( allProblems, Migration.DETAIL_LONG, "ide" );
}
}
catch( Exception e )
{
retval = ProjectUI.createErrorStatus( "Error in migrate command", e );
}
return retval;
}
};
try
{
PlatformUI.getWorkbench().getProgressService().showInDialog( Display.getDefault().getActiveShell(), job );
}
catch( Exception e )
{
}
job.schedule();
}
private boolean showMessageDialog( IProject project )
{
final Display display = Display.getDefault();
final Shell shell = display.getActiveShell();
return MessageDialog.openConfirm(
shell, "Migrate Liferay Plugin",
"This project already contains migration problem markers. All existing markers will be deleted. " +
"Do you want to continue to run migration tool?" );
}
private boolean shouldShowMessageDialog( IProject project )
{
final IMarker[] markers = MarkerUtil.findMarkers( project, MigrationConstants.MARKER_TYPE, null );
return markers != null && markers.length > 0;
}
private boolean shouldAdd( Problem problem )
{
String path = problem.getFile().getAbsolutePath().replaceAll( "\\\\", "/" );
if( path.contains( "WEB-INF/classes" ) || path.contains( "WEB-INF/service" ) )
{
return false;
}
IgnoredProblemsContainer ignoredProblemsContainer = MigrationUtil.getIgnoredProblemsContainer();
if( ignoredProblemsContainer != null )
{
Set<String> ticketSet = ignoredProblemsContainer.getProblemMap().keySet();
if( ticketSet != null && ticketSet.contains( problem.getTicket() ) )
{
final IResource resource = MigrationUtil.getIResourceFromProblem( problem );
final IMarker marker = resource.getMarker( problem.getMarkerId() );
if( marker.exists() )
{
try
{
marker.delete();
}
catch( CoreException e )
{
ProjectUI.logError( e );
}
}
return false;
}
}
if( path.endsWith( "java" ) )
{
CompilationUnit ast =
CUCache.getCU( problem.getFile(), FileUtil.readContents( problem.getFile() ).toCharArray() );
Name superClass = ( (TypeDeclaration) ast.types().get( 0 ) ).getSuperclass();
if( superClass != null )
{
return !checkClassIgnore( ast, superClass.toString() );
}
List<ASTNode> interfaces = ( (TypeDeclaration) ast.types().get( 0 ) ).superInterfaces();
if( interfaces != null )
{
for( ASTNode n : interfaces )
{
String name = n.toString();
if( checkClassIgnore( ast, name ) )
{
return false;
}
}
}
}
return true;
}
private boolean checkClassIgnore( CompilationUnit ast, String className )
{
List<ImportDeclaration> importDeclarationList = ast.imports();
if( importDeclarationList != null )
{
String fullClassName = "";
for( ImportDeclaration importDeclaration : importDeclarationList )
{
String importName = importDeclaration.getName().toString();
if( importName.endsWith( className ) )
{
fullClassName = importName;
break;
}
}
if( !fullClassName.equals( "" ) )
{
for( String ignoreSuperClass : ignoreSuperClasses )
{
if( ignoreSuperClass.equals( fullClassName ) )
{
return true;
}
}
}
}
return false;
}
private int isAlreadyExist(
List<MigrationProblems> migrationProblemsList, String[] projectName, int projectIndex )
{
int index = -1;
for( int i = 0; i < migrationProblemsList.size(); i++ )
{
UpgradeProblems upgradeProblems = migrationProblemsList.get( i );
if( ( (MigrationProblems) upgradeProblems ).getSuffix().equals( projectName[projectIndex] ) )
{
index = i;
break;
}
}
return index;
}
private void clearFileMarkers( File file )
{
IProject[] projects = ProjectUtil.getAllPluginsSDKProjects();
for( IProject project : projects )
{
String filePath = file.getPath().replaceAll( "\\\\", "/" );
String projectPath = project.getLocation().toString();
if( filePath.startsWith( projectPath ) )
{
int i = filePath.indexOf( projectPath ) + projectPath.length();
String projectFilePath = filePath.substring( i, filePath.length() );
IFile projectFile = project.getFile( projectFilePath );
if( projectFile.exists() )
{
MarkerUtil.clearMarkers( projectFile, MigrationConstants.MARKER_TYPE, null );
}
break;
}
}
}
protected void refreshViewer(List<Problem> allProblems)
{
FindBreakingChangesPage page = UpgradeView.getPage(Page.FINDBREACKINGCHANGES_PAGE_ID,FindBreakingChangesPage.class);
TableViewer problemsViewer = page.get_problemsViewer();
TreeViewer treeViewer = page.getTreeViewer();
UIUtil.async( new Runnable()
{
@Override
public void run()
{
problemsViewer.setInput( allProblems );
Object currentTreeNode = treeViewer.getStructuredSelection().getFirstElement();
String currentPath = null;
if( currentTreeNode instanceof FileProblems )
{
FileProblems currentNode = (FileProblems) currentTreeNode;
currentPath = currentNode.getFile().getAbsolutePath().toString();
}
MigrationContentProvider contentProvider = (MigrationContentProvider) treeViewer.getContentProvider();
MigrationProblemsContainer mc = (MigrationProblemsContainer) contentProvider._problems.get( 0 );
for( MigrationProblems project : mc.getProblemsArray() )
{
Iterator<FileProblems> fileProblemItertor = new LinkedList<FileProblems>(Arrays.asList( project.getProblems() )).iterator();
while( fileProblemItertor.hasNext())
{
FileProblems fileProblem = fileProblemItertor.next();
if( fileProblem.getFile().getAbsolutePath().toString().equals( currentPath ) )
{
fileProblem.getProblems().clear();
fileProblem.getProblems().addAll( allProblems );
break;
}
}
}
}
} );
}
}