/*******************************************************************************
* 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;
import com.liferay.ide.core.ILiferayConstants;
import com.liferay.ide.core.IWebProject;
import com.liferay.ide.core.LiferayCore;
import com.liferay.ide.core.util.CoreUtil;
import com.liferay.ide.core.util.StringPool;
import com.liferay.ide.project.core.util.ProjectUtil;
import com.liferay.ide.sdk.core.ISDKConstants;
import com.liferay.ide.server.util.ComponentUtil;
import com.liferay.ide.server.util.ServerUtil;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
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.jobs.Job;
import org.eclipse.jdt.core.ClasspathContainerInitializer;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.core.ClasspathEntry;
import org.eclipse.jst.common.jdt.internal.classpath.FlexibleProjectContainer;
import org.eclipse.jst.j2ee.internal.J2EEConstants;
import org.eclipse.jst.j2ee.internal.common.classpath.J2EEComponentClasspathContainerUtils;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.datamodel.properties.IAddReferenceDataModelProperties;
import org.eclipse.wst.common.componentcore.internal.operation.AddReferenceDataModelProvider;
import org.eclipse.wst.common.componentcore.internal.operation.RemoveReferenceDataModelProvider;
import org.eclipse.wst.common.componentcore.internal.resources.VirtualArchiveComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
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.IProjectFacet;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
/**
* @author Greg Amerson
* @author Simon Jiang
*/
@SuppressWarnings( "restriction" )
public class PluginPackageResourceListener implements IResourceChangeListener, IResourceDeltaVisitor
{
public static boolean isLiferayProject( IProject project )
{
boolean retval = false;
try
{
IFacetedProject facetedProject = ProjectFacetsManager.create( project );
if( facetedProject != null )
{
for( IProjectFacetVersion facet : facetedProject.getProjectFacets() )
{
IProjectFacet projectFacet = facet.getProjectFacet();
if( projectFacet.getId().startsWith( "liferay." ) ) //$NON-NLS-1$
{
retval = true;
break;
}
}
}
}
catch( CoreException e )
{
}
return retval;
}
public void resourceChanged( IResourceChangeEvent event )
{
if( event == null )
{
return;
}
try
{
event.getDelta().accept( this );
}
catch( Throwable e )
{
e.printStackTrace();
// ignore
}
}
protected boolean shouldProcessResourceChangedEvent( IResourceChangeEvent event )
{
if( event == null )
{
return false;
}
IResourceDelta delta = event.getDelta();
int deltaKind = delta.getKind();
if( deltaKind == IResourceDelta.REMOVED || deltaKind == IResourceDelta.REMOVED_PHANTOM )
{
return false;
}
return true;
}
protected boolean shouldProcessResourceDelta( IResourceDelta delta )
{
final IPath fullPath = delta.getFullPath();
if( fullPath.lastSegment() != null &&
fullPath.lastSegment().equals( ILiferayConstants.LIFERAY_PLUGIN_PACKAGE_PROPERTIES_FILE ) )
{
final IProject project = CoreUtil.getLiferayProject( delta.getResource() );
final IWebProject lrproject = LiferayCore.create( IWebProject.class, project );
if( lrproject != null )
{
final IResource propertiesFile =
lrproject.findDocrootResource( new Path( "WEB-INF/" +
ILiferayConstants.LIFERAY_PLUGIN_PACKAGE_PROPERTIES_FILE ) );
if( propertiesFile != null && propertiesFile.exists() )
{
final IPath filePath = propertiesFile.getFullPath();
if( filePath.equals( fullPath ) )
{
return true;
}
}
}
}
return false;
}
private IFile getWorkspaceFile( IPath path )
{
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IFile file = root.getFile( path );
if( !file.exists() )
{
file = root.getFileForLocation( path );
}
return file;
}
protected void addVirtualRef( IVirtualComponent rootComponent, IVirtualReference ref ) throws CoreException
{
processVirtualRef( rootComponent, ref, new AddReferenceDataModelProvider() );
}
protected boolean isLiferayPluginProject( IPath deltaPath )
{
IFile pluginPackagePropertiesFile = getWorkspaceFile( deltaPath );
if( pluginPackagePropertiesFile != null && pluginPackagePropertiesFile.exists() )
{
return isLiferayProject( pluginPackagePropertiesFile.getProject() );
}
return false;
}
protected IVirtualReference processContext( IVirtualComponent rootComponent, String context )
{
// first check for jar file
IFile serviceJar = ComponentUtil.findServiceJarForContext( context );
if( serviceJar == null )
{
return null;
}
IPath serviceJarPath = serviceJar.getFullPath();
if( rootComponent == null )
{
return null;
}
String type = VirtualArchiveComponent.LIBARCHIVETYPE + IPath.SEPARATOR;
IVirtualComponent archive =
ComponentCore.createArchiveComponent( rootComponent.getProject(), type +
serviceJarPath.makeRelative().toString() );
IVirtualReference ref =
ComponentCore.createReference( rootComponent, archive, new Path( J2EEConstants.WEB_INF_LIB ).makeAbsolute() );
ref.setArchiveName( serviceJarPath.lastSegment() );
return ref;
}
protected void processPortalDependencyTlds( Properties props, IProject project )
{
String portalDependencyTlds = props.getProperty( "portal-dependency-tlds" ); //$NON-NLS-1$
if( portalDependencyTlds != null )
{
String[] portalTlds = portalDependencyTlds.split( StringPool.COMMA );
IVirtualComponent comp = ComponentCore.createComponent( project );
if( comp != null )
{
IFolder webroot = (IFolder) comp.getRootFolder().getUnderlyingFolder();
final IFolder tldFolder = webroot.getFolder( "WEB-INF/tld" ); //$NON-NLS-1$
IPath portalDir = ServerUtil.getPortalDir( project );
final List<IPath> tldFilesToCopy = new ArrayList<IPath>();
if( portalDir != null )
{
for( String portalTld : portalTlds )
{
IFile tldFile = tldFolder.getFile( portalTld );
if( !tldFile.exists() )
{
IPath realPortalTld = portalDir.append( "WEB-INF/tld/" + portalTld ); //$NON-NLS-1$
if( realPortalTld.toFile().exists() )
{
tldFilesToCopy.add( realPortalTld );
}
}
}
}
if( tldFilesToCopy.size() > 0 )
{
new WorkspaceJob( "copy portal tlds" ) //$NON-NLS-1$
{
@Override
public IStatus runInWorkspace( IProgressMonitor monitor ) throws CoreException
{
CoreUtil.prepareFolder( tldFolder );
for( IPath tldFileToCopy : tldFilesToCopy )
{
IFile newTldFile = tldFolder.getFile( tldFileToCopy.lastSegment() );
try
{
newTldFile.create( new FileInputStream( tldFileToCopy.toFile() ), true, null );
}
catch( FileNotFoundException e )
{
throw new CoreException( ProjectCore.createErrorStatus( e ) );
}
}
return Status.OK_STATUS;
}
}.schedule();
}
}
}
}
protected void processRequiredDeploymentContexts( Properties props, IProject project )
{
final IVirtualComponent rootComponent = ComponentCore.createComponent( project );
if( rootComponent == null )
{
return;
}
final List<IVirtualReference> removeRefs = new ArrayList<IVirtualReference>();
final IClasspathContainer webAppLibrariesContainer =
J2EEComponentClasspathContainerUtils.getInstalledWebAppLibrariesContainer( project );
if( webAppLibrariesContainer == null )
{
return;
}
IClasspathEntry[] existingEntries = webAppLibrariesContainer.getClasspathEntries();
for( IClasspathEntry entry : existingEntries )
{
IPath path = entry.getPath();
String archiveName = path.lastSegment();
if( archiveName.endsWith( "-service.jar" ) ) //$NON-NLS-1$
{
IFile file = getWorkspaceFile( path );
if( file.exists() && ProjectUtil.isLiferayFacetedProject( file.getProject() ) )
{
for( IVirtualReference ref : rootComponent.getReferences() )
{
if( archiveName.equals( ref.getArchiveName() ) )
{
removeRefs.add( ref );
}
}
}
}
}
final List<IVirtualReference> addRefs = new ArrayList<IVirtualReference>();
String requiredDeploymenContexts = props.getProperty( "required-deployment-contexts" ); //$NON-NLS-1$
if( requiredDeploymenContexts != null )
{
String[] contexts = requiredDeploymenContexts.split( StringPool.COMMA );
if( !CoreUtil.isNullOrEmpty( contexts ) )
{
for( String context : contexts )
{
IVirtualReference ref = processContext( rootComponent, context );
if( ref != null )
{
addRefs.add( ref );
}
}
}
}
new WorkspaceJob( "Update virtual component." ) //$NON-NLS-1$
{
@Override
public IStatus runInWorkspace( IProgressMonitor monitor ) throws CoreException
{
updateVirtualComponent( rootComponent, removeRefs, addRefs );
updateWebClasspathContainer( rootComponent, addRefs );
return Status.OK_STATUS;
}
}.schedule();
}
protected void processResourceChanged( IResourceDelta delta ) throws CoreException
{
IPath deltaPath = delta.getFullPath();
final IFile pluginPackagePropertiesFile = getWorkspaceFile( deltaPath );
new WorkspaceJob( Msgs.processingPluginPackageResource )
{
@Override
public IStatus runInWorkspace( IProgressMonitor monitor ) throws CoreException
{
processPropertiesFile( pluginPackagePropertiesFile );
return Status.OK_STATUS;
}
}.schedule();
}
protected void processPropertiesFile( IFile pluginPackagePropertiesFile ) throws CoreException
{
IProject project = pluginPackagePropertiesFile.getProject();
IJavaProject javaProject = JavaCore.create( project );
IPath containerPath = null;
IClasspathEntry[] entries = javaProject.getRawClasspath();
for( IClasspathEntry entry : entries )
{
if( entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER )
{
if( entry.getPath().segment( 0 ).equals( PluginClasspathContainerInitializer.ID ) ||
entry.getPath().segment( 0 ).equals( SDKClasspathContainer.ID ))
{
containerPath = entry.getPath();
break;
}
}
}
if( containerPath != null )
{
IClasspathContainer classpathContainer = JavaCore.getClasspathContainer( containerPath, javaProject );
final String id = containerPath.segment( 0 );
if ( id.equals( PluginClasspathContainerInitializer.ID ) ||
id.equals( SDKClasspathContainer.ID ) )
{
ClasspathContainerInitializer initializer = JavaCore.getClasspathContainerInitializer( id );
initializer.requestClasspathContainerUpdate( containerPath, javaProject, classpathContainer );
}
}
Properties props = new Properties();
InputStream contents = null;
try
{
contents = pluginPackagePropertiesFile.getContents();
props.load( contents );
// processPortalDependencyTlds(props, pluginPackagePropertiesFile.getProject());
processRequiredDeploymentContexts( props, pluginPackagePropertiesFile.getProject() );
}
catch( Exception e )
{
ProjectCore.logError( e );
}
finally
{
if( contents != null )
{
try
{
contents.close();
}
catch( IOException e )
{
// ignore, this is best effort
}
}
}
}
protected void processVirtualRef(
IVirtualComponent rootComponent, IVirtualReference ref, IDataModelProvider provider ) throws CoreException
{
IDataModel dm = DataModelFactory.createDataModel( provider );
dm.setProperty( IAddReferenceDataModelProperties.SOURCE_COMPONENT, rootComponent );
dm.setProperty( IAddReferenceDataModelProperties.TARGET_REFERENCE_LIST, Arrays.asList( ref ) );
IStatus stat = dm.validateProperty( IAddReferenceDataModelProperties.TARGET_REFERENCE_LIST );
if( stat == null || ( !stat.isOK() ) )
{
throw new CoreException( stat );
}
try
{
dm.getDefaultOperation().execute( new NullProgressMonitor(), null );
}
catch( ExecutionException e )
{
ProjectCore.logError( e );
}
}
protected void removeVirtualRef( IVirtualComponent rootComponent, IVirtualReference ref ) throws CoreException
{
processVirtualRef( rootComponent, ref, new RemoveReferenceDataModelProvider() );
}
protected void updateVirtualComponent(
IVirtualComponent rootComponent, List<IVirtualReference> removeRefs, List<IVirtualReference> addRefs )
throws CoreException
{
for( IVirtualReference ref : removeRefs )
{
removeVirtualRef( rootComponent, ref );
}
for( IVirtualReference ref : addRefs )
{
addVirtualRef( rootComponent, ref );
}
}
protected void updateWebClasspathContainer( IVirtualComponent rootComponent, List<IVirtualReference> addRefs )
throws CoreException
{
IProject project = rootComponent.getProject();
IJavaProject javaProject = JavaCore.create( project );
FlexibleProjectContainer container =
J2EEComponentClasspathContainerUtils.getInstalledWebAppLibrariesContainer( project );
// If the container is present, refresh it
if( container == null )
{
return;
}
container.refresh();
// need to regrab this to get newest container
container = J2EEComponentClasspathContainerUtils.getInstalledWebAppLibrariesContainer( project );
if( container == null )
{
return;
}
IClasspathEntry[] webappEntries = container.getClasspathEntries();
for( IClasspathEntry entry : webappEntries )
{
String archiveName = entry.getPath().lastSegment();
for( IVirtualReference ref : addRefs )
{
if( ref.getArchiveName().equals( archiveName ) )
{
IFile referencedFile = (IFile) ref.getReferencedComponent().getAdapter( IFile.class );
IProject referencedFileProject = referencedFile.getProject();
// IDE-110 IDE-648
( (ClasspathEntry) entry ).sourceAttachmentPath =
referencedFileProject.getFolder( ISDKConstants.DEFAULT_DOCROOT_FOLDER + "/WEB-INF/service" ).getFullPath(); //$NON-NLS-1$
}
}
}
ClasspathContainerInitializer initializer =
JavaCore.getClasspathContainerInitializer( "org.eclipse.jst.j2ee.internal.web.container" ); //$NON-NLS-1$
initializer.requestClasspathContainerUpdate( container.getPath(), javaProject, container );
}
public boolean visit( final IResourceDelta delta ) throws CoreException
{
switch( delta.getResource().getType() )
{
case IResource.ROOT:
case IResource.PROJECT:
case IResource.FOLDER:
return true;
case IResource.FILE:
{
if( shouldProcessResourceDelta( delta ) )
{
Job job = new WorkspaceJob( Msgs.processingPluginPackageResource )
{
@Override
public IStatus runInWorkspace( IProgressMonitor monitor ) throws CoreException
{
final IResource resource = delta.getResource();
processPropertiesFile( (IFile) resource );
return Status.OK_STATUS;
}
};
job.setRule( CoreUtil.getWorkspaceRoot() );
job.schedule();
}
return false;
}
}
return false;
}
private static class Msgs extends NLS
{
public static String processingPluginPackageResource;
static
{
initializeMessages( PluginPackageResourceListener.class.getName(), Msgs.class );
}
}
}