/*******************************************************************************
* 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.core.modules;
import com.liferay.ide.core.util.CoreUtil;
import com.liferay.ide.core.util.FileUtil;
import com.liferay.ide.project.core.NewLiferayProjectProvider;
import com.liferay.ide.project.core.ProjectCore;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IResource;
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.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jface.text.Document;
import org.eclipse.sapphire.ElementList;
import org.eclipse.sapphire.modeling.ProgressMonitor;
import org.eclipse.sapphire.modeling.Status;
import org.eclipse.sapphire.platform.PathBridge;
import org.eclipse.sapphire.platform.ProgressMonitorBridge;
import org.eclipse.sapphire.platform.StatusBridge;
import org.eclipse.text.edits.TextEdit;
/**
* @author Simon Jiang
* @author Lovett Li
*/
public class NewLiferayModuleProjectOpMethods
{
public static final Status execute( final NewLiferayModuleProjectOp op, final ProgressMonitor pm )
{
final IProgressMonitor monitor = ProgressMonitorBridge.create( pm );
monitor.beginTask( "Creating Liferay module project (this process may take several minutes)", 100 ); //$NON-NLS-1$
Status retval = null;
try
{
final NewLiferayProjectProvider<NewLiferayModuleProjectOp> projectProvider = op.getProjectProvider().content( true );
final IStatus status = projectProvider.createNewProject( op, monitor );
retval = StatusBridge.create( status );
final String projectName = op.getProjectName().content();
final String className = op.getComponentName().content();
final String packageName = op.getPackageName().content();
final String projectTemplateName = op.getProjectTemplateName().content();
IPath location = PathBridge.create( op.getLocation().content() );
IPath projectLocation = location;
final String lastSegment = location.lastSegment();
if( location != null && location.segmentCount() > 0 )
{
if( !lastSegment.equals( projectName ) )
{
projectLocation = location.append( projectName );
}
}
final List<IPath> finalClassPaths = getClassFilePath( projectName, className, packageName, projectTemplateName, projectLocation );
for( IPath classFilePath : finalClassPaths )
{
final File finalClassFile = classFilePath.toFile();
if( finalClassFile.exists() )
{
ElementList<PropertyKey> propertyKeys = op.getPropertyKeys();
final List<String> properties = new ArrayList<String>();
for( PropertyKey propertyKey : propertyKeys )
{
properties.add( propertyKey.getName().content( true ) + "=" + propertyKey.getValue().content( true ) );
}
NewLiferayModuleProjectOpMethods.addProperties( finalClassFile, properties );
CoreUtil.getProject( op.getProjectName().content() ).refreshLocal( IResource.DEPTH_INFINITE, monitor );
}
}
if( retval.ok() )
{
updateBuildPrefs( op );
}
}
catch( Exception e )
{
final String msg = "Error creating Liferay module project."; //$NON-NLS-1$
ProjectCore.logError( msg, e );
return Status.createErrorStatus( msg + " " + e.getMessage(), e );
}
return retval;
}
private static void updateBuildPrefs( final NewLiferayModuleProjectOp op )
{
try
{
final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode( ProjectCore.PLUGIN_ID );
prefs.put( ProjectCore.PREF_DEFAULT_MODULE_PROJECT_BUILD_TYPE_OPTION, op.getProjectProvider().text() );
prefs.flush();
}
catch( Exception e )
{
final String msg = "Error updating default project build type."; //$NON-NLS-1$
ProjectCore.logError( msg, e );
}
}
private static void getClassFile( File packageRoot, List<IPath> classFiles )
{
File[] children = packageRoot.listFiles();
if( children != null && children.length > 0 )
{
for( File child : children )
{
if( child.isDirectory() )
{
getClassFile( child, classFiles );
}
else
{
try
{
boolean hasComponentAnnotation = checkComponentAnnotation( child.getAbsoluteFile() );
if( hasComponentAnnotation )
{
classFiles.add( new Path( child.getAbsolutePath() ) );
}
}
catch( Exception e )
{
ProjectCore.logError( e );;
}
}
}
}
}
private static List<IPath> getClassFilePath(
final String projectName, String className, final String packageName, final String projectTemplateName,
IPath projecLocation )
{
IPath packageNamePath = projecLocation.append( "src/main/java" );
File packageRoot = packageNamePath.toFile();
List<IPath> classFiles = new ArrayList<IPath>();
getClassFile( packageRoot, classFiles );
return classFiles;
}
public static String getMavenParentPomGroupId( NewLiferayModuleProjectOp op, String projectName, IPath path )
{
String retval = null;
final File parentProjectDir = path.toFile();
final IStatus locationStatus = op.getProjectProvider().content().validateProjectLocation( projectName, path );
if( locationStatus.isOK() && parentProjectDir.exists() && parentProjectDir.list().length > 0 )
{
List<String> groupId =
op.getProjectProvider().content().getData( "parentGroupId", String.class, parentProjectDir );
if( !CoreUtil.isNullOrEmpty( groupId ) )
{
retval = groupId.get( 0 );
}
}
return retval;
}
public static String getMavenParentPomVersion( NewLiferayModuleProjectOp op, String projectName, IPath path )
{
String retval = null;
final File parentProjectDir = path.toFile();
final IStatus locationStatus = op.getProjectProvider().content().validateProjectLocation( projectName, path );
if( locationStatus.isOK() && parentProjectDir.exists() && parentProjectDir.list().length > 0 )
{
List<String> version =
op.getProjectProvider().content().getData( "parentVersion", String.class, parentProjectDir );
if( !CoreUtil.isNullOrEmpty( version ) )
{
retval = version.get( 0 );
}
}
return retval;
}
private static class CheckComponentAnnotationVistor extends ASTVisitor
{
public CheckComponentAnnotationVistor()
{
super();
}
private boolean hasComponentAnnotation = false;
@Override
public boolean visit( NormalAnnotation node )
{
if( node.getTypeName().getFullyQualifiedName().equals( "Component" ) )
{
hasComponentAnnotation = true;
}
return super.visit( node );
}
public boolean hasComponentAnnotation()
{
return this.hasComponentAnnotation;
}
}
public static boolean checkComponentAnnotation( File dest ) throws Exception
{
try
{
ASTParser parser = ASTParser.newParser( AST.JLS8 );
String readContents = FileUtil.readContents( dest, true );
parser.setSource( readContents.toCharArray() );
parser.setKind( ASTParser.K_COMPILATION_UNIT );
parser.setResolveBindings( true );
final CompilationUnit cu = (CompilationUnit) parser.createAST( new NullProgressMonitor() );
CheckComponentAnnotationVistor componentAnnotationVistor = new CheckComponentAnnotationVistor();
cu.accept( componentAnnotationVistor );
return componentAnnotationVistor.hasComponentAnnotation();
}
catch( Exception e )
{
ProjectCore.logError( "error when adding properties to " + dest.getAbsolutePath(), e );
}
return false;
}
@SuppressWarnings( "unchecked" )
public static void addProperties( File dest, List<String> properties ) throws Exception
{
try
{
if( properties == null || properties.size() < 1 )
{
return;
}
ASTParser parser = ASTParser.newParser( AST.JLS8 );
String readContents = FileUtil.readContents( dest, true );
parser.setSource( readContents.toCharArray() );
parser.setKind( ASTParser.K_COMPILATION_UNIT );
parser.setResolveBindings( true );
final CompilationUnit cu = (CompilationUnit) parser.createAST( new NullProgressMonitor() );
cu.recordModifications();
Document document = new Document( new String( readContents ) );
cu.accept( new ASTVisitor()
{
@Override
public boolean visit( NormalAnnotation node )
{
if( node.getTypeName().getFullyQualifiedName().equals( "Component" ) )
{
ASTRewrite rewrite = ASTRewrite.create( cu.getAST() );
AST ast = cu.getAST();
List<ASTNode> values = node.values();
boolean hasProperty = false;
for( ASTNode astNode : values )
{
if( astNode instanceof MemberValuePair )
{
MemberValuePair pairNode = (MemberValuePair) astNode;
if( pairNode.getName().getFullyQualifiedName().equals( "property" ) )
{
Expression express = pairNode.getValue();
if( express instanceof ArrayInitializer )
{
ListRewrite lrw =
rewrite.getListRewrite( express, ArrayInitializer.EXPRESSIONS_PROPERTY );
ArrayInitializer initializer = (ArrayInitializer) express;
List<ASTNode> expressions = (List<ASTNode>) initializer.expressions();
ASTNode propertyNode = null;
for( int i = properties.size() - 1; i >= 0; i-- )
{
StringLiteral stringLiteral = ast.newStringLiteral();
stringLiteral.setLiteralValue( properties.get( i ) );
if( expressions.size() > 0 )
{
propertyNode = expressions.get( expressions.size() - 1 );
lrw.insertAfter( stringLiteral, propertyNode, null );
}
else
{
lrw.insertFirst( stringLiteral, null );
}
}
}
hasProperty = true;
}
}
}
if( hasProperty == false )
{
ListRewrite clrw = rewrite.getListRewrite( node, NormalAnnotation.VALUES_PROPERTY );
ASTNode lastNode = values.get( values.size() - 1 );
ArrayInitializer newArrayInitializer = ast.newArrayInitializer();
MemberValuePair propertyMemberValuePair = ast.newMemberValuePair();
propertyMemberValuePair.setName( ast.newSimpleName( "property" ) );
propertyMemberValuePair.setValue( newArrayInitializer );
clrw.insertBefore( propertyMemberValuePair, lastNode, null );
ListRewrite newLrw =
rewrite.getListRewrite( newArrayInitializer, ArrayInitializer.EXPRESSIONS_PROPERTY );
for( String property : properties )
{
StringLiteral stringLiteral = ast.newStringLiteral();
stringLiteral.setLiteralValue( property );
newLrw.insertAt( stringLiteral, 0, null );
}
}
try(FileOutputStream fos = new FileOutputStream( dest ))
{
TextEdit edits = rewrite.rewriteAST( document, null );
edits.apply( document );
fos.write( document.get().getBytes() );
fos.flush();
}
catch( Exception e )
{
ProjectCore.logError( e );
}
}
return super.visit( node );
}
} );
}
catch( Exception e )
{
ProjectCore.logError( "error when adding properties to " + dest.getAbsolutePath(), e );
}
}
}