/****************************************************************************** * Copyright (c) 2010-2013, Linagora * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Linagora - initial API and implementation *******************************************************************************/ package com.ebmwebsourcing.petals.services.sa.nature; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import com.ebmwebsourcing.petals.common.internal.provisional.builder.JbiXmlBuilder; import com.ebmwebsourcing.petals.common.internal.provisional.builder.MarkerBean; import com.ebmwebsourcing.petals.common.internal.provisional.emf.InvalidJbiXmlException; import com.ebmwebsourcing.petals.common.internal.provisional.maven.MavenUtils; import com.ebmwebsourcing.petals.common.internal.provisional.preferences.PreferencesManager; import com.ebmwebsourcing.petals.common.internal.provisional.utils.JbiXmlUtils; import com.ebmwebsourcing.petals.common.internal.provisional.utils.PetalsConstants; import com.ebmwebsourcing.petals.services.PetalsServicesPlugin; import com.ebmwebsourcing.petals.services.utils.ServiceProjectRelationUtils; import com.sun.java.xml.ns.jbi.Jbi; import com.sun.java.xml.ns.jbi.ServiceUnit; /** * An incremental builder to validate jbi.xml files of SA projects. * @author Vincent Zurczak - EBM WebSourcing */ public class SaBuilder extends JbiXmlBuilder { /** * The ID of this builder. */ public static final String BUILDER_ID = "com.ebmwebsourcing.petals.services.saBuilder"; //$NON-NLS-1$ /* * (non-Javadoc) * @see org.eclipse.core.resources.IncrementalProjectBuilder * #startupOnInitialize() */ @Override protected void startupOnInitialize() { super.startupOnInitialize(); SaDependencyResourceListener.getInstance().registerSaProject( getProject()); } /** * Runs a full build. * @param monitor * @throws CoreException */ @Override protected void fullBuild( final IProgressMonitor monitor ) throws CoreException { // Build... try { clean( monitor ); getProject().accept( new SaResourceVisitor( monitor )); } catch( CoreException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } } /** * Runs an incremental build. * @param delta * @param monitor * @throws CoreException */ @Override protected void incrementalBuild( IResourceDelta delta, IProgressMonitor monitor) throws CoreException { delta.accept( new SaDeltaVisitor( monitor )); } /** * The delta visitor used for the incremental build. */ private class SaDeltaVisitor implements IResourceDeltaVisitor { private final IProgressMonitor monitor; /** * @param monitor */ public SaDeltaVisitor( IProgressMonitor monitor ) { this.monitor = monitor; } /* * (non-Javadoc) * @see org.eclipse.core.resources.IResourceDeltaVisitor * #visit(org.eclipse.core.resources.IResourceDelta) */ public boolean visit( IResourceDelta delta ) throws CoreException { // Check for cancellation. checkCancel( this.monitor ); // Get the resource. IResource resource = delta.getResource(); if( resource == null ) return false; // Do the job: check if the META-INF/jbi.xml file was modified and update project properties. boolean visitChildren = visitResource( resource ); if( this.monitor != null ) this.monitor.worked( 1 ); // Return true to continue visiting children. return visitChildren; } } /** * Checks whether this resource must be validated or not. * <p> * If the resource is a container, true is returned.<br /> * If the resource is a jbi.xml file, it is validated and marked if necessary.<br /> * Otherwise, the resource is ignored. * </p> * * @param resource the resource to check * @return true if children resources should be visited, false otherwise */ private boolean visitResource( IResource resource ) { if( resource instanceof IContainer ) return true; // We only want one the file "jbi.xml". if( resource instanceof IFile && "jbi.xml".equals( resource.getName())) //$NON-NLS-1$ validateAndMarkJbiXmlFile((IFile) resource); return false; } /** * The resource visitor for the full build. */ private class SaResourceVisitor implements IResourceVisitor { private final IProgressMonitor monitor; /** * @param monitor */ public SaResourceVisitor(IProgressMonitor monitor) { this.monitor = monitor; } /* * (non-Javadoc) * @see org.eclipse.core.resources.IResourceVisitor * #visit(org.eclipse.core.resources.IResource) */ public boolean visit( IResource resource ) { // Check for cancellation. checkCancel( this.monitor ); // Do the job: check if the META-INF/jbi.xml file was modified and update project properties. boolean visitChildren = visitResource( resource ); if( this.monitor != null ) this.monitor.worked( 1 ); // Return true to continue visiting children. return visitChildren; } } /** * Validates a jbi.xml file. * @param jbiXmlFile */ @Override protected List<MarkerBean> validate( IFile jbiXmlFile ) { // This builder can only work if the project has the SU nature // MM validation List<MarkerBean> markerBeans = super.validate( jbiXmlFile ); if( ! markerBeans.isEmpty()) return markerBeans; // Check the file position IFile expectedFile = null; try { expectedFile = JbiXmlUtils.getJbiXmlFile( jbiXmlFile.getProject()); } catch( FileNotFoundException e1 ) { // nothing } Jbi jbi = null; try { jbi = JbiXmlUtils.getJbiXmlModel( jbiXmlFile ); } catch( InvalidJbiXmlException e ) { // nothing } if( expectedFile == null || ! jbiXmlFile.equals( expectedFile )) { markerBeans.add( new MarkerBean( IMarker.SEVERITY_INFO, "This jbi.xml file is not placed at one of the expected locations (" + PetalsConstants.LOC_JBI_FILE + ").", jbi, jbiXmlFile )); } // Get the SU List<IProject> suDependencies = new ArrayList<IProject> (); if( jbi != null &&jbi.getServiceAssembly() != null && jbi.getServiceAssembly().getServiceUnit() != null ) { IWorkspaceRoot iwr = ResourcesPlugin.getWorkspace().getRoot(); for( ServiceUnit su : jbi.getServiceAssembly().getServiceUnit()) { String suName = su.getIdentification() != null ? su.getIdentification().getName() : ""; IProject p = iwr.getProject( suName ); if( ! p.exists()) { MarkerBean bean = new MarkerBean( IMarker.SEVERITY_WARNING, "No matching Service Unit project could be found in the workspace.", su, jbiXmlFile ); markerBeans.add( bean ); // Add the reference anyway (in case where the project would be imported later) suDependencies.add( p ); } else if( suDependencies.contains( p )) { MarkerBean bean = new MarkerBean( IMarker.SEVERITY_ERROR, "Duplicate reference to this Service Unit.", su, jbiXmlFile ); markerBeans.add( bean ); } else { // SU project? File suJbiXmlFile = p.getLocation().append( PetalsConstants.LOC_JBI_FILE ).toFile(); boolean isSu = suJbiXmlFile.exists() && JbiXmlUtils.describesServiceUnit( suJbiXmlFile ); if( ! isSu ) { MarkerBean bean = new MarkerBean( IMarker.SEVERITY_ERROR, "The referenced service unit is not a Service Unit project.", su, jbiXmlFile ); markerBeans.add( bean ); } else { // Referenced by several SA? if( ServiceProjectRelationUtils.isReferencedBySeveralSa( p )) { MarkerBean bean = new MarkerBean( IMarker.SEVERITY_INFO, "The service unit " + p.getName() + " is included into several Service Assembly projects.", su, jbiXmlFile ); markerBeans.add( bean ); } // Closed SU project? if( ! p.isAccessible()) { MarkerBean bean = new MarkerBean( IMarker.SEVERITY_INFO, "The service unit project " + p.getName() + " is closed and thus cannot be exported.", su, jbiXmlFile ); markerBeans.add( bean ); } } // Add the reference anyway (in case where the project would be imported later) suDependencies.add( p ); } } } // Add the dependencies IProgressMonitor monitor = new NullProgressMonitor(); try { IProjectDescription desc = jbiXmlFile.getProject().getDescription(); IProject[] projects = new IProject[ suDependencies.size()]; desc.setReferencedProjects( suDependencies.toArray( projects )); jbiXmlFile.getProject().setDescription( desc, monitor ); } catch( CoreException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } // Update the Maven dependencies if( PreferencesManager.regeneratePomAutomatically()) { // Granted permission => get the SU's POM List<File> suPoms = new ArrayList<File>( suDependencies.size()); for( IProject p : suDependencies ) { if( p.isAccessible()) { IFile pomFile = p.getFile( PetalsConstants.LOC_POM_FILE ); if( pomFile.exists()) suPoms.add( pomFile.getLocation().toFile()); } } // Update the SA's POM IFile saPomFile = jbiXmlFile.getProject().getFile( PetalsConstants.LOC_POM_FILE ); MavenUtils.setPomDependencies( saPomFile.getLocation().toFile(), suPoms ); try { saPomFile.refreshLocal( IResource.DEPTH_ZERO, monitor ); } catch( CoreException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } } return markerBeans; } }